1 /*******************************************************************************
2 * Copyright (c) 2000, 2003 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 net.sourceforge.phpeclipse.internal.compiler.ast;
13 import net.sourceforge.phpdt.internal.compiler.ASTVisitor;
14 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
15 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
16 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
17 import net.sourceforge.phpdt.internal.compiler.lookup.InvocationSite;
18 import net.sourceforge.phpdt.internal.compiler.lookup.LocalTypeBinding;
19 import net.sourceforge.phpdt.internal.compiler.lookup.LocalVariableBinding;
20 import net.sourceforge.phpdt.internal.compiler.lookup.MethodBinding;
21 import net.sourceforge.phpdt.internal.compiler.lookup.NestedTypeBinding;
22 import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding;
23 import net.sourceforge.phpdt.internal.compiler.lookup.SourceTypeBinding;
24 import net.sourceforge.phpdt.internal.compiler.lookup.SyntheticArgumentBinding;
25 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
27 public class AllocationExpression
29 implements InvocationSite {
31 public TypeReference type;
32 public Expression[] arguments;
33 public MethodBinding binding;
35 MethodBinding syntheticAccessor;
37 public AllocationExpression() {
40 public FlowInfo analyseCode(
41 BlockScope currentScope,
42 FlowContext flowContext,
45 // check captured variables are initialized in current context (26134)
46 checkCapturedLocalInitializationIfNecessary(this.binding.declaringClass, currentScope, flowInfo);
49 if (arguments != null) {
50 for (int i = 0, count = arguments.length; i < count; i++) {
53 .analyseCode(currentScope, flowContext, flowInfo)
54 .unconditionalInits();
57 // record some dependency information for exception types
58 ReferenceBinding[] thrownExceptions;
59 if (((thrownExceptions = this.binding.thrownExceptions).length) != 0) {
60 // check exception handling
61 flowContext.checkExceptionHandlers(
67 manageEnclosingInstanceAccessIfNecessary(currentScope);
68 manageSyntheticAccessIfNecessary(currentScope);
73 public void checkCapturedLocalInitializationIfNecessary(ReferenceBinding checkedType, BlockScope currentScope, FlowInfo flowInfo) {
75 if (checkedType.isLocalType()
76 && !checkedType.isAnonymousType()
77 && !currentScope.isDefinedInType(checkedType)) { // only check external allocations
78 NestedTypeBinding nestedType = (NestedTypeBinding) checkedType;
79 SyntheticArgumentBinding[] syntheticArguments = nestedType.syntheticOuterLocalVariables();
80 if (syntheticArguments != null)
81 for (int i = 0, count = syntheticArguments.length; i < count; i++){
82 SyntheticArgumentBinding syntheticArgument = syntheticArguments[i];
83 LocalVariableBinding targetLocal;
84 if ((targetLocal = syntheticArgument.actualOuterLocalVariable) == null) continue;
85 if (targetLocal.declaration != null && !flowInfo.isDefinitelyAssigned(targetLocal)){
86 currentScope.problemReporter().uninitializedLocalVariable(targetLocal, this);
93 public Expression enclosingInstance() {
97 // public void generateCode(
98 // BlockScope currentScope,
99 // CodeStream codeStream,
100 // boolean valueRequired) {
102 // int pc = codeStream.position;
103 // ReferenceBinding allocatedType = binding.declaringClass;
105 // codeStream.new_(allocatedType);
106 // if (valueRequired) {
109 // // better highlight for allocation: display the type individually
110 // codeStream.recordPositionsFrom(pc, type.sourceStart);
112 // // handling innerclass instance allocation - enclosing instance arguments
113 // if (allocatedType.isNestedType()) {
114 // codeStream.generateSyntheticEnclosingInstanceValues(
117 // enclosingInstance(),
120 // // generate the arguments for constructor
121 // if (arguments != null) {
122 // for (int i = 0, count = arguments.length; i < count; i++) {
123 // arguments[i].generateCode(currentScope, codeStream, true);
126 // // handling innerclass instance allocation - outer local arguments
127 // if (allocatedType.isNestedType()) {
128 // codeStream.generateSyntheticOuterArgumentValues(
133 // // invoke constructor
134 // if (syntheticAccessor == null) {
135 // codeStream.invokespecial(binding);
137 // // synthetic accessor got some extra arguments appended to its signature, which need values
139 // max = syntheticAccessor.parameters.length - binding.parameters.length;
142 // codeStream.aconst_null();
144 // codeStream.invokespecial(syntheticAccessor);
146 // codeStream.recordPositionsFrom(pc, this.sourceStart);
149 public boolean isSuperAccess() {
154 public boolean isTypeAccess() {
159 /* Inner emulation consists in either recording a dependency
160 * link only, or performing one level of propagation.
162 * Dependency mechanism is used whenever dealing with source target
163 * types, since by the time we reach them, we might not yet know their
166 public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
168 ReferenceBinding allocatedType;
170 // perform some emulation work in case there is some and we are inside a local type only
171 if ((allocatedType = binding.declaringClass).isNestedType()
172 && currentScope.enclosingSourceType().isLocalType()) {
174 if (allocatedType.isLocalType()) {
175 ((LocalTypeBinding) allocatedType).addInnerEmulationDependent(currentScope, false);
176 // request cascade of accesses
178 // locally propagate, since we already now the desired shape for sure
179 currentScope.propagateInnerEmulation(allocatedType, false);
180 // request cascade of accesses
185 public void manageSyntheticAccessIfNecessary(BlockScope currentScope) {
187 if (binding.isPrivate()
188 && (currentScope.enclosingSourceType() != binding.declaringClass)) {
193 // .isPrivateConstructorAccessChangingVisibility) {
194 // binding.tagForClearingPrivateModifier();
195 // // constructor will not be dumped as private, no emulation required thus
198 ((SourceTypeBinding) binding.declaringClass).addSyntheticMethod(binding, isSuperAccess());
199 currentScope.problemReporter().needToEmulateMethodAccess(binding, this);
203 public StringBuffer printExpression(int indent, StringBuffer output) {
205 output.append("new "); //$NON-NLS-1$
206 type.printExpression(0, output);
208 if (arguments != null) {
209 for (int i = 0; i < arguments.length; i++) {
210 if (i > 0) output.append(", "); //$NON-NLS-1$
211 arguments[i].printExpression(0, output);
214 return output.append(')');
216 public TypeBinding resolveType(BlockScope scope) {
218 // Propagate the type checking to the arguments, and check if the constructor is defined.
219 constant = NotAConstant;
220 this.resolvedType = type.resolveType(scope);
221 // will check for null after args are resolved
223 // buffering the arguments' types
224 TypeBinding[] argumentTypes = NoParameters;
225 if (arguments != null) {
226 boolean argHasError = false;
227 int length = arguments.length;
228 argumentTypes = new TypeBinding[length];
229 for (int i = 0; i < length; i++)
230 if ((argumentTypes[i] = arguments[i].resolveType(scope)) == null)
233 return this.resolvedType;
235 if (this.resolvedType == null)
238 if (!this.resolvedType.canBeInstantiated()) {
239 scope.problemReporter().cannotInstantiate(type, this.resolvedType);
240 return this.resolvedType;
242 ReferenceBinding allocatedType = (ReferenceBinding) this.resolvedType;
243 if (!(binding = scope.getConstructor(allocatedType, argumentTypes, this))
245 if (binding.declaringClass == null)
246 binding.declaringClass = allocatedType;
247 scope.problemReporter().invalidConstructor(this, binding);
248 return this.resolvedType;
250 if (isMethodUseDeprecated(binding, scope))
251 scope.problemReporter().deprecatedMethod(binding, this);
253 if (arguments != null)
254 for (int i = 0; i < arguments.length; i++)
255 arguments[i].implicitWidening(binding.parameters[i], argumentTypes[i]);
256 return allocatedType;
259 public void setActualReceiverType(ReferenceBinding receiverType) {
263 public void setDepth(int i) {
267 public void setFieldIndex(int i) {
271 public String toStringExpression() {
273 String s = "new " + type.toString(0); //$NON-NLS-1$
274 if (arguments == null)
275 s = s + "()"; //$NON-NLS-1$
277 s = s + "("; //$NON-NLS-1$
278 for (int i = 0; i < arguments.length; i++) {
279 s = s + arguments[i].toStringExpression();
280 if (i == (arguments.length - 1))
281 s = s + ")"; //$NON-NLS-1$
283 s = s + ", "; //$NON-NLS-1$
289 public void traverse(ASTVisitor visitor, BlockScope scope) {
291 if (visitor.visit(this, scope)) {
293 type.traverse(visitor, scope);
294 if (arguments != null) {
295 argumentsLength = arguments.length;
296 for (int i = 0; i < argumentsLength; i++)
297 arguments[i].traverse(visitor, scope);
300 visitor.endVisit(this, scope);