1 /*******************************************************************************
2 * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v0.5
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v05.html
9 * IBM Corporation - initial API and implementation
10 ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.ast;
13 import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor;
14 import net.sourceforge.phpdt.internal.compiler.codegen.*;
15 import net.sourceforge.phpdt.internal.compiler.flow.*;
16 import net.sourceforge.phpdt.internal.compiler.lookup.*;
18 public class QualifiedAllocationExpression extends AllocationExpression {
20 //qualification may be on both side
21 public Expression enclosingInstance;
22 public AnonymousLocalTypeDeclaration anonymousType;
24 public QualifiedAllocationExpression() {
27 public QualifiedAllocationExpression(AnonymousLocalTypeDeclaration anonymousType) {
28 this.anonymousType = anonymousType;
31 public FlowInfo analyseCode(
32 BlockScope currentScope,
33 FlowContext flowContext,
36 // variation on allocation, where can be specified an enclosing instance and an anonymous type
38 // analyse the enclosing instance
39 if (enclosingInstance != null) {
40 flowInfo = enclosingInstance.analyseCode(currentScope, flowContext, flowInfo);
43 if (arguments != null) {
44 for (int i = 0, count = arguments.length; i < count; i++) {
45 flowInfo = arguments[i].analyseCode(currentScope, flowContext, flowInfo);
49 // analyse the anonymous nested type
50 if (anonymousType != null) {
51 flowInfo = anonymousType.analyseCode(currentScope, flowContext, flowInfo);
54 // record some dependency information for exception types
55 ReferenceBinding[] thrownExceptions;
56 if (((thrownExceptions = binding.thrownExceptions).length) != 0) {
57 // check exception handling
58 flowContext.checkExceptionHandlers(
64 manageEnclosingInstanceAccessIfNecessary(currentScope);
65 manageSyntheticAccessIfNecessary(currentScope);
69 public Expression enclosingInstance() {
71 return enclosingInstance;
74 public void generateCode(
75 BlockScope currentScope,
76 CodeStream codeStream,
77 boolean valueRequired) {
79 int pc = codeStream.position;
80 ReferenceBinding allocatedType = binding.declaringClass;
81 if (allocatedType.isLocalType()) {
82 LocalTypeBinding localType = (LocalTypeBinding) allocatedType;
83 localType.constantPoolName(
84 codeStream.classFile.outerMostEnclosingClassFile().computeConstantPoolName(
87 codeStream.new_(allocatedType);
91 // better highlight for allocation: display the type individually
92 codeStream.recordPositionsFrom(pc, type.sourceStart);
94 // handling innerclass instance allocation
95 if (allocatedType.isNestedType()) {
96 // make sure its name is computed before arguments, since may be necessary for argument emulation
97 codeStream.generateSyntheticArgumentValues(
103 // generate the arguments for constructor
104 if (arguments != null) {
105 for (int i = 0, count = arguments.length; i < count; i++) {
106 arguments[i].generateCode(currentScope, codeStream, true);
109 // invoke constructor
110 if (syntheticAccessor == null) {
111 codeStream.invokespecial(binding);
113 // synthetic accessor got some extra arguments appended to its signature, which need values
115 max = syntheticAccessor.parameters.length - binding.parameters.length;
118 codeStream.aconst_null();
120 codeStream.invokespecial(syntheticAccessor);
122 codeStream.recordPositionsFrom(pc, this.sourceStart);
123 if (anonymousType != null) {
124 anonymousType.generateCode(currentScope, codeStream);
128 public boolean isSuperAccess() {
130 // necessary to lookup super constructor of anonymous type
131 return anonymousType != null;
134 /* Inner emulation consists in either recording a dependency
135 * link only, or performing one level of propagation.
137 * Dependency mechanism is used whenever dealing with source target
138 * types, since by the time we reach them, we might not yet know their
141 public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
143 ReferenceBinding allocatedType;
145 // perform some emulation work in case there is some and we are inside a local type only
146 if ((allocatedType = binding.declaringClass).isNestedType()
147 && currentScope.enclosingSourceType().isLocalType()) {
149 if (allocatedType.isLocalType()) {
150 ((LocalTypeBinding) allocatedType).addInnerEmulationDependent(
152 enclosingInstance != null,
154 // request cascade of accesses
156 // locally propagate, since we already now the desired shape for sure
157 currentScope.propagateInnerEmulation(
159 enclosingInstance != null,
161 // request cascade of accesses
166 public TypeBinding resolveType(BlockScope scope) {
168 if (anonymousType == null && enclosingInstance == null)
169 return super.resolveType(scope);
170 // added for code assist... is not possible with 'normal' code
172 // Propagate the type checking to the arguments, and checks if the constructor is defined.
174 // ClassInstanceCreationExpression ::= Primary '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt
175 // ClassInstanceCreationExpression ::= Name '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt
176 // ==> by construction, when there is an enclosing instance the typename may NOT be qualified
177 // ==> therefore by construction the type is always a SingleTypeReferenceType instead of being either
178 // sometime a SingleTypeReference and sometime a QualifedTypeReference
180 constant = NotAConstant;
181 TypeBinding enclosingInstTb = null;
183 if (anonymousType == null) {
184 //----------------no anonymous class------------------------
185 if ((enclosingInstTb = enclosingInstance.resolveType(scope)) == null)
187 if (enclosingInstTb.isBaseType() | enclosingInstTb.isArrayType()) {
188 scope.problemReporter().illegalPrimitiveOrArrayTypeForEnclosingInstance(
194 ((SingleTypeReference) type).resolveTypeEnclosing(
196 (ReferenceBinding) enclosingInstTb);
197 // will check for null after args are resolved
198 TypeBinding[] argumentTypes = NoParameters;
199 if (arguments != null) {
200 boolean argHasError = false;
201 int length = arguments.length;
202 argumentTypes = new TypeBinding[length];
203 for (int i = 0; i < length; i++)
204 if ((argumentTypes[i] = arguments[i].resolveType(scope)) == null)
211 if (!recType.canBeInstantiated()) {
212 scope.problemReporter().cannotInstantiate(type, recType);
216 scope.getConstructor((ReferenceBinding) recType, argumentTypes, this))
218 if (isMethodUseDeprecated(binding, scope))
219 scope.problemReporter().deprecatedMethod(binding, this);
221 if (arguments != null)
222 for (int i = 0; i < arguments.length; i++)
223 arguments[i].implicitWidening(binding.parameters[i], argumentTypes[i]);
225 if (binding.declaringClass == null)
226 binding.declaringClass = (ReferenceBinding) recType;
227 scope.problemReporter().invalidConstructor(this, binding);
231 // The enclosing instance must be compatible with the innermost enclosing type
232 ReferenceBinding expectedType = binding.declaringClass.enclosingType();
233 if (scope.areTypesCompatible(enclosingInstTb, expectedType))
235 scope.problemReporter().typeMismatchErrorActualTypeExpectedType(
242 //--------------there is an anonymous type declaration-----------------
243 if (enclosingInstance != null) {
244 if ((enclosingInstTb = enclosingInstance.resolveType(scope)) == null)
246 if (enclosingInstTb.isBaseType() | enclosingInstTb.isArrayType()) {
247 scope.problemReporter().illegalPrimitiveOrArrayTypeForEnclosingInstance(
253 // due to syntax-construction, recType is a ReferenceBinding
255 (enclosingInstance == null)
256 ? type.resolveType(scope)
257 : ((SingleTypeReference) type).resolveTypeEnclosing(
259 (ReferenceBinding) enclosingInstTb);
262 if (((ReferenceBinding) recType).isFinal()) {
263 scope.problemReporter().anonymousClassCannotExtendFinalClass(type, recType);
266 TypeBinding[] argumentTypes = NoParameters;
267 if (arguments != null) {
268 int length = arguments.length;
269 argumentTypes = new TypeBinding[length];
270 for (int i = 0; i < length; i++)
271 if ((argumentTypes[i] = arguments[i].resolveType(scope)) == null)
275 // an anonymous class inherits from java.lang.Object when declared "after" an interface
276 ReferenceBinding superBinding =
277 recType.isInterface() ? scope.getJavaLangObject() : (ReferenceBinding) recType;
278 MethodBinding inheritedBinding =
279 scope.getConstructor(superBinding, argumentTypes, this);
280 if (!inheritedBinding.isValidBinding()) {
281 if (inheritedBinding.declaringClass == null)
282 inheritedBinding.declaringClass = superBinding;
283 scope.problemReporter().invalidConstructor(this, inheritedBinding);
286 if (enclosingInstance != null) {
290 inheritedBinding.declaringClass.enclosingType())) {
291 scope.problemReporter().typeMismatchErrorActualTypeExpectedType(
294 inheritedBinding.declaringClass.enclosingType());
299 // this promotion has to be done somewhere: here or inside the constructor of the
300 // anonymous class. We do it here while the constructor of the inner is then easier.
301 if (arguments != null)
302 for (int i = 0; i < arguments.length; i++)
303 arguments[i].implicitWidening(inheritedBinding.parameters[i], argumentTypes[i]);
305 // Update the anonymous inner class : superclass, interface
306 scope.addAnonymousType(anonymousType, (ReferenceBinding) recType);
307 anonymousType.resolve(scope);
308 binding = anonymousType.createsInternalConstructorWithBinding(inheritedBinding);
309 return anonymousType.binding; // 1.2 change
312 public String toStringExpression(int tab) {
314 String s = ""; //$NON-NLS-1$
315 if (enclosingInstance != null)
316 s += enclosingInstance.toString() + "."; //$NON-NLS-1$
317 s += super.toStringExpression(tab);
318 if (anonymousType != null) {
319 s += anonymousType.toString(tab);
320 } //allows to restart just after the } one line under ....
324 public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
326 if (visitor.visit(this, scope)) {
327 if (enclosingInstance != null)
328 enclosingInstance.traverse(visitor, scope);
329 type.traverse(visitor, scope);
330 if (arguments != null) {
331 int argumentsLength = arguments.length;
332 for (int i = 0; i < argumentsLength; i++)
333 arguments[i].traverse(visitor, scope);
335 if (anonymousType != null)
336 anonymousType.traverse(visitor, scope);
338 visitor.endVisit(this, scope);