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.*;
015: import org.eclipse.jdt.internal.compiler.flow.*;
016: import org.eclipse.jdt.internal.compiler.impl.Constant;
017: import org.eclipse.jdt.internal.compiler.lookup.*;
018:
019: public class AllocationExpression extends Expression implements
020: InvocationSite {
021:
022: public TypeReference type;
023: public Expression[] arguments;
024: public MethodBinding binding; // exact binding resulting from lookup
025: protected MethodBinding codegenBinding; // actual binding used for code generation (if no synthetic accessor)
026: MethodBinding syntheticAccessor; // synthetic accessor for inner-emulation
027: public TypeReference[] typeArguments;
028: public TypeBinding[] genericTypeArguments;
029: public FieldDeclaration enumConstant; // for enum constant initializations
030:
031: public FlowInfo analyseCode(BlockScope currentScope,
032: FlowContext flowContext, FlowInfo flowInfo) {
033: // check captured variables are initialized in current context (26134)
034: checkCapturedLocalInitializationIfNecessary(
035: (ReferenceBinding) this .binding.declaringClass
036: .erasure(), currentScope, flowInfo);
037:
038: // process arguments
039: if (arguments != null) {
040: for (int i = 0, count = arguments.length; i < count; i++) {
041: flowInfo = arguments[i].analyseCode(currentScope,
042: flowContext, flowInfo).unconditionalInits();
043: }
044: }
045: // record some dependency information for exception types
046: ReferenceBinding[] thrownExceptions;
047: if (((thrownExceptions = this .binding.thrownExceptions).length) != 0) {
048: // check exception handling
049: flowContext.checkExceptionHandlers(thrownExceptions, this ,
050: flowInfo.unconditionalCopy(), currentScope);
051: }
052: manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
053: manageSyntheticAccessIfNecessary(currentScope, flowInfo);
054:
055: return flowInfo;
056: }
057:
058: public void checkCapturedLocalInitializationIfNecessary(
059: ReferenceBinding checkedType, BlockScope currentScope,
060: FlowInfo flowInfo) {
061: if (checkedType.isLocalType() && !checkedType.isAnonymousType()
062: && !currentScope.isDefinedInType(checkedType)) { // only check external allocations
063: NestedTypeBinding nestedType = (NestedTypeBinding) checkedType;
064: SyntheticArgumentBinding[] syntheticArguments = nestedType
065: .syntheticOuterLocalVariables();
066: if (syntheticArguments != null)
067: for (int i = 0, count = syntheticArguments.length; i < count; i++) {
068: SyntheticArgumentBinding syntheticArgument = syntheticArguments[i];
069: LocalVariableBinding targetLocal;
070: if ((targetLocal = syntheticArgument.actualOuterLocalVariable) == null)
071: continue;
072: if (targetLocal.declaration != null
073: && !flowInfo
074: .isDefinitelyAssigned(targetLocal)) {
075: currentScope.problemReporter()
076: .uninitializedLocalVariable(
077: targetLocal, this );
078: }
079: }
080: }
081: }
082:
083: public Expression enclosingInstance() {
084: return null;
085: }
086:
087: public void generateCode(BlockScope currentScope,
088: CodeStream codeStream, boolean valueRequired) {
089: int pc = codeStream.position;
090: ReferenceBinding allocatedType = this .codegenBinding.declaringClass;
091:
092: codeStream.new_(allocatedType);
093: boolean isUnboxing = (this .implicitConversion & TypeIds.UNBOXING) != 0;
094: if (valueRequired || isUnboxing) {
095: codeStream.dup();
096: }
097: // better highlight for allocation: display the type individually
098: if (this .type != null) { // null for enum constant body
099: 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, allocatedType, enclosingInstance(),
110: this );
111: }
112: // generate the arguments for constructor
113: generateArguments(binding, arguments, currentScope, codeStream);
114: // handling innerclass instance allocation - outer local arguments
115: if (allocatedType.isNestedType()) {
116: codeStream.generateSyntheticOuterArgumentValues(
117: currentScope, allocatedType, this );
118: }
119: // invoke constructor
120: if (syntheticAccessor == null) {
121: codeStream.invokespecial(this .codegenBinding);
122: } else {
123: // synthetic accessor got some extra arguments appended to its signature, which need values
124: for (int i = 0, max = syntheticAccessor.parameters.length
125: - this .codegenBinding.parameters.length; i < max; i++) {
126: codeStream.aconst_null();
127: }
128: codeStream.invokespecial(syntheticAccessor);
129: }
130: if (valueRequired) {
131: codeStream
132: .generateImplicitConversion(this .implicitConversion);
133: } else if (isUnboxing) {
134: // conversion only generated if unboxing
135: codeStream
136: .generateImplicitConversion(this .implicitConversion);
137: switch (postConversionType(currentScope).id) {
138: case T_long:
139: case T_double:
140: codeStream.pop2();
141: break;
142: default:
143: codeStream.pop();
144: }
145: }
146: codeStream.recordPositionsFrom(pc, this .sourceStart);
147: }
148:
149: /**
150: * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#genericTypeArguments()
151: */
152: public TypeBinding[] genericTypeArguments() {
153: return this .genericTypeArguments;
154: }
155:
156: public boolean isSuperAccess() {
157: return false;
158: }
159:
160: public boolean isTypeAccess() {
161: return true;
162: }
163:
164: /* Inner emulation consists in either recording a dependency
165: * link only, or performing one level of propagation.
166: *
167: * Dependency mechanism is used whenever dealing with source target
168: * types, since by the time we reach them, we might not yet know their
169: * exact need.
170: */
171: public void manageEnclosingInstanceAccessIfNecessary(
172: BlockScope currentScope, FlowInfo flowInfo) {
173: if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0)
174: return;
175: ReferenceBinding allocatedTypeErasure = (ReferenceBinding) binding.declaringClass
176: .erasure();
177:
178: // perform some emulation work in case there is some and we are inside a local type only
179: if (allocatedTypeErasure.isNestedType()
180: && currentScope.enclosingSourceType().isLocalType()) {
181:
182: if (allocatedTypeErasure.isLocalType()) {
183: ((LocalTypeBinding) allocatedTypeErasure)
184: .addInnerEmulationDependent(currentScope, false);
185: // request cascade of accesses
186: } else {
187: // locally propagate, since we already now the desired shape for sure
188: currentScope.propagateInnerEmulation(
189: allocatedTypeErasure, false);
190: // request cascade of accesses
191: }
192: }
193: }
194:
195: public void manageSyntheticAccessIfNecessary(
196: BlockScope currentScope, FlowInfo flowInfo) {
197: if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0)
198: return;
199: // if constructor from parameterized type got found, use the original constructor at codegen time
200: this .codegenBinding = this .binding.original();
201:
202: ReferenceBinding declaringClass;
203: if (this .codegenBinding.isPrivate()
204: && currentScope.enclosingSourceType() != (declaringClass = this .codegenBinding.declaringClass)) {
205:
206: // from 1.4 on, local type constructor can lose their private flag to ease emulation
207: if ((declaringClass.tagBits & TagBits.IsLocalType) != 0
208: && currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4) {
209: // constructor will not be dumped as private, no emulation required thus
210: this .codegenBinding.tagBits |= TagBits.ClearPrivateModifier;
211: } else {
212: syntheticAccessor = ((SourceTypeBinding) declaringClass)
213: .addSyntheticMethod(this .codegenBinding,
214: isSuperAccess());
215: currentScope.problemReporter()
216: .needToEmulateMethodAccess(this .codegenBinding,
217: this );
218: }
219: }
220: }
221:
222: public StringBuffer printExpression(int indent, StringBuffer output) {
223: if (this .type != null) { // type null for enum constant initializations
224: output.append("new "); //$NON-NLS-1$
225: }
226: if (typeArguments != null) {
227: output.append('<');
228: int max = typeArguments.length - 1;
229: for (int j = 0; j < max; j++) {
230: typeArguments[j].print(0, output);
231: output.append(", ");//$NON-NLS-1$
232: }
233: typeArguments[max].print(0, output);
234: output.append('>');
235: }
236: if (type != null) { // type null for enum constant initializations
237: type.printExpression(0, output);
238: }
239: output.append('(');
240: if (arguments != null) {
241: for (int i = 0; i < arguments.length; i++) {
242: if (i > 0)
243: output.append(", "); //$NON-NLS-1$
244: arguments[i].printExpression(0, output);
245: }
246: }
247: return output.append(')');
248: }
249:
250: public TypeBinding resolveType(BlockScope scope) {
251: // Propagate the type checking to the arguments, and check if the constructor is defined.
252: constant = Constant.NotAConstant;
253: if (this .type == null) {
254: // initialization of an enum constant
255: this .resolvedType = scope.enclosingReceiverType();
256: } else {
257: this .resolvedType = this .type
258: .resolveType(scope, true /* check bounds*/);
259: checkParameterizedAllocation: {
260: if (this .type instanceof ParameterizedQualifiedTypeReference) { // disallow new X<String>.Y<Integer>()
261: ReferenceBinding currentType = (ReferenceBinding) this .resolvedType;
262: if (currentType == null)
263: return null;
264: do {
265: // isStatic() is answering true for toplevel types
266: if ((currentType.modifiers & ClassFileConstants.AccStatic) != 0)
267: break checkParameterizedAllocation;
268: if (currentType.isRawType())
269: break checkParameterizedAllocation;
270: } while ((currentType = currentType.enclosingType()) != null);
271: ParameterizedQualifiedTypeReference qRef = (ParameterizedQualifiedTypeReference) this .type;
272: for (int i = qRef.typeArguments.length - 2; i >= 0; i--) {
273: if (qRef.typeArguments[i] != null) {
274: scope
275: .problemReporter()
276: .illegalQualifiedParameterizedTypeAllocation(
277: this .type,
278: this .resolvedType);
279: break;
280: }
281: }
282: }
283: }
284: }
285: // will check for null after args are resolved
286:
287: // resolve type arguments (for generic constructor call)
288: if (this .typeArguments != null) {
289: int length = this .typeArguments.length;
290: boolean argHasError = false; // typeChecks all arguments
291: this .genericTypeArguments = new TypeBinding[length];
292: for (int i = 0; i < length; i++) {
293: TypeReference typeReference = this .typeArguments[i];
294: if ((this .genericTypeArguments[i] = typeReference
295: .resolveType(scope, true /* check bounds*/)) == null) {
296: argHasError = true;
297: }
298: if (argHasError && typeReference instanceof Wildcard) {
299: scope.problemReporter().illegalUsageOfWildcard(
300: typeReference);
301: }
302: }
303: if (argHasError) {
304: return null;
305: }
306: }
307:
308: // buffering the arguments' types
309: boolean argsContainCast = false;
310: TypeBinding[] argumentTypes = Binding.NO_PARAMETERS;
311: if (arguments != null) {
312: boolean argHasError = false;
313: int length = arguments.length;
314: argumentTypes = new TypeBinding[length];
315: for (int i = 0; i < length; i++) {
316: Expression argument = this .arguments[i];
317: if (argument instanceof CastExpression) {
318: argument.bits |= DisableUnnecessaryCastCheck; // will check later on
319: argsContainCast = true;
320: }
321: if ((argumentTypes[i] = argument.resolveType(scope)) == null) {
322: argHasError = true;
323: }
324: }
325: if (argHasError) {
326: if (this .resolvedType instanceof ReferenceBinding) {
327: // record a best guess, for clients who need hint about possible contructor match
328: TypeBinding[] pseudoArgs = new TypeBinding[length];
329: for (int i = length; --i >= 0;) {
330: pseudoArgs[i] = argumentTypes[i] == null ? TypeBinding.NULL
331: : argumentTypes[i]; // replace args with errors with null type
332: }
333: this .binding = scope.findMethod(
334: (ReferenceBinding) this .resolvedType,
335: TypeConstants.INIT, pseudoArgs, this );
336: if (this .binding != null
337: && !this .binding.isValidBinding()) {
338: MethodBinding closestMatch = ((ProblemMethodBinding) this .binding).closestMatch;
339: // record the closest match, for clients who may still need hint about possible method match
340: if (closestMatch != null) {
341: if (closestMatch.original().typeVariables != Binding.NO_TYPE_VARIABLES) { // generic method
342: // shouldn't return generic method outside its context, rather convert it to raw method (175409)
343: closestMatch = scope
344: .environment()
345: .createParameterizedGenericMethod(
346: closestMatch.original(),
347: (RawTypeBinding) null);
348: }
349: this .binding = closestMatch;
350: MethodBinding closestMatchOriginal = closestMatch
351: .original();
352: if ((closestMatchOriginal.isPrivate() || closestMatchOriginal.declaringClass
353: .isLocalType())
354: && !scope
355: .isDefinedInMethod(closestMatchOriginal)) {
356: // ignore cases where method is used from within inside itself (e.g. direct recursions)
357: closestMatchOriginal.modifiers |= ExtraCompilerModifiers.AccLocallyUsed;
358: }
359: }
360: }
361: }
362: return this .resolvedType;
363: }
364: }
365: if (this .resolvedType == null)
366: return null;
367:
368: // null type denotes fake allocation for enum constant inits
369: if (this .type != null && !this .resolvedType.canBeInstantiated()) {
370: scope.problemReporter().cannotInstantiate(type,
371: this .resolvedType);
372: return this .resolvedType;
373: }
374: ReferenceBinding allocationType = (ReferenceBinding) this .resolvedType;
375: if (!(binding = scope.getConstructor(allocationType,
376: argumentTypes, this )).isValidBinding()) {
377: if (binding.declaringClass == null)
378: binding.declaringClass = allocationType;
379: scope.problemReporter().invalidConstructor(this , binding);
380: return this .resolvedType;
381: }
382: if (isMethodUseDeprecated(binding, scope, true))
383: scope.problemReporter().deprecatedMethod(binding, this );
384: checkInvocationArguments(scope, null, allocationType,
385: this .binding, this .arguments, argumentTypes,
386: argsContainCast, this );
387:
388: return allocationType;
389: }
390:
391: public void setActualReceiverType(ReferenceBinding receiverType) {
392: // ignored
393: }
394:
395: public void setDepth(int i) {
396: // ignored
397: }
398:
399: public void setFieldIndex(int i) {
400: // ignored
401: }
402:
403: public void traverse(ASTVisitor visitor, BlockScope scope) {
404: if (visitor.visit(this , scope)) {
405: if (this .typeArguments != null) {
406: for (int i = 0, typeArgumentsLength = this .typeArguments.length; i < typeArgumentsLength; i++) {
407: this .typeArguments[i].traverse(visitor, scope);
408: }
409: }
410: if (this .type != null) { // enum constant scenario
411: this .type.traverse(visitor, scope);
412: }
413: if (this .arguments != null) {
414: for (int i = 0, argumentsLength = this.arguments.length; i < argumentsLength; i++)
415: this.arguments[i].traverse(visitor, scope);
416: }
417: }
418: visitor.endVisit(this, scope);
419: }
420: }
|