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
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.ast;
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.*;
19 * Variation on allocation, where can be specified an enclosing instance and an anonymous type
21 public class QualifiedAllocationExpression extends AllocationExpression {
23 //qualification may be on both side
24 public Expression enclosingInstance;
25 public TypeDeclaration anonymousType;
26 public ReferenceBinding superTypeBinding;
28 public QualifiedAllocationExpression() {
32 public QualifiedAllocationExpression(TypeDeclaration anonymousType) {
33 this.anonymousType = anonymousType;
36 public FlowInfo analyseCode(
37 BlockScope currentScope,
38 FlowContext flowContext,
41 // analyse the enclosing instance
42 if (enclosingInstance != null) {
43 flowInfo = enclosingInstance.analyseCode(currentScope, flowContext, flowInfo);
46 // check captured variables are initialized in current context (26134)
47 checkCapturedLocalInitializationIfNecessary(
48 this.superTypeBinding == null ? this.binding.declaringClass : this.superTypeBinding,
53 if (arguments != null) {
54 for (int i = 0, count = arguments.length; i < count; i++) {
55 flowInfo = arguments[i].analyseCode(currentScope, flowContext, flowInfo);
59 // analyse the anonymous nested type
60 if (anonymousType != null) {
61 flowInfo = anonymousType.analyseCode(currentScope, flowContext, flowInfo);
64 // record some dependency information for exception types
65 ReferenceBinding[] thrownExceptions;
66 if (((thrownExceptions = binding.thrownExceptions).length) != 0) {
67 // check exception handling
68 flowContext.checkExceptionHandlers(
74 manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
75 manageSyntheticAccessIfNecessary(currentScope, flowInfo);
79 public Expression enclosingInstance() {
81 return enclosingInstance;
84 public void generateCode(
85 BlockScope currentScope,
86 CodeStream codeStream,
87 boolean valueRequired) {
89 int pc = codeStream.position;
90 ReferenceBinding allocatedType = binding.declaringClass;
91 codeStream.new_(allocatedType);
95 // better highlight for allocation: display the type individually
96 codeStream.recordPositionsFrom(pc, type.sourceStart);
98 // handling innerclass instance allocation - enclosing instance arguments
99 if (allocatedType.isNestedType()) {
100 codeStream.generateSyntheticEnclosingInstanceValues(
106 // generate the arguments for constructor
107 if (arguments != null) {
108 for (int i = 0, count = arguments.length; i < count; i++) {
109 arguments[i].generateCode(currentScope, codeStream, true);
112 // handling innerclass instance allocation - outer local arguments
113 if (allocatedType.isNestedType()) {
114 codeStream.generateSyntheticOuterArgumentValues(
120 // invoke constructor
121 if (syntheticAccessor == null) {
122 codeStream.invokespecial(binding);
124 // synthetic accessor got some extra arguments appended to its signature, which need values
126 max = syntheticAccessor.parameters.length - binding.parameters.length;
129 codeStream.aconst_null();
131 codeStream.invokespecial(syntheticAccessor);
133 codeStream.recordPositionsFrom(pc, this.sourceStart);
135 if (anonymousType != null) {
136 anonymousType.generateCode(currentScope, codeStream);
140 public boolean isSuperAccess() {
142 // necessary to lookup super constructor of anonymous type
143 return anonymousType != null;
146 /* Inner emulation consists in either recording a dependency
147 * link only, or performing one level of propagation.
149 * Dependency mechanism is used whenever dealing with source target
150 * types, since by the time we reach them, we might not yet know their
153 public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
155 if (!flowInfo.isReachable()) return;
156 ReferenceBinding allocatedType;
158 // perform some emulation work in case there is some and we are inside a local type only
159 if ((allocatedType = binding.declaringClass).isNestedType()
160 && currentScope.enclosingSourceType().isLocalType()) {
162 if (allocatedType.isLocalType()) {
163 ((LocalTypeBinding) allocatedType).addInnerEmulationDependent(currentScope, enclosingInstance != null);
165 // locally propagate, since we already now the desired shape for sure
166 currentScope.propagateInnerEmulation(allocatedType, enclosingInstance != null);
171 public StringBuffer printExpression(int indent, StringBuffer output) {
173 if (enclosingInstance != null)
174 enclosingInstance.printExpression(0, output).append('.');
175 super.printExpression(0, output);
176 if (anonymousType != null) {
177 anonymousType.print(indent, output);
182 public TypeBinding resolveType(BlockScope scope) {
184 // added for code assist...cannot occur with 'normal' code
185 if (anonymousType == null && enclosingInstance == null) {
186 return super.resolveType(scope);
189 // Propagate the type checking to the arguments, and checks if the constructor is defined.
190 // ClassInstanceCreationExpression ::= Primary '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt
191 // ClassInstanceCreationExpression ::= Name '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt
192 // ==> by construction, when there is an enclosing instance the typename may NOT be qualified
193 // ==> therefore by construction the type is always a SingleTypeReferenceType instead of being either
194 // sometime a SingleTypeReference and sometime a QualifedTypeReference
196 constant = NotAConstant;
197 TypeBinding enclosingInstanceType = null;
198 TypeBinding receiverType = null;
199 boolean hasError = false;
200 boolean enclosingInstanceContainsCast = false;
201 boolean argsContainCast = false;
203 if (enclosingInstance != null) {
204 if (enclosingInstance instanceof CastExpression) {
205 enclosingInstance.bits |= IgnoreNeedForCastCheckMASK; // will check later on
206 enclosingInstanceContainsCast = true;
208 if ((enclosingInstanceType = enclosingInstance.resolveType(scope)) == null){
210 } else if (enclosingInstanceType.isBaseType() || enclosingInstanceType.isArrayType()) {
211 scope.problemReporter().illegalPrimitiveOrArrayTypeForEnclosingInstance(
212 enclosingInstanceType,
216 receiverType = ((SingleTypeReference) type).resolveTypeEnclosing(scope, (ReferenceBinding) enclosingInstanceType);
217 if (receiverType != null && enclosingInstanceContainsCast) {
218 CastExpression.checkNeedForEnclosingInstanceCast(scope, enclosingInstance, enclosingInstanceType, receiverType);
222 receiverType = type.resolveType(scope);
224 if (receiverType == null) {
226 } else if (((ReferenceBinding) receiverType).isFinal() && this.anonymousType != null) {
227 scope.problemReporter().anonymousClassCannotExtendFinalClass(type, receiverType);
231 // will check for null after args are resolved
232 TypeBinding[] argumentTypes = NoParameters;
233 if (arguments != null) {
234 int length = arguments.length;
235 argumentTypes = new TypeBinding[length];
236 for (int i = 0; i < length; i++) {
237 Expression argument = this.arguments[i];
238 if (argument instanceof CastExpression) {
239 argument.bits |= IgnoreNeedForCastCheckMASK; // will check later on
240 argsContainCast = true;
242 if ((argumentTypes[i] = argument.resolveType(scope)) == null){
247 // limit of fault-tolerance
248 if (hasError) return this.resolvedType = receiverType;
250 if (this.anonymousType == null) {
251 // qualified allocation with no anonymous type
252 ReferenceBinding allocationType = (ReferenceBinding) receiverType;
253 if (!receiverType.canBeInstantiated()) {
254 scope.problemReporter().cannotInstantiate(type, receiverType);
255 return this.resolvedType = receiverType;
257 if ((this.binding = scope.getConstructor(allocationType, argumentTypes, this)).isValidBinding()) {
258 if (isMethodUseDeprecated(binding, scope)) {
259 scope.problemReporter().deprecatedMethod(this.binding, this);
261 if (arguments != null) {
262 for (int i = 0; i < arguments.length; i++) {
263 arguments[i].implicitWidening(this.binding.parameters[i], argumentTypes[i]);
265 if (argsContainCast) {
266 CastExpression.checkNeedForArgumentCasts(scope, null, allocationType, binding, this.arguments, argumentTypes, this);
270 if (this.binding.declaringClass == null) {
271 this.binding.declaringClass = allocationType;
273 scope.problemReporter().invalidConstructor(this, this.binding);
274 return this.resolvedType = receiverType;
277 // The enclosing instance must be compatible with the innermost enclosing type
278 ReferenceBinding expectedType = this.binding.declaringClass.enclosingType();
279 if (enclosingInstanceType.isCompatibleWith(expectedType)) {
282 scope.problemReporter().typeMismatchErrorActualTypeExpectedType(
283 this.enclosingInstance,
284 enclosingInstanceType,
286 return this.resolvedType = receiverType;
289 // anonymous type scenario
290 // an anonymous class inherits from java.lang.Object when declared "after" an interface
291 this.superTypeBinding = receiverType.isInterface() ? scope.getJavaLangObject() : (ReferenceBinding) receiverType;
292 // insert anonymous type in scope
293 scope.addAnonymousType(this.anonymousType, (ReferenceBinding) receiverType);
294 this.anonymousType.resolve(scope);
296 // find anonymous super constructor
297 MethodBinding inheritedBinding = scope.getConstructor(this.superTypeBinding, argumentTypes, this);
298 if (!inheritedBinding.isValidBinding()) {
299 if (inheritedBinding.declaringClass == null) {
300 inheritedBinding.declaringClass = this.superTypeBinding;
302 scope.problemReporter().invalidConstructor(this, inheritedBinding);
303 return this.resolvedType = anonymousType.binding;
305 if (enclosingInstance != null) {
306 ReferenceBinding targetEnclosing = inheritedBinding.declaringClass.enclosingType();
307 if (targetEnclosing == null) {
308 scope.problemReporter().unnecessaryEnclosingInstanceSpecification(enclosingInstance, (ReferenceBinding)receiverType);
309 return this.resolvedType = anonymousType.binding;
310 } else if (!enclosingInstanceType.isCompatibleWith(targetEnclosing)) {
311 scope.problemReporter().typeMismatchErrorActualTypeExpectedType(enclosingInstance, enclosingInstanceType, targetEnclosing);
312 return this.resolvedType = anonymousType.binding;
316 // this promotion has to be done somewhere: here or inside the constructor of the
317 // anonymous class. We do it here while the constructor of the inner is then easier.
318 if (arguments != null) {
319 for (int i = 0; i < arguments.length; i++) {
320 arguments[i].implicitWidening(inheritedBinding.parameters[i], argumentTypes[i]);
322 if (argsContainCast) {
323 CastExpression.checkNeedForArgumentCasts(scope, null, this.superTypeBinding, inheritedBinding, this.arguments, argumentTypes, this);
326 // Update the anonymous inner class : superclass, interface
327 binding = anonymousType.createsInternalConstructorWithBinding(inheritedBinding);
328 return this.resolvedType = anonymousType.binding; // 1.2 change
331 public void traverse(ASTVisitor visitor, BlockScope scope) {
333 if (visitor.visit(this, scope)) {
334 if (enclosingInstance != null)
335 enclosingInstance.traverse(visitor, scope);
336 type.traverse(visitor, scope);
337 if (arguments != null) {
338 int argumentsLength = arguments.length;
339 for (int i = 0; i < argumentsLength; i++)
340 arguments[i].traverse(visitor, scope);
342 if (anonymousType != null)
343 anonymousType.traverse(visitor, scope);
345 visitor.endVisit(this, scope);