Initial import of the Guide contributed to the project byRobert Kraske. Was originall...
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / AllocationExpression.java
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
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.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.InvocationSite;
18 import net.sourceforge.phpdt.internal.compiler.lookup.LocalTypeBinding;
19 import net.sourceforge.phpdt.internal.compiler.lookup.LocalVariableBinding;
20 import net.sourceforge.phpdt.internal.compiler.lookup.MethodBinding;
21 import net.sourceforge.phpdt.internal.compiler.lookup.NestedTypeBinding;
22 import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding;
23 import net.sourceforge.phpdt.internal.compiler.lookup.SourceTypeBinding;
24 import net.sourceforge.phpdt.internal.compiler.lookup.SyntheticArgumentBinding;
25 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
26
27 public class AllocationExpression extends Expression implements InvocationSite {
28
29         public TypeReference type;
30
31         public Expression[] arguments;
32
33         public MethodBinding binding;
34
35         MethodBinding syntheticAccessor;
36
37         public AllocationExpression() {
38         }
39
40         public FlowInfo analyseCode(BlockScope currentScope,
41                         FlowContext flowContext, FlowInfo flowInfo) {
42
43                 // check captured variables are initialized in current context (26134)
44                 checkCapturedLocalInitializationIfNecessary(
45                                 this.binding.declaringClass, currentScope, 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,
51                                                 flowInfo).unconditionalInits();
52                         }
53                 }
54                 // record some dependency information for exception types
55                 ReferenceBinding[] thrownExceptions;
56                 if (((thrownExceptions = this.binding.thrownExceptions).length) != 0) {
57                         // check exception handling
58                         flowContext.checkExceptionHandlers(thrownExceptions, this,
59                                         flowInfo, currentScope);
60                 }
61                 manageEnclosingInstanceAccessIfNecessary(currentScope);
62                 manageSyntheticAccessIfNecessary(currentScope);
63
64                 return flowInfo;
65         }
66
67         public void checkCapturedLocalInitializationIfNecessary(
68                         ReferenceBinding checkedType, BlockScope currentScope,
69                         FlowInfo flowInfo) {
70
71                 if (checkedType.isLocalType() && !checkedType.isAnonymousType()
72                                 && !currentScope.isDefinedInType(checkedType)) { // only
73                                                                                                                                         // check
74                                                                                                                                         // external
75                                                                                                                                         // allocations
76                         NestedTypeBinding nestedType = (NestedTypeBinding) checkedType;
77                         SyntheticArgumentBinding[] syntheticArguments = nestedType
78                                         .syntheticOuterLocalVariables();
79                         if (syntheticArguments != null)
80                                 for (int i = 0, count = syntheticArguments.length; i < count; i++) {
81                                         SyntheticArgumentBinding syntheticArgument = syntheticArguments[i];
82                                         LocalVariableBinding targetLocal;
83                                         if ((targetLocal = syntheticArgument.actualOuterLocalVariable) == null)
84                                                 continue;
85                                         // if (targetLocal.declaration != null &&
86                                         // !flowInfo.isDefinitelyAssigned(targetLocal)){
87                                         // currentScope.problemReporter().uninitializedLocalVariable(targetLocal,
88                                         // this);
89                                         // }
90                                 }
91
92                 }
93         }
94
95         public Expression enclosingInstance() {
96                 return null;
97         }
98
99         // public void generateCode(
100         // BlockScope currentScope,
101         // CodeStream codeStream,
102         // boolean valueRequired) {
103         //
104         // int pc = codeStream.position;
105         // ReferenceBinding allocatedType = binding.declaringClass;
106         //
107         // codeStream.new_(allocatedType);
108         // if (valueRequired) {
109         // codeStream.dup();
110         // }
111         // // better highlight for allocation: display the type individually
112         // codeStream.recordPositionsFrom(pc, type.sourceStart);
113         //
114         // // handling innerclass instance allocation - enclosing instance arguments
115         // if (allocatedType.isNestedType()) {
116         // codeStream.generateSyntheticEnclosingInstanceValues(
117         // currentScope,
118         // allocatedType,
119         // enclosingInstance(),
120         // this);
121         // }
122         // // generate the arguments for constructor
123         // if (arguments != null) {
124         // for (int i = 0, count = arguments.length; i < count; i++) {
125         // arguments[i].generateCode(currentScope, codeStream, true);
126         // }
127         // }
128         // // handling innerclass instance allocation - outer local arguments
129         // if (allocatedType.isNestedType()) {
130         // codeStream.generateSyntheticOuterArgumentValues(
131         // currentScope,
132         // allocatedType,
133         // this);
134         // }
135         // // invoke constructor
136         // if (syntheticAccessor == null) {
137         // codeStream.invokespecial(binding);
138         // } else {
139         // // synthetic accessor got some extra arguments appended to its signature,
140         // which need values
141         // for (int i = 0,
142         // max = syntheticAccessor.parameters.length - binding.parameters.length;
143         // i < max;
144         // i++) {
145         // codeStream.aconst_null();
146         // }
147         // codeStream.invokespecial(syntheticAccessor);
148         // }
149         // codeStream.recordPositionsFrom(pc, this.sourceStart);
150         // }
151
152         public boolean isSuperAccess() {
153
154                 return false;
155         }
156
157         public boolean isTypeAccess() {
158
159                 return true;
160         }
161
162         /*
163          * Inner emulation consists in either recording a dependency link only, or
164          * performing one level of propagation.
165          * 
166          * Dependency mechanism is used whenever dealing with source target types,
167          * since by the time we reach them, we might not yet know their exact need.
168          */
169         public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
170
171                 ReferenceBinding allocatedType;
172
173                 // perform some emulation work in case there is some and we are inside a
174                 // local type only
175                 if ((allocatedType = binding.declaringClass).isNestedType()
176                                 && currentScope.enclosingSourceType().isLocalType()) {
177
178                         if (allocatedType.isLocalType()) {
179                                 ((LocalTypeBinding) allocatedType).addInnerEmulationDependent(
180                                                 currentScope, false);
181                                 // request cascade of accesses
182                         } else {
183                                 // locally propagate, since we already now the desired shape for
184                                 // sure
185                                 currentScope.propagateInnerEmulation(allocatedType, false);
186                                 // request cascade of accesses
187                         }
188                 }
189         }
190
191         public void manageSyntheticAccessIfNecessary(BlockScope currentScope) {
192
193                 if (binding.isPrivate()
194                                 && (currentScope.enclosingSourceType() != binding.declaringClass)) {
195
196                         // if (currentScope
197                         // .environment()
198                         // .options
199                         // .isPrivateConstructorAccessChangingVisibility) {
200                         // binding.tagForClearingPrivateModifier();
201                         // // constructor will not be dumped as private, no emulation
202                         // required thus
203                         // } else {
204                         syntheticAccessor = ((SourceTypeBinding) binding.declaringClass)
205                                         .addSyntheticMethod(binding, isSuperAccess());
206                         currentScope.problemReporter().needToEmulateMethodAccess(binding,
207                                         this);
208                         // }
209                 }
210         }
211
212         public StringBuffer printExpression(int indent, StringBuffer output) {
213
214                 output.append("new "); //$NON-NLS-1$
215                 type.printExpression(0, output);
216                 output.append('(');
217                 if (arguments != null) {
218                         for (int i = 0; i < arguments.length; i++) {
219                                 if (i > 0)
220                                         output.append(", "); //$NON-NLS-1$
221                                 arguments[i].printExpression(0, output);
222                         }
223                 }
224                 return output.append(')');
225         }
226
227         public TypeBinding resolveType(BlockScope scope) {
228
229                 // Propagate the type checking to the arguments, and check if the
230                 // constructor is defined.
231                 constant = NotAConstant;
232                 this.resolvedType = type.resolveType(scope);
233                 // will check for null after args are resolved
234
235                 // buffering the arguments' types
236                 TypeBinding[] argumentTypes = NoParameters;
237                 if (arguments != null) {
238                         boolean argHasError = false;
239                         int length = arguments.length;
240                         argumentTypes = new TypeBinding[length];
241                         for (int i = 0; i < length; i++)
242                                 if ((argumentTypes[i] = arguments[i].resolveType(scope)) == null)
243                                         argHasError = true;
244                         if (argHasError)
245                                 return this.resolvedType;
246                 }
247                 if (this.resolvedType == null)
248                         return null;
249
250                 if (!this.resolvedType.canBeInstantiated()) {
251                         scope.problemReporter().cannotInstantiate(type, this.resolvedType);
252                         return this.resolvedType;
253                 }
254                 ReferenceBinding allocatedType = (ReferenceBinding) this.resolvedType;
255                 if (!(binding = scope
256                                 .getConstructor(allocatedType, argumentTypes, this))
257                                 .isValidBinding()) {
258                         if (binding.declaringClass == null)
259                                 binding.declaringClass = allocatedType;
260                         scope.problemReporter().invalidConstructor(this, binding);
261                         return this.resolvedType;
262                 }
263                 if (isMethodUseDeprecated(binding, scope))
264                         scope.problemReporter().deprecatedMethod(binding, this);
265
266                 if (arguments != null)
267                         for (int i = 0; i < arguments.length; i++)
268                                 arguments[i].implicitWidening(binding.parameters[i],
269                                                 argumentTypes[i]);
270                 return allocatedType;
271         }
272
273         public void setActualReceiverType(ReferenceBinding receiverType) {
274                 // ignored
275         }
276
277         public void setDepth(int i) {
278                 // ignored
279         }
280
281         public void setFieldIndex(int i) {
282                 // ignored
283         }
284
285         public String toStringExpression() {
286
287                 String s = "new " + type.toString(0); //$NON-NLS-1$
288                 if (arguments == null)
289                         s = s + "()"; //$NON-NLS-1$
290                 else {
291                         s = s + "("; //$NON-NLS-1$
292                         for (int i = 0; i < arguments.length; i++) {
293                                 s = s + arguments[i].toStringExpression();
294                                 if (i == (arguments.length - 1))
295                                         s = s + ")"; //$NON-NLS-1$
296                                 else
297                                         s = s + ", "; //$NON-NLS-1$
298                         }
299                 }
300                 return s;
301         }
302
303         public void traverse(ASTVisitor visitor, BlockScope scope) {
304
305                 if (visitor.visit(this, scope)) {
306                         int argumentsLength;
307                         type.traverse(visitor, scope);
308                         if (arguments != null) {
309                                 argumentsLength = arguments.length;
310                                 for (int i = 0; i < argumentsLength; i++)
311                                         arguments[i].traverse(visitor, scope);
312                         }
313                 }
314                 visitor.endVisit(this, scope);
315         }
316 }