Refactored packagename to net.sourceforge.phpdt.internal.compiler.ast
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / AllocationExpression.java
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/AllocationExpression.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/AllocationExpression.java
new file mode 100644 (file)
index 0000000..7eb480b
--- /dev/null
@@ -0,0 +1,302 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package net.sourceforge.phpdt.internal.compiler.ast;
+
+import net.sourceforge.phpdt.internal.compiler.ASTVisitor;
+import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
+import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
+import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
+import net.sourceforge.phpdt.internal.compiler.lookup.InvocationSite;
+import net.sourceforge.phpdt.internal.compiler.lookup.LocalTypeBinding;
+import net.sourceforge.phpdt.internal.compiler.lookup.LocalVariableBinding;
+import net.sourceforge.phpdt.internal.compiler.lookup.MethodBinding;
+import net.sourceforge.phpdt.internal.compiler.lookup.NestedTypeBinding;
+import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding;
+import net.sourceforge.phpdt.internal.compiler.lookup.SourceTypeBinding;
+import net.sourceforge.phpdt.internal.compiler.lookup.SyntheticArgumentBinding;
+import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
+
+public class AllocationExpression
+       extends Expression
+       implements InvocationSite {
+               
+       public TypeReference type;
+       public Expression[] arguments;
+       public MethodBinding binding;
+
+       MethodBinding syntheticAccessor;
+
+       public AllocationExpression() {
+       }
+
+       public FlowInfo analyseCode(
+               BlockScope currentScope,
+               FlowContext flowContext,
+               FlowInfo flowInfo) {
+
+               // check captured variables are initialized in current context (26134)
+               checkCapturedLocalInitializationIfNecessary(this.binding.declaringClass, currentScope, flowInfo);
+
+               // process arguments
+               if (arguments != null) {
+                       for (int i = 0, count = arguments.length; i < count; i++) {
+                               flowInfo =
+                                       arguments[i]
+                                               .analyseCode(currentScope, flowContext, flowInfo)
+                                               .unconditionalInits();
+                       }
+               }
+               // record some dependency information for exception types
+               ReferenceBinding[] thrownExceptions;
+               if (((thrownExceptions = this.binding.thrownExceptions).length) != 0) {
+                       // check exception handling
+                       flowContext.checkExceptionHandlers(
+                               thrownExceptions,
+                               this,
+                               flowInfo,
+                               currentScope);
+               }
+               manageEnclosingInstanceAccessIfNecessary(currentScope);
+               manageSyntheticAccessIfNecessary(currentScope);
+               
+               return flowInfo;
+       }
+
+       public void checkCapturedLocalInitializationIfNecessary(ReferenceBinding checkedType, BlockScope currentScope, FlowInfo flowInfo) {
+
+               if (checkedType.isLocalType() 
+                               && !checkedType.isAnonymousType()
+                               && !currentScope.isDefinedInType(checkedType)) { // only check external allocations
+                       NestedTypeBinding nestedType = (NestedTypeBinding) checkedType;
+                       SyntheticArgumentBinding[] syntheticArguments = nestedType.syntheticOuterLocalVariables();
+                       if (syntheticArguments != null) 
+                               for (int i = 0, count = syntheticArguments.length; i < count; i++){
+                                       SyntheticArgumentBinding syntheticArgument = syntheticArguments[i];
+                                       LocalVariableBinding targetLocal;
+                                       if ((targetLocal = syntheticArgument.actualOuterLocalVariable) == null) continue;
+//                                     if (targetLocal.declaration != null && !flowInfo.isDefinitelyAssigned(targetLocal)){
+//                                             currentScope.problemReporter().uninitializedLocalVariable(targetLocal, this);
+//                                     }
+                               }
+                                               
+               }
+       }
+       
+       public Expression enclosingInstance() {
+               return null;
+       }
+
+//     public void generateCode(
+//             BlockScope currentScope,
+//             CodeStream codeStream,
+//             boolean valueRequired) {
+//
+//             int pc = codeStream.position;
+//             ReferenceBinding allocatedType = binding.declaringClass;
+//
+//             codeStream.new_(allocatedType);
+//             if (valueRequired) {
+//                     codeStream.dup();
+//             }
+//             // better highlight for allocation: display the type individually
+//             codeStream.recordPositionsFrom(pc, type.sourceStart);
+//
+//             // handling innerclass instance allocation - enclosing instance arguments
+//             if (allocatedType.isNestedType()) {
+//                     codeStream.generateSyntheticEnclosingInstanceValues(
+//                             currentScope,
+//                             allocatedType,
+//                             enclosingInstance(),
+//                             this);
+//             }
+//             // generate the arguments for constructor
+//             if (arguments != null) {
+//                     for (int i = 0, count = arguments.length; i < count; i++) {
+//                             arguments[i].generateCode(currentScope, codeStream, true);
+//                     }
+//             }
+//             // handling innerclass instance allocation - outer local arguments
+//             if (allocatedType.isNestedType()) {
+//                     codeStream.generateSyntheticOuterArgumentValues(
+//                             currentScope,
+//                             allocatedType,
+//                             this);
+//             }
+//             // invoke constructor
+//             if (syntheticAccessor == null) {
+//                     codeStream.invokespecial(binding);
+//             } else {
+//                     // synthetic accessor got some extra arguments appended to its signature, which need values
+//                     for (int i = 0,
+//                             max = syntheticAccessor.parameters.length - binding.parameters.length;
+//                             i < max;
+//                             i++) {
+//                             codeStream.aconst_null();
+//                     }
+//                     codeStream.invokespecial(syntheticAccessor);
+//             }
+//             codeStream.recordPositionsFrom(pc, this.sourceStart);
+//     }
+
+       public boolean isSuperAccess() {
+
+               return false;
+       }
+
+       public boolean isTypeAccess() {
+
+               return true;
+       }
+
+       /* Inner emulation consists in either recording a dependency 
+        * link only, or performing one level of propagation.
+        *
+        * Dependency mechanism is used whenever dealing with source target
+        * types, since by the time we reach them, we might not yet know their
+        * exact need.
+        */
+       public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
+
+               ReferenceBinding allocatedType;
+
+               // perform some emulation work in case there is some and we are inside a local type only
+               if ((allocatedType = binding.declaringClass).isNestedType()
+                       && currentScope.enclosingSourceType().isLocalType()) {
+
+                       if (allocatedType.isLocalType()) {
+                               ((LocalTypeBinding) allocatedType).addInnerEmulationDependent(currentScope, false);
+                               // request cascade of accesses
+                       } else {
+                               // locally propagate, since we already now the desired shape for sure
+                               currentScope.propagateInnerEmulation(allocatedType, false);
+                               // request cascade of accesses
+                       }
+               }
+       }
+
+       public void manageSyntheticAccessIfNecessary(BlockScope currentScope) {
+
+               if (binding.isPrivate()
+                       && (currentScope.enclosingSourceType() != binding.declaringClass)) {
+
+//                     if (currentScope
+//                             .environment()
+//                             .options
+//                             .isPrivateConstructorAccessChangingVisibility) {
+//                             binding.tagForClearingPrivateModifier();
+//                             // constructor will not be dumped as private, no emulation required thus
+//                     } else {
+                               syntheticAccessor =
+                                       ((SourceTypeBinding) binding.declaringClass).addSyntheticMethod(binding, isSuperAccess());
+                               currentScope.problemReporter().needToEmulateMethodAccess(binding, this);
+//                     }
+               }
+       }
+       public StringBuffer printExpression(int indent, StringBuffer output) {
+
+               output.append("new "); //$NON-NLS-1$
+               type.printExpression(0, output); 
+               output.append('(');
+               if (arguments != null) {
+                       for (int i = 0; i < arguments.length; i++) {
+                               if (i > 0) output.append(", "); //$NON-NLS-1$
+                               arguments[i].printExpression(0, output);
+                       }
+               }
+               return output.append(')');
+       }
+       public TypeBinding resolveType(BlockScope scope) {
+
+               // Propagate the type checking to the arguments, and check if the constructor is defined.
+               constant = NotAConstant;
+               this.resolvedType = type.resolveType(scope);
+               // will check for null after args are resolved
+
+               // buffering the arguments' types
+               TypeBinding[] argumentTypes = NoParameters;
+               if (arguments != null) {
+                       boolean argHasError = false;
+                       int length = arguments.length;
+                       argumentTypes = new TypeBinding[length];
+                       for (int i = 0; i < length; i++)
+                               if ((argumentTypes[i] = arguments[i].resolveType(scope)) == null)
+                                       argHasError = true;
+                       if (argHasError)
+                               return this.resolvedType;
+               }
+               if (this.resolvedType == null)
+                       return null;
+
+               if (!this.resolvedType.canBeInstantiated()) {
+                       scope.problemReporter().cannotInstantiate(type, this.resolvedType);
+                       return this.resolvedType;
+               }
+               ReferenceBinding allocatedType = (ReferenceBinding) this.resolvedType;
+               if (!(binding = scope.getConstructor(allocatedType, argumentTypes, this))
+                       .isValidBinding()) {
+                       if (binding.declaringClass == null)
+                               binding.declaringClass = allocatedType;
+                       scope.problemReporter().invalidConstructor(this, binding);
+                       return this.resolvedType;
+               }
+               if (isMethodUseDeprecated(binding, scope))
+                       scope.problemReporter().deprecatedMethod(binding, this);
+
+               if (arguments != null)
+                       for (int i = 0; i < arguments.length; i++)
+                               arguments[i].implicitWidening(binding.parameters[i], argumentTypes[i]);
+               return allocatedType;
+       }
+
+       public void setActualReceiverType(ReferenceBinding receiverType) {
+               // ignored
+       }
+
+       public void setDepth(int i) {
+               // ignored
+       }
+
+       public void setFieldIndex(int i) {
+               // ignored
+       }
+
+       public String toStringExpression() {
+
+               String s = "new " + type.toString(0); //$NON-NLS-1$
+               if (arguments == null)
+                       s = s + "()"; //$NON-NLS-1$
+               else {
+                       s = s + "("; //$NON-NLS-1$
+                       for (int i = 0; i < arguments.length; i++) {
+                               s = s + arguments[i].toStringExpression();
+                               if (i == (arguments.length - 1))
+                                       s = s + ")"; //$NON-NLS-1$
+                               else
+                                       s = s + ", "; //$NON-NLS-1$
+                       }
+               }
+               return s;
+       }
+
+       public void traverse(ASTVisitor visitor, BlockScope scope) {
+
+               if (visitor.visit(this, scope)) {
+                       int argumentsLength;
+                       type.traverse(visitor, scope);
+                       if (arguments != null) {
+                               argumentsLength = arguments.length;
+                               for (int i = 0; i < argumentsLength; i++)
+                                       arguments[i].traverse(visitor, scope);
+                       }
+               }
+               visitor.endVisit(this, scope);
+       }
+}