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.phpdt.internal.compiler.ast.AbstractMethodDeclaration;
15 import net.sourceforge.phpdt.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;