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