1 /******************************************************************************* 2 * Copyright (c) 2000, 2004 IBM Corporation and others. 3 * All rights reserved. This program and the accompanying materials 4 * are made available under the terms of the Common Public License v1.0 5 * which accompanies this distribution, and is available at 6 * http://www.eclipse.org/legal/cpl-v10.html 7 * 8 * Contributors: 9 * IBM Corporation - initial API and implementation 10 *******************************************************************************/ 11 package org.eclipse.jdt.internal.compiler.ast; 12 13 import org.eclipse.jdt.internal.compiler.ASTVisitor; 14 import org.eclipse.jdt.internal.compiler.codegen.*; 15 import org.eclipse.jdt.internal.compiler.flow.*; 16 import org.eclipse.jdt.internal.compiler.lookup.*; 17 18 /** 19 * Variation on allocation, where can optionally be specified any of: 20 * - leading enclosing instance 21 * - trailing anonymous type 22 * - generic type arguments for generic constructor invocation 23 */ 24 public class QualifiedAllocationExpression extends AllocationExpression { 25 26 //qualification may be on both side 27 public Expression enclosingInstance; 28 public TypeDeclaration anonymousType; 29 public ReferenceBinding superTypeBinding; 30 QualifiedAllocationExpression()31 public QualifiedAllocationExpression() { 32 // for subtypes 33 } 34 QualifiedAllocationExpression(TypeDeclaration anonymousType)35 public QualifiedAllocationExpression(TypeDeclaration anonymousType) { 36 this.anonymousType = anonymousType; 37 } 38 analyseCode( BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo)39 public FlowInfo analyseCode( 40 BlockScope currentScope, 41 FlowContext flowContext, 42 FlowInfo flowInfo) { 43 44 // analyse the enclosing instance 45 if (enclosingInstance != null) { 46 flowInfo = enclosingInstance.analyseCode(currentScope, flowContext, flowInfo); 47 } 48 49 // check captured variables are initialized in current context (26134) 50 checkCapturedLocalInitializationIfNecessary( 51 this.superTypeBinding == null ? this.binding.declaringClass : this.superTypeBinding, 52 currentScope, 53 flowInfo); 54 55 // process arguments 56 if (arguments != null) { 57 for (int i = 0, count = arguments.length; i < count; i++) { 58 flowInfo = arguments[i].analyseCode(currentScope, flowContext, flowInfo); 59 } 60 } 61 62 // analyse the anonymous nested type 63 if (anonymousType != null) { 64 flowInfo = anonymousType.analyseCode(currentScope, flowContext, flowInfo); 65 } 66 67 // record some dependency information for exception types 68 ReferenceBinding[] thrownExceptions; 69 if (((thrownExceptions = binding.thrownExceptions).length) != 0) { 70 // check exception handling 71 flowContext.checkExceptionHandlers( 72 thrownExceptions, 73 this, 74 flowInfo, 75 currentScope); 76 } 77 manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo); 78 manageSyntheticAccessIfNecessary(currentScope, flowInfo); 79 return flowInfo; 80 } 81 enclosingInstance()82 public Expression enclosingInstance() { 83 84 return enclosingInstance; 85 } 86 generateCode( BlockScope currentScope, CodeStream codeStream, boolean valueRequired)87 public void generateCode( 88 BlockScope currentScope, 89 CodeStream codeStream, 90 boolean valueRequired) { 91 92 int pc = codeStream.position; 93 ReferenceBinding allocatedType = this.codegenBinding.declaringClass; 94 codeStream.new_(allocatedType); 95 if (valueRequired) { 96 codeStream.dup(); 97 } 98 // better highlight for allocation: display the type individually 99 codeStream.recordPositionsFrom(pc, type.sourceStart); 100 101 // handling innerclass instance allocation - enclosing instance arguments 102 if (allocatedType.isNestedType()) { 103 codeStream.generateSyntheticEnclosingInstanceValues( 104 currentScope, 105 allocatedType, 106 enclosingInstance(), 107 this); 108 } 109 // generate the arguments for constructor 110 if (arguments != null) { 111 for (int i = 0, count = arguments.length; i < count; i++) { 112 arguments[i].generateCode(currentScope, codeStream, true); 113 } 114 } 115 // handling innerclass instance allocation - outer local arguments 116 if (allocatedType.isNestedType()) { 117 codeStream.generateSyntheticOuterArgumentValues( 118 currentScope, 119 allocatedType, 120 this); 121 } 122 123 // invoke constructor 124 if (syntheticAccessor == null) { 125 codeStream.invokespecial(this.codegenBinding); 126 } else { 127 // synthetic accessor got some extra arguments appended to its signature, which need values 128 for (int i = 0, 129 max = syntheticAccessor.parameters.length - this.codegenBinding.parameters.length; 130 i < max; 131 i++) { 132 codeStream.aconst_null(); 133 } 134 codeStream.invokespecial(syntheticAccessor); 135 } 136 codeStream.recordPositionsFrom(pc, this.sourceStart); 137 138 if (anonymousType != null) { 139 anonymousType.generateCode(currentScope, codeStream); 140 } 141 } 142 isSuperAccess()143 public boolean isSuperAccess() { 144 145 // necessary to lookup super constructor of anonymous type 146 return anonymousType != null; 147 } 148 149 /* Inner emulation consists in either recording a dependency 150 * link only, or performing one level of propagation. 151 * 152 * Dependency mechanism is used whenever dealing with source target 153 * types, since by the time we reach them, we might not yet know their 154 * exact need. 155 */ manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo)156 public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) { 157 158 if (!flowInfo.isReachable()) return; 159 ReferenceBinding allocatedType; 160 161 // perform some emulation work in case there is some and we are inside a local type only 162 if ((allocatedType = binding.declaringClass).isNestedType() 163 && currentScope.enclosingSourceType().isLocalType()) { 164 165 if (allocatedType.isLocalType()) { 166 ((LocalTypeBinding) allocatedType).addInnerEmulationDependent(currentScope, enclosingInstance != null); 167 } else { 168 // locally propagate, since we already now the desired shape for sure 169 currentScope.propagateInnerEmulation(allocatedType, enclosingInstance != null); 170 } 171 } 172 } 173 printExpression(int indent, StringBuffer output)174 public StringBuffer printExpression(int indent, StringBuffer output) { 175 176 if (enclosingInstance != null) 177 enclosingInstance.printExpression(0, output).append('.'); 178 if (typeArguments != null) { 179 output.append('<');//$NON-NLS-1$ 180 int max = typeArguments.length - 1; 181 for (int j = 0; j < max; j++) { 182 typeArguments[j].print(0, output); 183 output.append(", ");//$NON-NLS-1$ 184 } 185 typeArguments[max].print(0, output); 186 output.append('>'); 187 } 188 super.printExpression(0, output); 189 if (anonymousType != null) { 190 anonymousType.print(indent, output); 191 } 192 return output; 193 } 194 resolveType(BlockScope scope)195 public TypeBinding resolveType(BlockScope scope) { 196 197 // added for code assist...cannot occur with 'normal' code 198 if (this.anonymousType == null && this.enclosingInstance == null) { 199 return super.resolveType(scope); 200 } 201 202 // Propagate the type checking to the arguments, and checks if the constructor is defined. 203 // ClassInstanceCreationExpression ::= Primary '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt 204 // ClassInstanceCreationExpression ::= Name '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt 205 206 constant = NotAConstant; 207 TypeBinding enclosingInstanceType = null; 208 TypeBinding receiverType = null; 209 boolean hasError = false; 210 boolean enclosingInstanceContainsCast = false; 211 boolean argsContainCast = false; 212 213 if (enclosingInstance != null) { 214 if (enclosingInstance instanceof CastExpression) { 215 enclosingInstance.bits |= IgnoreNeedForCastCheckMASK; // will check later on 216 enclosingInstanceContainsCast = true; 217 } 218 if ((enclosingInstanceType = enclosingInstance.resolveType(scope)) == null){ 219 hasError = true; 220 } else if (enclosingInstanceType.isBaseType() || enclosingInstanceType.isArrayType()) { 221 scope.problemReporter().illegalPrimitiveOrArrayTypeForEnclosingInstance( 222 enclosingInstanceType, 223 enclosingInstance); 224 hasError = true; 225 } else if (type instanceof QualifiedTypeReference) { 226 scope.problemReporter().illegalUsageOfQualifiedTypeReference((QualifiedTypeReference)type); 227 hasError = true; 228 } else { 229 receiverType = ((SingleTypeReference) type).resolveTypeEnclosing(scope, (ReferenceBinding) enclosingInstanceType); 230 if (receiverType != null && enclosingInstanceContainsCast) { 231 CastExpression.checkNeedForEnclosingInstanceCast(scope, enclosingInstance, enclosingInstanceType, receiverType); 232 } 233 } 234 } else { 235 receiverType = type.resolveType(scope); 236 } 237 if (receiverType == null) { 238 hasError = true; 239 } else if (((ReferenceBinding) receiverType).isFinal() && this.anonymousType != null) { 240 scope.problemReporter().anonymousClassCannotExtendFinalClass(type, receiverType); 241 hasError = true; 242 } 243 // resolve type arguments (for generic constructor call) 244 if (this.typeArguments != null) { 245 int length = this.typeArguments.length; 246 this.genericTypeArguments = new TypeBinding[length]; 247 for (int i = 0; i < length; i++) { 248 TypeBinding argType = this.typeArguments[i].resolveType(scope); 249 if (argType == null) return null; // error already reported 250 this.genericTypeArguments[i] = argType; 251 } 252 } 253 254 // will check for null after args are resolved 255 TypeBinding[] argumentTypes = NoParameters; 256 if (arguments != null) { 257 int length = arguments.length; 258 argumentTypes = new TypeBinding[length]; 259 for (int i = 0; i < length; i++) { 260 Expression argument = this.arguments[i]; 261 if (argument instanceof CastExpression) { 262 argument.bits |= IgnoreNeedForCastCheckMASK; // will check later on 263 argsContainCast = true; 264 } 265 if ((argumentTypes[i] = argument.resolveType(scope)) == null){ 266 hasError = true; 267 } 268 } 269 } 270 // limit of fault-tolerance 271 if (hasError) return this.resolvedType = receiverType; 272 if (this.anonymousType == null) { 273 // qualified allocation with no anonymous type 274 ReferenceBinding allocationType = (ReferenceBinding) receiverType; 275 if (!receiverType.canBeInstantiated()) { 276 scope.problemReporter().cannotInstantiate(type, receiverType); 277 return this.resolvedType = receiverType; 278 } 279 if ((this.binding = scope.getConstructor(allocationType, argumentTypes, this)).isValidBinding()) { 280 if (isMethodUseDeprecated(binding, scope)) { 281 scope.problemReporter().deprecatedMethod(this.binding, this); 282 } 283 if (this.arguments != null) 284 checkInvocationArguments(scope, null, allocationType, binding, this.arguments, argumentTypes, argsContainCast, this); 285 } else { 286 if (this.binding.declaringClass == null) { 287 this.binding.declaringClass = allocationType; 288 } 289 scope.problemReporter().invalidConstructor(this, this.binding); 290 return this.resolvedType = receiverType; 291 } 292 293 // The enclosing instance must be compatible with the innermost enclosing type 294 ReferenceBinding expectedType = this.binding.declaringClass.enclosingType(); 295 if (enclosingInstanceType.isCompatibleWith(expectedType)) { 296 enclosingInstance.computeConversion(scope, expectedType, enclosingInstanceType); 297 return receiverType; 298 } 299 scope.problemReporter().typeMismatchError(enclosingInstanceType, expectedType, this.enclosingInstance); 300 return this.resolvedType = receiverType; 301 } 302 303 // anonymous type scenario 304 // an anonymous class inherits from java.lang.Object when declared "after" an interface 305 this.superTypeBinding = receiverType.isInterface() ? scope.getJavaLangObject() : (ReferenceBinding) receiverType; 306 // insert anonymous type in scope 307 scope.addAnonymousType(this.anonymousType, (ReferenceBinding) receiverType); 308 this.anonymousType.resolve(scope); 309 310 // find anonymous super constructor 311 MethodBinding inheritedBinding = scope.getConstructor(this.superTypeBinding, argumentTypes, this); 312 if (!inheritedBinding.isValidBinding()) { 313 if (inheritedBinding.declaringClass == null) { 314 inheritedBinding.declaringClass = this.superTypeBinding; 315 } 316 scope.problemReporter().invalidConstructor(this, inheritedBinding); 317 return this.resolvedType = anonymousType.binding; 318 } 319 if (enclosingInstance != null) { 320 ReferenceBinding targetEnclosing = inheritedBinding.declaringClass.enclosingType(); 321 if (targetEnclosing == null) { 322 scope.problemReporter().unnecessaryEnclosingInstanceSpecification(enclosingInstance, (ReferenceBinding)receiverType); 323 return this.resolvedType = anonymousType.binding; 324 } else if (!enclosingInstanceType.isCompatibleWith(targetEnclosing)) { 325 scope.problemReporter().typeMismatchError(enclosingInstanceType, targetEnclosing, enclosingInstance); 326 return this.resolvedType = anonymousType.binding; 327 } 328 enclosingInstance.computeConversion(scope, targetEnclosing, enclosingInstanceType); 329 } 330 if (this.arguments != null) 331 checkInvocationArguments(scope, null, this.superTypeBinding, inheritedBinding, this.arguments, argumentTypes, argsContainCast, this); 332 333 // Update the anonymous inner class : superclass, interface 334 binding = anonymousType.createsInternalConstructorWithBinding(inheritedBinding); 335 return this.resolvedType = anonymousType.binding; // 1.2 change 336 } 337 traverse(ASTVisitor visitor, BlockScope scope)338 public void traverse(ASTVisitor visitor, BlockScope scope) { 339 340 if (visitor.visit(this, scope)) { 341 if (enclosingInstance != null) 342 enclosingInstance.traverse(visitor, scope); 343 if (this.typeArguments != null) { 344 for (int i = 0, typeArgumentsLength = this.typeArguments.length; i < typeArgumentsLength; i++) { 345 this.typeArguments[i].traverse(visitor, scope); 346 } 347 } 348 type.traverse(visitor, scope); 349 if (arguments != null) { 350 int argumentsLength = arguments.length; 351 for (int i = 0; i < argumentsLength; i++) 352 arguments[i].traverse(visitor, scope); 353 } 354 if (anonymousType != null) 355 anonymousType.traverse(visitor, scope); 356 } 357 visitor.endVisit(this, scope); 358 } 359 } 360