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