Makefile fixup
[org.ibex.tool.git] / repo / org.ibex.tool / src / org / eclipse / jdt / internal / compiler / ast / QualifiedAllocationExpression.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 /**
19  * Variation on allocation, where can be specified an enclosing instance and an anonymous type
20  */
21 public class QualifiedAllocationExpression extends AllocationExpression {
22         
23         //qualification may be on both side
24         public Expression enclosingInstance;
25         public TypeDeclaration anonymousType;
26         public ReferenceBinding superTypeBinding;
27         
28         public QualifiedAllocationExpression() {
29                 // for subtypes
30         }
31
32         public QualifiedAllocationExpression(TypeDeclaration anonymousType) {
33                 this.anonymousType = anonymousType;
34         }
35
36         public FlowInfo analyseCode(
37                 BlockScope currentScope,
38                 FlowContext flowContext,
39                 FlowInfo flowInfo) {
40
41                 // analyse the enclosing instance
42                 if (enclosingInstance != null) {
43                         flowInfo = enclosingInstance.analyseCode(currentScope, flowContext, flowInfo);
44                 }
45                 
46                 // check captured variables are initialized in current context (26134)
47                 checkCapturedLocalInitializationIfNecessary(
48                         this.superTypeBinding == null ? this.binding.declaringClass : this.superTypeBinding, 
49                         currentScope, 
50                         flowInfo);
51                 
52                 // process arguments
53                 if (arguments != null) {
54                         for (int i = 0, count = arguments.length; i < count; i++) {
55                                 flowInfo = arguments[i].analyseCode(currentScope, flowContext, flowInfo);
56                         }
57                 }
58
59                 // analyse the anonymous nested type
60                 if (anonymousType != null) {
61                         flowInfo = anonymousType.analyseCode(currentScope, flowContext, flowInfo);
62                 }
63
64                 // record some dependency information for exception types
65                 ReferenceBinding[] thrownExceptions;
66                 if (((thrownExceptions = binding.thrownExceptions).length) != 0) {
67                         // check exception handling
68                         flowContext.checkExceptionHandlers(
69                                 thrownExceptions,
70                                 this,
71                                 flowInfo,
72                                 currentScope);
73                 }
74                 manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
75                 manageSyntheticAccessIfNecessary(currentScope, flowInfo);
76                 return flowInfo;
77         }
78
79         public Expression enclosingInstance() {
80
81                 return enclosingInstance;
82         }
83
84         public void generateCode(
85                 BlockScope currentScope,
86                 CodeStream codeStream,
87                 boolean valueRequired) {
88
89                 int pc = codeStream.position;
90                 ReferenceBinding allocatedType = binding.declaringClass;
91                 codeStream.new_(allocatedType);
92                 if (valueRequired) {
93                         codeStream.dup();
94                 }
95                 // better highlight for allocation: display the type individually
96                 codeStream.recordPositionsFrom(pc, type.sourceStart);
97
98                 // handling innerclass instance allocation - enclosing instance arguments
99                 if (allocatedType.isNestedType()) {
100                         codeStream.generateSyntheticEnclosingInstanceValues(
101                                 currentScope,
102                                 allocatedType,
103                                 enclosingInstance(),
104                                 this);
105                 }
106                 // generate the arguments for constructor
107                 if (arguments != null) {
108                         for (int i = 0, count = arguments.length; i < count; i++) {
109                                 arguments[i].generateCode(currentScope, codeStream, true);
110                         }
111                 }
112                 // handling innerclass instance allocation - outer local arguments
113                 if (allocatedType.isNestedType()) {
114                         codeStream.generateSyntheticOuterArgumentValues(
115                                 currentScope,
116                                 allocatedType,
117                                 this);
118                 }
119                 
120                 // invoke constructor
121                 if (syntheticAccessor == null) {
122                         codeStream.invokespecial(binding);
123                 } else {
124                         // synthetic accessor got some extra arguments appended to its signature, which need values
125                         for (int i = 0,
126                                 max = syntheticAccessor.parameters.length - binding.parameters.length;
127                                 i < max;
128                                 i++) {
129                                 codeStream.aconst_null();
130                         }
131                         codeStream.invokespecial(syntheticAccessor);
132                 }
133                 codeStream.recordPositionsFrom(pc, this.sourceStart);
134
135                 if (anonymousType != null) {
136                         anonymousType.generateCode(currentScope, codeStream);
137                 }
138         }
139         
140         public boolean isSuperAccess() {
141
142                 // necessary to lookup super constructor of anonymous type
143                 return anonymousType != null;
144         }
145         
146         /* Inner emulation consists in either recording a dependency 
147          * link only, or performing one level of propagation.
148          *
149          * Dependency mechanism is used whenever dealing with source target
150          * types, since by the time we reach them, we might not yet know their
151          * exact need.
152          */
153         public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
154
155                 if (!flowInfo.isReachable()) return;
156                 ReferenceBinding allocatedType;
157
158                 // perform some emulation work in case there is some and we are inside a local type only
159                 if ((allocatedType = binding.declaringClass).isNestedType()
160                         && currentScope.enclosingSourceType().isLocalType()) {
161
162                         if (allocatedType.isLocalType()) {
163                                 ((LocalTypeBinding) allocatedType).addInnerEmulationDependent(currentScope, enclosingInstance != null);
164                         } else {
165                                 // locally propagate, since we already now the desired shape for sure
166                                 currentScope.propagateInnerEmulation(allocatedType, enclosingInstance != null);
167                         }
168                 }
169         }
170
171         public StringBuffer printExpression(int indent, StringBuffer output) {
172
173                 if (enclosingInstance != null)
174                         enclosingInstance.printExpression(0, output).append('.'); 
175                 super.printExpression(0, output);
176                 if (anonymousType != null) {
177                         anonymousType.print(indent, output);
178                 }
179                 return output;
180         }
181         
182         public TypeBinding resolveType(BlockScope scope) {
183
184                 // added for code assist...cannot occur with 'normal' code
185                 if (anonymousType == null && enclosingInstance == null) {
186                         return super.resolveType(scope);
187                 }
188
189                 // Propagate the type checking to the arguments, and checks if the constructor is defined.
190                 // ClassInstanceCreationExpression ::= Primary '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt
191                 // ClassInstanceCreationExpression ::= Name '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt
192                 // ==> by construction, when there is an enclosing instance the typename may NOT be qualified
193                 // ==> therefore by construction the type is always a SingleTypeReferenceType instead of being either 
194                 // sometime a SingleTypeReference and sometime a QualifedTypeReference
195
196                 constant = NotAConstant;
197                 TypeBinding enclosingInstanceType = null;
198                 TypeBinding receiverType = null;
199                 boolean hasError = false;
200                 boolean enclosingInstanceContainsCast = false;
201                 boolean argsContainCast = false;
202                 
203                 if (enclosingInstance != null) {
204                         if (enclosingInstance instanceof CastExpression) {
205                                 enclosingInstance.bits |= IgnoreNeedForCastCheckMASK; // will check later on
206                                 enclosingInstanceContainsCast = true;
207                         }
208                         if ((enclosingInstanceType = enclosingInstance.resolveType(scope)) == null){
209                                 hasError = true;
210                         } else if (enclosingInstanceType.isBaseType() || enclosingInstanceType.isArrayType()) {
211                                 scope.problemReporter().illegalPrimitiveOrArrayTypeForEnclosingInstance(
212                                         enclosingInstanceType,
213                                         enclosingInstance);
214                                 hasError = true;
215                         } else {
216                                 receiverType = ((SingleTypeReference) type).resolveTypeEnclosing(scope, (ReferenceBinding) enclosingInstanceType);
217                                 if (receiverType != null && enclosingInstanceContainsCast) {
218                                                 CastExpression.checkNeedForEnclosingInstanceCast(scope, enclosingInstance, enclosingInstanceType, receiverType);
219                                 }
220                         }
221                 } else {
222                         receiverType = type.resolveType(scope);
223                 }
224                 if (receiverType == null) {
225                         hasError = true;
226                 } else if (((ReferenceBinding) receiverType).isFinal() && this.anonymousType != null) {
227                         scope.problemReporter().anonymousClassCannotExtendFinalClass(type, receiverType);
228                         hasError = true;
229                 }
230
231                 // will check for null after args are resolved
232                 TypeBinding[] argumentTypes = NoParameters;
233                 if (arguments != null) {
234                         int length = arguments.length;
235                         argumentTypes = new TypeBinding[length];
236                         for (int i = 0; i < length; i++) {
237                                 Expression argument = this.arguments[i];
238                                 if (argument instanceof CastExpression) {
239                                         argument.bits |= IgnoreNeedForCastCheckMASK; // will check later on
240                                         argsContainCast = true;
241                                 }
242                                 if ((argumentTypes[i] = argument.resolveType(scope)) == null){
243                                         hasError = true;
244                                 }
245                         }
246                 }
247                 // limit of fault-tolerance
248                 if (hasError) return this.resolvedType = receiverType;
249                 
250                 if (this.anonymousType == null) {
251                         // qualified allocation with no anonymous type
252                         ReferenceBinding allocationType = (ReferenceBinding) receiverType;
253                         if (!receiverType.canBeInstantiated()) {
254                                 scope.problemReporter().cannotInstantiate(type, receiverType);
255                                 return this.resolvedType = receiverType;
256                         }
257                         if ((this.binding = scope.getConstructor(allocationType, argumentTypes, this)).isValidBinding()) {
258                                 if (isMethodUseDeprecated(binding, scope)) {
259                                         scope.problemReporter().deprecatedMethod(this.binding, this);
260                                 }
261                                 if (arguments != null) {
262                                         for (int i = 0; i < arguments.length; i++) {
263                                                 arguments[i].implicitWidening(this.binding.parameters[i], argumentTypes[i]);
264                                         }
265                                         if (argsContainCast) {
266                                                 CastExpression.checkNeedForArgumentCasts(scope, null, allocationType, binding, this.arguments, argumentTypes, this);
267                                         }
268                                 }
269                         } else {
270                                 if (this.binding.declaringClass == null) {
271                                         this.binding.declaringClass = allocationType;
272                                 }
273                                 scope.problemReporter().invalidConstructor(this, this.binding);
274                                 return this.resolvedType = receiverType;
275                         }
276
277                         // The enclosing instance must be compatible with the innermost enclosing type
278                         ReferenceBinding expectedType = this.binding.declaringClass.enclosingType();
279                         if (enclosingInstanceType.isCompatibleWith(expectedType)) {
280                                 return receiverType;
281                         }
282                         scope.problemReporter().typeMismatchErrorActualTypeExpectedType(
283                                 this.enclosingInstance,
284                                 enclosingInstanceType,
285                                 expectedType);
286                         return this.resolvedType = receiverType;
287                 }
288
289                 // anonymous type scenario
290                 // an anonymous class inherits from java.lang.Object when declared "after" an interface
291                 this.superTypeBinding = receiverType.isInterface() ? scope.getJavaLangObject() : (ReferenceBinding) receiverType;
292                 // insert anonymous type in scope
293                 scope.addAnonymousType(this.anonymousType, (ReferenceBinding) receiverType);
294                 this.anonymousType.resolve(scope);              
295                 
296                 // find anonymous super constructor
297                 MethodBinding inheritedBinding = scope.getConstructor(this.superTypeBinding, argumentTypes, this);
298                 if (!inheritedBinding.isValidBinding()) {
299                         if (inheritedBinding.declaringClass == null) {
300                                 inheritedBinding.declaringClass = this.superTypeBinding;
301                         }
302                         scope.problemReporter().invalidConstructor(this, inheritedBinding);
303                         return this.resolvedType = anonymousType.binding;
304                 }
305                 if (enclosingInstance != null) {
306                         ReferenceBinding targetEnclosing = inheritedBinding.declaringClass.enclosingType();
307                         if (targetEnclosing == null) {
308                                 scope.problemReporter().unnecessaryEnclosingInstanceSpecification(enclosingInstance, (ReferenceBinding)receiverType);
309                                 return this.resolvedType = anonymousType.binding;
310                         } else  if (!enclosingInstanceType.isCompatibleWith(targetEnclosing)) {
311                                 scope.problemReporter().typeMismatchErrorActualTypeExpectedType(enclosingInstance, enclosingInstanceType, targetEnclosing);
312                                 return this.resolvedType = anonymousType.binding;
313                         }
314                 }
315
316                 // this promotion has to be done somewhere: here or inside the constructor of the
317                 // anonymous class. We do it here while the constructor of the inner is then easier.
318                 if (arguments != null) {
319                         for (int i = 0; i < arguments.length; i++) {
320                                 arguments[i].implicitWidening(inheritedBinding.parameters[i], argumentTypes[i]);
321                         }
322                         if (argsContainCast) {
323                                 CastExpression.checkNeedForArgumentCasts(scope, null, this.superTypeBinding, inheritedBinding, this.arguments, argumentTypes, this);
324                         }
325                 }
326                 // Update the anonymous inner class : superclass, interface  
327                 binding = anonymousType.createsInternalConstructorWithBinding(inheritedBinding);
328                 return this.resolvedType = anonymousType.binding; // 1.2 change
329         }
330         
331         public void traverse(ASTVisitor visitor, BlockScope scope) {
332
333                 if (visitor.visit(this, scope)) {
334                         if (enclosingInstance != null)
335                                 enclosingInstance.traverse(visitor, scope);
336                         type.traverse(visitor, scope);
337                         if (arguments != null) {
338                                 int argumentsLength = arguments.length;
339                                 for (int i = 0; i < argumentsLength; i++)
340                                         arguments[i].traverse(visitor, scope);
341                         }
342                         if (anonymousType != null)
343                                 anonymousType.traverse(visitor, scope);
344                 }
345                 visitor.endVisit(this, scope);
346         }
347 }