1 /*******************************************************************************
2 * Copyright (c) 2000, 2003 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 net.sourceforge.phpdt.internal.compiler.ast;
13 import net.sourceforge.phpdt.internal.compiler.ASTVisitor;
14 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
15 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
16 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
17 import net.sourceforge.phpdt.internal.compiler.lookup.LocalTypeBinding;
18 import net.sourceforge.phpdt.internal.compiler.lookup.MethodBinding;
19 import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding;
20 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
23 * Variation on allocation, where can be specified an enclosing instance and an anonymous type
25 public class QualifiedAllocationExpression extends AllocationExpression {
27 //qualification may be on both side
28 public Expression enclosingInstance;
29 public AnonymousLocalTypeDeclaration anonymousType;
30 public ReferenceBinding superTypeBinding;
32 public QualifiedAllocationExpression() {
35 public QualifiedAllocationExpression(AnonymousLocalTypeDeclaration anonymousType) {
36 this.anonymousType = anonymousType;
39 public FlowInfo analyseCode(
40 BlockScope currentScope,
41 FlowContext flowContext,
44 // analyse the enclosing instance
45 if (enclosingInstance != null) {
46 flowInfo = enclosingInstance.analyseCode(currentScope, flowContext, flowInfo);
49 // check captured variables are initialized in current context (26134)
50 checkCapturedLocalInitializationIfNecessary(
51 this.superTypeBinding == null ? this.binding.declaringClass : this.superTypeBinding,
56 if (arguments != null) {
57 for (int i = 0, count = arguments.length; i < count; i++) {
58 flowInfo = arguments[i].analyseCode(currentScope, flowContext, flowInfo);
62 // analyse the anonymous nested type
63 if (anonymousType != null) {
64 flowInfo = anonymousType.analyseCode(currentScope, flowContext, flowInfo);
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(
77 manageEnclosingInstanceAccessIfNecessary(currentScope);
78 manageSyntheticAccessIfNecessary(currentScope);
82 public Expression enclosingInstance() {
84 return enclosingInstance;
87 // public void generateCode(
88 // BlockScope currentScope,
89 // CodeStream codeStream,
90 // boolean valueRequired) {
92 // int pc = codeStream.position;
93 // ReferenceBinding allocatedType = binding.declaringClass;
94 // codeStream.new_(allocatedType);
95 // if (valueRequired) {
98 // // better highlight for allocation: display the type individually
99 // codeStream.recordPositionsFrom(pc, type.sourceStart);
101 // // handling innerclass instance allocation - enclosing instance arguments
102 // if (allocatedType.isNestedType()) {
103 // codeStream.generateSyntheticEnclosingInstanceValues(
106 // enclosingInstance(),
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);
115 // // handling innerclass instance allocation - outer local arguments
116 // if (allocatedType.isNestedType()) {
117 // codeStream.generateSyntheticOuterArgumentValues(
123 // // invoke constructor
124 // if (syntheticAccessor == null) {
125 // codeStream.invokespecial(binding);
127 // // synthetic accessor got some extra arguments appended to its signature, which need values
129 // max = syntheticAccessor.parameters.length - binding.parameters.length;
132 // codeStream.aconst_null();
134 // codeStream.invokespecial(syntheticAccessor);
136 // codeStream.recordPositionsFrom(pc, this.sourceStart);
138 // if (anonymousType != null) {
139 // anonymousType.generateCode(currentScope, codeStream);
143 public boolean isSuperAccess() {
145 // necessary to lookup super constructor of anonymous type
146 return anonymousType != null;
149 /* Inner emulation consists in either recording a dependency
150 * link only, or performing one level of propagation.
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
156 public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
158 ReferenceBinding allocatedType;
160 // perform some emulation work in case there is some and we are inside a local type only
161 if ((allocatedType = binding.declaringClass).isNestedType()
162 && currentScope.enclosingSourceType().isLocalType()) {
164 if (allocatedType.isLocalType()) {
165 ((LocalTypeBinding) allocatedType).addInnerEmulationDependent(currentScope, enclosingInstance != null);
167 // locally propagate, since we already now the desired shape for sure
168 currentScope.propagateInnerEmulation(allocatedType, enclosingInstance != null);
173 public TypeBinding resolveType(BlockScope scope) {
175 // added for code assist...cannot occur with 'normal' code
176 if (anonymousType == null && enclosingInstance == null) {
177 return super.resolveType(scope);
180 // Propagate the type checking to the arguments, and checks if the constructor is defined.
181 // ClassInstanceCreationExpression ::= Primary '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt
182 // ClassInstanceCreationExpression ::= Name '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt
183 // ==> by construction, when there is an enclosing instance the typename may NOT be qualified
184 // ==> therefore by construction the type is always a SingleTypeReferenceType instead of being either
185 // sometime a SingleTypeReference and sometime a QualifedTypeReference
187 constant = NotAConstant;
188 TypeBinding enclosingInstanceType = null;
189 TypeBinding receiverType = null;
190 boolean hasError = false;
191 if (anonymousType == null) { //----------------no anonymous class------------------------
192 if ((enclosingInstanceType = enclosingInstance.resolveType(scope)) == null){
194 } else if (enclosingInstanceType.isBaseType() || enclosingInstanceType.isArrayType()) {
195 scope.problemReporter().illegalPrimitiveOrArrayTypeForEnclosingInstance(
196 enclosingInstanceType,
199 } else if ((this.resolvedType = receiverType = ((SingleTypeReference) type).resolveTypeEnclosing(
201 (ReferenceBinding) enclosingInstanceType)) == null) {
204 // will check for null after args are resolved
205 TypeBinding[] argumentTypes = NoParameters;
206 if (arguments != null) {
207 int length = arguments.length;
208 argumentTypes = new TypeBinding[length];
209 for (int i = 0; i < length; i++)
210 if ((argumentTypes[i] = arguments[i].resolveType(scope)) == null){
214 // limit of fault-tolerance
215 if (hasError) return receiverType;
217 if (!receiverType.canBeInstantiated()) {
218 scope.problemReporter().cannotInstantiate(type, receiverType);
221 if ((this.binding = scope.getConstructor((ReferenceBinding) receiverType, argumentTypes, this))
223 if (isMethodUseDeprecated(binding, scope))
224 scope.problemReporter().deprecatedMethod(this.binding, this);
226 if (arguments != null)
227 for (int i = 0; i < arguments.length; i++)
228 arguments[i].implicitWidening(this.binding.parameters[i], argumentTypes[i]);
230 if (this.binding.declaringClass == null)
231 this.binding.declaringClass = (ReferenceBinding) receiverType;
232 scope.problemReporter().invalidConstructor(this, this.binding);
236 // The enclosing instance must be compatible with the innermost enclosing type
237 ReferenceBinding expectedType = this.binding.declaringClass.enclosingType();
238 if (enclosingInstanceType.isCompatibleWith(expectedType))
240 scope.problemReporter().typeMismatchErrorActualTypeExpectedType(
241 this.enclosingInstance,
242 enclosingInstanceType,
247 //--------------there is an anonymous type declaration-----------------
248 if (this.enclosingInstance != null) {
249 if ((enclosingInstanceType = this.enclosingInstance.resolveType(scope)) == null) {
251 } else if (enclosingInstanceType.isBaseType() || enclosingInstanceType.isArrayType()) {
252 scope.problemReporter().illegalPrimitiveOrArrayTypeForEnclosingInstance(
253 enclosingInstanceType,
254 this.enclosingInstance);
257 receiverType = ((SingleTypeReference) type).resolveTypeEnclosing(
259 (ReferenceBinding) enclosingInstanceType);
262 receiverType = type.resolveType(scope);
264 if (receiverType == null) {
266 } else if (((ReferenceBinding) receiverType).isFinal()) {
267 scope.problemReporter().anonymousClassCannotExtendFinalClass(type, receiverType);
270 TypeBinding[] argumentTypes = NoParameters;
271 if (arguments != null) {
272 int length = arguments.length;
273 argumentTypes = new TypeBinding[length];
274 for (int i = 0; i < length; i++)
275 if ((argumentTypes[i] = arguments[i].resolveType(scope)) == null) {
279 // limit of fault-tolerance
284 // an anonymous class inherits from java.lang.Object when declared "after" an interface
285 this.superTypeBinding =
286 receiverType.isInterface() ? scope.getJavaLangObject() : (ReferenceBinding) receiverType;
287 MethodBinding inheritedBinding =
288 scope.getConstructor(this.superTypeBinding, argumentTypes, this);
289 if (!inheritedBinding.isValidBinding()) {
290 if (inheritedBinding.declaringClass == null)
291 inheritedBinding.declaringClass = this.superTypeBinding;
292 scope.problemReporter().invalidConstructor(this, inheritedBinding);
295 if (enclosingInstance != null) {
296 if (!enclosingInstanceType.isCompatibleWith(inheritedBinding.declaringClass.enclosingType())) {
297 scope.problemReporter().typeMismatchErrorActualTypeExpectedType(
299 enclosingInstanceType,
300 inheritedBinding.declaringClass.enclosingType());
305 // this promotion has to be done somewhere: here or inside the constructor of the
306 // anonymous class. We do it here while the constructor of the inner is then easier.
307 if (arguments != null)
308 for (int i = 0; i < arguments.length; i++)
309 arguments[i].implicitWidening(inheritedBinding.parameters[i], argumentTypes[i]);
311 // Update the anonymous inner class : superclass, interface
312 scope.addAnonymousType(anonymousType, (ReferenceBinding) receiverType);
313 anonymousType.resolve(scope);
314 binding = anonymousType.createsInternalConstructorWithBinding(inheritedBinding);
315 return anonymousType.binding; // 1.2 change
318 public String toStringExpression() {
319 return this.toStringExpression(0);
322 public String toStringExpression(int tab) {
324 String s = ""; //$NON-NLS-1$
325 if (enclosingInstance != null)
326 s += enclosingInstance.toString() + "."; //$NON-NLS-1$
327 s += super.toStringExpression();
328 if (anonymousType != null) {
329 s += anonymousType.toString(tab);
330 } //allows to restart just after the } one line under ....
334 public void traverse(ASTVisitor visitor, BlockScope scope) {
336 if (visitor.visit(this, scope)) {
337 if (enclosingInstance != null)
338 enclosingInstance.traverse(visitor, scope);
339 type.traverse(visitor, scope);
340 if (arguments != null) {
341 int argumentsLength = arguments.length;
342 for (int i = 0; i < argumentsLength; i++)
343 arguments[i].traverse(visitor, scope);
345 if (anonymousType != null)
346 anonymousType.traverse(visitor, scope);
348 visitor.endVisit(this, scope);