A variable description (like PHPFunctionDeclaration)
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / AllocationExpression.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.*;
15 import net.sourceforge.phpdt.internal.compiler.flow.*;
16 import net.sourceforge.phpdt.internal.compiler.lookup.*;
17
18 public class AllocationExpression
19         extends Expression
20         implements InvocationSite {
21                 
22         public TypeReference type;
23         public Expression[] arguments;
24         public MethodBinding binding;
25
26         MethodBinding syntheticAccessor;
27
28         public AllocationExpression() {
29                 super();
30         }
31
32         public FlowInfo analyseCode(
33                 BlockScope currentScope,
34                 FlowContext flowContext,
35                 FlowInfo flowInfo) {
36
37                 // must verify that exceptions potentially thrown by this expression are caught in the method
38
39                 // process arguments
40                 if (arguments != null) {
41                         for (int i = 0, count = arguments.length; i < count; i++) {
42                                 flowInfo =
43                                         arguments[i]
44                                                 .analyseCode(currentScope, flowContext, flowInfo)
45                                                 .unconditionalInits();
46                         }
47                 }
48                 // record some dependency information for exception types
49                 ReferenceBinding[] thrownExceptions;
50                 if (((thrownExceptions = binding.thrownExceptions).length) != 0) {
51                         // check exception handling
52                         flowContext.checkExceptionHandlers(
53                                 thrownExceptions,
54                                 this,
55                                 flowInfo,
56                                 currentScope);
57                 }
58                 manageEnclosingInstanceAccessIfNecessary(currentScope);
59                 manageSyntheticAccessIfNecessary(currentScope);
60                 return flowInfo;
61         }
62
63         public Expression enclosingInstance() {
64                 return null;
65         }
66
67         public void generateCode(
68                 BlockScope currentScope,
69                 CodeStream codeStream,
70                 boolean valueRequired) {
71
72                 int pc = codeStream.position;
73                 ReferenceBinding allocatedType = binding.declaringClass;
74
75                 codeStream.new_(allocatedType);
76                 if (valueRequired) {
77                         codeStream.dup();
78                 }
79                 // better highlight for allocation: display the type individually
80                 codeStream.recordPositionsFrom(pc, type.sourceStart);
81
82                 // handling innerclass instance allocation
83                 if (allocatedType.isNestedType()) {
84                         codeStream.generateSyntheticArgumentValues(
85                                 currentScope,
86                                 allocatedType,
87                                 enclosingInstance(),
88                                 this);
89                 }
90                 // generate the arguments for constructor
91                 if (arguments != null) {
92                         for (int i = 0, count = arguments.length; i < count; i++) {
93                                 arguments[i].generateCode(currentScope, codeStream, true);
94                         }
95                 }
96                 // invoke constructor
97                 if (syntheticAccessor == null) {
98                         codeStream.invokespecial(binding);
99                 } else {
100                         // synthetic accessor got some extra arguments appended to its signature, which need values
101                         for (int i = 0,
102                                 max = syntheticAccessor.parameters.length - binding.parameters.length;
103                                 i < max;
104                                 i++) {
105                                 codeStream.aconst_null();
106                         }
107                         codeStream.invokespecial(syntheticAccessor);
108                 }
109                 codeStream.recordPositionsFrom(pc, this.sourceStart);
110         }
111
112         public boolean isSuperAccess() {
113
114                 return false;
115         }
116
117         public boolean isTypeAccess() {
118
119                 return true;
120         }
121
122         /* Inner emulation consists in either recording a dependency 
123          * link only, or performing one level of propagation.
124          *
125          * Dependency mechanism is used whenever dealing with source target
126          * types, since by the time we reach them, we might not yet know their
127          * exact need.
128          */
129         public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
130
131                 ReferenceBinding allocatedType;
132
133                 // perform some emulation work in case there is some and we are inside a local type only
134                 if ((allocatedType = binding.declaringClass).isNestedType()
135                         && currentScope.enclosingSourceType().isLocalType()) {
136
137                         if (allocatedType.isLocalType()) {
138                                 ((LocalTypeBinding) allocatedType).addInnerEmulationDependent(
139                                         currentScope,
140                                         false,
141                                         false);
142                                 // request cascade of accesses
143                         } else {
144                                 // locally propagate, since we already now the desired shape for sure
145                                 currentScope.propagateInnerEmulation(allocatedType, false, false);
146                                 // request cascade of accesses
147                         }
148                 }
149         }
150
151         public void manageSyntheticAccessIfNecessary(BlockScope currentScope) {
152
153                 if (binding.isPrivate()
154                         && (currentScope.enclosingSourceType() != binding.declaringClass)) {
155
156                         if (currentScope
157                                 .environment()
158                                 .options
159                                 .isPrivateConstructorAccessChangingVisibility) {
160                                 binding.tagForClearingPrivateModifier();
161                                 // constructor will not be dumped as private, no emulation required thus
162                         } else {
163                                 syntheticAccessor =
164                                         ((SourceTypeBinding) binding.declaringClass).addSyntheticMethod(binding);
165                                 currentScope.problemReporter().needToEmulateMethodAccess(binding, this);
166                         }
167                 }
168         }
169
170         public TypeBinding resolveType(BlockScope scope) {
171
172                 // Propagate the type checking to the arguments, and check if the constructor is defined.
173                 constant = NotAConstant;
174                 TypeBinding typeBinding = type.resolveType(scope);
175                 // will check for null after args are resolved
176
177                 // buffering the arguments' types
178                 TypeBinding[] argumentTypes = NoParameters;
179                 if (arguments != null) {
180                         boolean argHasError = false;
181                         int length = arguments.length;
182                         argumentTypes = new TypeBinding[length];
183                         for (int i = 0; i < length; i++)
184                                 if ((argumentTypes[i] = arguments[i].resolveType(scope)) == null)
185                                         argHasError = true;
186                         if (argHasError)
187                                 return typeBinding;
188                 }
189                 if (typeBinding == null)
190                         return null;
191
192                 if (!typeBinding.canBeInstantiated()) {
193                         scope.problemReporter().cannotInstantiate(type, typeBinding);
194                         return typeBinding;
195                 }
196                 ReferenceBinding allocatedType = (ReferenceBinding) typeBinding;
197                 if (!(binding = scope.getConstructor(allocatedType, argumentTypes, this))
198                         .isValidBinding()) {
199                         if (binding.declaringClass == null)
200                                 binding.declaringClass = allocatedType;
201                         scope.problemReporter().invalidConstructor(this, binding);
202                         return typeBinding;
203                 }
204                 if (isMethodUseDeprecated(binding, scope))
205                         scope.problemReporter().deprecatedMethod(binding, this);
206
207                 if (arguments != null)
208                         for (int i = 0; i < arguments.length; i++)
209                                 arguments[i].implicitWidening(binding.parameters[i], argumentTypes[i]);
210                 return allocatedType;
211         }
212
213         public void setActualReceiverType(ReferenceBinding receiverType) {
214                 // ignored
215         }
216
217         public void setDepth(int i) {
218                 // ignored
219         }
220
221         public void setFieldIndex(int i) {
222                 // ignored
223         }
224
225         public String toStringExpression() {
226
227                 String s = "new " + type.toString(0); //$NON-NLS-1$
228                 if (arguments == null)
229                         s = s + "()"; //$NON-NLS-1$
230                 else {
231                         s = s + "("; //$NON-NLS-1$
232                         for (int i = 0; i < arguments.length; i++) {
233                                 s = s + arguments[i].toStringExpression();
234                                 if (i == (arguments.length - 1))
235                                         s = s + ")"; //$NON-NLS-1$
236                                 else
237                                         s = s + ", "; //$NON-NLS-1$
238                         }
239                 }
240                 return s;
241         }
242
243         public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
244
245                 if (visitor.visit(this, scope)) {
246                         int argumentsLength;
247                         type.traverse(visitor, scope);
248                         if (arguments != null) {
249                                 argumentsLength = arguments.length;
250                                 for (int i = 0; i < argumentsLength; i++)
251                                         arguments[i].traverse(visitor, scope);
252                         }
253                 }
254                 visitor.endVisit(this, scope);
255         }
256 }