Improved ${cursor} handling in HTML and TPL (smarty) files
[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.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
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         public StringBuffer printExpression(int indent, StringBuffer output) {
204
205                 output.append("new "); //$NON-NLS-1$
206                 type.printExpression(0, output); 
207                 output.append('(');
208                 if (arguments != null) {
209                         for (int i = 0; i < arguments.length; i++) {
210                                 if (i > 0) output.append(", "); //$NON-NLS-1$
211                                 arguments[i].printExpression(0, output);
212                         }
213                 }
214                 return output.append(')');
215         }
216         public TypeBinding resolveType(BlockScope scope) {
217
218                 // Propagate the type checking to the arguments, and check if the constructor is defined.
219                 constant = NotAConstant;
220                 this.resolvedType = type.resolveType(scope);
221                 // will check for null after args are resolved
222
223                 // buffering the arguments' types
224                 TypeBinding[] argumentTypes = NoParameters;
225                 if (arguments != null) {
226                         boolean argHasError = false;
227                         int length = arguments.length;
228                         argumentTypes = new TypeBinding[length];
229                         for (int i = 0; i < length; i++)
230                                 if ((argumentTypes[i] = arguments[i].resolveType(scope)) == null)
231                                         argHasError = true;
232                         if (argHasError)
233                                 return this.resolvedType;
234                 }
235                 if (this.resolvedType == null)
236                         return null;
237
238                 if (!this.resolvedType.canBeInstantiated()) {
239                         scope.problemReporter().cannotInstantiate(type, this.resolvedType);
240                         return this.resolvedType;
241                 }
242                 ReferenceBinding allocatedType = (ReferenceBinding) this.resolvedType;
243                 if (!(binding = scope.getConstructor(allocatedType, argumentTypes, this))
244                         .isValidBinding()) {
245                         if (binding.declaringClass == null)
246                                 binding.declaringClass = allocatedType;
247                         scope.problemReporter().invalidConstructor(this, binding);
248                         return this.resolvedType;
249                 }
250                 if (isMethodUseDeprecated(binding, scope))
251                         scope.problemReporter().deprecatedMethod(binding, this);
252
253                 if (arguments != null)
254                         for (int i = 0; i < arguments.length; i++)
255                                 arguments[i].implicitWidening(binding.parameters[i], argumentTypes[i]);
256                 return allocatedType;
257         }
258
259         public void setActualReceiverType(ReferenceBinding receiverType) {
260                 // ignored
261         }
262
263         public void setDepth(int i) {
264                 // ignored
265         }
266
267         public void setFieldIndex(int i) {
268                 // ignored
269         }
270
271         public String toStringExpression() {
272
273                 String s = "new " + type.toString(0); //$NON-NLS-1$
274                 if (arguments == null)
275                         s = s + "()"; //$NON-NLS-1$
276                 else {
277                         s = s + "("; //$NON-NLS-1$
278                         for (int i = 0; i < arguments.length; i++) {
279                                 s = s + arguments[i].toStringExpression();
280                                 if (i == (arguments.length - 1))
281                                         s = s + ")"; //$NON-NLS-1$
282                                 else
283                                         s = s + ", "; //$NON-NLS-1$
284                         }
285                 }
286                 return s;
287         }
288
289         public void traverse(ASTVisitor visitor, BlockScope scope) {
290
291                 if (visitor.visit(this, scope)) {
292                         int argumentsLength;
293                         type.traverse(visitor, scope);
294                         if (arguments != null) {
295                                 argumentsLength = arguments.length;
296                                 for (int i = 0; i < argumentsLength; i++)
297                                         arguments[i].traverse(visitor, scope);
298                         }
299                 }
300                 visitor.endVisit(this, scope);
301         }
302 }