KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > compiler > lookup > SyntheticMethodBinding


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.compiler.lookup;
12
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;
16 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
17
18 public class SyntheticMethodBinding extends MethodBinding {
19
20     public FieldBinding targetReadField; // read access to a field
21
public FieldBinding targetWriteField; // write access to a field
22
public MethodBinding targetMethod; // method or constructor
23
public TypeBinding targetEnumType; // enum type
24

25     public int kind;
26
27     public final static int FieldReadAccess = 1; // field read
28
public final static int FieldWriteAccess = 2; // field write
29
public final static int MethodAccess = 3; // normal method
30
public final static int ConstructorAccess = 4; // constructor
31
public final static int SuperMethodAccess = 5; // super method
32
public final static int BridgeMethod = 6; // bridge method
33
public final static int EnumValues = 7; // enum #values()
34
public final static int EnumValueOf = 8; // enum #valueOf(String)
35
public final static int SwitchTable = 9; // switch table method
36

37     public int sourceStart = 0; // start position of the matching declaration
38
public int index; // used for sorting access methods in the class file
39

40     public SyntheticMethodBinding(FieldBinding targetField, boolean isReadAccess, ReferenceBinding declaringClass) {
41
42         this.modifiers = ClassFileConstants.AccDefault | ClassFileConstants.AccStatic | ClassFileConstants.AccSynthetic;
43         this.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved);
44         SourceTypeBinding declaringSourceType = (SourceTypeBinding) declaringClass;
45         SyntheticMethodBinding[] knownAccessMethods = declaringSourceType.syntheticMethods();
46         int methodId = knownAccessMethods == null ? 0 : knownAccessMethods.length;
47         this.index = methodId;
48         this.selector = CharOperation.concat(TypeConstants.SYNTHETIC_ACCESS_METHOD_PREFIX, String.valueOf(methodId).toCharArray());
49         if (isReadAccess) {
50             this.returnType = targetField.type;
51             if (targetField.isStatic()) {
52                 this.parameters = Binding.NO_PARAMETERS;
53             } else {
54                 this.parameters = new TypeBinding[1];
55                 this.parameters[0] = declaringSourceType;
56             }
57             this.targetReadField = targetField;
58             this.kind = FieldReadAccess;
59         } else {
60             this.returnType = TypeBinding.VOID;
61             if (targetField.isStatic()) {
62                 this.parameters = new TypeBinding[1];
63                 this.parameters[0] = targetField.type;
64             } else {
65                 this.parameters = new TypeBinding[2];
66                 this.parameters[0] = declaringSourceType;
67                 this.parameters[1] = targetField.type;
68             }
69             this.targetWriteField = targetField;
70             this.kind = FieldWriteAccess;
71         }
72         this.thrownExceptions = Binding.NO_EXCEPTIONS;
73         this.declaringClass = declaringSourceType;
74     
75         // check for method collision
76
boolean needRename;
77         do {
78             check : {
79                 needRename = false;
80                 // check for collision with known methods
81
long range;
82                 MethodBinding[] methods = declaringSourceType.methods();
83                 if ((range = ReferenceBinding.binarySearch(this.selector, methods)) >= 0) {
84                     int paramCount = this.parameters.length;
85                     nextMethod: for (int imethod = (int)range, end = (int)(range >> 32); imethod <= end; imethod++) {
86                         MethodBinding method = methods[imethod];
87                         if (method.parameters.length == paramCount) {
88                             TypeBinding[] toMatch = method.parameters;
89                             for (int i = 0; i < paramCount; i++) {
90                                 if (toMatch[i] != this.parameters[i]) {
91                                     continue nextMethod;
92                                 }
93                             }
94                             needRename = true;
95                             break check;
96                         }
97                     }
98                 }
99                 // check for collision with synthetic accessors
100
if (knownAccessMethods != null) {
101                     for (int i = 0, length = knownAccessMethods.length; i < length; i++) {
102                         if (knownAccessMethods[i] == null) continue;
103                         if (CharOperation.equals(this.selector, knownAccessMethods[i].selector) && this.areParametersEqual(methods[i])) {
104                             needRename = true;
105                             break check;
106                         }
107                     }
108                 }
109             }
110             if (needRename) { // retry with a selector postfixed by a growing methodId
111
this.setSelector(CharOperation.concat(TypeConstants.SYNTHETIC_ACCESS_METHOD_PREFIX, String.valueOf(++methodId).toCharArray()));
112             }
113         } while (needRename);
114     
115         // retrieve sourceStart position for the target field for line number attributes
116
FieldDeclaration[] fieldDecls = declaringSourceType.scope.referenceContext.fields;
117         if (fieldDecls != null) {
118             for (int i = 0, max = fieldDecls.length; i < max; i++) {
119                 if (fieldDecls[i].binding == targetField) {
120                     this.sourceStart = fieldDecls[i].sourceStart;
121                     return;
122                 }
123             }
124         }
125     
126     /* did not find the target field declaration - it is a synthetic one
127         public class A {
128             public class B {
129                 public class C {
130                     void foo() {
131                         System.out.println("A.this = " + A.this);
132                     }
133                 }
134             }
135             public static void main(String args[]) {
136                 new A().new B().new C().foo();
137             }
138         }
139     */

140         // We now at this point - per construction - it is for sure an enclosing instance, we are going to
141
// show the target field type declaration location.
142
this.sourceStart = declaringSourceType.scope.referenceContext.sourceStart; // use the target declaring class name position instead
143
}
144
145     public SyntheticMethodBinding(FieldBinding targetField, ReferenceBinding declaringClass, TypeBinding enumBinding, char[] selector) {
146         this.modifiers = ClassFileConstants.AccDefault | ClassFileConstants.AccStatic | ClassFileConstants.AccSynthetic;
147         this.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved);
148         SourceTypeBinding declaringSourceType = (SourceTypeBinding) declaringClass;
149         SyntheticMethodBinding[] knownAccessMethods = declaringSourceType.syntheticMethods();
150         int methodId = knownAccessMethods == null ? 0 : knownAccessMethods.length;
151         this.index = methodId;
152         this.selector = selector;
153         this.returnType = declaringSourceType.scope.createArrayType(TypeBinding.INT, 1);
154         this.parameters = Binding.NO_PARAMETERS;
155         this.targetReadField = targetField;
156         this.targetEnumType = enumBinding;
157         this.kind = SwitchTable;
158         this.thrownExceptions = Binding.NO_EXCEPTIONS;
159         this.declaringClass = declaringSourceType;
160   
161         if (declaringSourceType.isStrictfp()) {
162             this.modifiers |= ClassFileConstants.AccStrictfp;
163         }
164         // check for method collision
165
boolean needRename;
166         do {
167             check : {
168                 needRename = false;
169                 // check for collision with known methods
170
long range;
171                 MethodBinding[] methods = declaringSourceType.methods();
172                 if ((range = ReferenceBinding.binarySearch(this.selector, methods)) >= 0) {
173                     int paramCount = this.parameters.length;
174                     nextMethod: for (int imethod = (int)range, end = (int)(range >> 32); imethod <= end; imethod++) {
175                         MethodBinding method = methods[imethod];
176                         if (method.parameters.length == paramCount) {
177                             TypeBinding[] toMatch = method.parameters;
178                             for (int i = 0; i < paramCount; i++) {
179                                 if (toMatch[i] != this.parameters[i]) {
180                                     continue nextMethod;
181                                 }
182                             }
183                             needRename = true;
184                             break check;
185                         }
186                     }
187                 }
188                 // check for collision with synthetic accessors
189
if (knownAccessMethods != null) {
190                     for (int i = 0, length = knownAccessMethods.length; i < length; i++) {
191                         if (knownAccessMethods[i] == null) continue;
192                         if (CharOperation.equals(this.selector, knownAccessMethods[i].selector) && this.areParametersEqual(methods[i])) {
193                             needRename = true;
194                             break check;
195                         }
196                     }
197                 }
198             }
199             if (needRename) { // retry with a selector postfixed by a growing methodId
200
this.setSelector(CharOperation.concat(selector, String.valueOf(++methodId).toCharArray()));
201             }
202         } while (needRename);
203
204         // We now at this point - per construction - it is for sure an enclosing instance, we are going to
205
// show the target field type declaration location.
206
this.sourceStart = declaringSourceType.scope.referenceContext.sourceStart; // use the target declaring class name position instead
207
}
208     
209     public SyntheticMethodBinding(MethodBinding targetMethod, boolean isSuperAccess, ReferenceBinding receiverType) {
210     
211         if (targetMethod.isConstructor()) {
212             this.initializeConstructorAccessor(targetMethod);
213         } else {
214             this.initializeMethodAccessor(targetMethod, isSuperAccess, receiverType);
215         }
216     }
217
218     /**
219      * Construct a bridge method
220      */

221     public SyntheticMethodBinding(MethodBinding overridenMethodToBridge, MethodBinding targetMethod, SourceTypeBinding declaringClass) {
222         
223         this.declaringClass = declaringClass;
224         this.selector = overridenMethodToBridge.selector;
225         // amongst other, clear the AccGenericSignature, so as to ensure no remains of original inherited persist (101794)
226
// also use the modifiers from the target method, as opposed to inherited one (147690)
227
this.modifiers = (targetMethod.modifiers | ClassFileConstants.AccBridge | ClassFileConstants.AccSynthetic) & ~(ClassFileConstants.AccAbstract | ClassFileConstants.AccNative | ClassFileConstants.AccFinal | ExtraCompilerModifiers.AccGenericSignature);
228         this.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved);
229         this.returnType = overridenMethodToBridge.returnType;
230         this.parameters = overridenMethodToBridge.parameters;
231         this.thrownExceptions = overridenMethodToBridge.thrownExceptions;
232         this.targetMethod = targetMethod;
233         this.kind = BridgeMethod;
234         SyntheticMethodBinding[] knownAccessMethods = declaringClass.syntheticMethods();
235         int methodId = knownAccessMethods == null ? 0 : knownAccessMethods.length;
236         this.index = methodId;
237     }
238     
239     /**
240      * Construct enum special methods: values or valueOf methods
241      */

242     public SyntheticMethodBinding(SourceTypeBinding declaringEnum, char[] selector) {
243         this.declaringClass = declaringEnum;
244         this.selector = selector;
245         this.modifiers = ClassFileConstants.AccPublic | ClassFileConstants.AccStatic;
246         this.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved);
247         this.thrownExceptions = Binding.NO_EXCEPTIONS;
248         if (selector == TypeConstants.VALUES) {
249             this.returnType = declaringEnum.scope.createArrayType(declaringEnum, 1);
250             this.parameters = Binding.NO_PARAMETERS;
251             this.kind = EnumValues;
252         } else if (selector == TypeConstants.VALUEOF) {
253             this.returnType = declaringEnum;
254             this.parameters = new TypeBinding[]{ declaringEnum.scope.getJavaLangString() };
255             this.kind = EnumValueOf;
256         }
257         SyntheticMethodBinding[] knownAccessMethods = ((SourceTypeBinding)this.declaringClass).syntheticMethods();
258         int methodId = knownAccessMethods == null ? 0 : knownAccessMethods.length;
259         this.index = methodId;
260         if (declaringEnum.isStrictfp()) {
261             this.modifiers |= ClassFileConstants.AccStrictfp;
262         }
263     }
264
265     /**
266      * An constructor accessor is a constructor with an extra argument (declaringClass), in case of
267      * collision with an existing constructor, then add again an extra argument (declaringClass again).
268      */

269      public void initializeConstructorAccessor(MethodBinding accessedConstructor) {
270     
271         this.targetMethod = accessedConstructor;
272         this.modifiers = ClassFileConstants.AccDefault | ClassFileConstants.AccSynthetic;
273         this.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved);
274         SourceTypeBinding sourceType = (SourceTypeBinding) accessedConstructor.declaringClass;
275         SyntheticMethodBinding[] knownSyntheticMethods =
276             sourceType.syntheticMethods();
277         this.index = knownSyntheticMethods == null ? 0 : knownSyntheticMethods.length;
278     
279         this.selector = accessedConstructor.selector;
280         this.returnType = accessedConstructor.returnType;
281         this.kind = ConstructorAccess;
282         this.parameters = new TypeBinding[accessedConstructor.parameters.length + 1];
283         System.arraycopy(
284             accessedConstructor.parameters,
285             0,
286             this.parameters,
287             0,
288             accessedConstructor.parameters.length);
289         parameters[accessedConstructor.parameters.length] =
290             accessedConstructor.declaringClass;
291         this.thrownExceptions = accessedConstructor.thrownExceptions;
292         this.declaringClass = sourceType;
293     
294         // check for method collision
295
boolean needRename;
296         do {
297             check : {
298                 needRename = false;
299                 // check for collision with known methods
300
MethodBinding[] methods = sourceType.methods();
301                 for (int i = 0, length = methods.length; i < length; i++) {
302                     if (CharOperation.equals(this.selector, methods[i].selector)
303                         && this.areParametersEqual(methods[i])) {
304                         needRename = true;
305                         break check;
306                     }
307                 }
308                 // check for collision with synthetic accessors
309
if (knownSyntheticMethods != null) {
310                     for (int i = 0, length = knownSyntheticMethods.length; i < length; i++) {
311                         if (knownSyntheticMethods[i] == null)
312                             continue;
313                         if (CharOperation.equals(this.selector, knownSyntheticMethods[i].selector)
314                             && this.areParametersEqual(knownSyntheticMethods[i])) {
315                             needRename = true;
316                             break check;
317                         }
318                     }
319                 }
320             }
321             if (needRename) { // retry with a new extra argument
322
int length = this.parameters.length;
323                 System.arraycopy(
324                     this.parameters,
325                     0,
326                     this.parameters = new TypeBinding[length + 1],
327                     0,
328                     length);
329                 this.parameters[length] = this.declaringClass;
330             }
331         } while (needRename);
332     
333         // retrieve sourceStart position for the target method for line number attributes
334
AbstractMethodDeclaration[] methodDecls =
335             sourceType.scope.referenceContext.methods;
336         if (methodDecls != null) {
337             for (int i = 0, length = methodDecls.length; i < length; i++) {
338                 if (methodDecls[i].binding == accessedConstructor) {
339                     this.sourceStart = methodDecls[i].sourceStart;
340                     return;
341                 }
342             }
343         }
344     }
345
346     /**
347      * An method accessor is a method with an access$N selector, where N is incremented in case of collisions.
348      */

349     public void initializeMethodAccessor(MethodBinding accessedMethod, boolean isSuperAccess, ReferenceBinding receiverType) {
350         
351         this.targetMethod = accessedMethod;
352         this.modifiers = ClassFileConstants.AccDefault | ClassFileConstants.AccStatic | ClassFileConstants.AccSynthetic;
353         this.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved);
354         SourceTypeBinding declaringSourceType = (SourceTypeBinding) receiverType;
355         SyntheticMethodBinding[] knownAccessMethods = declaringSourceType.syntheticMethods();
356         int methodId = knownAccessMethods == null ? 0 : knownAccessMethods.length;
357         this.index = methodId;
358     
359         this.selector = CharOperation.concat(TypeConstants.SYNTHETIC_ACCESS_METHOD_PREFIX, String.valueOf(methodId).toCharArray());
360         this.returnType = accessedMethod.returnType;
361         this.kind = isSuperAccess ? SuperMethodAccess : MethodAccess;
362         
363         if (accessedMethod.isStatic()) {
364             this.parameters = accessedMethod.parameters;
365         } else {
366             this.parameters = new TypeBinding[accessedMethod.parameters.length + 1];
367             this.parameters[0] = declaringSourceType;
368             System.arraycopy(accessedMethod.parameters, 0, this.parameters, 1, accessedMethod.parameters.length);
369         }
370         this.thrownExceptions = accessedMethod.thrownExceptions;
371         this.declaringClass = declaringSourceType;
372     
373         // check for method collision
374
boolean needRename;
375         do {
376             check : {
377                 needRename = false;
378                 // check for collision with known methods
379
MethodBinding[] methods = declaringSourceType.methods();
380                 for (int i = 0, length = methods.length; i < length; i++) {
381                     if (CharOperation.equals(this.selector, methods[i].selector) && this.areParametersEqual(methods[i])) {
382                         needRename = true;
383                         break check;
384                     }
385                 }
386                 // check for collision with synthetic accessors
387
if (knownAccessMethods != null) {
388                     for (int i = 0, length = knownAccessMethods.length; i < length; i++) {
389                         if (knownAccessMethods[i] == null) continue;
390                         if (CharOperation.equals(this.selector, knownAccessMethods[i].selector) && this.areParametersEqual(knownAccessMethods[i])) {
391                             needRename = true;
392                             break check;
393                         }
394                     }
395                 }
396             }
397             if (needRename) { // retry with a selector & a growing methodId
398
this.setSelector(CharOperation.concat(TypeConstants.SYNTHETIC_ACCESS_METHOD_PREFIX, String.valueOf(++methodId).toCharArray()));
399             }
400         } while (needRename);
401     
402         // retrieve sourceStart position for the target method for line number attributes
403
AbstractMethodDeclaration[] methodDecls = declaringSourceType.scope.referenceContext.methods;
404         if (methodDecls != null) {
405             for (int i = 0, length = methodDecls.length; i < length; i++) {
406                 if (methodDecls[i].binding == accessedMethod) {
407                     this.sourceStart = methodDecls[i].sourceStart;
408                     return;
409                 }
410             }
411         }
412     }
413
414     protected boolean isConstructorRelated() {
415         return kind == ConstructorAccess;
416     }
417 }
418
Popular Tags