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.phpdt.internal.compiler.lookup;
 
  13 import net.sourceforge.phpdt.core.compiler.CharOperation;
 
  14 import net.sourceforge.phpeclipse.internal.compiler.ast.AbstractMethodDeclaration;
 
  15 import net.sourceforge.phpeclipse.internal.compiler.ast.FieldDeclaration;
 
  17 public class SyntheticAccessMethodBinding extends MethodBinding {
 
  19         public FieldBinding targetReadField;            // read access to a field
 
  20         public FieldBinding targetWriteField;           // write access to a field
 
  21         public MethodBinding targetMethod;      // method or constructor
 
  23         public int accessType;
 
  25         public final static int FieldReadAccess = 1;            // field read
 
  26         public final static int FieldWriteAccess = 2;           // field write
 
  27         public final static int MethodAccess = 3;               // normal method 
 
  28         public final static int ConstructorAccess = 4;  // constructor
 
  29         public final static int SuperMethodAccess = 5; // super method
 
  31         final static char[] AccessMethodPrefix = { 'a', 'c', 'c', 'e', 's', 's', '$' };
 
  33         public int sourceStart = 0; // start position of the matching declaration
 
  34         public int index; // used for sorting access methods in the class file
 
  36         public SyntheticAccessMethodBinding(FieldBinding targetField, boolean isReadAccess, ReferenceBinding declaringClass) {
 
  38                 this.modifiers = AccDefault | AccStatic;// | AccSynthetic;
 
  39                 SourceTypeBinding declaringSourceType = (SourceTypeBinding) declaringClass;
 
  40                 SyntheticAccessMethodBinding[] knownAccessMethods = declaringSourceType.syntheticAccessMethods();
 
  41                 int methodId = knownAccessMethods == null ? 0 : knownAccessMethods.length;
 
  42                 this.index = methodId;
 
  43                 this.selector = CharOperation.concat(AccessMethodPrefix, String.valueOf(methodId).toCharArray());
 
  45                         this.returnType = targetField.type;
 
  46                         if (targetField.isStatic()) {
 
  47                                 this.parameters = NoParameters;
 
  49                                 this.parameters = new TypeBinding[1];
 
  50                                 this.parameters[0] = declaringSourceType;
 
  52                         this.targetReadField = targetField;
 
  53                         this.accessType = FieldReadAccess;
 
  55                         this.returnType = VoidBinding;
 
  56                         if (targetField.isStatic()) {
 
  57                                 this.parameters = new TypeBinding[1];
 
  58                                 this.parameters[0] = targetField.type;
 
  60                                 this.parameters = new TypeBinding[2];
 
  61                                 this.parameters[0] = declaringSourceType;
 
  62                                 this.parameters[1] = targetField.type;
 
  64                         this.targetWriteField = targetField;
 
  65                         this.accessType = FieldWriteAccess;
 
  67                 this.thrownExceptions = NoExceptions;
 
  68                 this.declaringClass = declaringSourceType;
 
  70                 // check for method collision
 
  75                                 // check for collision with known methods
 
  76                                 MethodBinding[] methods = declaringSourceType.methods;
 
  77                                 for (int i = 0, length = methods.length; i < length; i++) {
 
  78                                         if (this.selector == methods[i].selector && this.areParametersEqual(methods[i])) {
 
  83                                 // check for collision with synthetic accessors
 
  84                                 if (knownAccessMethods != null) {
 
  85                                         for (int i = 0, length = knownAccessMethods.length; i < length; i++) {
 
  86                                                 if (knownAccessMethods[i] == null) continue;
 
  87                                                 if (this.selector == knownAccessMethods[i].selector && this.areParametersEqual(methods[i])) {
 
  94                         if (needRename) { // retry with a selector postfixed by a growing methodId
 
  95                                 this.selector(CharOperation.concat(AccessMethodPrefix, String.valueOf(++methodId).toCharArray()));
 
  99                 // retrieve sourceStart position for the target field for line number attributes
 
 100                 FieldDeclaration[] fieldDecls = declaringSourceType.scope.referenceContext.fields;
 
 101                 if (fieldDecls != null) {
 
 102                         for (int i = 0, max = fieldDecls.length; i < max; i++) {
 
 103                                 if (fieldDecls[i].binding == targetField) {
 
 104                                         this.sourceStart = fieldDecls[i].sourceStart;
 
 110         /* did not find the target field declaration - it is a synthetic one
 
 115                                                 System.out.println("A.this = " + A.this);
 
 119                         public static void main(String args[]) {
 
 120                                 new A().new B().new C().foo();
 
 124                 // We now at this point - per construction - it is for sure an enclosing instance, we are going to
 
 125                 // show the target field type declaration location.
 
 126                 this.sourceStart = declaringSourceType.scope.referenceContext.sourceStart; // use the target declaring class name position instead
 
 129         public SyntheticAccessMethodBinding(MethodBinding targetMethod, boolean isSuperAccess, ReferenceBinding receiverType) {
 
 131                 if (targetMethod.isConstructor()) {
 
 132                         this.initializeConstructorAccessor(targetMethod);
 
 134                         this.initializeMethodAccessor(targetMethod, isSuperAccess, receiverType);
 
 139          * An constructor accessor is a constructor with an extra argument (declaringClass), in case of
 
 140          * collision with an existing constructor, then add again an extra argument (declaringClass again).
 
 142          public void initializeConstructorAccessor(MethodBinding targetConstructor) {
 
 144                 this.targetMethod = targetConstructor;
 
 145                 this.modifiers = AccDefault;// | AccSynthetic;
 
 146                 SourceTypeBinding sourceType = (SourceTypeBinding) targetConstructor.declaringClass; 
 
 147                 SyntheticAccessMethodBinding[] knownAccessMethods = 
 
 148                         sourceType.syntheticAccessMethods(); 
 
 149                 this.index = knownAccessMethods == null ? 0 : knownAccessMethods.length;
 
 151                 this.selector = targetConstructor.selector;
 
 152                 this.returnType = targetConstructor.returnType;
 
 153                 this.accessType = ConstructorAccess;
 
 154                 this.parameters = new TypeBinding[targetConstructor.parameters.length + 1];
 
 156                         targetConstructor.parameters, 
 
 160                         targetConstructor.parameters.length); 
 
 161                 parameters[targetConstructor.parameters.length] = 
 
 162                         targetConstructor.declaringClass; 
 
 163                 this.thrownExceptions = targetConstructor.thrownExceptions;
 
 164                 this.declaringClass = sourceType;
 
 166                 // check for method collision
 
 171                                 // check for collision with known methods
 
 172                                 MethodBinding[] methods = sourceType.methods;
 
 173                                 for (int i = 0, length = methods.length; i < length; i++) {
 
 174                                         if (this.selector == methods[i].selector
 
 175                                                 && this.areParametersEqual(methods[i])) {
 
 180                                 // check for collision with synthetic accessors
 
 181                                 if (knownAccessMethods != null) {
 
 182                                         for (int i = 0, length = knownAccessMethods.length; i < length; i++) {
 
 183                                                 if (knownAccessMethods[i] == null)
 
 185                                                 if (this.selector == knownAccessMethods[i].selector
 
 186                                                         && this.areParametersEqual(knownAccessMethods[i])) {
 
 193                         if (needRename) { // retry with a new extra argument
 
 194                                 int length = this.parameters.length;
 
 198                                         this.parameters = new TypeBinding[length + 1], 
 
 201                                 this.parameters[length] = this.declaringClass;
 
 203                 } while (needRename);
 
 205                 // retrieve sourceStart position for the target method for line number attributes
 
 206                 AbstractMethodDeclaration[] methodDecls = 
 
 207                         sourceType.scope.referenceContext.methods; 
 
 208                 if (methodDecls != null) {
 
 209                         for (int i = 0, length = methodDecls.length; i < length; i++) {
 
 210                                 if (methodDecls[i].binding == targetConstructor) {
 
 211                                         this.sourceStart = methodDecls[i].sourceStart;
 
 219          * An method accessor is a method with an access$N selector, where N is incremented in case of collisions.
 
 221         public void initializeMethodAccessor(MethodBinding targetMethod, boolean isSuperAccess, ReferenceBinding declaringClass) {
 
 223                 this.targetMethod = targetMethod;
 
 224                 this.modifiers = AccDefault | AccStatic;// | AccSynthetic;
 
 225                 SourceTypeBinding declaringSourceType = (SourceTypeBinding) declaringClass;
 
 226                 SyntheticAccessMethodBinding[] knownAccessMethods = declaringSourceType.syntheticAccessMethods();
 
 227                 int methodId = knownAccessMethods == null ? 0 : knownAccessMethods.length;
 
 228                 this.index = methodId;
 
 230                 this.selector = CharOperation.concat(AccessMethodPrefix, String.valueOf(methodId).toCharArray());
 
 231                 this.returnType = targetMethod.returnType;
 
 232                 this.accessType = isSuperAccess ? SuperMethodAccess : MethodAccess;
 
 234                 if (targetMethod.isStatic()) {
 
 235                         this.parameters = targetMethod.parameters;
 
 237                         this.parameters = new TypeBinding[targetMethod.parameters.length + 1];
 
 238                         this.parameters[0] = declaringSourceType;
 
 239                         System.arraycopy(targetMethod.parameters, 0, this.parameters, 1, targetMethod.parameters.length);
 
 241                 this.thrownExceptions = targetMethod.thrownExceptions;
 
 242                 this.declaringClass = declaringSourceType;
 
 244                 // check for method collision
 
 249                                 // check for collision with known methods
 
 250                                 MethodBinding[] methods = declaringSourceType.methods;
 
 251                                 for (int i = 0, length = methods.length; i < length; i++) {
 
 252                                         if (this.selector == methods[i].selector && this.areParametersEqual(methods[i])) {
 
 257                                 // check for collision with synthetic accessors
 
 258                                 if (knownAccessMethods != null) {
 
 259                                         for (int i = 0, length = knownAccessMethods.length; i < length; i++) {
 
 260                                                 if (knownAccessMethods[i] == null) continue;
 
 261                                                 if (this.selector == knownAccessMethods[i].selector && this.areParametersEqual(knownAccessMethods[i])) {
 
 268                         if (needRename) { // retry with a selector & a growing methodId
 
 269                                 this.selector(CharOperation.concat(AccessMethodPrefix, String.valueOf(++methodId).toCharArray()));
 
 271                 } while (needRename);
 
 273                 // retrieve sourceStart position for the target method for line number attributes
 
 274                 AbstractMethodDeclaration[] methodDecls = declaringSourceType.scope.referenceContext.methods;
 
 275                 if (methodDecls != null) {
 
 276                         for (int i = 0, length = methodDecls.length; i < length; i++) {
 
 277                                 if (methodDecls[i].binding == targetMethod) {
 
 278                                         this.sourceStart = methodDecls[i].sourceStart;
 
 285         protected boolean isConstructorRelated() {
 
 286                 return accessType == ConstructorAccess;