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