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
21 public FieldBinding targetWriteField; // write access to a field
23 public MethodBinding targetMethod; // method or constructor
25 public int accessType;
27 public final static int FieldReadAccess = 1; // field read
29 public final static int FieldWriteAccess = 2; // field write
31 public final static int MethodAccess = 3; // normal method
33 public final static int ConstructorAccess = 4; // constructor
35 public final static int SuperMethodAccess = 5; // super method
37 final static char[] AccessMethodPrefix = { 'a', 'c', 'c', 'e', 's', 's',
40 public int sourceStart = 0; // start position of the matching declaration
42 public int index; // used for sorting access methods in the class file
44 public SyntheticAccessMethodBinding(FieldBinding targetField,
45 boolean isReadAccess, ReferenceBinding declaringClass) {
47 this.modifiers = AccDefault | AccStatic;// | AccSynthetic;
48 SourceTypeBinding declaringSourceType = (SourceTypeBinding) declaringClass;
49 SyntheticAccessMethodBinding[] knownAccessMethods = declaringSourceType
50 .syntheticAccessMethods();
51 int methodId = knownAccessMethods == null ? 0
52 : knownAccessMethods.length;
53 this.index = methodId;
54 this.selector = CharOperation.concat(AccessMethodPrefix, String
55 .valueOf(methodId).toCharArray());
57 this.returnType = targetField.type;
58 if (targetField.isStatic()) {
59 this.parameters = NoParameters;
61 this.parameters = new TypeBinding[1];
62 this.parameters[0] = declaringSourceType;
64 this.targetReadField = targetField;
65 this.accessType = FieldReadAccess;
67 this.returnType = VoidBinding;
68 if (targetField.isStatic()) {
69 this.parameters = new TypeBinding[1];
70 this.parameters[0] = targetField.type;
72 this.parameters = new TypeBinding[2];
73 this.parameters[0] = declaringSourceType;
74 this.parameters[1] = targetField.type;
76 this.targetWriteField = targetField;
77 this.accessType = FieldWriteAccess;
79 this.thrownExceptions = NoExceptions;
80 this.declaringClass = declaringSourceType;
82 // check for method collision
87 // check for collision with known methods
88 MethodBinding[] methods = declaringSourceType.methods;
89 for (int i = 0, length = methods.length; i < length; i++) {
90 if (this.selector == methods[i].selector
91 && this.areParametersEqual(methods[i])) {
96 // check for collision with synthetic accessors
97 if (knownAccessMethods != null) {
98 for (int i = 0, length = knownAccessMethods.length; i < length; i++) {
99 if (knownAccessMethods[i] == null)
101 if (this.selector == knownAccessMethods[i].selector
102 && this.areParametersEqual(methods[i])) {
109 if (needRename) { // retry with a selector postfixed by a growing
111 this.selector(CharOperation.concat(AccessMethodPrefix, String
112 .valueOf(++methodId).toCharArray()));
114 } while (needRename);
116 // retrieve sourceStart position for the target field for line number
118 FieldDeclaration[] fieldDecls = declaringSourceType.scope.referenceContext.fields;
119 if (fieldDecls != null) {
120 for (int i = 0, max = fieldDecls.length; i < max; i++) {
121 if (fieldDecls[i].binding == targetField) {
122 this.sourceStart = fieldDecls[i].sourceStart;
129 * did not find the target field declaration - it is a synthetic one
130 * public class A { public class B { public class C { void foo() {
131 * System.out.println("A.this = " + A.this); } } } public static void
132 * main(String args[]) { new A().new B().new C().foo(); } }
134 // We now at this point - per construction - it is for sure an enclosing
135 // instance, we are going to
136 // show the target field type declaration location.
137 this.sourceStart = declaringSourceType.scope.referenceContext.sourceStart; // use
147 public SyntheticAccessMethodBinding(MethodBinding targetMethod,
148 boolean isSuperAccess, ReferenceBinding receiverType) {
150 if (targetMethod.isConstructor()) {
151 this.initializeConstructorAccessor(targetMethod);
153 this.initializeMethodAccessor(targetMethod, isSuperAccess,
159 * An constructor accessor is a constructor with an extra argument
160 * (declaringClass), in case of collision with an existing constructor, then
161 * add again an extra argument (declaringClass again).
163 public void initializeConstructorAccessor(MethodBinding targetConstructor) {
165 this.targetMethod = targetConstructor;
166 this.modifiers = AccDefault;// | AccSynthetic;
167 SourceTypeBinding sourceType = (SourceTypeBinding) targetConstructor.declaringClass;
168 SyntheticAccessMethodBinding[] knownAccessMethods = sourceType
169 .syntheticAccessMethods();
170 this.index = knownAccessMethods == null ? 0 : knownAccessMethods.length;
172 this.selector = targetConstructor.selector;
173 this.returnType = targetConstructor.returnType;
174 this.accessType = ConstructorAccess;
175 this.parameters = new TypeBinding[targetConstructor.parameters.length + 1];
176 System.arraycopy(targetConstructor.parameters, 0, this.parameters, 0,
177 targetConstructor.parameters.length);
178 parameters[targetConstructor.parameters.length] = targetConstructor.declaringClass;
179 this.thrownExceptions = targetConstructor.thrownExceptions;
180 this.declaringClass = sourceType;
182 // check for method collision
187 // check for collision with known methods
188 MethodBinding[] methods = sourceType.methods;
189 for (int i = 0, length = methods.length; i < length; i++) {
190 if (this.selector == methods[i].selector
191 && this.areParametersEqual(methods[i])) {
196 // check for collision with synthetic accessors
197 if (knownAccessMethods != null) {
198 for (int i = 0, length = knownAccessMethods.length; i < length; i++) {
199 if (knownAccessMethods[i] == null)
201 if (this.selector == knownAccessMethods[i].selector
203 .areParametersEqual(knownAccessMethods[i])) {
210 if (needRename) { // retry with a new extra argument
211 int length = this.parameters.length;
212 System.arraycopy(this.parameters, 0,
213 this.parameters = new TypeBinding[length + 1], 0,
215 this.parameters[length] = this.declaringClass;
217 } while (needRename);
219 // retrieve sourceStart position for the target method for line number
221 AbstractMethodDeclaration[] methodDecls = sourceType.scope.referenceContext.methods;
222 if (methodDecls != null) {
223 for (int i = 0, length = methodDecls.length; i < length; i++) {
224 if (methodDecls[i].binding == targetConstructor) {
225 this.sourceStart = methodDecls[i].sourceStart;
233 * An method accessor is a method with an access$N selector, where N is
234 * incremented in case of collisions.
236 public void initializeMethodAccessor(MethodBinding targetMethod,
237 boolean isSuperAccess, ReferenceBinding declaringClass) {
239 this.targetMethod = targetMethod;
240 this.modifiers = AccDefault | AccStatic;// | AccSynthetic;
241 SourceTypeBinding declaringSourceType = (SourceTypeBinding) declaringClass;
242 SyntheticAccessMethodBinding[] knownAccessMethods = declaringSourceType
243 .syntheticAccessMethods();
244 int methodId = knownAccessMethods == null ? 0
245 : knownAccessMethods.length;
246 this.index = methodId;
248 this.selector = CharOperation.concat(AccessMethodPrefix, String
249 .valueOf(methodId).toCharArray());
250 this.returnType = targetMethod.returnType;
251 this.accessType = isSuperAccess ? SuperMethodAccess : MethodAccess;
253 if (targetMethod.isStatic()) {
254 this.parameters = targetMethod.parameters;
256 this.parameters = new TypeBinding[targetMethod.parameters.length + 1];
257 this.parameters[0] = declaringSourceType;
258 System.arraycopy(targetMethod.parameters, 0, this.parameters, 1,
259 targetMethod.parameters.length);
261 this.thrownExceptions = targetMethod.thrownExceptions;
262 this.declaringClass = declaringSourceType;
264 // check for method collision
269 // check for collision with known methods
270 MethodBinding[] methods = declaringSourceType.methods;
271 for (int i = 0, length = methods.length; i < length; i++) {
272 if (this.selector == methods[i].selector
273 && this.areParametersEqual(methods[i])) {
278 // check for collision with synthetic accessors
279 if (knownAccessMethods != null) {
280 for (int i = 0, length = knownAccessMethods.length; i < length; i++) {
281 if (knownAccessMethods[i] == null)
283 if (this.selector == knownAccessMethods[i].selector
285 .areParametersEqual(knownAccessMethods[i])) {
292 if (needRename) { // retry with a selector & a growing methodId
293 this.selector(CharOperation.concat(AccessMethodPrefix, String
294 .valueOf(++methodId).toCharArray()));
296 } while (needRename);
298 // retrieve sourceStart position for the target method for line number
300 AbstractMethodDeclaration[] methodDecls = declaringSourceType.scope.referenceContext.methods;
301 if (methodDecls != null) {
302 for (int i = 0, length = methodDecls.length; i < length; i++) {
303 if (methodDecls[i].binding == targetMethod) {
304 this.sourceStart = methodDecls[i].sourceStart;
311 protected boolean isConstructorRelated() {
312 return accessType == ConstructorAccess;