KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > compiler > ast > QualifiedAllocationExpression


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-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.classfmt.ClassFileConstants;
15 import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
16 import org.eclipse.jdt.internal.compiler.flow.FlowContext;
17 import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
18 import org.eclipse.jdt.internal.compiler.impl.Constant;
19 import org.eclipse.jdt.internal.compiler.lookup.Binding;
20 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
21 import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
22 import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding;
23 import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
24 import org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding;
25 import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons;
26 import org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding;
27 import org.eclipse.jdt.internal.compiler.lookup.RawTypeBinding;
28 import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
29 import org.eclipse.jdt.internal.compiler.lookup.TagBits;
30 import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
31 import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
32 import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
33
34 /**
35  * Variation on allocation, where can optionally be specified any of:
36  * - leading enclosing instance
37  * - trailing anonymous type
38  * - generic type arguments for generic constructor invocation
39  */

40 public class QualifiedAllocationExpression extends AllocationExpression {
41     
42     //qualification may be on both side
43
public Expression enclosingInstance;
44     public TypeDeclaration anonymousType;
45     public ReferenceBinding superTypeBinding;
46     
47     public QualifiedAllocationExpression() {
48         // for subtypes
49
}
50
51     public QualifiedAllocationExpression(TypeDeclaration anonymousType) {
52         this.anonymousType = anonymousType;
53         anonymousType.allocation = this;
54     }
55
56     public FlowInfo analyseCode(
57         BlockScope currentScope,
58         FlowContext flowContext,
59         FlowInfo flowInfo) {
60
61         // analyse the enclosing instance
62
if (this.enclosingInstance != null) {
63             flowInfo = this.enclosingInstance.analyseCode(currentScope, flowContext, flowInfo);
64         }
65         
66         // check captured variables are initialized in current context (26134)
67
ReferenceBinding allocatedType = this.superTypeBinding == null ? this.binding.declaringClass : this.superTypeBinding;
68         checkCapturedLocalInitializationIfNecessary(
69             (ReferenceBinding) allocatedType.erasure(),
70             currentScope,
71             flowInfo);
72         
73         // process arguments
74
if (this.arguments != null) {
75             for (int i = 0, count = this.arguments.length; i < count; i++) {
76                 flowInfo = this.arguments[i].analyseCode(currentScope, flowContext, flowInfo);
77             }
78         }
79
80         // analyse the anonymous nested type
81
if (this.anonymousType != null) {
82             flowInfo = this.anonymousType.analyseCode(currentScope, flowContext, flowInfo);
83         }
84
85         // record some dependency information for exception types
86
ReferenceBinding[] thrownExceptions;
87         if (((thrownExceptions = this.binding.thrownExceptions).length) != 0) {
88             // check exception handling
89
flowContext.checkExceptionHandlers(
90                 thrownExceptions,
91                 this,
92                 flowInfo.unconditionalCopy(),
93                 currentScope);
94         }
95         manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
96         manageSyntheticAccessIfNecessary(currentScope, flowInfo);
97         return flowInfo;
98     }
99
100     public Expression enclosingInstance() {
101
102         return this.enclosingInstance;
103     }
104
105     public void generateCode(
106         BlockScope currentScope,
107         CodeStream codeStream,
108         boolean valueRequired) {
109
110         int pc = codeStream.position;
111         ReferenceBinding allocatedType = this.codegenBinding.declaringClass;
112         codeStream.new_(allocatedType);
113         boolean isUnboxing = (this.implicitConversion & TypeIds.UNBOXING) != 0;
114         if (valueRequired || isUnboxing) {
115             codeStream.dup();
116         }
117         // better highlight for allocation: display the type individually
118
if (this.type != null) { // null for enum constant body
119
codeStream.recordPositionsFrom(pc, this.type.sourceStart);
120         } else {
121             // push enum constant name and ordinal
122
codeStream.ldc(String.valueOf(this.enumConstant.name));
123             codeStream.generateInlinedValue(this.enumConstant.binding.id);
124         }
125         // handling innerclass instance allocation - enclosing instance arguments
126
if (allocatedType.isNestedType()) {
127             codeStream.generateSyntheticEnclosingInstanceValues(
128                 currentScope,
129                 allocatedType,
130                 enclosingInstance(),
131                 this);
132         }
133         // generate the arguments for constructor
134
generateArguments(this.binding, this.arguments, currentScope, codeStream);
135         // handling innerclass instance allocation - outer local arguments
136
if (allocatedType.isNestedType()) {
137             codeStream.generateSyntheticOuterArgumentValues(
138                 currentScope,
139                 allocatedType,
140                 this);
141         }
142         
143         // invoke constructor
144
if (this.syntheticAccessor == null) {
145             codeStream.invokespecial(this.codegenBinding);
146         } else {
147             // synthetic accessor got some extra arguments appended to its signature, which need values
148
for (int i = 0,
149                 max = this.syntheticAccessor.parameters.length - this.codegenBinding.parameters.length;
150                 i < max;
151                 i++) {
152                 codeStream.aconst_null();
153             }
154             codeStream.invokespecial(this.syntheticAccessor);
155         }
156         if (valueRequired) {
157             codeStream.generateImplicitConversion(implicitConversion);
158         } else if (isUnboxing) {
159             // conversion only generated if unboxing
160
codeStream.generateImplicitConversion(implicitConversion);
161             switch (postConversionType(currentScope).id) {
162                 case T_long :
163                 case T_double :
164                     codeStream.pop2();
165                     break;
166                 default :
167                     codeStream.pop();
168             }
169         }
170         codeStream.recordPositionsFrom(pc, this.sourceStart);
171
172         if (this.anonymousType != null) {
173             this.anonymousType.generateCode(currentScope, codeStream);
174         }
175     }
176     
177     public boolean isSuperAccess() {
178
179         // necessary to lookup super constructor of anonymous type
180
return this.anonymousType != null;
181     }
182     
183     /* Inner emulation consists in either recording a dependency
184      * link only, or performing one level of propagation.
185      *
186      * Dependency mechanism is used whenever dealing with source target
187      * types, since by the time we reach them, we might not yet know their
188      * exact need.
189      */

190     public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
191
192         if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
193         ReferenceBinding allocatedTypeErasure = (ReferenceBinding) this.binding.declaringClass.erasure();
194
195         // perform some extra emulation work in case there is some and we are inside a local type only
196
if (allocatedTypeErasure.isNestedType()
197             && currentScope.enclosingSourceType().isLocalType()) {
198
199             if (allocatedTypeErasure.isLocalType()) {
200                 ((LocalTypeBinding) allocatedTypeErasure).addInnerEmulationDependent(currentScope, this.enclosingInstance != null);
201             } else {
202                 // locally propagate, since we already now the desired shape for sure
203
currentScope.propagateInnerEmulation(allocatedTypeErasure, this.enclosingInstance != null);
204             }
205         }
206         }
207     }
208
209     public StringBuffer JavaDoc printExpression(int indent, StringBuffer JavaDoc output) {
210
211         if (this.enclosingInstance != null)
212             this.enclosingInstance.printExpression(0, output).append('.');
213         super.printExpression(0, output);
214         if (this.anonymousType != null) {
215             this.anonymousType.print(indent, output);
216         }
217         return output;
218     }
219     
220     public TypeBinding resolveType(BlockScope scope) {
221
222         // added for code assist...cannot occur with 'normal' code
223
if (this.anonymousType == null && this.enclosingInstance == null) {
224             return super.resolveType(scope);
225         }
226
227         // Propagate the type checking to the arguments, and checks if the constructor is defined.
228
// ClassInstanceCreationExpression ::= Primary '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt
229
// ClassInstanceCreationExpression ::= Name '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt
230

231         this.constant = Constant.NotAConstant;
232         TypeBinding enclosingInstanceType = null;
233         TypeBinding receiverType = null;
234         boolean hasError = false;
235         boolean enclosingInstanceContainsCast = false;
236         boolean argsContainCast = false;
237         
238         if (this.enclosingInstance != null) {
239             if (this.enclosingInstance instanceof CastExpression) {
240                 this.enclosingInstance.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on
241
enclosingInstanceContainsCast = true;
242             }
243             if ((enclosingInstanceType = this.enclosingInstance.resolveType(scope)) == null){
244                 hasError = true;
245             } else if (enclosingInstanceType.isBaseType() || enclosingInstanceType.isArrayType()) {
246                 scope.problemReporter().illegalPrimitiveOrArrayTypeForEnclosingInstance(
247                     enclosingInstanceType,
248                     this.enclosingInstance);
249                 hasError = true;
250             } else if (this.type instanceof QualifiedTypeReference) {
251                 scope.problemReporter().illegalUsageOfQualifiedTypeReference((QualifiedTypeReference)this.type);
252                 hasError = true;
253             } else {
254                 receiverType = ((SingleTypeReference) this.type).resolveTypeEnclosing(scope, (ReferenceBinding) enclosingInstanceType);
255                 if (receiverType != null && enclosingInstanceContainsCast) {
256                     CastExpression.checkNeedForEnclosingInstanceCast(scope, this.enclosingInstance, enclosingInstanceType, receiverType);
257                 }
258             }
259         } else {
260             if (this.type == null) {
261                 // initialization of an enum constant
262
receiverType = scope.enclosingSourceType();
263             } else {
264                 receiverType = this.type.resolveType(scope, true /* check bounds*/);
265                 checkParameterizedAllocation: {
266                     if (receiverType == null) break checkParameterizedAllocation;
267                     if (this.type instanceof ParameterizedQualifiedTypeReference) { // disallow new X<String>.Y<Integer>()
268
ReferenceBinding currentType = (ReferenceBinding)receiverType;
269                         do {
270                             // isStatic() is answering true for toplevel types
271
if ((currentType.modifiers & ClassFileConstants.AccStatic) != 0) break checkParameterizedAllocation;
272                             if (currentType.isRawType()) break checkParameterizedAllocation;
273                         } while ((currentType = currentType.enclosingType())!= null);
274                         ParameterizedQualifiedTypeReference qRef = (ParameterizedQualifiedTypeReference) this.type;
275                         for (int i = qRef.typeArguments.length - 2; i >= 0; i--) {
276                             if (qRef.typeArguments[i] != null) {
277                                 scope.problemReporter().illegalQualifiedParameterizedTypeAllocation(this.type, receiverType);
278                                 break;
279                             }
280                         }
281                     }
282                 }
283             }
284         }
285         if (receiverType == null) {
286             hasError = true;
287         } else if (((ReferenceBinding) receiverType).isFinal()) {
288             if (this.anonymousType != null) {
289                 if (!receiverType.isEnum()) {
290                     scope.problemReporter().anonymousClassCannotExtendFinalClass(this.type, receiverType);
291                     hasError = true;
292                 }
293             } else if (!receiverType.canBeInstantiated()) {
294                 scope.problemReporter().cannotInstantiate(this.type, receiverType);
295                 return this.resolvedType = receiverType;
296             }
297         }
298         // resolve type arguments (for generic constructor call)
299
if (this.typeArguments != null) {
300             int length = this.typeArguments.length;
301             this.genericTypeArguments = new TypeBinding[length];
302             for (int i = 0; i < length; i++) {
303                 TypeReference typeReference = this.typeArguments[i];
304                 TypeBinding argType = typeReference.resolveType(scope, true /* check bounds*/);
305                 if (argType == null) {
306                     if (typeReference instanceof Wildcard) {
307                         scope.problemReporter().illegalUsageOfWildcard(typeReference);
308                     }
309                     return null; // error already reported
310
}
311                 this.genericTypeArguments[i] = argType;
312             }
313         }
314         
315         // will check for null after args are resolved
316
TypeBinding[] argumentTypes = Binding.NO_PARAMETERS;
317         if (this.arguments != null) {
318             int length = this.arguments.length;
319             argumentTypes = new TypeBinding[length];
320             for (int i = 0; i < length; i++) {
321                 Expression argument = this.arguments[i];
322                 if (argument instanceof CastExpression) {
323                     argument.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on
324
argsContainCast = true;
325                 }
326                 if ((argumentTypes[i] = argument.resolveType(scope)) == null){
327                     hasError = true;
328                 }
329             }
330         }
331         // limit of fault-tolerance
332
if (hasError) {
333             if (receiverType instanceof ReferenceBinding) {
334                 // record a best guess, for clients who need hint about possible contructor match
335
int length = this.arguments == null ? 0 : this.arguments.length;
336                 TypeBinding[] pseudoArgs = new TypeBinding[length];
337                 for (int i = length; --i >= 0;) {
338                     pseudoArgs[i] = argumentTypes[i] == null ? TypeBinding.NULL : argumentTypes[i]; // replace args with errors with null type
339
}
340                 this.binding = scope.findMethod((ReferenceBinding) receiverType, TypeConstants.INIT, pseudoArgs, this);
341                 if (this.binding != null && !this.binding.isValidBinding()) {
342                     MethodBinding closestMatch = ((ProblemMethodBinding)this.binding).closestMatch;
343                     // record the closest match, for clients who may still need hint about possible method match
344
if (closestMatch != null) {
345                         if (closestMatch.original().typeVariables != Binding.NO_TYPE_VARIABLES) { // generic method
346
// shouldn't return generic method outside its context, rather convert it to raw method (175409)
347
closestMatch = scope.environment().createParameterizedGenericMethod(closestMatch.original(), (RawTypeBinding)null);
348                         }
349                         this.binding = closestMatch;
350                         MethodBinding closestMatchOriginal = closestMatch.original();
351                         if ((closestMatchOriginal.isPrivate() || closestMatchOriginal.declaringClass.isLocalType()) && !scope.isDefinedInMethod(closestMatchOriginal)) {
352                             // ignore cases where method is used from within inside itself (e.g. direct recursions)
353
closestMatchOriginal.modifiers |= ExtraCompilerModifiers.AccLocallyUsed;
354                         }
355                     }
356                 }
357                 
358             }
359             return this.resolvedType = receiverType;
360         }
361         if (this.anonymousType == null) {
362             // qualified allocation with no anonymous type
363
if (!receiverType.canBeInstantiated()) {
364                 scope.problemReporter().cannotInstantiate(this.type, receiverType);
365                 return this.resolvedType = receiverType;
366             }
367             ReferenceBinding allocationType = (ReferenceBinding) receiverType;
368             if ((this.binding = scope.getConstructor(allocationType, argumentTypes, this)).isValidBinding()) {
369                 if (isMethodUseDeprecated(this.binding, scope, true)) {
370                     scope.problemReporter().deprecatedMethod(this.binding, this);
371                 }
372                 checkInvocationArguments(scope, null, allocationType, this.binding, this.arguments, argumentTypes, argsContainCast, this);
373             } else {
374                 if (this.binding.declaringClass == null) {
375                     this.binding.declaringClass = allocationType;
376                 }
377                 scope.problemReporter().invalidConstructor(this, this.binding);
378                 return this.resolvedType = receiverType;
379             }
380
381             // The enclosing instance must be compatible with the innermost enclosing type
382
ReferenceBinding expectedType = this.binding.declaringClass.enclosingType();
383             if (expectedType != enclosingInstanceType) // must call before computeConversion() and typeMismatchError()
384
scope.compilationUnitScope().recordTypeConversion(expectedType, enclosingInstanceType);
385             if (enclosingInstanceType.isCompatibleWith(expectedType) || scope.isBoxingCompatibleWith(enclosingInstanceType, expectedType)) {
386                 this.enclosingInstance.computeConversion(scope, expectedType, enclosingInstanceType);
387                 return this.resolvedType = receiverType;
388             }
389             scope.problemReporter().typeMismatchError(enclosingInstanceType, expectedType, this.enclosingInstance);
390             return this.resolvedType = receiverType;
391         }
392
393         if (receiverType.isTypeVariable()) {
394             receiverType = new ProblemReferenceBinding(receiverType.sourceName(), (ReferenceBinding)receiverType, ProblemReasons.IllegalSuperTypeVariable);
395             scope.problemReporter().invalidType(this, receiverType);
396             return null;
397         } else if (this.type != null && receiverType.isEnum()) { // tolerate enum constant body
398
scope.problemReporter().cannotInstantiate(this.type, receiverType);
399             return this.resolvedType = receiverType;
400         }
401         // anonymous type scenario
402
// an anonymous class inherits from java.lang.Object when declared "after" an interface
403
this.superTypeBinding = receiverType.isInterface() ? scope.getJavaLangObject() : (ReferenceBinding) receiverType;
404         // insert anonymous type in scope
405
scope.addAnonymousType(this.anonymousType, (ReferenceBinding) receiverType);
406         this.anonymousType.resolve(scope);
407         if (this.superTypeBinding.erasure().id == TypeIds.T_JavaLangEnum) {
408             scope.problemReporter().cannotExtendEnum(this.anonymousType.binding, this.type, this.superTypeBinding);
409         }
410         
411         if ((receiverType.tagBits & TagBits.HasDirectWildcard) != 0) {
412             scope.problemReporter().superTypeCannotUseWildcard(this.anonymousType.binding, this.type, receiverType);
413         }
414         // find anonymous super constructor
415
MethodBinding inheritedBinding = scope.getConstructor(this.superTypeBinding, argumentTypes, this);
416         if (!inheritedBinding.isValidBinding()) {
417             if (inheritedBinding.declaringClass == null) {
418                 inheritedBinding.declaringClass = this.superTypeBinding;
419             }
420             scope.problemReporter().invalidConstructor(this, inheritedBinding);
421             return this.resolvedType = this.anonymousType.binding;
422         }
423         if (this.enclosingInstance != null) {
424             ReferenceBinding targetEnclosing = inheritedBinding.declaringClass.enclosingType();
425             if (targetEnclosing == null) {
426                 scope.problemReporter().unnecessaryEnclosingInstanceSpecification(this.enclosingInstance, (ReferenceBinding)receiverType);
427                 return this.resolvedType = this.anonymousType.binding;
428             } else if (!enclosingInstanceType.isCompatibleWith(targetEnclosing) && !scope.isBoxingCompatibleWith(enclosingInstanceType, targetEnclosing)) {
429                 scope.problemReporter().typeMismatchError(enclosingInstanceType, targetEnclosing, this.enclosingInstance);
430                 return this.resolvedType = this.anonymousType.binding;
431             }
432             this.enclosingInstance.computeConversion(scope, targetEnclosing, enclosingInstanceType);
433         }
434         if (this.arguments != null)
435             checkInvocationArguments(scope, null, this.superTypeBinding, inheritedBinding, this.arguments, argumentTypes, argsContainCast, this);
436
437         // Update the anonymous inner class : superclass, interface
438
this.binding = this.anonymousType.createDefaultConstructorWithBinding(inheritedBinding);
439         return this.resolvedType = this.anonymousType.binding; // 1.2 change
440
}
441     
442     public void traverse(ASTVisitor visitor, BlockScope scope) {
443
444         if (visitor.visit(this, scope)) {
445             if (this.enclosingInstance != null)
446                 this.enclosingInstance.traverse(visitor, scope);
447             if (this.typeArguments != null) {
448                 for (int i = 0, typeArgumentsLength = this.typeArguments.length; i < typeArgumentsLength; i++) {
449                     this.typeArguments[i].traverse(visitor, scope);
450                 }
451             }
452             if (this.type != null) // case of enum constant
453
this.type.traverse(visitor, scope);
454             if (this.arguments != null) {
455                 int argumentsLength = this.arguments.length;
456                 for (int i = 0; i < argumentsLength; i++)
457                     this.arguments[i].traverse(visitor, scope);
458             }
459             if (this.anonymousType != null)
460                 this.anonymousType.traverse(visitor, scope);
461         }
462         visitor.endVisit(this, scope);
463     }
464 }
465
Popular Tags