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 |
} |