View | Details | Raw Unified | Return to bug 155423
Collapse All | Expand All

(-)src/org/eclipse/jdt/core/tests/compiler/regression/FlowAnalysisTest.java (+254 lines)
Lines 10-19 Link Here
10
 *******************************************************************************/
10
 *******************************************************************************/
11
package org.eclipse.jdt.core.tests.compiler.regression;
11
package org.eclipse.jdt.core.tests.compiler.regression;
12
12
13
import java.io.File;
14
import java.io.IOException;
13
import java.util.Map;
15
import java.util.Map;
14
16
17
import org.eclipse.jdt.core.ToolFactory;
15
import org.eclipse.jdt.core.compiler.CategorizedProblem;
18
import org.eclipse.jdt.core.compiler.CategorizedProblem;
16
import org.eclipse.jdt.core.compiler.IProblem;
19
import org.eclipse.jdt.core.compiler.IProblem;
20
import org.eclipse.jdt.core.tests.util.Util;
21
import org.eclipse.jdt.core.util.ClassFileBytesDisassembler;
17
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
22
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
18
import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
23
import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
19
import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
24
import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
Lines 777-782 Link Here
777
		},
782
		},
778
		"s-s-s-s-s-s-s-s-s-s-s-s-s-s-s-");
783
		"s-s-s-s-s-s-s-s-s-s-s-s-s-s-s-");
779
}
784
}
785
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=155423
786
public void test028() {
787
	this.runConformTest(
788
		new String[] {
789
			"X.java",
790
			"public class X {\n" + 
791
			"   {\n" + 
792
			"      if (true) throw new NullPointerException();\n" + 
793
			"   }\n" + 
794
			"}\n" // =================
795
		},
796
		"");
797
	// check no default return opcode is appended
798
	String expectedOutput =
799
		"  public X();\n" + 
800
		"     0  aload_0 [this]\n" + 
801
		"     1  invokespecial java.lang.Object() [8]\n" + 
802
		"     4  new java.lang.NullPointerException [10]\n" + 
803
		"     7  dup\n" + 
804
		"     8  invokespecial java.lang.NullPointerException() [12]\n" + 
805
		"    11  athrow\n" + 
806
		"      Line numbers:\n" + 
807
		"        [pc: 0, line: 1]\n" + 
808
		"        [pc: 4, line: 3]\n" + 
809
		"      Local variable table:\n" + 
810
		"        [pc: 0, pc: 12] local: this index: 0 type: X\n";
811
	
812
	try {
813
		File f = new File(OUTPUT_DIR + File.separator + "X.class");
814
		byte[] classFileBytes = org.eclipse.jdt.internal.compiler.util.Util.getFileByteContent(f);
815
		ClassFileBytesDisassembler disassembler = ToolFactory.createDefaultClassFileBytesDisassembler();
816
		String result = disassembler.disassemble(classFileBytes, "\n", ClassFileBytesDisassembler.DETAILED);
817
		int index = result.indexOf(expectedOutput);
818
		if (index == -1 || expectedOutput.length() == 0) {
819
			System.out.println(Util.displayString(result, 3));
820
		}
821
		if (index == -1) {
822
			assertEquals("Wrong contents", expectedOutput, result);
823
		}
824
	} catch (org.eclipse.jdt.core.util.ClassFormatException e) {
825
		assertTrue(false);
826
	} catch (IOException e) {
827
		assertTrue(false);
828
	}	
829
}
830
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=155423 - variation
831
public void test029() {
832
	this.runConformTest(
833
		new String[] {
834
			"X.java",
835
			"public class X {\n" + 
836
			"   {\n" + 
837
			"      if (true) throw new NullPointerException();\n" + 
838
			"   }\n" + 
839
			"   X() {\n" + 
840
			"      System.out.println();\n" + 
841
			"   }\n" + 
842
			"}\n", // =================
843
		},
844
		"");
845
	// check no default return opcode is appended
846
	String expectedOutput =
847
		"  // Method descriptor #6 ()V\n" + 
848
		"  // Stack: 2, Locals: 1\n" + 
849
		"  X();\n" + 
850
		"     0  aload_0 [this]\n" + 
851
		"     1  invokespecial java.lang.Object() [8]\n" + 
852
		"     4  new java.lang.NullPointerException [10]\n" + 
853
		"     7  dup\n" + 
854
		"     8  invokespecial java.lang.NullPointerException() [12]\n" + 
855
		"    11  athrow\n" + 
856
		"      Line numbers:\n" + 
857
		"        [pc: 0, line: 5]\n" + 
858
		"        [pc: 4, line: 3]\n" + 
859
		"      Local variable table:\n" + 
860
		"        [pc: 0, pc: 12] local: this index: 0 type: X\n";
861
	
862
	try {
863
		File f = new File(OUTPUT_DIR + File.separator + "X.class");
864
		byte[] classFileBytes = org.eclipse.jdt.internal.compiler.util.Util.getFileByteContent(f);
865
		ClassFileBytesDisassembler disassembler = ToolFactory.createDefaultClassFileBytesDisassembler();
866
		String result = disassembler.disassemble(classFileBytes, "\n", ClassFileBytesDisassembler.DETAILED);
867
		int index = result.indexOf(expectedOutput);
868
		if (index == -1 || expectedOutput.length() == 0) {
869
			System.out.println(Util.displayString(result, 3));
870
		}
871
		if (index == -1) {
872
			assertEquals("Wrong contents", expectedOutput, result);
873
		}
874
	} catch (org.eclipse.jdt.core.util.ClassFormatException e) {
875
		assertTrue(false);
876
	} catch (IOException e) {
877
		assertTrue(false);
878
	}	
879
}
880
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=155423 - variation
881
public void test030() {
882
	this.runConformTest(
883
		new String[] {
884
			"X.java",
885
			"class Y {\n" + 
886
			"	Y(Object o) {\n" + 
887
			"		System.out.print(o);\n" + 
888
			"	}\n" + 
889
			"}\n" + 
890
			"\n" + 
891
			"public class X extends Y {\n" + 
892
			"	{\n" + 
893
			"		if (true)\n" + 
894
			"			throw new NullPointerException();\n" + 
895
			"	}\n" + 
896
			"\n" + 
897
			"	X() {\n" + 
898
			"		super(new Object() {\n" + 
899
			"			public String toString() {\n" + 
900
			"				return \"SUCCESS:\";\n" + 
901
			"			}\n" + 
902
			"		});\n" + 
903
			"		System.out.println();\n" + 
904
			"	}\n" + 
905
			"	public static void main(String[] args) {\n" + 
906
			"		try {\n" + 
907
			"			new X();\n" + 
908
			"		} catch(NullPointerException e) {\n" + 
909
			"			System.out.println(\"caught:NPE\");\n" + 
910
			"		}\n" + 
911
			"	}\n" + 
912
			"}\n", // =================
913
		},
914
		"SUCCESS:caught:NPE");
915
	// check no default return opcode is appended
916
	String expectedOutput =
917
		"  // Method descriptor #6 ()V\n" + 
918
		"  // Stack: 3, Locals: 1\n" + 
919
		"  X();\n" + 
920
		"     0  aload_0 [this]\n" + 
921
		"     1  new X$1 [8]\n" + 
922
		"     4  dup\n" + 
923
		"     5  invokespecial X$1() [10]\n" + 
924
		"     8  invokespecial Y(java.lang.Object) [12]\n" + 
925
		"    11  new java.lang.NullPointerException [15]\n" + 
926
		"    14  dup\n" + 
927
		"    15  invokespecial java.lang.NullPointerException() [17]\n" + 
928
		"    18  athrow\n" + 
929
		"      Line numbers:\n" + 
930
		"        [pc: 0, line: 14]\n" + 
931
		"        [pc: 11, line: 10]\n" + 
932
		"      Local variable table:\n" + 
933
		"        [pc: 0, pc: 19] local: this index: 0 type: X\n";
934
	
935
	try {
936
		File f = new File(OUTPUT_DIR + File.separator + "X.class");
937
		byte[] classFileBytes = org.eclipse.jdt.internal.compiler.util.Util.getFileByteContent(f);
938
		ClassFileBytesDisassembler disassembler = ToolFactory.createDefaultClassFileBytesDisassembler();
939
		String result = disassembler.disassemble(classFileBytes, "\n", ClassFileBytesDisassembler.DETAILED);
940
		int index = result.indexOf(expectedOutput);
941
		if (index == -1 || expectedOutput.length() == 0) {
942
			System.out.println(Util.displayString(result, 3));
943
		}
944
		if (index == -1) {
945
			assertEquals("Wrong contents", expectedOutput, result);
946
		}
947
	} catch (org.eclipse.jdt.core.util.ClassFormatException e) {
948
		assertTrue(false);
949
	} catch (IOException e) {
950
		assertTrue(false);
951
	}	
952
}
953
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=155423 - variation
954
public void test031() {
955
	this.runNegativeTest(
956
		new String[] {
957
			"X.java",
958
			"class Y {\n" + 
959
			"	Y(Object o) {\n" + 
960
			"	}\n" + 
961
			"}\n" + 
962
			"\n" + 
963
			"public class X extends Y {\n" + 
964
			"	final int blank;\n" + 
965
			"	{\n" + 
966
			"		if (true)\n" + 
967
			"			throw new NullPointerException();\n" + 
968
			"	}\n" + 
969
			"\n" + 
970
			"	X() {\n" + 
971
			"		super(new Object() {});\n" + 
972
			"	}\n" + 
973
			"}\n", // =================
974
		},
975
		"----------\n" + 
976
		"1. ERROR in X.java (at line 13)\n" + 
977
		"	X() {\n" + 
978
		"	^^^\n" + 
979
		"The blank final field blank may not have been initialized\n" + 
980
		"----------\n");
981
}
982
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=155423 - variation
983
public void test032() {
984
	this.runNegativeTest(
985
		new String[] {
986
			"X.java",
987
			"class Y {\n" + 
988
			"	Y(int i) {\n" + 
989
			"	}\n" + 
990
			"}\n" + 
991
			"\n" + 
992
			"public class X extends Y {\n" + 
993
			"	final int blank;\n" + 
994
			"	{\n" + 
995
			"		if (true)\n" + 
996
			"			throw new NullPointerException();\n" + 
997
			"	}\n" + 
998
			"\n" + 
999
			"	X() {\n" + 
1000
			"		super(blank = 0);\n" + 
1001
			"	}\n" + 
1002
			"}\n", // =================
1003
		},
1004
		"----------\n" + 
1005
		"1. ERROR in X.java (at line 14)\n" + 
1006
		"	super(blank = 0);\n" + 
1007
		"	      ^^^^^\n" + 
1008
		"Cannot refer to an instance field blank while explicitly invoking a constructor\n" + 
1009
		"----------\n");
1010
}
1011
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=155423 - variation
1012
public void test033() {
1013
	this.runConformTest(
1014
		new String[] {
1015
			"X.java",
1016
			"class Y {\n" + 
1017
			"	Y(int i) {\n" + 
1018
			"	}\n" + 
1019
			"}\n" + 
1020
			"public class X extends Y {\n" + 
1021
			"	final int blank;\n" + 
1022
			"	{\n" + 
1023
			"		if (true)\n" + 
1024
			"			throw new NullPointerException();\n" + 
1025
			"	}\n" + 
1026
			"	X() {\n" + 
1027
			"		super(0);\n" + 
1028
			"		blank = 0;\n" + 
1029
			"	}\n" + 
1030
			"}\n", // =================
1031
		},
1032
		"");
1033
}
780
public static Class testClass() {
1034
public static Class testClass() {
781
	return FlowAnalysisTest.class;
1035
	return FlowAnalysisTest.class;
782
}
1036
}
(-)compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java (-5 / +2 lines)
Lines 665-676 Link Here
665
					method.analyseCode(
665
					method.analyseCode(
666
						this.scope, 
666
						this.scope, 
667
						staticInitializerContext,  
667
						staticInitializerContext,  
668
						staticFieldInfo.unconditionalInits().discardNonFieldInitializations().addInitializationsFrom(outerInfo).setReachMode(flowInfo.reachMode()));  // reset reach mode in case initializers did abrupt completely
668
						staticFieldInfo.unconditionalInits().discardNonFieldInitializations().addInitializationsFrom(outerInfo));
669
				} else { // constructor
669
				} else { // constructor
670
					method.analyseCode(this.scope, initializerContext, constructorInfo.copy().setReachMode(flowInfo.reachMode())); // reset reach mode in case initializers did abrupt completely
670
					((ConstructorDeclaration)method).analyseCode(this.scope, initializerContext, constructorInfo.copy(), flowInfo.reachMode());
671
					if (method.needFreeReturn) {
672
						method.needFreeReturn = (constructorInfo.tagBits & FlowInfo.UNREACHABLE) == 0;
673
					}
674
				}
671
				}
675
			} else { // regular method
672
			} else { // regular method
676
				method.analyseCode(this.scope, null, flowInfo.copy());
673
				method.analyseCode(this.scope, null, flowInfo.copy());
(-)compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java (-386 / +385 lines)
Lines 28-482 Link Here
28
	public boolean isDefaultConstructor = false;
28
	public boolean isDefaultConstructor = false;
29
	public TypeParameter[] typeParameters;
29
	public TypeParameter[] typeParameters;
30
30
31
	public ConstructorDeclaration(CompilationResult compilationResult){
31
public ConstructorDeclaration(CompilationResult compilationResult){
32
		super(compilationResult);
32
	super(compilationResult);
33
	}
33
}
34
35
/** 
36
 * @see org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration#analyseCode(org.eclipse.jdt.internal.compiler.lookup.ClassScope, org.eclipse.jdt.internal.compiler.flow.InitializationFlowContext, org.eclipse.jdt.internal.compiler.flow.FlowInfo)
37
 * @deprecated use instead {@link #analyseCode(ClassScope, InitializationFlowContext, FlowInfo, int)}
38
 */
39
public void analyseCode(ClassScope classScope, InitializationFlowContext initializerFlowContext, FlowInfo flowInfo) {
40
	analyseCode(classScope, initializerFlowContext, flowInfo, FlowInfo.REACHABLE);
41
}
42
43
/**
44
 * The flowInfo corresponds to non-static field initialization infos. It may be unreachable (155423), but still the explicit constructor call must be
45
 * analysed as reachable, since it will be generated in the end.
46
 */
47
public void analyseCode(ClassScope classScope, InitializationFlowContext initializerFlowContext, FlowInfo flowInfo, int initialReachMode) {
48
	if (this.ignoreFurtherInvestigation)
49
		return;
50
51
	int nonStaticFieldInfoReachMode = flowInfo.reachMode();
52
	flowInfo.setReachMode(initialReachMode);
34
	
53
	
35
	public void analyseCode(
54
	if (this.binding != null && !this.binding.isUsed() && (this.binding.isPrivate() || (this.binding.declaringClass.tagBits & (TagBits.IsAnonymousType|TagBits.IsLocalType)) == TagBits.IsLocalType)) {
36
		ClassScope classScope,
55
		if (!classScope.referenceCompilationUnit().compilationResult.hasSyntaxError) {
37
		InitializationFlowContext initializerFlowContext,
56
			this.scope.problemReporter().unusedPrivateConstructor(this);
38
		FlowInfo flowInfo) {
39
40
		if (ignoreFurtherInvestigation)
41
			return;
42
43
		if (this.binding != null && !this.binding.isUsed() && (this.binding.isPrivate() || (this.binding.declaringClass.tagBits & (TagBits.IsAnonymousType|TagBits.IsLocalType)) == TagBits.IsLocalType)) {
44
			if (!classScope.referenceCompilationUnit().compilationResult.hasSyntaxError) {
45
				scope.problemReporter().unusedPrivateConstructor(this);
46
			}
47
		}
57
		}
48
			
58
	}
49
		// check constructor recursion, once all constructor got resolved
59
		
50
		if (isRecursive(null /*lazy initialized visited list*/)) {				
60
	// check constructor recursion, once all constructor got resolved
51
			this.scope.problemReporter().recursiveConstructorInvocation(this.constructorCall);
61
	if (isRecursive(null /*lazy initialized visited list*/)) {				
52
		}
62
		this.scope.problemReporter().recursiveConstructorInvocation(this.constructorCall);
53
			
63
	}
54
		try {
64
		
55
			ExceptionHandlingFlowContext constructorContext =
65
	try {
56
				new ExceptionHandlingFlowContext(
66
		ExceptionHandlingFlowContext constructorContext =
57
					initializerFlowContext.parent,
67
			new ExceptionHandlingFlowContext(
58
					this,
68
				initializerFlowContext.parent,
59
					binding.thrownExceptions,
69
				this,
60
					scope,
70
				this.binding.thrownExceptions,
61
					FlowInfo.DEAD_END);
71
				this.scope,
62
			initializerFlowContext.checkInitializerExceptions(
72
				FlowInfo.DEAD_END);
63
				scope,
73
		initializerFlowContext.checkInitializerExceptions(
64
				constructorContext,
74
			this.scope,
65
				flowInfo);
75
			constructorContext,
66
76
			flowInfo);
67
			// anonymous constructor can gain extra thrown exceptions from unhandled ones
77
68
			if (binding.declaringClass.isAnonymousType()) {
78
		// anonymous constructor can gain extra thrown exceptions from unhandled ones
69
				ArrayList computedExceptions = constructorContext.extendedExceptions;
79
		if (this.binding.declaringClass.isAnonymousType()) {
70
				if (computedExceptions != null){
80
			ArrayList computedExceptions = constructorContext.extendedExceptions;
71
					int size;
81
			if (computedExceptions != null){
72
					if ((size = computedExceptions.size()) > 0){
82
				int size;
73
						ReferenceBinding[] actuallyThrownExceptions;
83
				if ((size = computedExceptions.size()) > 0){
74
						computedExceptions.toArray(actuallyThrownExceptions = new ReferenceBinding[size]);
84
					ReferenceBinding[] actuallyThrownExceptions;
75
						binding.thrownExceptions = actuallyThrownExceptions;
85
					computedExceptions.toArray(actuallyThrownExceptions = new ReferenceBinding[size]);
76
					}
86
					this.binding.thrownExceptions = actuallyThrownExceptions;
77
				}
87
				}
78
			}
88
			}
79
			
89
		}
80
			// tag parameters as being set
90
		
81
			if (this.arguments != null) {
91
		// tag parameters as being set
82
				for (int i = 0, count = this.arguments.length; i < count; i++) {
92
		if (this.arguments != null) {
83
					flowInfo.markAsDefinitelyAssigned(this.arguments[i].binding);
93
			for (int i = 0, count = this.arguments.length; i < count; i++) {
84
				}
94
				flowInfo.markAsDefinitelyAssigned(this.arguments[i].binding);
85
			}
95
			}
86
			
96
		}
87
			// propagate to constructor call
97
		
88
			if (constructorCall != null) {
98
		// propagate to constructor call
89
				// if calling 'this(...)', then flag all non-static fields as definitely
99
		if (this.constructorCall != null) {
90
				// set since they are supposed to be set inside other local constructor
100
			// if calling 'this(...)', then flag all non-static fields as definitely
91
				if (constructorCall.accessMode == ExplicitConstructorCall.This) {
101
			// set since they are supposed to be set inside other local constructor
92
					FieldBinding[] fields = binding.declaringClass.fields();
102
			if (this.constructorCall.accessMode == ExplicitConstructorCall.This) {
93
					for (int i = 0, count = fields.length; i < count; i++) {
103
				FieldBinding[] fields = this.binding.declaringClass.fields();
94
						FieldBinding field;
104
				for (int i = 0, count = fields.length; i < count; i++) {
95
						if (!(field = fields[i]).isStatic()) {
105
					FieldBinding field;
96
							flowInfo.markAsDefinitelyAssigned(field);
106
					if (!(field = fields[i]).isStatic()) {
97
						}
107
						flowInfo.markAsDefinitelyAssigned(field);
98
					}
108
					}
99
				}
109
				}
100
				flowInfo = constructorCall.analyseCode(scope, constructorContext, flowInfo);
101
			}
110
			}
102
			// propagate to statements
111
			flowInfo = this.constructorCall.analyseCode(this.scope, constructorContext, flowInfo);
103
			if (statements != null) {
112
		}
104
				boolean didAlreadyComplain = false;
113
		
105
				for (int i = 0, count = statements.length; i < count; i++) {
114
		// reuse the reachMode from non static field info
106
					Statement stat = statements[i];
115
		flowInfo.setReachMode(nonStaticFieldInfoReachMode);
107
					if (!stat.complainIfUnreachable(flowInfo, scope, didAlreadyComplain)) {
116
108
						flowInfo = stat.analyseCode(scope, constructorContext, flowInfo);
117
		// propagate to statements
109
					} else {
118
		if (this.statements != null) {
110
						didAlreadyComplain = true;
119
			boolean didAlreadyComplain = false;
111
					}
120
			for (int i = 0, count = this.statements.length; i < count; i++) {
121
				Statement stat = this.statements[i];
122
				if (!stat.complainIfUnreachable(flowInfo, this.scope, didAlreadyComplain)) {
123
					flowInfo = stat.analyseCode(this.scope, constructorContext, flowInfo);
124
				} else {
125
					didAlreadyComplain = true;
112
				}
126
				}
113
			}
127
			}
114
			// check for missing returning path
128
		}
115
			this.needFreeReturn = (flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0;
129
		// check for missing returning path
116
130
		this.needFreeReturn = (flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0;
117
131
118
			// check missing blank final field initializations
132
		// reuse the initial reach mode for diagnosing missing blank finals
119
			if ((constructorCall != null)
133
		flowInfo.setReachMode(initialReachMode);		
120
				&& (constructorCall.accessMode != ExplicitConstructorCall.This)) {
134
121
				flowInfo = flowInfo.mergedWith(constructorContext.initsOnReturn);
135
		// check missing blank final field initializations
122
				FieldBinding[] fields = binding.declaringClass.fields();
136
		if ((this.constructorCall != null)
123
				for (int i = 0, count = fields.length; i < count; i++) {
137
			&& (this.constructorCall.accessMode != ExplicitConstructorCall.This)) {
124
					FieldBinding field;
138
			flowInfo = flowInfo.mergedWith(constructorContext.initsOnReturn);
125
					if ((!(field = fields[i]).isStatic())
139
			FieldBinding[] fields = this.binding.declaringClass.fields();
126
						&& field.isFinal()
140
			for (int i = 0, count = fields.length; i < count; i++) {
127
						&& (!flowInfo.isDefinitelyAssigned(fields[i]))) {
141
				FieldBinding field;
128
						scope.problemReporter().uninitializedBlankFinalField(
142
				if ((!(field = fields[i]).isStatic())
129
							field,
143
					&& field.isFinal()
130
							isDefaultConstructor ? (ASTNode) scope.referenceType() : this);
144
					&& (!flowInfo.isDefinitelyAssigned(fields[i]))) {
131
					}
145
					this.scope.problemReporter().uninitializedBlankFinalField(
146
						field,
147
						this.isDefaultConstructor ? (ASTNode) this.scope.referenceType() : this);
132
				}
148
				}
133
			}
149
			}
134
			// check unreachable catch blocks
135
			constructorContext.complainIfUnusedExceptionHandlers(this);
136
		} catch (AbortMethod e) {
137
			this.ignoreFurtherInvestigation = true;
138
		}
150
		}
151
		// check unreachable catch blocks
152
		constructorContext.complainIfUnusedExceptionHandlers(this);
153
	} catch (AbortMethod e) {
154
		this.ignoreFurtherInvestigation = true;
139
	}
155
	}
156
}
140
157
141
	/**
158
/**
142
	 * Bytecode generation for a constructor
159
 * Bytecode generation for a constructor
143
	 *
160
 *
144
	 * @param classScope org.eclipse.jdt.internal.compiler.lookup.ClassScope
161
 * @param classScope org.eclipse.jdt.internal.compiler.lookup.ClassScope
145
	 * @param classFile org.eclipse.jdt.internal.compiler.codegen.ClassFile
162
 * @param classFile org.eclipse.jdt.internal.compiler.codegen.ClassFile
146
	 */
163
 */
147
	public void generateCode(ClassScope classScope, ClassFile classFile) {
164
public void generateCode(ClassScope classScope, ClassFile classFile) {
148
		
165
	int problemResetPC = 0;
149
		int problemResetPC = 0;
166
	if (this.ignoreFurtherInvestigation) {
150
		if (ignoreFurtherInvestigation) {
167
		if (this.binding == null)
151
			if (this.binding == null)
168
			return; // Handle methods with invalid signature or duplicates
152
				return; // Handle methods with invalid signature or duplicates
169
		int problemsLength;
153
			int problemsLength;
170
		CategorizedProblem[] problems =
154
			CategorizedProblem[] problems =
171
			this.scope.referenceCompilationUnit().compilationResult.getProblems();
155
				scope.referenceCompilationUnit().compilationResult.getProblems();
172
		CategorizedProblem[] problemsCopy = new CategorizedProblem[problemsLength = problems.length];
156
			CategorizedProblem[] problemsCopy = new CategorizedProblem[problemsLength = problems.length];
173
		System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
157
			System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
174
		classFile.addProblemConstructor(this, this.binding, problemsCopy);
158
			classFile.addProblemConstructor(this, binding, problemsCopy);
175
		return;
159
			return;
176
	}
160
		}
177
	try {
161
		try {
178
		problemResetPC = classFile.contentsOffset;
162
			problemResetPC = classFile.contentsOffset;
179
		this.internalGenerateCode(classScope, classFile);
163
			this.internalGenerateCode(classScope, classFile);
180
	} catch (AbortMethod e) {
164
		} catch (AbortMethod e) {
181
		if (e.compilationResult == CodeStream.RESTART_IN_WIDE_MODE) {
165
			if (e.compilationResult == CodeStream.RESTART_IN_WIDE_MODE) {
182
			// a branch target required a goto_w, restart code gen in wide mode.
166
				// a branch target required a goto_w, restart code gen in wide mode.
183
			try {
167
				try {
184
				classFile.contentsOffset = problemResetPC;
168
					classFile.contentsOffset = problemResetPC;
185
				classFile.methodCount--;
169
					classFile.methodCount--;
186
				classFile.codeStream.wideMode = true; // request wide mode 
170
					classFile.codeStream.wideMode = true; // request wide mode 
187
				this.internalGenerateCode(classScope, classFile); // restart method generation
171
					this.internalGenerateCode(classScope, classFile); // restart method generation
188
			} catch (AbortMethod e2) {
172
				} catch (AbortMethod e2) {
173
					int problemsLength;
174
					CategorizedProblem[] problems =
175
						scope.referenceCompilationUnit().compilationResult.getAllProblems();
176
					CategorizedProblem[] problemsCopy = new CategorizedProblem[problemsLength = problems.length];
177
					System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
178
					classFile.addProblemConstructor(this, binding, problemsCopy, problemResetPC);
179
				}
180
			} else {
181
				int problemsLength;
189
				int problemsLength;
182
				CategorizedProblem[] problems =
190
				CategorizedProblem[] problems =
183
					scope.referenceCompilationUnit().compilationResult.getAllProblems();
191
					this.scope.referenceCompilationUnit().compilationResult.getAllProblems();
184
				CategorizedProblem[] problemsCopy = new CategorizedProblem[problemsLength = problems.length];
192
				CategorizedProblem[] problemsCopy = new CategorizedProblem[problemsLength = problems.length];
185
				System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
193
				System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
186
				classFile.addProblemConstructor(this, binding, problemsCopy, problemResetPC);
194
				classFile.addProblemConstructor(this, this.binding, problemsCopy, problemResetPC);
187
			}
195
			}
196
		} else {
197
			int problemsLength;
198
			CategorizedProblem[] problems =
199
				this.scope.referenceCompilationUnit().compilationResult.getAllProblems();
200
			CategorizedProblem[] problemsCopy = new CategorizedProblem[problemsLength = problems.length];
201
			System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
202
			classFile.addProblemConstructor(this, this.binding, problemsCopy, problemResetPC);
188
		}
203
		}
189
	}
204
	}
205
}
190
206
191
	public void generateSyntheticFieldInitializationsIfNecessary(
207
public void generateSyntheticFieldInitializationsIfNecessary(MethodScope methodScope, CodeStream codeStream, ReferenceBinding declaringClass) {
192
		MethodScope methodScope,
208
	if (!declaringClass.isNestedType()) return;
193
		CodeStream codeStream,
209
	
194
		ReferenceBinding declaringClass) {
210
	NestedTypeBinding nestedType = (NestedTypeBinding) declaringClass;
195
			
196
		if (!declaringClass.isNestedType()) return;
197
		
198
		NestedTypeBinding nestedType = (NestedTypeBinding) declaringClass;
199
211
200
		SyntheticArgumentBinding[] syntheticArgs = nestedType.syntheticEnclosingInstances();
212
	SyntheticArgumentBinding[] syntheticArgs = nestedType.syntheticEnclosingInstances();
201
		for (int i = 0, max = syntheticArgs == null ? 0 : syntheticArgs.length; i < max; i++) {
213
	for (int i = 0, max = syntheticArgs == null ? 0 : syntheticArgs.length; i < max; i++) {
202
			SyntheticArgumentBinding syntheticArg;
214
		SyntheticArgumentBinding syntheticArg;
203
			if ((syntheticArg = syntheticArgs[i]).matchingField != null) {
215
		if ((syntheticArg = syntheticArgs[i]).matchingField != null) {
204
				codeStream.aload_0();
216
			codeStream.aload_0();
205
				codeStream.load(syntheticArg);
217
			codeStream.load(syntheticArg);
206
				codeStream.putfield(syntheticArg.matchingField);
218
			codeStream.putfield(syntheticArg.matchingField);
207
			}
219
		}
208
		}
220
	}
209
		syntheticArgs = nestedType.syntheticOuterLocalVariables();
221
	syntheticArgs = nestedType.syntheticOuterLocalVariables();
210
		for (int i = 0, max = syntheticArgs == null ? 0 : syntheticArgs.length; i < max; i++) {
222
	for (int i = 0, max = syntheticArgs == null ? 0 : syntheticArgs.length; i < max; i++) {
211
			SyntheticArgumentBinding syntheticArg;
223
		SyntheticArgumentBinding syntheticArg;
212
			if ((syntheticArg = syntheticArgs[i]).matchingField != null) {
224
		if ((syntheticArg = syntheticArgs[i]).matchingField != null) {
213
				codeStream.aload_0();
225
			codeStream.aload_0();
214
				codeStream.load(syntheticArg);
226
			codeStream.load(syntheticArg);
215
				codeStream.putfield(syntheticArg.matchingField);
227
			codeStream.putfield(syntheticArg.matchingField);
216
			}
217
		}
228
		}
218
	}
229
	}
230
}
219
231
220
	private void internalGenerateCode(ClassScope classScope, ClassFile classFile) {
232
private void internalGenerateCode(ClassScope classScope, ClassFile classFile) {
233
	classFile.generateMethodInfoHeader(this.binding);
234
	int methodAttributeOffset = classFile.contentsOffset;
235
	int attributeNumber = classFile.generateMethodInfoAttribute(this.binding);
236
	if ((!this.binding.isNative()) && (!this.binding.isAbstract())) {
221
		
237
		
222
		classFile.generateMethodInfoHeader(binding);
238
		TypeDeclaration declaringType = classScope.referenceContext;
223
		int methodAttributeOffset = classFile.contentsOffset;
239
		int codeAttributeOffset = classFile.contentsOffset;
224
		int attributeNumber = classFile.generateMethodInfoAttribute(this.binding);
240
		classFile.generateCodeAttributeHeader();
225
		if ((!binding.isNative()) && (!binding.isAbstract())) {
241
		CodeStream codeStream = classFile.codeStream;
242
		codeStream.reset(this, classFile);
243
244
		// initialize local positions - including initializer scope.
245
		ReferenceBinding declaringClass = this.binding.declaringClass;
246
247
		int enumOffset = declaringClass.isEnum() ? 2 : 0; // String name, int ordinal
248
		int argSlotSize = 1 + enumOffset; // this==aload0
249
250
		if (declaringClass.isNestedType()){
251
			NestedTypeBinding nestedType = (NestedTypeBinding) declaringClass;
252
			this.scope.extraSyntheticArguments = nestedType.syntheticOuterLocalVariables();
253
			this.scope.computeLocalVariablePositions(// consider synthetic arguments if any
254
				nestedType.enclosingInstancesSlotSize + 1 + enumOffset,
255
				codeStream);
256
			argSlotSize += nestedType.enclosingInstancesSlotSize;
257
			argSlotSize += nestedType.outerLocalVariablesSlotSize;
258
		} else {
259
			this.scope.computeLocalVariablePositions(1 + enumOffset,  codeStream);
260
		}
226
			
261
			
227
			TypeDeclaration declaringType = classScope.referenceContext;
262
		if (this.arguments != null) {
228
			int codeAttributeOffset = classFile.contentsOffset;
263
			for (int i = 0, max = this.arguments.length; i < max; i++) {
229
			classFile.generateCodeAttributeHeader();
264
				// arguments initialization for local variable debug attributes
230
			CodeStream codeStream = classFile.codeStream;
265
				LocalVariableBinding argBinding;
231
			codeStream.reset(this, classFile);
266
				codeStream.addVisibleLocalVariable(argBinding = this.arguments[i].binding);
232
267
				argBinding.recordInitializationStartPC(0);
233
			// initialize local positions - including initializer scope.
268
				TypeBinding argType;
234
			ReferenceBinding declaringClass = binding.declaringClass;
269
				if ((argType = argBinding.type) == TypeBinding.LONG || (argType == TypeBinding.DOUBLE)) {
235
270
					argSlotSize += 2;
236
			int enumOffset = declaringClass.isEnum() ? 2 : 0; // String name, int ordinal
271
				} else {
237
			int argSlotSize = 1 + enumOffset; // this==aload0
272
					argSlotSize++;
238
239
			if (declaringClass.isNestedType()){
240
				NestedTypeBinding nestedType = (NestedTypeBinding) declaringClass;
241
				this.scope.extraSyntheticArguments = nestedType.syntheticOuterLocalVariables();
242
				scope.computeLocalVariablePositions(// consider synthetic arguments if any
243
					nestedType.enclosingInstancesSlotSize + 1 + enumOffset,
244
					codeStream);
245
				argSlotSize += nestedType.enclosingInstancesSlotSize;
246
				argSlotSize += nestedType.outerLocalVariablesSlotSize;
247
			} else {
248
				scope.computeLocalVariablePositions(1 + enumOffset,  codeStream);
249
			}
250
				
251
			if (arguments != null) {
252
				for (int i = 0, max = arguments.length; i < max; i++) {
253
					// arguments initialization for local variable debug attributes
254
					LocalVariableBinding argBinding;
255
					codeStream.addVisibleLocalVariable(argBinding = arguments[i].binding);
256
					argBinding.recordInitializationStartPC(0);
257
					TypeBinding argType;
258
					if ((argType = argBinding.type) == TypeBinding.LONG || (argType == TypeBinding.DOUBLE)) {
259
						argSlotSize += 2;
260
					} else {
261
						argSlotSize++;
262
					}
263
				}
273
				}
264
			}
274
			}
265
			
275
		}
266
			MethodScope initializerScope = declaringType.initializerScope;
276
		
267
			initializerScope.computeLocalVariablePositions(argSlotSize, codeStream); // offset by the argument size (since not linked to method scope)
277
		MethodScope initializerScope = declaringType.initializerScope;
278
		initializerScope.computeLocalVariablePositions(argSlotSize, codeStream); // offset by the argument size (since not linked to method scope)
268
279
269
			boolean needFieldInitializations = constructorCall == null || constructorCall.accessMode != ExplicitConstructorCall.This;
280
		boolean needFieldInitializations = this.constructorCall == null || this.constructorCall.accessMode != ExplicitConstructorCall.This;
270
281
271
			// post 1.4 target level, synthetic initializations occur prior to explicit constructor call
282
		// post 1.4 target level, synthetic initializations occur prior to explicit constructor call
272
			boolean preInitSyntheticFields = scope.compilerOptions().targetJDK >= ClassFileConstants.JDK1_4;
283
		boolean preInitSyntheticFields = this.scope.compilerOptions().targetJDK >= ClassFileConstants.JDK1_4;
273
284
274
			if (needFieldInitializations && preInitSyntheticFields){
285
		if (needFieldInitializations && preInitSyntheticFields){
275
				generateSyntheticFieldInitializationsIfNecessary(scope, codeStream, declaringClass);
286
			generateSyntheticFieldInitializationsIfNecessary(this.scope, codeStream, declaringClass);
276
			}			
287
		}			
277
			// generate constructor call
288
		// generate constructor call
278
			if (constructorCall != null) {
289
		if (this.constructorCall != null) {
279
				constructorCall.generateCode(scope, codeStream);
290
			this.constructorCall.generateCode(this.scope, codeStream);
280
			}
291
		}
281
			// generate field initialization - only if not invoking another constructor call of the same class
292
		// generate field initialization - only if not invoking another constructor call of the same class
282
			if (needFieldInitializations) {
293
		if (needFieldInitializations) {
283
				if (!preInitSyntheticFields){
294
			if (!preInitSyntheticFields){
284
					generateSyntheticFieldInitializationsIfNecessary(scope, codeStream, declaringClass);
295
				generateSyntheticFieldInitializationsIfNecessary(this.scope, codeStream, declaringClass);
285
				}
296
			}
286
				// generate user field initialization
297
			// generate user field initialization
287
				if (declaringType.fields != null) {
298
			if (declaringType.fields != null) {
288
					for (int i = 0, max = declaringType.fields.length; i < max; i++) {
299
				for (int i = 0, max = declaringType.fields.length; i < max; i++) {
289
						FieldDeclaration fieldDecl;
300
					FieldDeclaration fieldDecl;
290
						if (!(fieldDecl = declaringType.fields[i]).isStatic()) {
301
					if (!(fieldDecl = declaringType.fields[i]).isStatic()) {
291
							fieldDecl.generateCode(initializerScope, codeStream);
302
						fieldDecl.generateCode(initializerScope, codeStream);
292
						}
293
					}
303
					}
294
				}
304
				}
295
			}
305
			}
296
			// generate statements
297
			if (statements != null) {
298
				for (int i = 0, max = statements.length; i < max; i++) {
299
					statements[i].generateCode(scope, codeStream);
300
				}
301
			}
302
			if (this.needFreeReturn) {
303
				codeStream.return_();
304
			}
305
			// local variable attributes
306
			codeStream.exitUserScope(scope);
307
			codeStream.recordPositionsFrom(0, this.bodyEnd);
308
			classFile.completeCodeAttribute(codeAttributeOffset);
309
			attributeNumber++;
310
		}
311
		classFile.completeMethodInfo(methodAttributeOffset, attributeNumber);
312
313
		// if a problem got reported during code gen, then trigger problem method creation
314
		if (ignoreFurtherInvestigation) {
315
			throw new AbortMethod(scope.referenceCompilationUnit().compilationResult, null);
316
		}
306
		}
307
		// generate statements
308
		if (this.statements != null) {
309
			for (int i = 0, max = this.statements.length; i < max; i++) {
310
				this.statements[i].generateCode(this.scope, codeStream);
311
			}
312
		}
313
		if (this.needFreeReturn) {
314
			codeStream.return_();
315
		}
316
		// local variable attributes
317
		codeStream.exitUserScope(this.scope);
318
		codeStream.recordPositionsFrom(0, this.bodyEnd);
319
		classFile.completeCodeAttribute(codeAttributeOffset);
320
		attributeNumber++;
321
	}
322
	classFile.completeMethodInfo(methodAttributeOffset, attributeNumber);
323
324
	// if a problem got reported during code gen, then trigger problem method creation
325
	if (this.ignoreFurtherInvestigation) {
326
		throw new AbortMethod(this.scope.referenceCompilationUnit().compilationResult, null);
317
	}
327
	}
328
}
318
329
319
	public boolean isConstructor() {
330
public boolean isConstructor() {
331
	return true;
332
}
320
333
321
		return true;
334
public boolean isDefaultConstructor() {
322
	}
335
	return this.isDefaultConstructor;
336
}
323
337
324
	public boolean isDefaultConstructor() {
338
public boolean isInitializationMethod() {
339
	return true;
340
}
325
341
326
		return this.isDefaultConstructor;
342
/*
343
 * Returns true if the constructor is directly involved in a cycle.
344
 * Given most constructors aren't, we only allocate the visited list
345
 * lazily.
346
 */
347
public boolean isRecursive(ArrayList visited) {
348
	if (this.binding == null
349
			|| this.constructorCall == null
350
			|| this.constructorCall.binding == null
351
			|| this.constructorCall.isSuperAccess()
352
			|| !this.constructorCall.binding.isValidBinding()) {
353
		return false;
327
	}
354
	}
328
355
	
329
	public boolean isInitializationMethod() {
356
	ConstructorDeclaration targetConstructor = 
330
357
		((ConstructorDeclaration)this.scope.referenceType().declarationOf(this.constructorCall.binding.original()));
331
		return true;
358
	if (this == targetConstructor) return true; // direct case
359
360
	if (visited == null) { // lazy allocation
361
		visited = new ArrayList(1);
362
	} else {
363
		int index = visited.indexOf(this);
364
		if (index >= 0) return index == 0; // only blame if directly part of the cycle
332
	}
365
	}
366
	visited.add(this);
333
367
334
	/*
368
	return targetConstructor.isRecursive(visited);
335
	 * Returns true if the constructor is directly involved in a cycle.
369
}
336
	 * Given most constructors aren't, we only allocate the visited list
337
	 * lazily.
338
	 */
339
	public boolean isRecursive(ArrayList visited) {
340
370
341
		if (this.binding == null
371
public void parseStatements(Parser parser, CompilationUnitDeclaration unit) {
342
				|| this.constructorCall == null
372
	//fill up the constructor body with its statements
343
				|| this.constructorCall.binding == null
373
	if (this.ignoreFurtherInvestigation)
344
				|| this.constructorCall.isSuperAccess()
374
		return;
345
				|| !this.constructorCall.binding.isValidBinding()) {
375
	if (this.isDefaultConstructor && this.constructorCall == null){
346
			return false;
376
		this.constructorCall = SuperReference.implicitSuperConstructorCall();
347
		}
377
		this.constructorCall.sourceStart = this.sourceStart;
348
		
378
		this.constructorCall.sourceEnd = this.sourceEnd; 
349
		ConstructorDeclaration targetConstructor = 
379
		return;
350
			((ConstructorDeclaration)this.scope.referenceType().declarationOf(constructorCall.binding.original()));
380
	}
351
		if (this == targetConstructor) return true; // direct case
381
	parser.parse(this, unit);
352
382
353
		if (visited == null) { // lazy allocation
383
}
354
			visited = new ArrayList(1);
355
		} else {
356
			int index = visited.indexOf(this);
357
			if (index >= 0) return index == 0; // only blame if directly part of the cycle
358
		}
359
		visited.add(this);
360
384
361
		return targetConstructor.isRecursive(visited);
385
public StringBuffer printBody(int indent, StringBuffer output) {
386
	output.append(" {"); //$NON-NLS-1$
387
	if (this.constructorCall != null) {
388
		output.append('\n');
389
		this.constructorCall.printStatement(indent, output);
362
	}
390
	}
363
	
391
	if (this.statements != null) {
364
	public void parseStatements(Parser parser, CompilationUnitDeclaration unit) {
392
		for (int i = 0; i < this.statements.length; i++) {
365
393
			output.append('\n');
366
		//fill up the constructor body with its statements
394
			this.statements[i].printStatement(indent, output);
367
		if (ignoreFurtherInvestigation)
368
			return;
369
		if (isDefaultConstructor && this.constructorCall == null){
370
			this.constructorCall = SuperReference.implicitSuperConstructorCall();
371
			this.constructorCall.sourceStart = this.sourceStart;
372
			this.constructorCall.sourceEnd = this.sourceEnd; 
373
			return;
374
		}
395
		}
375
		parser.parse(this, unit);
396
	}
397
	output.append('\n');
398
	printIndent(indent == 0 ? 0 : indent - 1, output).append('}');
399
	return output;
400
}
376
401
402
public void resolveJavadoc() {
403
	if (this.binding == null || this.javadoc != null) {
404
		super.resolveJavadoc();
405
	} else if (!this.isDefaultConstructor) {
406
		this.scope.problemReporter().javadocMissing(this.sourceStart, this.sourceEnd, this.binding.modifiers);
377
	}
407
	}
408
}
378
409
379
	public StringBuffer printBody(int indent, StringBuffer output) {
410
/*
411
 * Type checking for constructor, just another method, except for special check
412
 * for recursive constructor invocations.
413
 */
414
public void resolveStatements() {
415
	if (!CharOperation.equals(this.scope.enclosingSourceType().sourceName, this.selector)){
416
		this.scope.problemReporter().missingReturnType(this);
417
	}
380
418
381
		output.append(" {"); //$NON-NLS-1$
419
	if (this.typeParameters != null) {
382
		if (constructorCall != null) {
420
		for (int i = 0, length = this.typeParameters.length; i < length; i++) {
383
			output.append('\n');
421
			this.typeParameters[i].resolve(this.scope);
384
			constructorCall.printStatement(indent, output);
385
		}
422
		}
386
		if (statements != null) {
387
			for (int i = 0; i < statements.length; i++) {
388
				output.append('\n');
389
				statements[i].printStatement(indent, output);
390
			}
391
		}
392
		output.append('\n');
393
		printIndent(indent == 0 ? 0 : indent - 1, output).append('}');
394
		return output;
395
	}
423
	}
396
	
424
	
397
	public void resolveJavadoc() {
425
	// if null ==> an error has occurs at parsing time ....
398
		
426
	if (this.constructorCall != null) {
399
		if (this.binding == null || this.javadoc != null) {
427
		// e.g. using super() in java.lang.Object
400
			super.resolveJavadoc();
428
		if (this.binding != null
401
		} else if (!isDefaultConstructor) {
429
			&& this.binding.declaringClass.id == TypeIds.T_JavaLangObject
402
			this.scope.problemReporter().javadocMissing(this.sourceStart, this.sourceEnd, this.binding.modifiers);
430
			&& this.constructorCall.accessMode != ExplicitConstructorCall.This) {
431
				if (this.constructorCall.accessMode == ExplicitConstructorCall.Super) {
432
					this.scope.problemReporter().cannotUseSuperInJavaLangObject(this.constructorCall);
433
				}
434
				this.constructorCall = null;
435
		} else {
436
			this.constructorCall.resolve(this.scope);
403
		}
437
		}
404
	}
438
	}
439
	if ((this.modifiers & ExtraCompilerModifiers.AccSemicolonBody) != 0) {
440
		this.scope.problemReporter().methodNeedBody(this);		
441
	}
442
	super.resolveStatements();
443
}
405
444
406
	/*
445
public void traverse(ASTVisitor visitor,	ClassScope classScope) {
407
	 * Type checking for constructor, just another method, except for special check
446
	if (visitor.visit(this, classScope)) {
408
	 * for recursive constructor invocations.
447
		if (this.annotations != null) {
409
	 */
448
			int annotationsLength = this.annotations.length;
410
	public void resolveStatements() {
449
			for (int i = 0; i < annotationsLength; i++)
411
450
				this.annotations[i].traverse(visitor, this.scope);
412
		if (!CharOperation.equals(this.scope.enclosingSourceType().sourceName, selector)){
413
			this.scope.problemReporter().missingReturnType(this);
414
		}
451
		}
415
416
		if (this.typeParameters != null) {
452
		if (this.typeParameters != null) {
417
			for (int i = 0, length = this.typeParameters.length; i < length; i++) {
453
			int typeParametersLength = this.typeParameters.length;
418
				this.typeParameters[i].resolve(this.scope);
454
			for (int i = 0; i < typeParametersLength; i++) {
419
			}
455
				this.typeParameters[i].traverse(visitor, this.scope);
420
		}
456
			}
421
		
457
		}			
422
		// if null ==> an error has occurs at parsing time ....
458
		if (this.arguments != null) {
423
		if (this.constructorCall != null) {
459
			int argumentLength = this.arguments.length;
424
			// e.g. using super() in java.lang.Object
460
			for (int i = 0; i < argumentLength; i++)
425
			if (this.binding != null
461
				this.arguments[i].traverse(visitor, this.scope);
426
				&& this.binding.declaringClass.id == T_JavaLangObject
462
		}
427
				&& this.constructorCall.accessMode != ExplicitConstructorCall.This) {
463
		if (this.thrownExceptions != null) {
428
					if (this.constructorCall.accessMode == ExplicitConstructorCall.Super) {
464
			int thrownExceptionsLength = this.thrownExceptions.length;
429
						this.scope.problemReporter().cannotUseSuperInJavaLangObject(this.constructorCall);
465
			for (int i = 0; i < thrownExceptionsLength; i++)
430
					}
466
				this.thrownExceptions[i].traverse(visitor, this.scope);
431
					this.constructorCall = null;
467
		}
432
			} else {
468
		if (this.constructorCall != null)
433
				this.constructorCall.resolve(this.scope);
469
			this.constructorCall.traverse(visitor, this.scope);
434
			}
470
		if (this.statements != null) {
435
		}
471
			int statementsLength = this.statements.length;
436
		if ((this.modifiers & ExtraCompilerModifiers.AccSemicolonBody) != 0) {
472
			for (int i = 0; i < statementsLength; i++)
437
			this.scope.problemReporter().methodNeedBody(this);		
473
				this.statements[i].traverse(visitor, this.scope);
438
		}
474
		}
439
		super.resolveStatements();
440
	}
475
	}
441
476
	visitor.endVisit(this, classScope);
442
	public void traverse(
477
}
443
		ASTVisitor visitor,
478
public TypeParameter[] typeParameters() {
444
		ClassScope classScope) {
479
    return this.typeParameters;
445
480
}		
446
		
447
		if (visitor.visit(this, classScope)) {
448
			if (this.annotations != null) {
449
				int annotationsLength = this.annotations.length;
450
				for (int i = 0; i < annotationsLength; i++)
451
					this.annotations[i].traverse(visitor, scope);
452
			}
453
			if (this.typeParameters != null) {
454
				int typeParametersLength = this.typeParameters.length;
455
				for (int i = 0; i < typeParametersLength; i++) {
456
					this.typeParameters[i].traverse(visitor, scope);
457
				}
458
			}			
459
			if (arguments != null) {
460
				int argumentLength = arguments.length;
461
				for (int i = 0; i < argumentLength; i++)
462
					arguments[i].traverse(visitor, scope);
463
			}
464
			if (thrownExceptions != null) {
465
				int thrownExceptionsLength = thrownExceptions.length;
466
				for (int i = 0; i < thrownExceptionsLength; i++)
467
					thrownExceptions[i].traverse(visitor, scope);
468
			}
469
			if (constructorCall != null)
470
				constructorCall.traverse(visitor, scope);
471
			if (statements != null) {
472
				int statementsLength = statements.length;
473
				for (int i = 0; i < statementsLength; i++)
474
					statements[i].traverse(visitor, scope);
475
			}
476
		}
477
		visitor.endVisit(this, classScope);
478
	}
479
	public TypeParameter[] typeParameters() {
480
	    return this.typeParameters;
481
	}		
482
}
481
}

Return to bug 155423