org.eclipse.jdt.internal.compiler.lookup.SyntheticMethodBinding Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of vaadin-client-compiler-deps Show documentation
Show all versions of vaadin-client-compiler-deps Show documentation
Vaadin is a web application framework for Rich Internet Applications (RIA).
Vaadin enables easy development and maintenance of fast and
secure rich web
applications with a stunning look and feel and a wide browser support.
It features a server-side architecture with the majority of the logic
running
on the server. Ajax technology is used at the browser-side to ensure a
rich
and interactive user experience.
/*******************************************************************************
* Copyright (c) 2000, 2007 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.lookup;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
public class SyntheticMethodBinding extends MethodBinding {
public FieldBinding targetReadField; // read access to a field
public FieldBinding targetWriteField; // write access to a field
public MethodBinding targetMethod; // method or constructor
public TypeBinding targetEnumType; // enum type
public int purpose;
public final static int FieldReadAccess = 1; // field read
public final static int FieldWriteAccess = 2; // field write
public final static int MethodAccess = 3; // normal method
public final static int ConstructorAccess = 4; // constructor
public final static int SuperMethodAccess = 5; // super method
public final static int BridgeMethod = 6; // bridge method
public final static int EnumValues = 7; // enum #values()
public final static int EnumValueOf = 8; // enum #valueOf(String)
public final static int SwitchTable = 9; // switch table method
public int sourceStart = 0; // start position of the matching declaration
public int index; // used for sorting access methods in the class file
public SyntheticMethodBinding(FieldBinding targetField, boolean isReadAccess, ReferenceBinding declaringClass) {
this.modifiers = ClassFileConstants.AccDefault | ClassFileConstants.AccStatic | ClassFileConstants.AccSynthetic;
this.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved);
SourceTypeBinding declaringSourceType = (SourceTypeBinding) declaringClass;
SyntheticMethodBinding[] knownAccessMethods = declaringSourceType.syntheticMethods();
int methodId = knownAccessMethods == null ? 0 : knownAccessMethods.length;
this.index = methodId;
this.selector = CharOperation.concat(TypeConstants.SYNTHETIC_ACCESS_METHOD_PREFIX, String.valueOf(methodId).toCharArray());
if (isReadAccess) {
this.returnType = targetField.type;
if (targetField.isStatic()) {
this.parameters = Binding.NO_PARAMETERS;
} else {
this.parameters = new TypeBinding[1];
this.parameters[0] = declaringSourceType;
}
this.targetReadField = targetField;
this.purpose = SyntheticMethodBinding.FieldReadAccess;
} else {
this.returnType = TypeBinding.VOID;
if (targetField.isStatic()) {
this.parameters = new TypeBinding[1];
this.parameters[0] = targetField.type;
} else {
this.parameters = new TypeBinding[2];
this.parameters[0] = declaringSourceType;
this.parameters[1] = targetField.type;
}
this.targetWriteField = targetField;
this.purpose = SyntheticMethodBinding.FieldWriteAccess;
}
this.thrownExceptions = Binding.NO_EXCEPTIONS;
this.declaringClass = declaringSourceType;
// check for method collision
boolean needRename;
do {
check : {
needRename = false;
// check for collision with known methods
long range;
MethodBinding[] methods = declaringSourceType.methods();
if ((range = ReferenceBinding.binarySearch(this.selector, methods)) >= 0) {
int paramCount = this.parameters.length;
nextMethod: for (int imethod = (int)range, end = (int)(range >> 32); imethod <= end; imethod++) {
MethodBinding method = methods[imethod];
if (method.parameters.length == paramCount) {
TypeBinding[] toMatch = method.parameters;
for (int i = 0; i < paramCount; i++) {
if (toMatch[i] != this.parameters[i]) {
continue nextMethod;
}
}
needRename = true;
break check;
}
}
}
// check for collision with synthetic accessors
if (knownAccessMethods != null) {
for (int i = 0, length = knownAccessMethods.length; i < length; i++) {
if (knownAccessMethods[i] == null) continue;
if (CharOperation.equals(this.selector, knownAccessMethods[i].selector) && this.areParametersEqual(methods[i])) {
needRename = true;
break check;
}
}
}
}
if (needRename) { // retry with a selector postfixed by a growing methodId
this.setSelector(CharOperation.concat(TypeConstants.SYNTHETIC_ACCESS_METHOD_PREFIX, String.valueOf(++methodId).toCharArray()));
}
} while (needRename);
// retrieve sourceStart position for the target field for line number attributes
FieldDeclaration[] fieldDecls = declaringSourceType.scope.referenceContext.fields;
if (fieldDecls != null) {
for (int i = 0, max = fieldDecls.length; i < max; i++) {
if (fieldDecls[i].binding == targetField) {
this.sourceStart = fieldDecls[i].sourceStart;
return;
}
}
}
/* did not find the target field declaration - it is a synthetic one
public class A {
public class B {
public class C {
void foo() {
System.out.println("A.this = " + A.this);
}
}
}
public static void main(String args[]) {
new A().new B().new C().foo();
}
}
*/
// We now at this point - per construction - it is for sure an enclosing instance, we are going to
// show the target field type declaration location.
this.sourceStart = declaringSourceType.scope.referenceContext.sourceStart; // use the target declaring class name position instead
}
public SyntheticMethodBinding(FieldBinding targetField, ReferenceBinding declaringClass, TypeBinding enumBinding, char[] selector) {
this.modifiers = ClassFileConstants.AccDefault | ClassFileConstants.AccStatic | ClassFileConstants.AccSynthetic;
this.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved);
SourceTypeBinding declaringSourceType = (SourceTypeBinding) declaringClass;
SyntheticMethodBinding[] knownAccessMethods = declaringSourceType.syntheticMethods();
int methodId = knownAccessMethods == null ? 0 : knownAccessMethods.length;
this.index = methodId;
this.selector = selector;
this.returnType = declaringSourceType.scope.createArrayType(TypeBinding.INT, 1);
this.parameters = Binding.NO_PARAMETERS;
this.targetReadField = targetField;
this.targetEnumType = enumBinding;
this.purpose = SyntheticMethodBinding.SwitchTable;
this.thrownExceptions = Binding.NO_EXCEPTIONS;
this.declaringClass = declaringSourceType;
if (declaringSourceType.isStrictfp()) {
this.modifiers |= ClassFileConstants.AccStrictfp;
}
// check for method collision
boolean needRename;
do {
check : {
needRename = false;
// check for collision with known methods
long range;
MethodBinding[] methods = declaringSourceType.methods();
if ((range = ReferenceBinding.binarySearch(this.selector, methods)) >= 0) {
int paramCount = this.parameters.length;
nextMethod: for (int imethod = (int)range, end = (int)(range >> 32); imethod <= end; imethod++) {
MethodBinding method = methods[imethod];
if (method.parameters.length == paramCount) {
TypeBinding[] toMatch = method.parameters;
for (int i = 0; i < paramCount; i++) {
if (toMatch[i] != this.parameters[i]) {
continue nextMethod;
}
}
needRename = true;
break check;
}
}
}
// check for collision with synthetic accessors
if (knownAccessMethods != null) {
for (int i = 0, length = knownAccessMethods.length; i < length; i++) {
if (knownAccessMethods[i] == null) continue;
if (CharOperation.equals(this.selector, knownAccessMethods[i].selector) && this.areParametersEqual(methods[i])) {
needRename = true;
break check;
}
}
}
}
if (needRename) { // retry with a selector postfixed by a growing methodId
this.setSelector(CharOperation.concat(selector, String.valueOf(++methodId).toCharArray()));
}
} while (needRename);
// We now at this point - per construction - it is for sure an enclosing instance, we are going to
// show the target field type declaration location.
this.sourceStart = declaringSourceType.scope.referenceContext.sourceStart; // use the target declaring class name position instead
}
public SyntheticMethodBinding(MethodBinding targetMethod, boolean isSuperAccess, ReferenceBinding receiverType) {
if (targetMethod.isConstructor()) {
this.initializeConstructorAccessor(targetMethod);
} else {
this.initializeMethodAccessor(targetMethod, isSuperAccess, receiverType);
}
}
/**
* Construct a bridge method
*/
public SyntheticMethodBinding(MethodBinding overridenMethodToBridge, MethodBinding targetMethod, SourceTypeBinding declaringClass) {
this.declaringClass = declaringClass;
this.selector = overridenMethodToBridge.selector;
// amongst other, clear the AccGenericSignature, so as to ensure no remains of original inherited persist (101794)
// also use the modifiers from the target method, as opposed to inherited one (147690)
this.modifiers = (targetMethod.modifiers | ClassFileConstants.AccBridge | ClassFileConstants.AccSynthetic) & ~(ClassFileConstants.AccAbstract | ClassFileConstants.AccNative | ClassFileConstants.AccFinal | ExtraCompilerModifiers.AccGenericSignature);
this.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved);
this.returnType = overridenMethodToBridge.returnType;
this.parameters = overridenMethodToBridge.parameters;
this.thrownExceptions = overridenMethodToBridge.thrownExceptions;
this.targetMethod = targetMethod;
this.purpose = SyntheticMethodBinding.BridgeMethod;
SyntheticMethodBinding[] knownAccessMethods = declaringClass.syntheticMethods();
int methodId = knownAccessMethods == null ? 0 : knownAccessMethods.length;
this.index = methodId;
}
/**
* Construct enum special methods: values or valueOf methods
*/
public SyntheticMethodBinding(SourceTypeBinding declaringEnum, char[] selector) {
this.declaringClass = declaringEnum;
this.selector = selector;
this.modifiers = ClassFileConstants.AccPublic | ClassFileConstants.AccStatic;
this.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved);
LookupEnvironment environment = declaringEnum.scope.environment();
this.thrownExceptions = Binding.NO_EXCEPTIONS;
if (selector == TypeConstants.VALUES) {
this.returnType = environment.createArrayType(environment.convertToParameterizedType(declaringEnum), 1);
this.parameters = Binding.NO_PARAMETERS;
this.purpose = SyntheticMethodBinding.EnumValues;
} else if (selector == TypeConstants.VALUEOF) {
this.returnType = environment.convertToParameterizedType(declaringEnum);
this.parameters = new TypeBinding[]{ declaringEnum.scope.getJavaLangString() };
this.purpose = SyntheticMethodBinding.EnumValueOf;
}
SyntheticMethodBinding[] knownAccessMethods = ((SourceTypeBinding)this.declaringClass).syntheticMethods();
int methodId = knownAccessMethods == null ? 0 : knownAccessMethods.length;
this.index = methodId;
if (declaringEnum.isStrictfp()) {
this.modifiers |= ClassFileConstants.AccStrictfp;
}
}
/**
* An constructor accessor is a constructor with an extra argument (declaringClass), in case of
* collision with an existing constructor, then add again an extra argument (declaringClass again).
*/
public void initializeConstructorAccessor(MethodBinding accessedConstructor) {
this.targetMethod = accessedConstructor;
this.modifiers = ClassFileConstants.AccDefault | ClassFileConstants.AccSynthetic;
this.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved);
SourceTypeBinding sourceType = (SourceTypeBinding) accessedConstructor.declaringClass;
SyntheticMethodBinding[] knownSyntheticMethods =
sourceType.syntheticMethods();
this.index = knownSyntheticMethods == null ? 0 : knownSyntheticMethods.length;
this.selector = accessedConstructor.selector;
this.returnType = accessedConstructor.returnType;
this.purpose = SyntheticMethodBinding.ConstructorAccess;
this.parameters = new TypeBinding[accessedConstructor.parameters.length + 1];
System.arraycopy(
accessedConstructor.parameters,
0,
this.parameters,
0,
accessedConstructor.parameters.length);
this.parameters[accessedConstructor.parameters.length] =
accessedConstructor.declaringClass;
this.thrownExceptions = accessedConstructor.thrownExceptions;
this.declaringClass = sourceType;
// check for method collision
boolean needRename;
do {
check : {
needRename = false;
// check for collision with known methods
MethodBinding[] methods = sourceType.methods();
for (int i = 0, length = methods.length; i < length; i++) {
if (CharOperation.equals(this.selector, methods[i].selector)
&& this.areParametersEqual(methods[i])) {
needRename = true;
break check;
}
}
// check for collision with synthetic accessors
if (knownSyntheticMethods != null) {
for (int i = 0, length = knownSyntheticMethods.length; i < length; i++) {
if (knownSyntheticMethods[i] == null)
continue;
if (CharOperation.equals(this.selector, knownSyntheticMethods[i].selector)
&& this.areParametersEqual(knownSyntheticMethods[i])) {
needRename = true;
break check;
}
}
}
}
if (needRename) { // retry with a new extra argument
int length = this.parameters.length;
System.arraycopy(
this.parameters,
0,
this.parameters = new TypeBinding[length + 1],
0,
length);
this.parameters[length] = this.declaringClass;
}
} while (needRename);
// retrieve sourceStart position for the target method for line number attributes
AbstractMethodDeclaration[] methodDecls =
sourceType.scope.referenceContext.methods;
if (methodDecls != null) {
for (int i = 0, length = methodDecls.length; i < length; i++) {
if (methodDecls[i].binding == accessedConstructor) {
this.sourceStart = methodDecls[i].sourceStart;
return;
}
}
}
}
/**
* An method accessor is a method with an access$N selector, where N is incremented in case of collisions.
*/
public void initializeMethodAccessor(MethodBinding accessedMethod, boolean isSuperAccess, ReferenceBinding receiverType) {
this.targetMethod = accessedMethod;
this.modifiers = ClassFileConstants.AccDefault | ClassFileConstants.AccStatic | ClassFileConstants.AccSynthetic;
this.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved);
SourceTypeBinding declaringSourceType = (SourceTypeBinding) receiverType;
SyntheticMethodBinding[] knownAccessMethods = declaringSourceType.syntheticMethods();
int methodId = knownAccessMethods == null ? 0 : knownAccessMethods.length;
this.index = methodId;
this.selector = CharOperation.concat(TypeConstants.SYNTHETIC_ACCESS_METHOD_PREFIX, String.valueOf(methodId).toCharArray());
this.returnType = accessedMethod.returnType;
this.purpose = isSuperAccess ? SyntheticMethodBinding.SuperMethodAccess : SyntheticMethodBinding.MethodAccess;
if (accessedMethod.isStatic()) {
this.parameters = accessedMethod.parameters;
} else {
this.parameters = new TypeBinding[accessedMethod.parameters.length + 1];
this.parameters[0] = declaringSourceType;
System.arraycopy(accessedMethod.parameters, 0, this.parameters, 1, accessedMethod.parameters.length);
}
this.thrownExceptions = accessedMethod.thrownExceptions;
this.declaringClass = declaringSourceType;
// check for method collision
boolean needRename;
do {
check : {
needRename = false;
// check for collision with known methods
MethodBinding[] methods = declaringSourceType.methods();
for (int i = 0, length = methods.length; i < length; i++) {
if (CharOperation.equals(this.selector, methods[i].selector) && this.areParametersEqual(methods[i])) {
needRename = true;
break check;
}
}
// check for collision with synthetic accessors
if (knownAccessMethods != null) {
for (int i = 0, length = knownAccessMethods.length; i < length; i++) {
if (knownAccessMethods[i] == null) continue;
if (CharOperation.equals(this.selector, knownAccessMethods[i].selector) && this.areParametersEqual(knownAccessMethods[i])) {
needRename = true;
break check;
}
}
}
}
if (needRename) { // retry with a selector & a growing methodId
this.setSelector(CharOperation.concat(TypeConstants.SYNTHETIC_ACCESS_METHOD_PREFIX, String.valueOf(++methodId).toCharArray()));
}
} while (needRename);
// retrieve sourceStart position for the target method for line number attributes
AbstractMethodDeclaration[] methodDecls = declaringSourceType.scope.referenceContext.methods;
if (methodDecls != null) {
for (int i = 0, length = methodDecls.length; i < length; i++) {
if (methodDecls[i].binding == accessedMethod) {
this.sourceStart = methodDecls[i].sourceStart;
return;
}
}
}
}
protected boolean isConstructorRelated() {
return this.purpose == SyntheticMethodBinding.ConstructorAccess;
}
}