1 /*******************************************************************************
2 * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v0.5
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v05.html
9 * IBM Corporation - initial API and implementation
10 ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.lookup;
13 import net.sourceforge.phpdt.internal.compiler.ast.AbstractMethodDeclaration;
14 import net.sourceforge.phpdt.internal.compiler.ast.FieldDeclaration;
15 import net.sourceforge.phpdt.internal.compiler.util.CharOperation;
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;
26 public final static int FieldWriteAccess = 2;
27 public final static int MethodAccess = 3;
28 public final static int ConstructorAccess = 4;
30 final static char[] AccessMethodPrefix = { 'a', 'c', 'c', 'e', 's', 's', '$' };
32 public int sourceStart = 0; // start position of the matching declaration
33 public int index; // used for sorting access methods in the class file
34 public SyntheticAccessMethodBinding(FieldBinding targetField, boolean isReadAccess, ReferenceBinding declaringClass) {
35 this.modifiers = AccDefault | AccStatic | AccSynthetic;
36 SourceTypeBinding declaringSourceType = (SourceTypeBinding) declaringClass;
37 SyntheticAccessMethodBinding[] knownAccessMethods = declaringSourceType.syntheticAccessMethods();
38 int methodId = knownAccessMethods == null ? 0 : knownAccessMethods.length;
39 this.index = methodId;
40 this.selector = CharOperation.concat(AccessMethodPrefix, String.valueOf(methodId).toCharArray());
42 this.returnType = targetField.type;
43 if (targetField.isStatic()) {
44 this.parameters = NoParameters;
46 this.parameters = new TypeBinding[1];
47 this.parameters[0] = declaringSourceType;
49 this.targetReadField = targetField;
50 this.accessType = FieldReadAccess;
52 this.returnType = VoidBinding;
53 if (targetField.isStatic()) {
54 this.parameters = new TypeBinding[1];
55 this.parameters[0] = targetField.type;
57 this.parameters = new TypeBinding[2];
58 this.parameters[0] = declaringSourceType;
59 this.parameters[1] = targetField.type;
61 this.targetWriteField = targetField;
62 this.accessType = FieldWriteAccess;
64 this.thrownExceptions = NoExceptions;
65 this.declaringClass = declaringSourceType;
67 // check for method collision
72 // check for collision with known methods
73 MethodBinding[] methods = declaringSourceType.methods;
74 for (int i = 0, length = methods.length; i < length; i++) {
75 if (this.selector == methods[i].selector && this.areParametersEqual(methods[i])) {
80 // check for collision with synthetic accessors
81 if (knownAccessMethods != null) {
82 for (int i = 0, length = knownAccessMethods.length; i < length; i++) {
83 if (knownAccessMethods[i] == null) continue;
84 if (this.selector == knownAccessMethods[i].selector && this.areParametersEqual(methods[i])) {
91 if (needRename) { // retry with a selector postfixed by a growing methodId
92 this.selector(CharOperation.concat(AccessMethodPrefix, String.valueOf(++methodId).toCharArray()));
96 // retrieve sourceStart position for the target field for line number attributes
97 FieldDeclaration[] fieldDecls = declaringSourceType.scope.referenceContext.fields;
98 if (fieldDecls != null) {
99 for (int i = 0, max = fieldDecls.length; i < max; i++) {
100 if (fieldDecls[i].binding == targetField) {
101 this.sourceStart = fieldDecls[i].sourceStart;
107 /* did not find the target field declaration - it is a synthetic one
112 System.out.println("A.this = " + A.this);
116 public static void main(String args[]) {
117 new A().new B().new C().foo();
121 // We now at this point - per construction - it is for sure an enclosing instance, we are going to
122 // show the target field type declaration location.
123 this.sourceStart = declaringSourceType.scope.referenceContext.sourceStart; // use the target declaring class name position instead
125 public SyntheticAccessMethodBinding(MethodBinding targetMethod, ReferenceBinding receiverType) {
127 if (targetMethod.isConstructor()) {
128 this.initializeConstructorAccessor(targetMethod);
130 this.initializeMethodAccessor(targetMethod, receiverType);
134 * An constructor accessor is a constructor with an extra argument (declaringClass), in case of
135 * collision with an existing constructor, then add again an extra argument (declaringClass again).
137 public void initializeConstructorAccessor(MethodBinding targetConstructor) {
139 this.targetMethod = targetConstructor;
140 this.modifiers = AccDefault | AccSynthetic;
141 SourceTypeBinding sourceType =
142 (SourceTypeBinding) targetConstructor.declaringClass;
143 SyntheticAccessMethodBinding[] knownAccessMethods =
144 sourceType.syntheticAccessMethods();
145 this.index = knownAccessMethods == null ? 0 : knownAccessMethods.length;
147 this.selector = targetConstructor.selector;
148 this.returnType = targetConstructor.returnType;
149 this.accessType = ConstructorAccess;
150 this.parameters = new TypeBinding[targetConstructor.parameters.length + 1];
152 targetConstructor.parameters,
156 targetConstructor.parameters.length);
157 parameters[targetConstructor.parameters.length] =
158 targetConstructor.declaringClass;
159 this.thrownExceptions = targetConstructor.thrownExceptions;
160 this.declaringClass = sourceType;
162 // check for method collision
167 // check for collision with known methods
168 MethodBinding[] methods = sourceType.methods;
169 for (int i = 0, length = methods.length; i < length; i++) {
170 if (this.selector == methods[i].selector
171 && this.areParametersEqual(methods[i])) {
176 // check for collision with synthetic accessors
177 if (knownAccessMethods != null) {
178 for (int i = 0, length = knownAccessMethods.length; i < length; i++) {
179 if (knownAccessMethods[i] == null)
181 if (this.selector == knownAccessMethods[i].selector
182 && this.areParametersEqual(methods[i])) {
189 if (needRename) { // retry with a new extra argument
190 int length = this.parameters.length;
194 this.parameters = new TypeBinding[length + 1],
197 this.parameters[length] = this.declaringClass;
199 } while (needRename);
201 // retrieve sourceStart position for the target method for line number attributes
202 AbstractMethodDeclaration[] methodDecls =
203 sourceType.scope.referenceContext.methods;
204 if (methodDecls != null) {
205 for (int i = 0, length = methodDecls.length; i < length; i++) {
206 if (methodDecls[i].binding == targetConstructor) {
207 this.sourceStart = methodDecls[i].sourceStart;
214 * An method accessor is a method with an access$N selector, where N is incremented in case of collisions.
217 public void initializeMethodAccessor(MethodBinding targetMethod, ReferenceBinding declaringClass) {
219 this.targetMethod = targetMethod;
220 this.modifiers = AccDefault | AccStatic | AccSynthetic;
221 SourceTypeBinding declaringSourceType = (SourceTypeBinding) declaringClass;
222 SyntheticAccessMethodBinding[] knownAccessMethods = declaringSourceType.syntheticAccessMethods();
223 int methodId = knownAccessMethods == null ? 0 : knownAccessMethods.length;
224 this.index = methodId;
226 this.selector = CharOperation.concat(AccessMethodPrefix, String.valueOf(methodId).toCharArray());
227 this.returnType = targetMethod.returnType;
228 this.accessType = MethodAccess;
230 if (targetMethod.isStatic()) {
231 this.parameters = targetMethod.parameters;
233 this.parameters = new TypeBinding[targetMethod.parameters.length + 1];
234 this.parameters[0] = declaringSourceType;
235 System.arraycopy(targetMethod.parameters, 0, this.parameters, 1, targetMethod.parameters.length);
237 this.thrownExceptions = targetMethod.thrownExceptions;
238 this.declaringClass = declaringSourceType;
240 // check for method collision
245 // check for collision with known methods
246 MethodBinding[] methods = declaringSourceType.methods;
247 for (int i = 0, length = methods.length; i < length; i++) {
248 if (this.selector == methods[i].selector && this.areParametersEqual(methods[i])) {
253 // check for collision with synthetic accessors
254 if (knownAccessMethods != null) {
255 for (int i = 0, length = knownAccessMethods.length; i < length; i++) {
256 if (knownAccessMethods[i] == null) continue;
257 if (this.selector == knownAccessMethods[i].selector && this.areParametersEqual(methods[i])) {
264 if (needRename) { // retry with a selector & a growing methodId
265 this.selector(CharOperation.concat(AccessMethodPrefix, String.valueOf(++methodId).toCharArray()));
267 } while (needRename);
269 // retrieve sourceStart position for the target method for line number attributes
270 AbstractMethodDeclaration[] methodDecls = declaringSourceType.scope.referenceContext.methods;
271 if (methodDecls != null) {
272 for (int i = 0, length = methodDecls.length; i < length; i++) {
273 if (methodDecls[i].binding == targetMethod) {
274 this.sourceStart = methodDecls[i].sourceStart;
280 protected boolean isConstructorRelated() {
281 return accessType == ConstructorAccess;