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