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
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.ast;
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.*;
18 public class AllocationExpression extends Expression implements InvocationSite {
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
29 public FlowInfo analyseCode(
30 BlockScope currentScope,
31 FlowContext flowContext,
34 // check captured variables are initialized in current context (26134)
35 checkCapturedLocalInitializationIfNecessary((ReferenceBinding)this.binding.declaringClass.erasure(), currentScope, flowInfo);
38 if (arguments != null) {
39 for (int i = 0, count = arguments.length; i < count; i++) {
42 .analyseCode(currentScope, flowContext, flowInfo)
43 .unconditionalInits();
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(
56 manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
57 manageSyntheticAccessIfNecessary(currentScope, flowInfo);
62 public void checkCapturedLocalInitializationIfNecessary(ReferenceBinding checkedType, BlockScope currentScope, FlowInfo flowInfo) {
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);
81 public Expression enclosingInstance() {
85 public void generateCode(
86 BlockScope currentScope,
87 CodeStream codeStream,
88 boolean valueRequired) {
90 int pc = codeStream.position;
91 ReferenceBinding allocatedType = this.codegenBinding.declaringClass;
93 codeStream.new_(allocatedType);
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);
101 // push enum constant name and ordinal
102 codeStream.ldc(String.valueOf(enumConstant.name));
103 codeStream.generateInlinedValue(enumConstant.binding.id);
106 // handling innerclass instance allocation - enclosing instance arguments
107 if (allocatedType.isNestedType()) {
108 codeStream.generateSyntheticEnclosingInstanceValues(
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(
123 // invoke constructor
124 if (syntheticAccessor == null) {
125 codeStream.invokespecial(this.codegenBinding);
127 // synthetic accessor got some extra arguments appended to its signature, which need values
129 max = syntheticAccessor.parameters.length - this.codegenBinding.parameters.length;
132 codeStream.aconst_null();
134 codeStream.invokespecial(syntheticAccessor);
136 codeStream.generateImplicitConversion(this.implicitConversion);
137 codeStream.recordPositionsFrom(pc, this.sourceStart);
140 * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#genericTypeArguments()
142 public TypeBinding[] genericTypeArguments() {
143 return this.genericTypeArguments;
146 public boolean isSuperAccess() {
151 public boolean isTypeAccess() {
156 /* Inner emulation consists in either recording a dependency
157 * link only, or performing one level of propagation.
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
163 public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
165 if (!flowInfo.isReachable()) return;
166 ReferenceBinding allocatedTypeErasure = (ReferenceBinding) binding.declaringClass.erasure();
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()) {
172 if (allocatedTypeErasure.isLocalType()) {
173 ((LocalTypeBinding) allocatedTypeErasure).addInnerEmulationDependent(currentScope, false);
174 // request cascade of accesses
176 // locally propagate, since we already now the desired shape for sure
177 currentScope.propagateInnerEmulation(allocatedTypeErasure, false);
178 // request cascade of accesses
183 public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
185 if (!flowInfo.isReachable()) return;
187 // if constructor from parameterized type got found, use the original constructor at codegen time
188 this.codegenBinding = this.binding.original();
190 if (this.codegenBinding.isPrivate()
191 && (currentScope.enclosingSourceType() != this.codegenBinding.declaringClass)) {
193 if (currentScope.environment().options.isPrivateConstructorAccessChangingVisibility) {
194 this.codegenBinding.tagForClearingPrivateModifier();
195 // constructor will not be dumped as private, no emulation required thus
198 ((SourceTypeBinding) this.codegenBinding.declaringClass).addSyntheticMethod(this.codegenBinding, isSuperAccess());
199 currentScope.problemReporter().needToEmulateMethodAccess(this.codegenBinding, this);
204 public StringBuffer printExpression(int indent, StringBuffer output) {
206 if (this.type != null) { // type null for enum constant initializations
207 output.append("new "); //$NON-NLS-1$
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$
216 typeArguments[max].print(0, output);
219 if (type != null) { // type null for enum constant initializations
220 type.printExpression(0, output);
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);
229 return output.append(')');
232 public TypeBinding resolveType(BlockScope scope) {
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();
240 this.resolvedType = this.type.resolveType(scope, true /* check bounds*/);
242 // will check for null after args are resolved
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) {
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;
272 if ((argumentTypes[i] = argument.resolveType(scope)) == null) {
277 return this.resolvedType;
280 if (this.resolvedType == null)
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;
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;
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);
300 return allocationType;
303 public void setActualReceiverType(ReferenceBinding receiverType) {
307 public void setDepth(int i) {
311 public void setFieldIndex(int i) {
315 public void traverse(ASTVisitor visitor, BlockScope scope) {
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);
323 if (this.type != null) { // enum constant scenario
324 this.type.traverse(visitor, scope);
326 if (this.arguments != null) {
327 for (int i = 0, argumentsLength = this.arguments.length; i < argumentsLength; i++)
328 this.arguments[i].traverse(visitor, scope);
331 visitor.endVisit(this, scope);