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
26 public class QualifiedAllocationExpression extends AllocationExpression {
28 // qualification may be on both side
29 public Expression enclosingInstance;
31 public AnonymousLocalTypeDeclaration anonymousType;
33 public ReferenceBinding superTypeBinding;
35 public QualifiedAllocationExpression() {
38 public QualifiedAllocationExpression(
39 AnonymousLocalTypeDeclaration anonymousType) {
40 this.anonymousType = anonymousType;
43 public FlowInfo analyseCode(BlockScope currentScope,
44 FlowContext flowContext, FlowInfo flowInfo) {
46 // analyse the enclosing instance
47 if (enclosingInstance != null) {
48 flowInfo = enclosingInstance.analyseCode(currentScope, flowContext,
52 // check captured variables are initialized in current context (26134)
53 checkCapturedLocalInitializationIfNecessary(
54 this.superTypeBinding == null ? this.binding.declaringClass
55 : this.superTypeBinding, currentScope, flowInfo);
58 if (arguments != null) {
59 for (int i = 0, count = arguments.length; i < count; i++) {
60 flowInfo = arguments[i].analyseCode(currentScope, flowContext,
65 // analyse the anonymous nested type
66 if (anonymousType != null) {
67 flowInfo = anonymousType.analyseCode(currentScope, flowContext,
71 // record some dependency information for exception types
72 ReferenceBinding[] thrownExceptions;
73 if (((thrownExceptions = binding.thrownExceptions).length) != 0) {
74 // check exception handling
75 flowContext.checkExceptionHandlers(thrownExceptions, this,
76 flowInfo, currentScope);
78 manageEnclosingInstanceAccessIfNecessary(currentScope);
79 manageSyntheticAccessIfNecessary(currentScope);
83 public Expression enclosingInstance() {
85 return enclosingInstance;
88 // public void generateCode(
89 // BlockScope currentScope,
90 // CodeStream codeStream,
91 // boolean valueRequired) {
93 // int pc = codeStream.position;
94 // ReferenceBinding allocatedType = binding.declaringClass;
95 // codeStream.new_(allocatedType);
96 // if (valueRequired) {
99 // // better highlight for allocation: display the type individually
100 // codeStream.recordPositionsFrom(pc, type.sourceStart);
102 // // handling innerclass instance allocation - enclosing instance arguments
103 // if (allocatedType.isNestedType()) {
104 // codeStream.generateSyntheticEnclosingInstanceValues(
107 // enclosingInstance(),
110 // // generate the arguments for constructor
111 // if (arguments != null) {
112 // for (int i = 0, count = arguments.length; i < count; i++) {
113 // arguments[i].generateCode(currentScope, codeStream, true);
116 // // handling innerclass instance allocation - outer local arguments
117 // if (allocatedType.isNestedType()) {
118 // codeStream.generateSyntheticOuterArgumentValues(
124 // // invoke constructor
125 // if (syntheticAccessor == null) {
126 // codeStream.invokespecial(binding);
128 // // synthetic accessor got some extra arguments appended to its signature,
131 // max = syntheticAccessor.parameters.length - binding.parameters.length;
134 // codeStream.aconst_null();
136 // codeStream.invokespecial(syntheticAccessor);
138 // codeStream.recordPositionsFrom(pc, this.sourceStart);
140 // if (anonymousType != null) {
141 // anonymousType.generateCode(currentScope, codeStream);
145 public boolean isSuperAccess() {
147 // necessary to lookup super constructor of anonymous type
148 return anonymousType != null;
152 * Inner emulation consists in either recording a dependency link only, or
153 * performing one level of propagation.
155 * Dependency mechanism is used whenever dealing with source target types,
156 * since by the time we reach them, we might not yet know their exact need.
158 public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
160 ReferenceBinding allocatedType;
162 // perform some emulation work in case there is some and we are inside a
164 if ((allocatedType = binding.declaringClass).isNestedType()
165 && currentScope.enclosingSourceType().isLocalType()) {
167 if (allocatedType.isLocalType()) {
168 ((LocalTypeBinding) allocatedType).addInnerEmulationDependent(
169 currentScope, enclosingInstance != null);
171 // locally propagate, since we already now the desired shape for
173 currentScope.propagateInnerEmulation(allocatedType,
174 enclosingInstance != null);
179 public TypeBinding resolveType(BlockScope scope) {
181 // added for code assist...cannot occur with 'normal' code
182 if (anonymousType == null && enclosingInstance == null) {
183 return super.resolveType(scope);
186 // Propagate the type checking to the arguments, and checks if the
187 // constructor is defined.
188 // ClassInstanceCreationExpression ::= Primary '.' 'new' SimpleName '('
189 // ArgumentListopt ')' ClassBodyopt
190 // ClassInstanceCreationExpression ::= Name '.' 'new' SimpleName '('
191 // ArgumentListopt ')' ClassBodyopt
192 // ==> by construction, when there is an enclosing instance the typename
193 // may NOT be qualified
194 // ==> therefore by construction the type is always a
195 // SingleTypeReferenceType instead of being either
196 // sometime a SingleTypeReference and sometime a QualifedTypeReference
198 constant = NotAConstant;
199 TypeBinding enclosingInstanceType = null;
200 TypeBinding receiverType = null;
201 boolean hasError = false;
202 if (anonymousType == null) { // ----------------no anonymous
203 // class------------------------
204 if ((enclosingInstanceType = enclosingInstance.resolveType(scope)) == null) {
206 } else if (enclosingInstanceType.isBaseType()
207 || enclosingInstanceType.isArrayType()) {
208 scope.problemReporter()
209 .illegalPrimitiveOrArrayTypeForEnclosingInstance(
210 enclosingInstanceType, enclosingInstance);
212 } else if ((this.resolvedType = receiverType = ((SingleTypeReference) type)
213 .resolveTypeEnclosing(scope,
214 (ReferenceBinding) enclosingInstanceType)) == null) {
217 // will check for null after args are resolved
218 TypeBinding[] argumentTypes = NoParameters;
219 if (arguments != null) {
220 int length = arguments.length;
221 argumentTypes = new TypeBinding[length];
222 for (int i = 0; i < length; i++)
223 if ((argumentTypes[i] = arguments[i].resolveType(scope)) == null) {
227 // limit of fault-tolerance
231 if (!receiverType.canBeInstantiated()) {
232 scope.problemReporter().cannotInstantiate(type, receiverType);
235 if ((this.binding = scope.getConstructor(
236 (ReferenceBinding) receiverType, argumentTypes, this))
238 if (isMethodUseDeprecated(binding, scope))
239 scope.problemReporter()
240 .deprecatedMethod(this.binding, this);
242 if (arguments != null)
243 for (int i = 0; i < arguments.length; i++)
244 arguments[i].implicitWidening(
245 this.binding.parameters[i], argumentTypes[i]);
247 if (this.binding.declaringClass == null)
248 this.binding.declaringClass = (ReferenceBinding) receiverType;
249 scope.problemReporter().invalidConstructor(this, this.binding);
253 // The enclosing instance must be compatible with the innermost
255 ReferenceBinding expectedType = this.binding.declaringClass
257 if (enclosingInstanceType.isCompatibleWith(expectedType))
259 scope.problemReporter()
260 .typeMismatchErrorActualTypeExpectedType(
261 this.enclosingInstance, enclosingInstanceType,
266 // --------------there is an anonymous type declaration-----------------
267 if (this.enclosingInstance != null) {
268 if ((enclosingInstanceType = this.enclosingInstance
269 .resolveType(scope)) == null) {
271 } else if (enclosingInstanceType.isBaseType()
272 || enclosingInstanceType.isArrayType()) {
273 scope.problemReporter()
274 .illegalPrimitiveOrArrayTypeForEnclosingInstance(
275 enclosingInstanceType, this.enclosingInstance);
278 receiverType = ((SingleTypeReference) type)
279 .resolveTypeEnclosing(scope,
280 (ReferenceBinding) enclosingInstanceType);
283 receiverType = type.resolveType(scope);
285 if (receiverType == null) {
287 } else if (((ReferenceBinding) receiverType).isFinal()) {
288 scope.problemReporter().anonymousClassCannotExtendFinalClass(type,
292 TypeBinding[] argumentTypes = NoParameters;
293 if (arguments != null) {
294 int length = arguments.length;
295 argumentTypes = new TypeBinding[length];
296 for (int i = 0; i < length; i++)
297 if ((argumentTypes[i] = arguments[i].resolveType(scope)) == null) {
301 // limit of fault-tolerance
306 // an anonymous class inherits from java.lang.Object when declared
307 // "after" an interface
308 this.superTypeBinding = receiverType.isInterface() ? scope
309 .getJavaLangObject() : (ReferenceBinding) receiverType;
310 MethodBinding inheritedBinding = scope.getConstructor(
311 this.superTypeBinding, argumentTypes, this);
312 if (!inheritedBinding.isValidBinding()) {
313 if (inheritedBinding.declaringClass == null)
314 inheritedBinding.declaringClass = this.superTypeBinding;
315 scope.problemReporter().invalidConstructor(this, inheritedBinding);
318 if (enclosingInstance != null) {
319 if (!enclosingInstanceType
320 .isCompatibleWith(inheritedBinding.declaringClass
324 .typeMismatchErrorActualTypeExpectedType(
325 enclosingInstance, enclosingInstanceType,
326 inheritedBinding.declaringClass.enclosingType());
331 // this promotion has to be done somewhere: here or inside the
332 // constructor of the
333 // anonymous class. We do it here while the constructor of the inner is
335 if (arguments != null)
336 for (int i = 0; i < arguments.length; i++)
337 arguments[i].implicitWidening(inheritedBinding.parameters[i],
340 // Update the anonymous inner class : superclass, interface
341 scope.addAnonymousType(anonymousType, (ReferenceBinding) receiverType);
342 anonymousType.resolve(scope);
343 binding = anonymousType
344 .createsInternalConstructorWithBinding(inheritedBinding);
345 return anonymousType.binding; // 1.2 change
348 public String toStringExpression() {
349 return this.toStringExpression(0);
352 public String toStringExpression(int tab) {
354 String s = ""; //$NON-NLS-1$
355 if (enclosingInstance != null)
356 s += enclosingInstance.toString() + "."; //$NON-NLS-1$
357 s += super.toStringExpression();
358 if (anonymousType != null) {
359 s += anonymousType.toString(tab);
360 } // allows to restart just after the } one line under ....
364 public void traverse(ASTVisitor visitor, BlockScope scope) {
366 if (visitor.visit(this, scope)) {
367 if (enclosingInstance != null)
368 enclosingInstance.traverse(visitor, scope);
369 type.traverse(visitor, scope);
370 if (arguments != null) {
371 int argumentsLength = arguments.length;
372 for (int i = 0; i < argumentsLength; i++)
373 arguments[i].traverse(visitor, scope);
375 if (anonymousType != null)
376 anonymousType.traverse(visitor, scope);
378 visitor.endVisit(this, scope);