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.CodeStream;
15 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
16 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
17 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
18 import net.sourceforge.phpdt.internal.compiler.lookup.LocalTypeBinding;
19 import net.sourceforge.phpdt.internal.compiler.lookup.MethodBinding;
20 import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding;
21 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
23 public class QualifiedAllocationExpression extends AllocationExpression {
25 //qualification may be on both side
26 public Expression enclosingInstance;
27 public AnonymousLocalTypeDeclaration anonymousType;
29 public QualifiedAllocationExpression() {
32 public QualifiedAllocationExpression(AnonymousLocalTypeDeclaration anonymousType) {
33 this.anonymousType = anonymousType;
36 public FlowInfo analyseCode(
37 BlockScope currentScope,
38 FlowContext flowContext,
41 // variation on allocation, where can be specified an enclosing instance and an anonymous type
43 // analyse the enclosing instance
44 if (enclosingInstance != null) {
45 flowInfo = enclosingInstance.analyseCode(currentScope, flowContext, flowInfo);
48 if (arguments != null) {
49 for (int i = 0, count = arguments.length; i < count; i++) {
50 flowInfo = arguments[i].analyseCode(currentScope, flowContext, flowInfo);
54 // analyse the anonymous nested type
55 if (anonymousType != null) {
56 flowInfo = anonymousType.analyseCode(currentScope, flowContext, flowInfo);
59 // record some dependency information for exception types
60 ReferenceBinding[] thrownExceptions;
61 if (((thrownExceptions = binding.thrownExceptions).length) != 0) {
62 // check exception handling
63 flowContext.checkExceptionHandlers(
69 manageEnclosingInstanceAccessIfNecessary(currentScope);
70 manageSyntheticAccessIfNecessary(currentScope);
74 public Expression enclosingInstance() {
76 return enclosingInstance;
79 public void generateCode(
80 BlockScope currentScope,
81 CodeStream codeStream,
82 boolean valueRequired) {
84 int pc = codeStream.position;
85 ReferenceBinding allocatedType = binding.declaringClass;
86 if (allocatedType.isLocalType()) {
87 LocalTypeBinding localType = (LocalTypeBinding) allocatedType;
88 localType.constantPoolName(
89 codeStream.classFile.outerMostEnclosingClassFile().computeConstantPoolName(
92 codeStream.new_(allocatedType);
96 // better highlight for allocation: display the type individually
97 codeStream.recordPositionsFrom(pc, type.sourceStart);
99 // handling innerclass instance allocation
100 if (allocatedType.isNestedType()) {
101 // make sure its name is computed before arguments, since may be necessary for argument emulation
102 codeStream.generateSyntheticArgumentValues(
108 // generate the arguments for constructor
109 if (arguments != null) {
110 for (int i = 0, count = arguments.length; i < count; i++) {
111 arguments[i].generateCode(currentScope, codeStream, true);
114 // invoke constructor
115 if (syntheticAccessor == null) {
116 codeStream.invokespecial(binding);
118 // synthetic accessor got some extra arguments appended to its signature, which need values
120 max = syntheticAccessor.parameters.length - binding.parameters.length;
123 codeStream.aconst_null();
125 codeStream.invokespecial(syntheticAccessor);
127 codeStream.recordPositionsFrom(pc, this.sourceStart);
128 if (anonymousType != null) {
129 anonymousType.generateCode(currentScope, codeStream);
133 public boolean isSuperAccess() {
135 // necessary to lookup super constructor of anonymous type
136 return anonymousType != null;
139 /* Inner emulation consists in either recording a dependency
140 * link only, or performing one level of propagation.
142 * Dependency mechanism is used whenever dealing with source target
143 * types, since by the time we reach them, we might not yet know their
146 public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
148 ReferenceBinding allocatedType;
150 // perform some emulation work in case there is some and we are inside a local type only
151 if ((allocatedType = binding.declaringClass).isNestedType()
152 && currentScope.enclosingSourceType().isLocalType()) {
154 if (allocatedType.isLocalType()) {
155 ((LocalTypeBinding) allocatedType).addInnerEmulationDependent(
157 enclosingInstance != null,
159 // request cascade of accesses
161 // locally propagate, since we already now the desired shape for sure
162 currentScope.propagateInnerEmulation(
164 enclosingInstance != null,
166 // request cascade of accesses
171 public TypeBinding resolveType(BlockScope scope) {
173 if (anonymousType == null && enclosingInstance == null)
174 return super.resolveType(scope);
175 // added for code assist... is not possible with 'normal' code
177 // Propagate the type checking to the arguments, and checks if the constructor is defined.
179 // ClassInstanceCreationExpression ::= Primary '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt
180 // ClassInstanceCreationExpression ::= Name '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt
181 // ==> by construction, when there is an enclosing instance the typename may NOT be qualified
182 // ==> therefore by construction the type is always a SingleTypeReferenceType instead of being either
183 // sometime a SingleTypeReference and sometime a QualifedTypeReference
185 constant = NotAConstant;
186 TypeBinding enclosingInstTb = null;
188 if (anonymousType == null) {
189 //----------------no anonymous class------------------------
190 if ((enclosingInstTb = enclosingInstance.resolveType(scope)) == null)
192 if (enclosingInstTb.isBaseType() | enclosingInstTb.isArrayType()) {
193 scope.problemReporter().illegalPrimitiveOrArrayTypeForEnclosingInstance(
199 ((SingleTypeReference) type).resolveTypeEnclosing(
201 (ReferenceBinding) enclosingInstTb);
202 // will check for null after args are resolved
203 TypeBinding[] argumentTypes = NoParameters;
204 if (arguments != null) {
205 boolean argHasError = false;
206 int length = arguments.length;
207 argumentTypes = new TypeBinding[length];
208 for (int i = 0; i < length; i++)
209 if ((argumentTypes[i] = arguments[i].resolveType(scope)) == null)
216 if (!recType.canBeInstantiated()) {
217 scope.problemReporter().cannotInstantiate(type, recType);
221 scope.getConstructor((ReferenceBinding) recType, argumentTypes, this))
223 if (isMethodUseDeprecated(binding, scope))
224 scope.problemReporter().deprecatedMethod(binding, this);
226 if (arguments != null)
227 for (int i = 0; i < arguments.length; i++)
228 arguments[i].implicitWidening(binding.parameters[i], argumentTypes[i]);
230 if (binding.declaringClass == null)
231 binding.declaringClass = (ReferenceBinding) recType;
232 scope.problemReporter().invalidConstructor(this, binding);
236 // The enclosing instance must be compatible with the innermost enclosing type
237 ReferenceBinding expectedType = binding.declaringClass.enclosingType();
238 if (BlockScope.areTypesCompatible(enclosingInstTb, expectedType))
240 scope.problemReporter().typeMismatchErrorActualTypeExpectedType(
247 //--------------there is an anonymous type declaration-----------------
248 if (enclosingInstance != null) {
249 if ((enclosingInstTb = enclosingInstance.resolveType(scope)) == null)
251 if (enclosingInstTb.isBaseType() | enclosingInstTb.isArrayType()) {
252 scope.problemReporter().illegalPrimitiveOrArrayTypeForEnclosingInstance(
258 // due to syntax-construction, recType is a ReferenceBinding
260 (enclosingInstance == null)
261 ? type.resolveType(scope)
262 : ((SingleTypeReference) type).resolveTypeEnclosing(
264 (ReferenceBinding) enclosingInstTb);
267 if (((ReferenceBinding) recType).isFinal()) {
268 scope.problemReporter().anonymousClassCannotExtendFinalClass(type, recType);
271 TypeBinding[] argumentTypes = NoParameters;
272 if (arguments != null) {
273 int length = arguments.length;
274 argumentTypes = new TypeBinding[length];
275 for (int i = 0; i < length; i++)
276 if ((argumentTypes[i] = arguments[i].resolveType(scope)) == null)
280 // an anonymous class inherits from java.lang.Object when declared "after" an interface
281 ReferenceBinding superBinding =
282 recType.isInterface() ? scope.getJavaLangObject() : (ReferenceBinding) recType;
283 MethodBinding inheritedBinding =
284 scope.getConstructor(superBinding, argumentTypes, this);
285 if (!inheritedBinding.isValidBinding()) {
286 if (inheritedBinding.declaringClass == null)
287 inheritedBinding.declaringClass = superBinding;
288 scope.problemReporter().invalidConstructor(this, inheritedBinding);
291 if (enclosingInstance != null) {
295 inheritedBinding.declaringClass.enclosingType())) {
296 scope.problemReporter().typeMismatchErrorActualTypeExpectedType(
299 inheritedBinding.declaringClass.enclosingType());
304 // this promotion has to be done somewhere: here or inside the constructor of the
305 // anonymous class. We do it here while the constructor of the inner is then easier.
306 if (arguments != null)
307 for (int i = 0; i < arguments.length; i++)
308 arguments[i].implicitWidening(inheritedBinding.parameters[i], argumentTypes[i]);
310 // Update the anonymous inner class : superclass, interface
311 scope.addAnonymousType(anonymousType, (ReferenceBinding) recType);
312 anonymousType.resolve(scope);
313 binding = anonymousType.createsInternalConstructorWithBinding(inheritedBinding);
314 return anonymousType.binding; // 1.2 change
317 public String toStringExpression(int tab) {
319 String s = ""; //$NON-NLS-1$
320 if (enclosingInstance != null)
321 s += enclosingInstance.toString() + "."; //$NON-NLS-1$
322 s += super.toStringExpression(tab);
323 if (anonymousType != null) {
324 s += anonymousType.toString(tab);
325 } //allows to restart just after the } one line under ....
329 public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
331 if (visitor.visit(this, scope)) {
332 if (enclosingInstance != null)
333 enclosingInstance.traverse(visitor, scope);
334 type.traverse(visitor, scope);
335 if (arguments != null) {
336 int argumentsLength = arguments.length;
337 for (int i = 0; i < argumentsLength; i++)
338 arguments[i].traverse(visitor, scope);
340 if (anonymousType != null)
341 anonymousType.traverse(visitor, scope);
343 visitor.endVisit(this, scope);