1 11 package org.eclipse.jdt.internal.compiler.ast; 12 13 import java.util.ArrayList ; 14 15 import org.eclipse.jdt.core.compiler.*; 16 import org.eclipse.jdt.internal.compiler.*; 17 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; 18 import org.eclipse.jdt.internal.compiler.codegen.*; 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.*; 23 24 public class ConstructorDeclaration extends AbstractMethodDeclaration { 25 26 public ExplicitConstructorCall constructorCall; 27 28 public TypeParameter[] typeParameters; 29 30 public ConstructorDeclaration(CompilationResult compilationResult){ 31 super(compilationResult); 32 } 33 34 38 public void analyseCode(ClassScope classScope, InitializationFlowContext initializerFlowContext, FlowInfo flowInfo) { 39 analyseCode(classScope, initializerFlowContext, flowInfo, FlowInfo.REACHABLE); 40 } 41 42 46 public void analyseCode(ClassScope classScope, InitializationFlowContext initializerFlowContext, FlowInfo flowInfo, int initialReachMode) { 47 if (this.ignoreFurtherInvestigation) 48 return; 49 50 int nonStaticFieldInfoReachMode = flowInfo.reachMode(); 51 flowInfo.setReachMode(initialReachMode); 52 53 checkUnused: { 54 MethodBinding constructorBinding; 55 if ((constructorBinding = this.binding) == null) break checkUnused; 56 if ((this.bits & ASTNode.IsDefaultConstructor) != 0) break checkUnused; 57 if (constructorBinding.isUsed()) break checkUnused; 58 if (constructorBinding.isPrivate()) { 59 if ((this.binding.declaringClass.tagBits & TagBits.HasNonPrivateConstructor) == 0) 60 break checkUnused; } else if ((this.binding.declaringClass.tagBits & (TagBits.IsAnonymousType|TagBits.IsLocalType)) != TagBits.IsLocalType) { 62 break checkUnused; 63 } 64 this.scope.problemReporter().unusedPrivateConstructor(this); 66 } 67 68 if (isRecursive(null )) { 70 this.scope.problemReporter().recursiveConstructorInvocation(this.constructorCall); 71 } 72 73 try { 74 ExceptionHandlingFlowContext constructorContext = 75 new ExceptionHandlingFlowContext( 76 initializerFlowContext.parent, 77 this, 78 this.binding.thrownExceptions, 79 this.scope, 80 FlowInfo.DEAD_END); 81 initializerFlowContext.checkInitializerExceptions( 82 this.scope, 83 constructorContext, 84 flowInfo); 85 86 if (this.binding.declaringClass.isAnonymousType()) { 88 ArrayList computedExceptions = constructorContext.extendedExceptions; 89 if (computedExceptions != null){ 90 int size; 91 if ((size = computedExceptions.size()) > 0){ 92 ReferenceBinding[] actuallyThrownExceptions; 93 computedExceptions.toArray(actuallyThrownExceptions = new ReferenceBinding[size]); 94 this.binding.thrownExceptions = actuallyThrownExceptions; 95 } 96 } 97 } 98 99 if (this.arguments != null) { 101 for (int i = 0, count = this.arguments.length; i < count; i++) { 102 flowInfo.markAsDefinitelyAssigned(this.arguments[i].binding); 103 } 104 } 105 106 if (this.constructorCall != null) { 108 if (this.constructorCall.accessMode == ExplicitConstructorCall.This) { 111 FieldBinding[] fields = this.binding.declaringClass.fields(); 112 for (int i = 0, count = fields.length; i < count; i++) { 113 FieldBinding field; 114 if (!(field = fields[i]).isStatic()) { 115 flowInfo.markAsDefinitelyAssigned(field); 116 } 117 } 118 } 119 flowInfo = this.constructorCall.analyseCode(this.scope, constructorContext, flowInfo); 120 } 121 122 flowInfo.setReachMode(nonStaticFieldInfoReachMode); 124 125 if (this.statements != null) { 127 boolean didAlreadyComplain = false; 128 for (int i = 0, count = this.statements.length; i < count; i++) { 129 Statement stat = this.statements[i]; 130 if (!stat.complainIfUnreachable(flowInfo, this.scope, didAlreadyComplain)) { 131 flowInfo = stat.analyseCode(this.scope, constructorContext, flowInfo); 132 } else { 133 didAlreadyComplain = true; 134 } 135 } 136 } 137 if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) { 139 this.bits |= ASTNode.NeedFreeReturn; 140 } 141 142 flowInfo.setReachMode(initialReachMode); 144 145 if ((this.constructorCall != null) 147 && (this.constructorCall.accessMode != ExplicitConstructorCall.This)) { 148 flowInfo = flowInfo.mergedWith(constructorContext.initsOnReturn); 149 FieldBinding[] fields = this.binding.declaringClass.fields(); 150 for (int i = 0, count = fields.length; i < count; i++) { 151 FieldBinding field; 152 if ((!(field = fields[i]).isStatic()) 153 && field.isFinal() 154 && (!flowInfo.isDefinitelyAssigned(fields[i]))) { 155 this.scope.problemReporter().uninitializedBlankFinalField( 156 field, 157 ((this.bits & ASTNode.IsDefaultConstructor) != 0) ? (ASTNode) this.scope.referenceType() : this); 158 } 159 } 160 } 161 constructorContext.complainIfUnusedExceptionHandlers(this); 163 } catch (AbortMethod e) { 164 this.ignoreFurtherInvestigation = true; 165 } 166 } 167 168 174 public void generateCode(ClassScope classScope, ClassFile classFile) { 175 int problemResetPC = 0; 176 if (this.ignoreFurtherInvestigation) { 177 if (this.binding == null) 178 return; int problemsLength; 180 CategorizedProblem[] problems = 181 this.scope.referenceCompilationUnit().compilationResult.getProblems(); 182 CategorizedProblem[] problemsCopy = new CategorizedProblem[problemsLength = problems.length]; 183 System.arraycopy(problems, 0, problemsCopy, 0, problemsLength); 184 classFile.addProblemConstructor(this, this.binding, problemsCopy); 185 return; 186 } 187 try { 188 problemResetPC = classFile.contentsOffset; 189 this.internalGenerateCode(classScope, classFile); 190 } catch (AbortMethod e) { 191 if (e.compilationResult == CodeStream.RESTART_IN_WIDE_MODE) { 192 try { 194 classFile.contentsOffset = problemResetPC; 195 classFile.methodCount--; 196 classFile.codeStream.wideMode = true; this.internalGenerateCode(classScope, classFile); } catch (AbortMethod e2) { 199 int problemsLength; 200 CategorizedProblem[] problems = 201 this.scope.referenceCompilationUnit().compilationResult.getAllProblems(); 202 CategorizedProblem[] problemsCopy = new CategorizedProblem[problemsLength = problems.length]; 203 System.arraycopy(problems, 0, problemsCopy, 0, problemsLength); 204 classFile.addProblemConstructor(this, this.binding, problemsCopy, problemResetPC); 205 } 206 } else { 207 int problemsLength; 208 CategorizedProblem[] problems = 209 this.scope.referenceCompilationUnit().compilationResult.getAllProblems(); 210 CategorizedProblem[] problemsCopy = new CategorizedProblem[problemsLength = problems.length]; 211 System.arraycopy(problems, 0, problemsCopy, 0, problemsLength); 212 classFile.addProblemConstructor(this, this.binding, problemsCopy, problemResetPC); 213 } 214 } 215 } 216 217 public void generateSyntheticFieldInitializationsIfNecessary(MethodScope methodScope, CodeStream codeStream, ReferenceBinding declaringClass) { 218 if (!declaringClass.isNestedType()) return; 219 220 NestedTypeBinding nestedType = (NestedTypeBinding) declaringClass; 221 222 SyntheticArgumentBinding[] syntheticArgs = nestedType.syntheticEnclosingInstances(); 223 for (int i = 0, max = syntheticArgs == null ? 0 : syntheticArgs.length; i < max; i++) { 224 SyntheticArgumentBinding syntheticArg; 225 if ((syntheticArg = syntheticArgs[i]).matchingField != null) { 226 codeStream.aload_0(); 227 codeStream.load(syntheticArg); 228 codeStream.putfield(syntheticArg.matchingField); 229 } 230 } 231 syntheticArgs = nestedType.syntheticOuterLocalVariables(); 232 for (int i = 0, max = syntheticArgs == null ? 0 : syntheticArgs.length; i < max; i++) { 233 SyntheticArgumentBinding syntheticArg; 234 if ((syntheticArg = syntheticArgs[i]).matchingField != null) { 235 codeStream.aload_0(); 236 codeStream.load(syntheticArg); 237 codeStream.putfield(syntheticArg.matchingField); 238 } 239 } 240 } 241 242 private void internalGenerateCode(ClassScope classScope, ClassFile classFile) { 243 classFile.generateMethodInfoHeader(this.binding); 244 int methodAttributeOffset = classFile.contentsOffset; 245 int attributeNumber = classFile.generateMethodInfoAttribute(this.binding); 246 if ((!this.binding.isNative()) && (!this.binding.isAbstract())) { 247 248 TypeDeclaration declaringType = classScope.referenceContext; 249 int codeAttributeOffset = classFile.contentsOffset; 250 classFile.generateCodeAttributeHeader(); 251 CodeStream codeStream = classFile.codeStream; 252 codeStream.reset(this, classFile); 253 254 ReferenceBinding declaringClass = this.binding.declaringClass; 256 257 int enumOffset = declaringClass.isEnum() ? 2 : 0; int argSlotSize = 1 + enumOffset; 260 if (declaringClass.isNestedType()){ 261 NestedTypeBinding nestedType = (NestedTypeBinding) declaringClass; 262 this.scope.extraSyntheticArguments = nestedType.syntheticOuterLocalVariables(); 263 this.scope.computeLocalVariablePositions( nestedType.enclosingInstancesSlotSize + 1 + enumOffset, 265 codeStream); 266 argSlotSize += nestedType.enclosingInstancesSlotSize; 267 argSlotSize += nestedType.outerLocalVariablesSlotSize; 268 } else { 269 this.scope.computeLocalVariablePositions(1 + enumOffset, codeStream); 270 } 271 272 if (this.arguments != null) { 273 for (int i = 0, max = this.arguments.length; i < max; i++) { 274 LocalVariableBinding argBinding; 276 codeStream.addVisibleLocalVariable(argBinding = this.arguments[i].binding); 277 argBinding.recordInitializationStartPC(0); 278 TypeBinding argType; 279 if ((argType = argBinding.type) == TypeBinding.LONG || (argType == TypeBinding.DOUBLE)) { 280 argSlotSize += 2; 281 } else { 282 argSlotSize++; 283 } 284 } 285 } 286 287 MethodScope initializerScope = declaringType.initializerScope; 288 initializerScope.computeLocalVariablePositions(argSlotSize, codeStream); 290 boolean needFieldInitializations = this.constructorCall == null || this.constructorCall.accessMode != ExplicitConstructorCall.This; 291 292 boolean preInitSyntheticFields = this.scope.compilerOptions().targetJDK >= ClassFileConstants.JDK1_4; 294 295 if (needFieldInitializations && preInitSyntheticFields){ 296 generateSyntheticFieldInitializationsIfNecessary(this.scope, codeStream, declaringClass); 297 } 298 if (this.constructorCall != null) { 300 this.constructorCall.generateCode(this.scope, codeStream); 301 } 302 if (needFieldInitializations) { 304 if (!preInitSyntheticFields){ 305 generateSyntheticFieldInitializationsIfNecessary(this.scope, codeStream, declaringClass); 306 } 307 if (declaringType.fields != null) { 309 for (int i = 0, max = declaringType.fields.length; i < max; i++) { 310 FieldDeclaration fieldDecl; 311 if (!(fieldDecl = declaringType.fields[i]).isStatic()) { 312 fieldDecl.generateCode(initializerScope, codeStream); 313 } 314 } 315 } 316 } 317 if (this.statements != null) { 319 for (int i = 0, max = this.statements.length; i < max; i++) { 320 this.statements[i].generateCode(this.scope, codeStream); 321 } 322 } 323 if ((this.bits & ASTNode.NeedFreeReturn) != 0) { 324 codeStream.return_(); 325 } 326 codeStream.exitUserScope(this.scope); 328 codeStream.recordPositionsFrom(0, this.bodyEnd); 329 classFile.completeCodeAttribute(codeAttributeOffset); 330 attributeNumber++; 331 } 332 classFile.completeMethodInfo(methodAttributeOffset, attributeNumber); 333 334 if (this.ignoreFurtherInvestigation) { 336 throw new AbortMethod(this.scope.referenceCompilationUnit().compilationResult, null); 337 } 338 } 339 340 public boolean isConstructor() { 341 return true; 342 } 343 344 public boolean isDefaultConstructor() { 345 return (this.bits & ASTNode.IsDefaultConstructor) != 0; 346 } 347 348 public boolean isInitializationMethod() { 349 return true; 350 } 351 352 357 public boolean isRecursive(ArrayList visited) { 358 if (this.binding == null 359 || this.constructorCall == null 360 || this.constructorCall.binding == null 361 || this.constructorCall.isSuperAccess() 362 || !this.constructorCall.binding.isValidBinding()) { 363 return false; 364 } 365 366 ConstructorDeclaration targetConstructor = 367 ((ConstructorDeclaration)this.scope.referenceType().declarationOf(this.constructorCall.binding.original())); 368 if (this == targetConstructor) return true; 370 if (visited == null) { visited = new ArrayList (1); 372 } else { 373 int index = visited.indexOf(this); 374 if (index >= 0) return index == 0; } 376 visited.add(this); 377 378 return targetConstructor.isRecursive(visited); 379 } 380 381 public void parseStatements(Parser parser, CompilationUnitDeclaration unit) { 382 if (this.ignoreFurtherInvestigation) 384 return; 385 if (((this.bits & ASTNode.IsDefaultConstructor) != 0) && this.constructorCall == null){ 386 this.constructorCall = SuperReference.implicitSuperConstructorCall(); 387 this.constructorCall.sourceStart = this.sourceStart; 388 this.constructorCall.sourceEnd = this.sourceEnd; 389 return; 390 } 391 parser.parse(this, unit); 392 393 } 394 395 public StringBuffer printBody(int indent, StringBuffer output) { 396 output.append(" {"); if (this.constructorCall != null) { 398 output.append('\n'); 399 this.constructorCall.printStatement(indent, output); 400 } 401 if (this.statements != null) { 402 for (int i = 0; i < this.statements.length; i++) { 403 output.append('\n'); 404 this.statements[i].printStatement(indent, output); 405 } 406 } 407 output.append('\n'); 408 printIndent(indent == 0 ? 0 : indent - 1, output).append('}'); 409 return output; 410 } 411 412 public void resolveJavadoc() { 413 if (this.binding == null || this.javadoc != null) { 414 super.resolveJavadoc(); 415 } else if ((this.bits & ASTNode.IsDefaultConstructor) == 0) { 416 this.scope.problemReporter().javadocMissing(this.sourceStart, this.sourceEnd, this.binding.modifiers); 417 } 418 } 419 420 424 public void resolveStatements() { 425 SourceTypeBinding sourceType = this.scope.enclosingSourceType(); 426 if (!CharOperation.equals(sourceType.sourceName, this.selector)){ 427 this.scope.problemReporter().missingReturnType(this); 428 } 429 if (this.typeParameters != null) { 430 for (int i = 0, length = this.typeParameters.length; i < length; i++) { 431 this.typeParameters[i].resolve(this.scope); 432 } 433 } 434 if (this.binding != null && !this.binding.isPrivate()) { 435 sourceType.tagBits |= TagBits.HasNonPrivateConstructor; 436 } 437 if (this.constructorCall != null) { 439 if (sourceType.id == TypeIds.T_JavaLangObject 440 && this.constructorCall.accessMode != ExplicitConstructorCall.This) { 441 if (this.constructorCall.accessMode == ExplicitConstructorCall.Super) { 443 this.scope.problemReporter().cannotUseSuperInJavaLangObject(this.constructorCall); 444 } 445 this.constructorCall = null; 446 } else { 447 this.constructorCall.resolve(this.scope); 448 } 449 } 450 if ((this.modifiers & ExtraCompilerModifiers.AccSemicolonBody) != 0) { 451 this.scope.problemReporter().methodNeedBody(this); 452 } 453 super.resolveStatements(); 454 } 455 456 public void traverse(ASTVisitor visitor, ClassScope classScope) { 457 if (visitor.visit(this, classScope)) { 458 if (this.javadoc != null) { 459 this.javadoc.traverse(visitor, this.scope); 460 } 461 if (this.annotations != null) { 462 int annotationsLength = this.annotations.length; 463 for (int i = 0; i < annotationsLength; i++) 464 this.annotations[i].traverse(visitor, this.scope); 465 } 466 if (this.typeParameters != null) { 467 int typeParametersLength = this.typeParameters.length; 468 for (int i = 0; i < typeParametersLength; i++) { 469 this.typeParameters[i].traverse(visitor, this.scope); 470 } 471 } 472 if (this.arguments != null) { 473 int argumentLength = this.arguments.length; 474 for (int i = 0; i < argumentLength; i++) 475 this.arguments[i].traverse(visitor, this.scope); 476 } 477 if (this.thrownExceptions != null) { 478 int thrownExceptionsLength = this.thrownExceptions.length; 479 for (int i = 0; i < thrownExceptionsLength; i++) 480 this.thrownExceptions[i].traverse(visitor, this.scope); 481 } 482 if (this.constructorCall != null) 483 this.constructorCall.traverse(visitor, this.scope); 484 if (this.statements != null) { 485 int statementsLength = this.statements.length; 486 for (int i = 0; i < statementsLength; i++) 487 this.statements[i].traverse(visitor, this.scope); 488 } 489 } 490 visitor.endVisit(this, classScope); 491 } 492 public TypeParameter[] typeParameters() { 493 return this.typeParameters; 494 } 495 } 496 | Popular Tags |