added -J option to preserve unmodified files in preexisting jarfile
[org.ibex.tool.git] / 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 extends Expression implements InvocationSite {
19                 
20         public TypeReference type;
21         public Expression[] arguments;
22         public MethodBinding binding;                                                   // exact binding resulting from lookup
23         protected MethodBinding codegenBinding; // actual binding used for code generation (if no synthetic accessor)
24         MethodBinding syntheticAccessor;                                                // synthetic accessor for inner-emulation
25         public TypeReference[] typeArguments;   
26         public TypeBinding[] genericTypeArguments;
27         public FieldDeclaration enumConstant; // for enum constant initializations
28
29         public FlowInfo analyseCode(
30                 BlockScope currentScope,
31                 FlowContext flowContext,
32                 FlowInfo flowInfo) {
33
34                 // check captured variables are initialized in current context (26134)
35                 checkCapturedLocalInitializationIfNecessary((ReferenceBinding)this.binding.declaringClass.erasure(), currentScope, flowInfo);
36
37                 // process arguments
38                 if (arguments != null) {
39                         for (int i = 0, count = arguments.length; i < count; i++) {
40                                 flowInfo =
41                                         arguments[i]
42                                                 .analyseCode(currentScope, flowContext, flowInfo)
43                                                 .unconditionalInits();
44                         }
45                 }
46                 // record some dependency information for exception types
47                 ReferenceBinding[] thrownExceptions;
48                 if (((thrownExceptions = this.binding.thrownExceptions).length) != 0) {
49                         // check exception handling
50                         flowContext.checkExceptionHandlers(
51                                 thrownExceptions,
52                                 this,
53                                 flowInfo,
54                                 currentScope);
55                 }
56                 manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
57                 manageSyntheticAccessIfNecessary(currentScope, flowInfo);
58                 
59                 return flowInfo;
60         }
61
62         public void checkCapturedLocalInitializationIfNecessary(ReferenceBinding checkedType, BlockScope currentScope, FlowInfo flowInfo) {
63
64                 if (checkedType.isLocalType() 
65                                 && !checkedType.isAnonymousType()
66                                 && !currentScope.isDefinedInType(checkedType)) { // only check external allocations
67                         NestedTypeBinding nestedType = (NestedTypeBinding) checkedType;
68                         SyntheticArgumentBinding[] syntheticArguments = nestedType.syntheticOuterLocalVariables();
69                         if (syntheticArguments != null) 
70                                 for (int i = 0, count = syntheticArguments.length; i < count; i++){
71                                         SyntheticArgumentBinding syntheticArgument = syntheticArguments[i];
72                                         LocalVariableBinding targetLocal;
73                                         if ((targetLocal = syntheticArgument.actualOuterLocalVariable) == null) continue;
74                                         if (targetLocal.declaration != null && !flowInfo.isDefinitelyAssigned(targetLocal)){
75                                                 currentScope.problemReporter().uninitializedLocalVariable(targetLocal, this);
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 = this.codegenBinding.declaringClass;
92
93                 codeStream.new_(allocatedType);
94                 if (valueRequired) {
95                         codeStream.dup();
96                 }
97                 // better highlight for allocation: display the type individually
98                 if (this.type != null) { // null for enum constant body
99                         codeStream.recordPositionsFrom(pc, this.type.sourceStart);
100                 } else {
101                         // push enum constant name and ordinal
102                         codeStream.ldc(String.valueOf(enumConstant.name));
103                         codeStream.generateInlinedValue(enumConstant.binding.id);
104                 }
105
106                 // handling innerclass instance allocation - enclosing instance arguments
107                 if (allocatedType.isNestedType()) {
108                         codeStream.generateSyntheticEnclosingInstanceValues(
109                                 currentScope,
110                                 allocatedType,
111                                 enclosingInstance(),
112                                 this);
113                 }
114                 // generate the arguments for constructor
115                 generateArguments(binding, arguments, currentScope, codeStream);
116                 // handling innerclass instance allocation - outer local arguments
117                 if (allocatedType.isNestedType()) {
118                         codeStream.generateSyntheticOuterArgumentValues(
119                                 currentScope,
120                                 allocatedType,
121                                 this);
122                 }
123                 // invoke constructor
124                 if (syntheticAccessor == null) {
125                         codeStream.invokespecial(this.codegenBinding);
126                 } else {
127                         // synthetic accessor got some extra arguments appended to its signature, which need values
128                         for (int i = 0,
129                                 max = syntheticAccessor.parameters.length - this.codegenBinding.parameters.length;
130                                 i < max;
131                                 i++) {
132                                 codeStream.aconst_null();
133                         }
134                         codeStream.invokespecial(syntheticAccessor);
135                 }
136                 codeStream.generateImplicitConversion(this.implicitConversion);
137                 codeStream.recordPositionsFrom(pc, this.sourceStart);
138         }
139         /**
140          * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#genericTypeArguments()
141          */
142         public TypeBinding[] genericTypeArguments() {
143                 return this.genericTypeArguments;
144         }
145         
146         public boolean isSuperAccess() {
147
148                 return false;
149         }
150
151         public boolean isTypeAccess() {
152
153                 return true;
154         }
155
156         /* Inner emulation consists in either recording a dependency 
157          * link only, or performing one level of propagation.
158          *
159          * Dependency mechanism is used whenever dealing with source target
160          * types, since by the time we reach them, we might not yet know their
161          * exact need.
162          */
163         public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
164
165                 if (!flowInfo.isReachable()) return;
166                 ReferenceBinding allocatedTypeErasure = (ReferenceBinding) binding.declaringClass.erasure();
167
168                 // perform some emulation work in case there is some and we are inside a local type only
169                 if (allocatedTypeErasure.isNestedType()
170                         && currentScope.enclosingSourceType().isLocalType()) {
171
172                         if (allocatedTypeErasure.isLocalType()) {
173                                 ((LocalTypeBinding) allocatedTypeErasure).addInnerEmulationDependent(currentScope, false);
174                                 // request cascade of accesses
175                         } else {
176                                 // locally propagate, since we already now the desired shape for sure
177                                 currentScope.propagateInnerEmulation(allocatedTypeErasure, false);
178                                 // request cascade of accesses
179                         }
180                 }
181         }
182
183         public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
184
185                 if (!flowInfo.isReachable()) return;
186
187                 // if constructor from parameterized type got found, use the original constructor at codegen time
188                 this.codegenBinding = this.binding.original();
189
190                 if (this.codegenBinding.isPrivate()
191                         && (currentScope.enclosingSourceType() != this.codegenBinding.declaringClass)) {
192
193                         if (currentScope.environment().options.isPrivateConstructorAccessChangingVisibility) {
194                                 this.codegenBinding.tagForClearingPrivateModifier();
195                                 // constructor will not be dumped as private, no emulation required thus
196                         } else {
197                                 syntheticAccessor =
198                                         ((SourceTypeBinding) this.codegenBinding.declaringClass).addSyntheticMethod(this.codegenBinding, isSuperAccess());
199                                 currentScope.problemReporter().needToEmulateMethodAccess(this.codegenBinding, this);
200                         }
201                 }
202         }
203
204         public StringBuffer printExpression(int indent, StringBuffer output) {
205
206                 if (this.type != null) { // type null for enum constant initializations
207                         output.append("new "); //$NON-NLS-1$
208                 }
209                 if (typeArguments != null) {
210                         output.append('<');//$NON-NLS-1$
211                         int max = typeArguments.length - 1;
212                         for (int j = 0; j < max; j++) {
213                                 typeArguments[j].print(0, output);
214                                 output.append(", ");//$NON-NLS-1$
215                         }
216                         typeArguments[max].print(0, output);
217                         output.append('>');
218                 }
219                 if (type != null) { // type null for enum constant initializations
220                         type.printExpression(0, output); 
221                 }
222                 output.append('(');
223                 if (arguments != null) {
224                         for (int i = 0; i < arguments.length; i++) {
225                                 if (i > 0) output.append(", "); //$NON-NLS-1$
226                                 arguments[i].printExpression(0, output);
227                         }
228                 }
229                 return output.append(')');
230         }
231         
232         public TypeBinding resolveType(BlockScope scope) {
233
234                 // Propagate the type checking to the arguments, and check if the constructor is defined.
235                 constant = NotAConstant;
236                 if (this.type == null) {
237                         // initialization of an enum constant
238                         this.resolvedType = scope.enclosingSourceType();
239                 } else {
240                         this.resolvedType = this.type.resolveType(scope, true /* check bounds*/);
241                 }
242                 // will check for null after args are resolved
243
244                 // resolve type arguments (for generic constructor call)
245                 if (this.typeArguments != null) {
246                         int length = this.typeArguments.length;
247                         boolean argHasError = false; // typeChecks all arguments
248                         this.genericTypeArguments = new TypeBinding[length];
249                         for (int i = 0; i < length; i++) {
250                                 if ((this.genericTypeArguments[i] = this.typeArguments[i].resolveType(scope, true /* check bounds*/)) == null) {
251                                         argHasError = true;
252                                 }
253                         }
254                         if (argHasError) {
255                                 return null;
256                         }
257                 }
258                 
259                 // buffering the arguments' types
260                 boolean argsContainCast = false;
261                 TypeBinding[] argumentTypes = NoParameters;
262                 if (arguments != null) {
263                         boolean argHasError = false;
264                         int length = arguments.length;
265                         argumentTypes = new TypeBinding[length];
266                         for (int i = 0; i < length; i++) {
267                                 Expression argument = this.arguments[i];
268                                 if (argument instanceof CastExpression) {
269                                         argument.bits |= IgnoreNeedForCastCheckMASK; // will check later on
270                                         argsContainCast = true;
271                                 }
272                                 if ((argumentTypes[i] = argument.resolveType(scope)) == null) {
273                                         argHasError = true;
274                                 }
275                         }
276                         if (argHasError) {
277                                 return this.resolvedType;
278                         }
279                 }
280                 if (this.resolvedType == null)
281                         return null;
282
283                 // null type denotes fake allocation for enum constant inits
284                 if (this.type != null && !this.resolvedType.canBeInstantiated()) {
285                         scope.problemReporter().cannotInstantiate(type, this.resolvedType);
286                         return this.resolvedType;
287                 }
288                 ReferenceBinding allocationType = (ReferenceBinding) this.resolvedType;
289                 if (!(binding = scope.getConstructor(allocationType, argumentTypes, this)).isValidBinding()) {
290                         if (binding.declaringClass == null)
291                                 binding.declaringClass = allocationType;
292                         scope.problemReporter().invalidConstructor(this, binding);
293                         return this.resolvedType;
294                 }
295                 if (isMethodUseDeprecated(binding, scope))
296                         scope.problemReporter().deprecatedMethod(binding, this);
297                 if (this.arguments != null)
298                         checkInvocationArguments(scope, null, allocationType, this.binding, this.arguments, argumentTypes, argsContainCast, this);
299
300                 return allocationType;
301         }
302
303         public void setActualReceiverType(ReferenceBinding receiverType) {
304                 // ignored
305         }
306
307         public void setDepth(int i) {
308                 // ignored
309         }
310
311         public void setFieldIndex(int i) {
312                 // ignored
313         }
314
315         public void traverse(ASTVisitor visitor, BlockScope scope) {
316
317                 if (visitor.visit(this, scope)) {
318                         if (this.typeArguments != null) {
319                                 for (int i = 0, typeArgumentsLength = this.typeArguments.length; i < typeArgumentsLength; i++) {
320                                         this.typeArguments[i].traverse(visitor, scope);
321                                 }
322                         }
323                         if (this.type != null) { // enum constant scenario
324                                 this.type.traverse(visitor, scope);
325                         }
326                         if (this.arguments != null) {
327                                 for (int i = 0, argumentsLength = this.arguments.length; i < argumentsLength; i++)
328                                         this.arguments[i].traverse(visitor, scope);
329                         }
330                 }
331                 visitor.endVisit(this, scope);
332         }
333 }