*** empty log message ***
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / QualifiedAllocationExpression.java
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
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.ast;
12
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;
22
23 public class QualifiedAllocationExpression extends AllocationExpression {
24         
25         //qualification may be on both side
26         public Expression enclosingInstance;
27         public AnonymousLocalTypeDeclaration anonymousType;
28
29         public QualifiedAllocationExpression() {
30         }
31
32         public QualifiedAllocationExpression(AnonymousLocalTypeDeclaration anonymousType) {
33                 this.anonymousType = anonymousType;
34         }
35
36         public FlowInfo analyseCode(
37                 BlockScope currentScope,
38                 FlowContext flowContext,
39                 FlowInfo flowInfo) {
40
41                 // variation on allocation, where can be specified an enclosing instance and an anonymous type
42
43                 // analyse the enclosing instance
44                 if (enclosingInstance != null) {
45                         flowInfo = enclosingInstance.analyseCode(currentScope, flowContext, flowInfo);
46                 }
47                 // process arguments
48                 if (arguments != null) {
49                         for (int i = 0, count = arguments.length; i < count; i++) {
50                                 flowInfo = arguments[i].analyseCode(currentScope, flowContext, flowInfo);
51                         }
52                 }
53
54                 // analyse the anonymous nested type
55                 if (anonymousType != null) {
56                         flowInfo = anonymousType.analyseCode(currentScope, flowContext, flowInfo);
57                 }
58
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(
64                                 thrownExceptions,
65                                 this,
66                                 flowInfo,
67                                 currentScope);
68                 }
69                 manageEnclosingInstanceAccessIfNecessary(currentScope);
70                 manageSyntheticAccessIfNecessary(currentScope);
71                 return flowInfo;
72         }
73
74         public Expression enclosingInstance() {
75
76                 return enclosingInstance;
77         }
78
79         public void generateCode(
80                 BlockScope currentScope,
81                 CodeStream codeStream,
82                 boolean valueRequired) {
83
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(
90                                         localType));
91                 }
92                 codeStream.new_(allocatedType);
93                 if (valueRequired) {
94                         codeStream.dup();
95                 }
96                 // better highlight for allocation: display the type individually
97                 codeStream.recordPositionsFrom(pc, type.sourceStart);
98
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(
103                                 currentScope,
104                                 allocatedType,
105                                 enclosingInstance(),
106                                 this);
107                 }
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);
112                         }
113                 }
114                 // invoke constructor
115                 if (syntheticAccessor == null) {
116                         codeStream.invokespecial(binding);
117                 } else {
118                         // synthetic accessor got some extra arguments appended to its signature, which need values
119                         for (int i = 0,
120                                 max = syntheticAccessor.parameters.length - binding.parameters.length;
121                                 i < max;
122                                 i++) {
123                                 codeStream.aconst_null();
124                         }
125                         codeStream.invokespecial(syntheticAccessor);
126                 }
127                 codeStream.recordPositionsFrom(pc, this.sourceStart);
128                 if (anonymousType != null) {
129                         anonymousType.generateCode(currentScope, codeStream);
130                 }
131         }
132         
133         public boolean isSuperAccess() {
134
135                 // necessary to lookup super constructor of anonymous type
136                 return anonymousType != null;
137         }
138         
139         /* Inner emulation consists in either recording a dependency 
140          * link only, or performing one level of propagation.
141          *
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
144          * exact need.
145          */
146         public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
147
148                 ReferenceBinding allocatedType;
149
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()) {
153
154                         if (allocatedType.isLocalType()) {
155                                 ((LocalTypeBinding) allocatedType).addInnerEmulationDependent(
156                                         currentScope,
157                                         enclosingInstance != null,
158                                         false);
159                                 // request cascade of accesses
160                         } else {
161                                 // locally propagate, since we already now the desired shape for sure
162                                 currentScope.propagateInnerEmulation(
163                                         allocatedType,
164                                         enclosingInstance != null,
165                                         false);
166                                 // request cascade of accesses
167                         }
168                 }
169         }
170
171         public TypeBinding resolveType(BlockScope scope) {
172
173                 if (anonymousType == null && enclosingInstance == null)
174                         return super.resolveType(scope);
175                 // added for code assist... is not possible with 'normal' code
176
177                 // Propagate the type checking to the arguments, and checks if the constructor is defined.
178
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
184
185                 constant = NotAConstant;
186                 TypeBinding enclosingInstTb = null;
187                 TypeBinding recType;
188                 if (anonymousType == null) {
189                         //----------------no anonymous class------------------------    
190                         if ((enclosingInstTb = enclosingInstance.resolveType(scope)) == null)
191                                 return null;
192                         if (enclosingInstTb.isBaseType() | enclosingInstTb.isArrayType()) {
193                                 scope.problemReporter().illegalPrimitiveOrArrayTypeForEnclosingInstance(
194                                         enclosingInstTb,
195                                         enclosingInstance);
196                                 return null;
197                         }
198                         recType =
199                                 ((SingleTypeReference) type).resolveTypeEnclosing(
200                                         scope,
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)
210                                                 argHasError = true;
211                                 if (argHasError)
212                                         return recType;
213                         }
214                         if (recType == null)
215                                 return null;
216                         if (!recType.canBeInstantiated()) {
217                                 scope.problemReporter().cannotInstantiate(type, recType);
218                                 return recType;
219                         }
220                         if ((binding =
221                                 scope.getConstructor((ReferenceBinding) recType, argumentTypes, this))
222                                 .isValidBinding()) {
223                                 if (isMethodUseDeprecated(binding, scope))
224                                         scope.problemReporter().deprecatedMethod(binding, this);
225
226                                 if (arguments != null)
227                                         for (int i = 0; i < arguments.length; i++)
228                                                 arguments[i].implicitWidening(binding.parameters[i], argumentTypes[i]);
229                         } else {
230                                 if (binding.declaringClass == null)
231                                         binding.declaringClass = (ReferenceBinding) recType;
232                                 scope.problemReporter().invalidConstructor(this, binding);
233                                 return recType;
234                         }
235
236                         // The enclosing instance must be compatible with the innermost enclosing type
237                         ReferenceBinding expectedType = binding.declaringClass.enclosingType();
238                         if (BlockScope.areTypesCompatible(enclosingInstTb, expectedType))
239                                 return recType;
240                         scope.problemReporter().typeMismatchErrorActualTypeExpectedType(
241                                 enclosingInstance,
242                                 enclosingInstTb,
243                                 expectedType);
244                         return recType;
245                 }
246
247                 //--------------there is an anonymous type declaration-----------------
248                 if (enclosingInstance != null) {
249                         if ((enclosingInstTb = enclosingInstance.resolveType(scope)) == null)
250                                 return null;
251                         if (enclosingInstTb.isBaseType() | enclosingInstTb.isArrayType()) {
252                                 scope.problemReporter().illegalPrimitiveOrArrayTypeForEnclosingInstance(
253                                         enclosingInstTb,
254                                         enclosingInstance);
255                                 return null;
256                         }
257                 }
258                 // due to syntax-construction, recType is a ReferenceBinding            
259                 recType =
260                         (enclosingInstance == null)
261                                 ? type.resolveType(scope)
262                                 : ((SingleTypeReference) type).resolveTypeEnclosing(
263                                         scope,
264                                         (ReferenceBinding) enclosingInstTb);
265                 if (recType == null)
266                         return null;
267                 if (((ReferenceBinding) recType).isFinal()) {
268                         scope.problemReporter().anonymousClassCannotExtendFinalClass(type, recType);
269                         return null;
270                 }
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)
277                                         return null;
278                 }
279
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);
289                         return null;
290                 }
291                 if (enclosingInstance != null) {
292                         if (!BlockScope
293                                 .areTypesCompatible(
294                                         enclosingInstTb,
295                                         inheritedBinding.declaringClass.enclosingType())) {
296                                 scope.problemReporter().typeMismatchErrorActualTypeExpectedType(
297                                         enclosingInstance,
298                                         enclosingInstTb,
299                                         inheritedBinding.declaringClass.enclosingType());
300                                 return null;
301                         }
302                 }
303
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]);
309
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
315         }
316
317         public String toStringExpression(int tab) {
318
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 ....
326                 return s;
327         }
328
329         public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
330
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);
339                         }
340                         if (anonymousType != null)
341                                 anonymousType.traverse(visitor, scope);
342                 }
343                 visitor.endVisit(this, scope);
344         }
345 }