1 /*******************************************************************************
2 * Copyright (c) 2000, 2004 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 org.eclipse.jdt.internal.compiler.lookup;
13 import org.eclipse.jdt.core.compiler.CharOperation;
14 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
15 import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
17 public class SyntheticMethodBinding 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
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
30 public final static int BridgeMethod = 6; // bridge method
31 public final static int EnumValues = 7; // enum #values()
32 public final static int EnumValueOf = 8; // enum #valueOf(String)
34 public int sourceStart = 0; // start position of the matching declaration
35 public int index; // used for sorting access methods in the class file
37 public SyntheticMethodBinding(FieldBinding targetField, boolean isReadAccess, ReferenceBinding declaringClass) {
39 this.modifiers = AccDefault | AccStatic | AccSynthetic;
40 SourceTypeBinding declaringSourceType = (SourceTypeBinding) declaringClass;
41 SyntheticMethodBinding[] knownAccessMethods = declaringSourceType.syntheticMethods();
42 int methodId = knownAccessMethods == null ? 0 : knownAccessMethods.length;
43 this.index = methodId;
44 this.selector = CharOperation.concat(TypeConstants.SYNTHETIC_ACCESS_METHOD_PREFIX, String.valueOf(methodId).toCharArray());
46 this.returnType = targetField.type;
47 if (targetField.isStatic()) {
48 this.parameters = NoParameters;
50 this.parameters = new TypeBinding[1];
51 this.parameters[0] = declaringSourceType;
53 this.targetReadField = targetField;
54 this.kind = FieldReadAccess;
56 this.returnType = VoidBinding;
57 if (targetField.isStatic()) {
58 this.parameters = new TypeBinding[1];
59 this.parameters[0] = targetField.type;
61 this.parameters = new TypeBinding[2];
62 this.parameters[0] = declaringSourceType;
63 this.parameters[1] = targetField.type;
65 this.targetWriteField = targetField;
66 this.kind = FieldWriteAccess;
68 this.thrownExceptions = NoExceptions;
69 this.declaringClass = declaringSourceType;
71 // check for method collision
76 // check for collision with known methods
77 MethodBinding[] methods = declaringSourceType.methods;
78 for (int i = 0, length = methods.length; i < length; i++) {
79 if (CharOperation.equals(this.selector, methods[i].selector) && this.areParametersEqual(methods[i])) {
84 // check for collision with synthetic accessors
85 if (knownAccessMethods != null) {
86 for (int i = 0, length = knownAccessMethods.length; i < length; i++) {
87 if (knownAccessMethods[i] == null) continue;
88 if (CharOperation.equals(this.selector, knownAccessMethods[i].selector) && this.areParametersEqual(methods[i])) {
95 if (needRename) { // retry with a selector postfixed by a growing methodId
96 this.setSelector(CharOperation.concat(TypeConstants.SYNTHETIC_ACCESS_METHOD_PREFIX, String.valueOf(++methodId).toCharArray()));
100 // retrieve sourceStart position for the target field for line number attributes
101 FieldDeclaration[] fieldDecls = declaringSourceType.scope.referenceContext.fields;
102 if (fieldDecls != null) {
103 for (int i = 0, max = fieldDecls.length; i < max; i++) {
104 if (fieldDecls[i].binding == targetField) {
105 this.sourceStart = fieldDecls[i].sourceStart;
111 /* did not find the target field declaration - it is a synthetic one
116 System.out.println("A.this = " + A.this);
120 public static void main(String args[]) {
121 new A().new B().new C().foo();
125 // We now at this point - per construction - it is for sure an enclosing instance, we are going to
126 // show the target field type declaration location.
127 this.sourceStart = declaringSourceType.scope.referenceContext.sourceStart; // use the target declaring class name position instead
130 public SyntheticMethodBinding(MethodBinding targetMethod, boolean isSuperAccess, ReferenceBinding receiverType) {
132 if (targetMethod.isConstructor()) {
133 this.initializeConstructorAccessor(targetMethod);
135 this.initializeMethodAccessor(targetMethod, isSuperAccess, receiverType);
140 * Construct a bridge method
142 public SyntheticMethodBinding(MethodBinding overridenMethodToBridge, MethodBinding localTargetMethod) {
144 this.declaringClass = localTargetMethod.declaringClass;
145 this.selector = overridenMethodToBridge.selector;
146 this.modifiers = overridenMethodToBridge.modifiers | AccBridge | AccSynthetic;
147 this.modifiers &= ~(AccAbstract | AccNative);
148 this.returnType = overridenMethodToBridge.returnType;
149 this.parameters = overridenMethodToBridge.parameters;
150 this.thrownExceptions = overridenMethodToBridge.thrownExceptions;
151 this.targetMethod = localTargetMethod;
152 this.kind = BridgeMethod;
153 SyntheticMethodBinding[] knownAccessMethods = ((SourceTypeBinding)this.declaringClass).syntheticMethods();
154 int methodId = knownAccessMethods == null ? 0 : knownAccessMethods.length;
155 this.index = methodId;
159 * Construct enum special methods: values or valueOf methods
161 public SyntheticMethodBinding(SourceTypeBinding declaringEnum, char[] selector) {
162 if (selector == TypeConstants.VALUES) {
163 this.declaringClass = declaringEnum;
164 this.selector = selector;
165 this.modifiers = AccFinal | AccPublic | AccStatic;
166 this.returnType = declaringEnum.scope.createArrayType(declaringEnum, 1);
167 this.parameters = NoParameters;
168 this.thrownExceptions = NoExceptions;
169 this.kind = EnumValues;
170 SyntheticMethodBinding[] knownAccessMethods = ((SourceTypeBinding)this.declaringClass).syntheticMethods();
171 int methodId = knownAccessMethods == null ? 0 : knownAccessMethods.length;
172 this.index = methodId;
173 } else if (selector == TypeConstants.VALUEOF) {
174 this.declaringClass = declaringEnum;
175 this.selector = selector;
176 this.modifiers = AccFinal | AccPublic | AccStatic;
177 this.returnType = declaringEnum;
178 this.parameters = new TypeBinding[]{ declaringEnum.scope.getJavaLangString() };
179 this.thrownExceptions = NoExceptions;
180 this.kind = EnumValueOf;
181 SyntheticMethodBinding[] knownAccessMethods = ((SourceTypeBinding)this.declaringClass).syntheticMethods();
182 int methodId = knownAccessMethods == null ? 0 : knownAccessMethods.length;
183 this.index = methodId;
188 * An constructor accessor is a constructor with an extra argument (declaringClass), in case of
189 * collision with an existing constructor, then add again an extra argument (declaringClass again).
191 public void initializeConstructorAccessor(MethodBinding accessedConstructor) {
193 this.targetMethod = accessedConstructor;
194 this.modifiers = AccDefault | AccSynthetic;
195 SourceTypeBinding sourceType = (SourceTypeBinding) accessedConstructor.declaringClass;
196 SyntheticMethodBinding[] knownSyntheticMethods =
197 sourceType.syntheticMethods();
198 this.index = knownSyntheticMethods == null ? 0 : knownSyntheticMethods.length;
200 this.selector = accessedConstructor.selector;
201 this.returnType = accessedConstructor.returnType;
202 this.kind = ConstructorAccess;
203 this.parameters = new TypeBinding[accessedConstructor.parameters.length + 1];
205 accessedConstructor.parameters,
209 accessedConstructor.parameters.length);
210 parameters[accessedConstructor.parameters.length] =
211 accessedConstructor.declaringClass;
212 this.thrownExceptions = accessedConstructor.thrownExceptions;
213 this.declaringClass = sourceType;
215 // check for method collision
220 // check for collision with known methods
221 MethodBinding[] methods = sourceType.methods;
222 for (int i = 0, length = methods.length; i < length; i++) {
223 if (CharOperation.equals(this.selector, methods[i].selector)
224 && this.areParametersEqual(methods[i])) {
229 // check for collision with synthetic accessors
230 if (knownSyntheticMethods != null) {
231 for (int i = 0, length = knownSyntheticMethods.length; i < length; i++) {
232 if (knownSyntheticMethods[i] == null)
234 if (CharOperation.equals(this.selector, knownSyntheticMethods[i].selector)
235 && this.areParametersEqual(knownSyntheticMethods[i])) {
242 if (needRename) { // retry with a new extra argument
243 int length = this.parameters.length;
247 this.parameters = new TypeBinding[length + 1],
250 this.parameters[length] = this.declaringClass;
252 } while (needRename);
254 // retrieve sourceStart position for the target method for line number attributes
255 AbstractMethodDeclaration[] methodDecls =
256 sourceType.scope.referenceContext.methods;
257 if (methodDecls != null) {
258 for (int i = 0, length = methodDecls.length; i < length; i++) {
259 if (methodDecls[i].binding == accessedConstructor) {
260 this.sourceStart = methodDecls[i].sourceStart;
268 * An method accessor is a method with an access$N selector, where N is incremented in case of collisions.
270 public void initializeMethodAccessor(MethodBinding accessedMethod, boolean isSuperAccess, ReferenceBinding receiverType) {
272 this.targetMethod = accessedMethod;
273 this.modifiers = AccDefault | AccStatic | AccSynthetic;
274 SourceTypeBinding declaringSourceType = (SourceTypeBinding) receiverType;
275 SyntheticMethodBinding[] knownAccessMethods = declaringSourceType.syntheticMethods();
276 int methodId = knownAccessMethods == null ? 0 : knownAccessMethods.length;
277 this.index = methodId;
279 this.selector = CharOperation.concat(TypeConstants.SYNTHETIC_ACCESS_METHOD_PREFIX, String.valueOf(methodId).toCharArray());
280 this.returnType = accessedMethod.returnType;
281 this.kind = isSuperAccess ? SuperMethodAccess : MethodAccess;
283 if (accessedMethod.isStatic()) {
284 this.parameters = accessedMethod.parameters;
286 this.parameters = new TypeBinding[accessedMethod.parameters.length + 1];
287 this.parameters[0] = declaringSourceType;
288 System.arraycopy(accessedMethod.parameters, 0, this.parameters, 1, accessedMethod.parameters.length);
290 this.thrownExceptions = accessedMethod.thrownExceptions;
291 this.declaringClass = declaringSourceType;
293 // check for method collision
298 // check for collision with known methods
299 MethodBinding[] methods = declaringSourceType.methods;
300 for (int i = 0, length = methods.length; i < length; i++) {
301 if (CharOperation.equals(this.selector, methods[i].selector) && this.areParametersEqual(methods[i])) {
306 // check for collision with synthetic accessors
307 if (knownAccessMethods != null) {
308 for (int i = 0, length = knownAccessMethods.length; i < length; i++) {
309 if (knownAccessMethods[i] == null) continue;
310 if (CharOperation.equals(this.selector, knownAccessMethods[i].selector) && this.areParametersEqual(knownAccessMethods[i])) {
317 if (needRename) { // retry with a selector & a growing methodId
318 this.setSelector(CharOperation.concat(TypeConstants.SYNTHETIC_ACCESS_METHOD_PREFIX, String.valueOf(++methodId).toCharArray()));
320 } while (needRename);
322 // retrieve sourceStart position for the target method for line number attributes
323 AbstractMethodDeclaration[] methodDecls = declaringSourceType.scope.referenceContext.methods;
324 if (methodDecls != null) {
325 for (int i = 0, length = methodDecls.length; i < length; i++) {
326 if (methodDecls[i].binding == accessedMethod) {
327 this.sourceStart = methodDecls[i].sourceStart;
334 protected boolean isConstructorRelated() {
335 return kind == ConstructorAccess;