001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.compiler.ast;
011:
012: import org.eclipse.jdt.internal.compiler.ASTVisitor;
013: import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
014: import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
015: import org.eclipse.jdt.internal.compiler.flow.FlowContext;
016: import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
017: import org.eclipse.jdt.internal.compiler.impl.Constant;
018: import org.eclipse.jdt.internal.compiler.lookup.Binding;
019: import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
020: import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
021: import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding;
022: import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
023: import org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding;
024: import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons;
025: import org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding;
026: import org.eclipse.jdt.internal.compiler.lookup.RawTypeBinding;
027: import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
028: import org.eclipse.jdt.internal.compiler.lookup.TagBits;
029: import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
030: import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
031: import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
032:
033: /**
034: * Variation on allocation, where can optionally be specified any of:
035: * - leading enclosing instance
036: * - trailing anonymous type
037: * - generic type arguments for generic constructor invocation
038: */
039: public class QualifiedAllocationExpression extends AllocationExpression {
040:
041: //qualification may be on both side
042: public Expression enclosingInstance;
043: public TypeDeclaration anonymousType;
044: public ReferenceBinding super TypeBinding;
045:
046: public QualifiedAllocationExpression() {
047: // for subtypes
048: }
049:
050: public QualifiedAllocationExpression(TypeDeclaration anonymousType) {
051: this .anonymousType = anonymousType;
052: anonymousType.allocation = this ;
053: }
054:
055: public FlowInfo analyseCode(BlockScope currentScope,
056: FlowContext flowContext, FlowInfo flowInfo) {
057:
058: // analyse the enclosing instance
059: if (this .enclosingInstance != null) {
060: flowInfo = this .enclosingInstance.analyseCode(currentScope,
061: flowContext, flowInfo);
062: }
063:
064: // check captured variables are initialized in current context (26134)
065: ReferenceBinding allocatedType = this .super TypeBinding == null ? this .binding.declaringClass
066: : this .super TypeBinding;
067: checkCapturedLocalInitializationIfNecessary(
068: (ReferenceBinding) allocatedType.erasure(),
069: currentScope, flowInfo);
070:
071: // process arguments
072: if (this .arguments != null) {
073: for (int i = 0, count = this .arguments.length; i < count; i++) {
074: flowInfo = this .arguments[i].analyseCode(currentScope,
075: flowContext, flowInfo);
076: }
077: }
078:
079: // analyse the anonymous nested type
080: if (this .anonymousType != null) {
081: flowInfo = this .anonymousType.analyseCode(currentScope,
082: flowContext, flowInfo);
083: }
084:
085: // record some dependency information for exception types
086: ReferenceBinding[] thrownExceptions;
087: if (((thrownExceptions = this .binding.thrownExceptions).length) != 0) {
088: // check exception handling
089: flowContext.checkExceptionHandlers(thrownExceptions, this ,
090: flowInfo.unconditionalCopy(), currentScope);
091: }
092: manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
093: manageSyntheticAccessIfNecessary(currentScope, flowInfo);
094: return flowInfo;
095: }
096:
097: public Expression enclosingInstance() {
098:
099: return this .enclosingInstance;
100: }
101:
102: public void generateCode(BlockScope currentScope,
103: CodeStream codeStream, boolean valueRequired) {
104:
105: int pc = codeStream.position;
106: ReferenceBinding allocatedType = this .codegenBinding.declaringClass;
107: codeStream.new_(allocatedType);
108: boolean isUnboxing = (this .implicitConversion & TypeIds.UNBOXING) != 0;
109: if (valueRequired || isUnboxing) {
110: codeStream.dup();
111: }
112: // better highlight for allocation: display the type individually
113: if (this .type != null) { // null for enum constant body
114: codeStream.recordPositionsFrom(pc, this .type.sourceStart);
115: } else {
116: // push enum constant name and ordinal
117: codeStream.ldc(String.valueOf(this .enumConstant.name));
118: codeStream
119: .generateInlinedValue(this .enumConstant.binding.id);
120: }
121: // handling innerclass instance allocation - enclosing instance arguments
122: if (allocatedType.isNestedType()) {
123: codeStream.generateSyntheticEnclosingInstanceValues(
124: currentScope, allocatedType, enclosingInstance(),
125: this );
126: }
127: // generate the arguments for constructor
128: generateArguments(this .binding, this .arguments, currentScope,
129: codeStream);
130: // handling innerclass instance allocation - outer local arguments
131: if (allocatedType.isNestedType()) {
132: codeStream.generateSyntheticOuterArgumentValues(
133: currentScope, allocatedType, this );
134: }
135:
136: // invoke constructor
137: if (this .syntheticAccessor == null) {
138: codeStream.invokespecial(this .codegenBinding);
139: } else {
140: // synthetic accessor got some extra arguments appended to its signature, which need values
141: for (int i = 0, max = this .syntheticAccessor.parameters.length
142: - this .codegenBinding.parameters.length; i < max; i++) {
143: codeStream.aconst_null();
144: }
145: codeStream.invokespecial(this .syntheticAccessor);
146: }
147: if (valueRequired) {
148: codeStream.generateImplicitConversion(implicitConversion);
149: } else if (isUnboxing) {
150: // conversion only generated if unboxing
151: codeStream.generateImplicitConversion(implicitConversion);
152: switch (postConversionType(currentScope).id) {
153: case T_long:
154: case T_double:
155: codeStream.pop2();
156: break;
157: default:
158: codeStream.pop();
159: }
160: }
161: codeStream.recordPositionsFrom(pc, this .sourceStart);
162:
163: if (this .anonymousType != null) {
164: this .anonymousType.generateCode(currentScope, codeStream);
165: }
166: }
167:
168: public boolean isSuperAccess() {
169:
170: // necessary to lookup super constructor of anonymous type
171: return this .anonymousType != null;
172: }
173:
174: /* Inner emulation consists in either recording a dependency
175: * link only, or performing one level of propagation.
176: *
177: * Dependency mechanism is used whenever dealing with source target
178: * types, since by the time we reach them, we might not yet know their
179: * exact need.
180: */
181: public void manageEnclosingInstanceAccessIfNecessary(
182: BlockScope currentScope, FlowInfo flowInfo) {
183:
184: if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
185: ReferenceBinding allocatedTypeErasure = (ReferenceBinding) this .binding.declaringClass
186: .erasure();
187:
188: // perform some extra emulation work in case there is some and we are inside a local type only
189: if (allocatedTypeErasure.isNestedType()
190: && currentScope.enclosingSourceType().isLocalType()) {
191:
192: if (allocatedTypeErasure.isLocalType()) {
193: ((LocalTypeBinding) allocatedTypeErasure)
194: .addInnerEmulationDependent(currentScope,
195: this .enclosingInstance != null);
196: } else {
197: // locally propagate, since we already now the desired shape for sure
198: currentScope.propagateInnerEmulation(
199: allocatedTypeErasure,
200: this .enclosingInstance != null);
201: }
202: }
203: }
204: }
205:
206: public StringBuffer printExpression(int indent, StringBuffer output) {
207:
208: if (this .enclosingInstance != null)
209: this .enclosingInstance.printExpression(0, output).append(
210: '.');
211: super .printExpression(0, output);
212: if (this .anonymousType != null) {
213: this .anonymousType.print(indent, output);
214: }
215: return output;
216: }
217:
218: public TypeBinding resolveType(BlockScope scope) {
219:
220: // added for code assist...cannot occur with 'normal' code
221: if (this .anonymousType == null
222: && this .enclosingInstance == null) {
223: return super .resolveType(scope);
224: }
225:
226: // Propagate the type checking to the arguments, and checks if the constructor is defined.
227: // ClassInstanceCreationExpression ::= Primary '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt
228: // ClassInstanceCreationExpression ::= Name '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt
229:
230: this .constant = Constant.NotAConstant;
231: TypeBinding enclosingInstanceType = null;
232: TypeBinding receiverType = null;
233: boolean hasError = false;
234: boolean enclosingInstanceContainsCast = false;
235: boolean argsContainCast = false;
236:
237: if (this .enclosingInstance != null) {
238: if (this .enclosingInstance instanceof CastExpression) {
239: this .enclosingInstance.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on
240: enclosingInstanceContainsCast = true;
241: }
242: if ((enclosingInstanceType = this .enclosingInstance
243: .resolveType(scope)) == null) {
244: hasError = true;
245: } else if (enclosingInstanceType.isBaseType()
246: || enclosingInstanceType.isArrayType()) {
247: scope
248: .problemReporter()
249: .illegalPrimitiveOrArrayTypeForEnclosingInstance(
250: enclosingInstanceType,
251: this .enclosingInstance);
252: hasError = true;
253: } else if (this .type instanceof QualifiedTypeReference) {
254: scope.problemReporter()
255: .illegalUsageOfQualifiedTypeReference(
256: (QualifiedTypeReference) this .type);
257: hasError = true;
258: } else {
259: receiverType = ((SingleTypeReference) this .type)
260: .resolveTypeEnclosing(
261: scope,
262: (ReferenceBinding) enclosingInstanceType);
263: if (receiverType != null
264: && enclosingInstanceContainsCast) {
265: CastExpression.checkNeedForEnclosingInstanceCast(
266: scope, this .enclosingInstance,
267: enclosingInstanceType, receiverType);
268: }
269: }
270: } else {
271: if (this .type == null) {
272: // initialization of an enum constant
273: receiverType = scope.enclosingSourceType();
274: } else {
275: receiverType = this .type
276: .resolveType(scope, true /* check bounds*/);
277: checkParameterizedAllocation: {
278: if (receiverType == null)
279: break checkParameterizedAllocation;
280: if (this .type instanceof ParameterizedQualifiedTypeReference) { // disallow new X<String>.Y<Integer>()
281: ReferenceBinding currentType = (ReferenceBinding) receiverType;
282: do {
283: // isStatic() is answering true for toplevel types
284: if ((currentType.modifiers & ClassFileConstants.AccStatic) != 0)
285: break checkParameterizedAllocation;
286: if (currentType.isRawType())
287: break checkParameterizedAllocation;
288: } while ((currentType = currentType
289: .enclosingType()) != null);
290: ParameterizedQualifiedTypeReference qRef = (ParameterizedQualifiedTypeReference) this .type;
291: for (int i = qRef.typeArguments.length - 2; i >= 0; i--) {
292: if (qRef.typeArguments[i] != null) {
293: scope
294: .problemReporter()
295: .illegalQualifiedParameterizedTypeAllocation(
296: this .type, receiverType);
297: break;
298: }
299: }
300: }
301: }
302: }
303: }
304: if (receiverType == null) {
305: hasError = true;
306: } else if (((ReferenceBinding) receiverType).isFinal()) {
307: if (this .anonymousType != null) {
308: if (!receiverType.isEnum()) {
309: scope.problemReporter()
310: .anonymousClassCannotExtendFinalClass(
311: this .type, receiverType);
312: hasError = true;
313: }
314: } else if (!receiverType.canBeInstantiated()) {
315: scope.problemReporter().cannotInstantiate(this .type,
316: receiverType);
317: return this .resolvedType = receiverType;
318: }
319: }
320: // resolve type arguments (for generic constructor call)
321: if (this .typeArguments != null) {
322: int length = this .typeArguments.length;
323: this .genericTypeArguments = new TypeBinding[length];
324: for (int i = 0; i < length; i++) {
325: TypeReference typeReference = this .typeArguments[i];
326: TypeBinding argType = typeReference.resolveType(scope,
327: true /* check bounds*/);
328: if (argType == null) {
329: if (typeReference instanceof Wildcard) {
330: scope.problemReporter().illegalUsageOfWildcard(
331: typeReference);
332: }
333: return null; // error already reported
334: }
335: this .genericTypeArguments[i] = argType;
336: }
337: }
338:
339: // will check for null after args are resolved
340: TypeBinding[] argumentTypes = Binding.NO_PARAMETERS;
341: if (this .arguments != null) {
342: int length = this .arguments.length;
343: argumentTypes = new TypeBinding[length];
344: for (int i = 0; i < length; i++) {
345: Expression argument = this .arguments[i];
346: if (argument instanceof CastExpression) {
347: argument.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on
348: argsContainCast = true;
349: }
350: if ((argumentTypes[i] = argument.resolveType(scope)) == null) {
351: hasError = true;
352: }
353: }
354: }
355: // limit of fault-tolerance
356: if (hasError) {
357: if (receiverType instanceof ReferenceBinding) {
358: // record a best guess, for clients who need hint about possible contructor match
359: int length = this .arguments == null ? 0
360: : this .arguments.length;
361: TypeBinding[] pseudoArgs = new TypeBinding[length];
362: for (int i = length; --i >= 0;) {
363: pseudoArgs[i] = argumentTypes[i] == null ? TypeBinding.NULL
364: : argumentTypes[i]; // replace args with errors with null type
365: }
366: this .binding = scope.findMethod(
367: (ReferenceBinding) receiverType,
368: TypeConstants.INIT, pseudoArgs, this );
369: if (this .binding != null
370: && !this .binding.isValidBinding()) {
371: MethodBinding closestMatch = ((ProblemMethodBinding) this .binding).closestMatch;
372: // record the closest match, for clients who may still need hint about possible method match
373: if (closestMatch != null) {
374: if (closestMatch.original().typeVariables != Binding.NO_TYPE_VARIABLES) { // generic method
375: // shouldn't return generic method outside its context, rather convert it to raw method (175409)
376: closestMatch = scope.environment()
377: .createParameterizedGenericMethod(
378: closestMatch.original(),
379: (RawTypeBinding) null);
380: }
381: this .binding = closestMatch;
382: MethodBinding closestMatchOriginal = closestMatch
383: .original();
384: if ((closestMatchOriginal.isPrivate() || closestMatchOriginal.declaringClass
385: .isLocalType())
386: && !scope
387: .isDefinedInMethod(closestMatchOriginal)) {
388: // ignore cases where method is used from within inside itself (e.g. direct recursions)
389: closestMatchOriginal.modifiers |= ExtraCompilerModifiers.AccLocallyUsed;
390: }
391: }
392: }
393:
394: }
395: return this .resolvedType = receiverType;
396: }
397: if (this .anonymousType == null) {
398: // qualified allocation with no anonymous type
399: if (!receiverType.canBeInstantiated()) {
400: scope.problemReporter().cannotInstantiate(this .type,
401: receiverType);
402: return this .resolvedType = receiverType;
403: }
404: ReferenceBinding allocationType = (ReferenceBinding) receiverType;
405: if ((this .binding = scope.getConstructor(allocationType,
406: argumentTypes, this )).isValidBinding()) {
407: if (isMethodUseDeprecated(this .binding, scope, true)) {
408: scope.problemReporter().deprecatedMethod(
409: this .binding, this );
410: }
411: checkInvocationArguments(scope, null, allocationType,
412: this .binding, this .arguments, argumentTypes,
413: argsContainCast, this );
414: } else {
415: if (this .binding.declaringClass == null) {
416: this .binding.declaringClass = allocationType;
417: }
418: scope.problemReporter().invalidConstructor(this ,
419: this .binding);
420: return this .resolvedType = receiverType;
421: }
422:
423: // The enclosing instance must be compatible with the innermost enclosing type
424: ReferenceBinding expectedType = this .binding.declaringClass
425: .enclosingType();
426: if (expectedType != enclosingInstanceType) // must call before computeConversion() and typeMismatchError()
427: scope.compilationUnitScope().recordTypeConversion(
428: expectedType, enclosingInstanceType);
429: if (enclosingInstanceType.isCompatibleWith(expectedType)
430: || scope.isBoxingCompatibleWith(
431: enclosingInstanceType, expectedType)) {
432: this .enclosingInstance.computeConversion(scope,
433: expectedType, enclosingInstanceType);
434: return this .resolvedType = receiverType;
435: }
436: scope.problemReporter().typeMismatchError(
437: enclosingInstanceType, expectedType,
438: this .enclosingInstance);
439: return this .resolvedType = receiverType;
440: }
441:
442: if (receiverType.isTypeVariable()) {
443: receiverType = new ProblemReferenceBinding(receiverType
444: .sourceName(), (ReferenceBinding) receiverType,
445: ProblemReasons.IllegalSuperTypeVariable);
446: scope.problemReporter().invalidType(this , receiverType);
447: return null;
448: } else if (this .type != null && receiverType.isEnum()) { // tolerate enum constant body
449: scope.problemReporter().cannotInstantiate(this .type,
450: receiverType);
451: return this .resolvedType = receiverType;
452: }
453: // anonymous type scenario
454: // an anonymous class inherits from java.lang.Object when declared "after" an interface
455: this .super TypeBinding = receiverType.isInterface() ? scope
456: .getJavaLangObject() : (ReferenceBinding) receiverType;
457: // insert anonymous type in scope
458: scope.addAnonymousType(this .anonymousType,
459: (ReferenceBinding) receiverType);
460: this .anonymousType.resolve(scope);
461: if (this .super TypeBinding.erasure().id == TypeIds.T_JavaLangEnum) {
462: scope.problemReporter().cannotExtendEnum(
463: this .anonymousType.binding, this .type,
464: this .super TypeBinding);
465: }
466:
467: if ((receiverType.tagBits & TagBits.HasDirectWildcard) != 0) {
468: scope.problemReporter()
469: .super TypeCannotUseWildcard(
470: this .anonymousType.binding, this .type,
471: receiverType);
472: }
473: // find anonymous super constructor
474: MethodBinding inheritedBinding = scope.getConstructor(
475: this .super TypeBinding, argumentTypes, this );
476: if (!inheritedBinding.isValidBinding()) {
477: if (inheritedBinding.declaringClass == null) {
478: inheritedBinding.declaringClass = this .super TypeBinding;
479: }
480: scope.problemReporter().invalidConstructor(this ,
481: inheritedBinding);
482: return this .resolvedType = this .anonymousType.binding;
483: }
484: if (this .enclosingInstance != null) {
485: ReferenceBinding targetEnclosing = inheritedBinding.declaringClass
486: .enclosingType();
487: if (targetEnclosing == null) {
488: scope.problemReporter()
489: .unnecessaryEnclosingInstanceSpecification(
490: this .enclosingInstance,
491: (ReferenceBinding) receiverType);
492: return this .resolvedType = this .anonymousType.binding;
493: } else if (!enclosingInstanceType
494: .isCompatibleWith(targetEnclosing)
495: && !scope.isBoxingCompatibleWith(
496: enclosingInstanceType, targetEnclosing)) {
497: scope.problemReporter().typeMismatchError(
498: enclosingInstanceType, targetEnclosing,
499: this .enclosingInstance);
500: return this .resolvedType = this .anonymousType.binding;
501: }
502: this .enclosingInstance.computeConversion(scope,
503: targetEnclosing, enclosingInstanceType);
504: }
505: if (this .arguments != null)
506: checkInvocationArguments(scope, null,
507: this .super TypeBinding, inheritedBinding,
508: this .arguments, argumentTypes, argsContainCast,
509: this );
510:
511: // Update the anonymous inner class : superclass, interface
512: this .binding = this .anonymousType
513: .createDefaultConstructorWithBinding(inheritedBinding);
514: return this .resolvedType = this .anonymousType.binding; // 1.2 change
515: }
516:
517: public void traverse(ASTVisitor visitor, BlockScope scope) {
518:
519: if (visitor.visit(this , scope)) {
520: if (this .enclosingInstance != null)
521: this .enclosingInstance.traverse(visitor, scope);
522: if (this .typeArguments != null) {
523: for (int i = 0, typeArgumentsLength = this .typeArguments.length; i < typeArgumentsLength; i++) {
524: this .typeArguments[i].traverse(visitor, scope);
525: }
526: }
527: if (this .type != null) // case of enum constant
528: this .type.traverse(visitor, scope);
529: if (this .arguments != null) {
530: int argumentsLength = this .arguments.length;
531: for (int i = 0; i < argumentsLength; i++)
532: this.arguments[i].traverse(visitor, scope);
533: }
534: if (this.anonymousType != null)
535: this.anonymousType.traverse(visitor, scope);
536: }
537: visitor.endVisit(this, scope);
538: }
539: }
|