blob: 21a8363317ec305f44129ce8d82847a5e9f3cfea [file] [log] [blame]
/**********************************************************************
* This file is part of "Object Teams Development Tooling"-Software
*
* Copyright 2003, 2014 Fraunhofer Gesellschaft, Munich, Germany,
* for its Fraunhofer Institute for Computer Architecture and Software
* Technology (FIRST), Berlin, Germany and Technical University Berlin,
* Germany.
*
* 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
*
* Please visit http://www.eclipse.org/objectteams for updates and contact.
*
* Contributors:
* Fraunhofer FIRST - Initial API and implementation
* Technical University Berlin - Initial API and implementation
**********************************************************************/
/**
* ObjectTeams Eclipse source extensions
* More information available at www.ObjectTeams.org
*
* @author Markus Witte
*
* @date 27.09.2003
*/
package org.eclipse.objectteams.otdt.internal.core.compiler.bytecode;
import java.util.Iterator;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileStruct;
import org.eclipse.jdt.internal.compiler.codegen.ConstantPool;
import org.eclipse.jdt.internal.compiler.env.ITypeAnnotationWalker;
import org.eclipse.jdt.internal.compiler.impl.Constant;
import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.Binding;
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.NestedTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.SignatureWrapper;
import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.SyntheticArgumentBinding;
import org.eclipse.jdt.internal.compiler.lookup.SyntheticMethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
import org.eclipse.jdt.internal.compiler.lookup.UnresolvedReferenceBinding;
import org.eclipse.objectteams.otdt.core.compiler.IOTConstants;
import org.eclipse.objectteams.otdt.core.exceptions.InternalCompilerError;
import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.SyntheticBaseCallSurrogate;
import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.SyntheticRoleFieldAccess;
import org.eclipse.objectteams.otdt.internal.core.compiler.mappings.CallinImplementorDyn;
import org.eclipse.objectteams.otdt.internal.core.compiler.mappings.CalloutImplementorDyn;
import org.eclipse.objectteams.otdt.internal.core.compiler.model.MethodModel;
import org.eclipse.objectteams.otdt.internal.core.compiler.model.RoleModel;
import org.eclipse.objectteams.otdt.internal.core.compiler.model.TypeModel;
/**
* Reads BinaryTypeBinding ConstantPool Entries
* and returns the Binding/Object at the specific ConstantPoolOffset
*
* @author Markus Witte
*/
public class ConstantPoolObjectReader extends ClassFileStruct implements ClassFileConstants
{
class IncompatibleBytecodeException extends RuntimeException {
// make the compiler happy:
private static final long serialVersionUID = -7100113603999284971L;
char[] _offendingName;
int _problemId;
IncompatibleBytecodeException(char[]offendingName, int problemId) {
this._offendingName = offendingName;
this._problemId = problemId;
}
}
private LookupEnvironment _environment;
private TypeModel _srcModel;
/**
* @param srcRole the source role being copied from
* @param reference the ConstantPool Bytecode which should be read
* @param environment
*/
public ConstantPoolObjectReader(RoleModel srcRole, byte[] reference, LookupEnvironment environment)
{
super(reference, srcRole.getConstantPoolOffsets(), 0);
this._srcModel = srcRole;
this._environment = environment;
}
public ConstantPoolObjectReader(MethodModel model, TypeModel srcModel, LookupEnvironment environment)
{
super(model.getBytes(), model.getConstantPoolOffsets(), 0);
this._srcModel = srcModel;
this._environment = environment;
}
public ConstantPoolObjectReader(byte[] bytes, int[] constantPoolOffsets, TypeModel srcModel, LookupEnvironment environment) {
super(bytes, constantPoolOffsets, 0);
this._srcModel = srcModel;
this._environment = environment;
}
/**
* The Type of an ConstantPool entry e.g. ClassTag or StringTag ...
* @param index the index to an entry of constantPoolOffsets[]
* @return Type
*/
int getConstantPoolEntryType(int index){
int offset = this.constantPoolOffsets[index];
return u1At(offset);
}
/**
* @param index the index to an entry of constantPoolOffsets[]
* @return the start position of the constantPool entry
*/
private int getConstantPoolStartPosition(int index){
int start = this.constantPoolOffsets[index];
return start;
}
public ConstantPoolObject readConstantPoolObject(int ref, int length){
// TODO (SH): check reference length (usually 1).
int type = getConstantPoolEntryType(ref);
switch(type){
case StringTag : return new ConstantPoolObject(type, getString(ref), ref);
case IntegerTag : return new ConstantPoolObject(type, getInteger(ref));
case FloatTag : return new ConstantPoolObject(type, getFloat(ref));
case LongTag : return new ConstantPoolObject(type, getLong(ref));
case DoubleTag : return new ConstantPoolObject(type, getDouble(ref));
case ClassTag : return new ConstantPoolObject(type, decodeClassEntry(ref));
case FieldRefTag : return new ConstantPoolObject(type, getFieldRef(ref));
case MethodRefTag : return new ConstantPoolObject(type, getMethodRef(ref));
case InterfaceMethodRefTag : return new ConstantPoolObject(type, getInterfaceMethodRef(ref));
case Utf8Tag : return new ConstantPoolObject(type, getUtf8(ref));
//case NameAndTypeTag : //...
default:
throw new RuntimeException();
}
}
public TypeBinding getSignatureBinding(int ref, boolean useGenerics)
{
char[] typeName = getUtf8(ref);
if (useGenerics)
return this._environment.getTypeFromTypeSignature(
new SignatureWrapper(typeName), Binding.NO_TYPE_VARIABLES, this._srcModel.getBinding(), null, ITypeAnnotationWalker.EMPTY_ANNOTATION_WALKER); // no missing type info available
else
return this._environment.getTypeFromSignature(
typeName, 0, typeName.length-1, false/*GENERIC*/, this._srcModel.getBinding(), null, ITypeAnnotationWalker.EMPTY_ANNOTATION_WALKER); // no missing type info available
}
private int getInteger(int index){
int start = getConstantPoolStartPosition(index);
assert(u1At(start)==IntegerTag);
return i4At(start+1);
}
private long getLong(int index){
int start = getConstantPoolStartPosition(index);
assert(u1At(start)==LongTag);
return i8At(start+1);
}
private float getFloat(int index){
int start = getConstantPoolStartPosition(index);
assert(u1At(start)==FloatTag);
return floatAt(start+1);
}
private double getDouble(int index){
int start = getConstantPoolStartPosition(index);
assert(u1At(start)==DoubleTag);
return doubleAt(start+1);
}
char[] getUtf8(int index){
int start = getConstantPoolStartPosition(index);
assert(u1At(start)==Utf8Tag);
return utf8At(start + 3, u2At(start + 1));
}
private String getString(int index){
int start = getConstantPoolStartPosition(index);
assert(u1At(start)==StringTag);
return new String(getUtf8(u2At(start+1)));
}
/** retrieve a class or array binding from the constant pool. */
private TypeBinding decodeClassEntry(int index) {
int start = getConstantPoolStartPosition(index);
assert(u1At(start)==ClassTag);
int name_index = u2At(start+1);
char[] name_str = getUtf8(name_index);
// first check scalar class type:
int dims=0;
while (name_str[dims] == '[') dims++;
if (dims == 0) {
// no '[' prefix -> plain class name, must not have 'L' prefix nor ';' suffix:
if (name_str[0] == 'L' || name_str[name_str.length-1] == ';')
throw new IncompatibleBytecodeException(name_str, 0);
return getClassBinding(index);
}
// follows: decoding of array, leaf component type needs 'L' for reference bindings:
TypeBinding typeBinding = this._environment.getTypeFromSignature(name_str, 0, -1, false, this._srcModel.getBinding(),
null, ITypeAnnotationWalker.EMPTY_ANNOTATION_WALKER);
if (!typeBinding.leafComponentType().isBaseType()) {
ReferenceBinding referenceBinding = (ReferenceBinding)typeBinding.leafComponentType();
if (referenceBinding instanceof UnresolvedReferenceBinding) {
ReferenceBinding localType = findLocalType(CharOperation.subarray(name_str, dims, -1));
if (localType != null)
referenceBinding = localType;
else
referenceBinding = (ReferenceBinding)BinaryTypeBinding.resolveType(referenceBinding, this._environment, false);
}
// check whether this type is actually an anchored type:
CPTypeAnchorAttribute typeAnchors = this._srcModel.getTypeAnchors();
if (typeAnchors != null) {
char[] anchorPath = typeAnchors.getPath(index);
if (anchorPath != null) {
// create a RTB using a dummy field:
ReferenceBinding teamType = referenceBinding.enclosingType();
FieldBinding anchor = new FieldBinding(anchorPath, teamType, AccFinal, this._srcModel.getBinding(), Constant.NotAConstant);
return anchor.getRoleTypeBinding(referenceBinding, dims);
}
}
}
return typeBinding;
}
private MethodBinding getMethodRef(int index){
int start = getConstantPoolStartPosition(index);
assert(u1At(start)==MethodRefTag);
int class_index = u2At(start+1);
int name_index = u2At(start+3);
ReferenceBinding class_rb = getClassBinding(class_index);
// deactivated, see below. ReferenceBinding actualReceiver = class_rb;
if(class_rb==null)
return null;
char[][] nameandtype = getNameAndType(name_index);
char[] name = nameandtype[0];
char[] type = nameandtype[1];
MethodBinding mb = findMethodBinding(class_rb,name,type);
// Note: donot revert to actual receiver, because the linkage of
// copyInheritanceSrc will otherwise be broken!
if (mb == null && CharOperation.endsWith(name, IOTConstants._OT_TAG)) {
// This method is faked within the compiler, will be added by the OTRE.
return new MethodBinding(ClassFileConstants.AccPublic, name, TypeBinding.SHORT, Binding.NO_PARAMETERS, Binding.NO_EXCEPTIONS, class_rb);
}
assert(mb != null);
return mb;
}
private FieldBinding getFieldRef(int index){
int start = getConstantPoolStartPosition(index);
assert(u1At(start)==FieldRefTag);
int class_index = u2At(start+1);
int name_index = u2At(start+3);
ReferenceBinding class_rb = getClassBinding(class_index);
ReferenceBinding actualReceiver = class_rb;
if(class_rb==null)
return null;
char[][] nameandtype = getNameAndType(name_index);
char[] name = nameandtype[0];
char[] type = nameandtype[1];
FieldBinding fb = null;
if (class_rb.erasure() instanceof SourceTypeBinding) {
SourceTypeBinding sourceType = (SourceTypeBinding)class_rb.erasure();
// can't find synthetics in 'fields'.
if (CharOperation.prefixEquals(TypeConstants.SYNTHETIC_OUTER_LOCAL_PREFIX, name))
return sourceType.getSyntheticOuterLocal(name);
if (CharOperation.prefixEquals(TypeConstants.SYNTHETIC_CLASS, name))
return sourceType.getSyntheticClassLiteral(name);
} // FIXME(SH): else read from RoleModel??
do {
fb = findFieldBinding(class_rb, name, type);
if (fb != null) {
if (TypeBinding.notEquals(actualReceiver, class_rb))
// return sourceType.getUpdatedFieldBinding(fb, actualReceiver);
// no sourceType available so directly create the updated binding:
return new FieldBinding(fb, actualReceiver);
return fb;
}
class_rb = class_rb.superclass();
} while (!CharOperation.equals(class_rb.constantPoolName(), ConstantPool.JavaLangObjectConstantPoolName));
return fb;
}
private MethodBinding getInterfaceMethodRef(int index)
{
int start = getConstantPoolStartPosition(index);
assert(u1At(start)==InterfaceMethodRefTag);
int class_index = u2At(start+1);
int name_index = u2At(start+3);
ReferenceBinding class_rb = getClassBinding(class_index);
if(class_rb==null)
return null;
char[][] nameandtype = getNameAndType(name_index);
char[] name = nameandtype[0];
char[] type = nameandtype[1];
MethodBinding mb = findMethodBinding(class_rb, name, type);
assert(mb != null);
if (TypeBinding.notEquals(mb.declaringClass, class_rb)) {
mb = new MethodBinding(mb, class_rb);
}
return mb;
}
//char[0][] name
//char[1][] descriptor
private char[][] getNameAndType(int index){
int start = getConstantPoolStartPosition(index);
assert(u1At(start)==NameAndTypeTag);
int name_index = u2At(start+1);
int descriptor_index = u2At(start+3);
char[] name = getUtf8(name_index);
char[] descriptor = getUtf8(descriptor_index);
char[][] result = {name, descriptor};
return result;
}
//*************************************************
// as used to retrieve the declaring class of various entries
// and for class entries without 'L' and ';'
private ReferenceBinding getClassBinding(int index) {
int start = getConstantPoolStartPosition(index);
assert(u1At(start)==ClassTag);
int name_index = u2At(start+1);
char[] name_str = getUtf8(name_index);
ReferenceBinding referenceBinding = this._environment.getTypeFromConstantPoolName(name_str, 0, -1, false, null);
if (referenceBinding instanceof UnresolvedReferenceBinding) {
ReferenceBinding localType = findLocalType(name_str);
if (localType != null)
return localType;
referenceBinding = (ReferenceBinding)BinaryTypeBinding.resolveType(referenceBinding, this._environment, false);
}
// check whether this type is actually an anchored type:
CPTypeAnchorAttribute typeAnchors = this._srcModel.getTypeAnchors();
if (typeAnchors != null) {
char[] anchorPath = typeAnchors.getPath(index);
if (anchorPath != null) {
// create a RTB using a dummy field:
ReferenceBinding teamType = referenceBinding.enclosingType();
FieldBinding anchor = new FieldBinding(anchorPath, teamType, AccFinal, this._srcModel.getBinding(), Constant.NotAConstant);
referenceBinding = (ReferenceBinding) anchor.getRoleTypeBinding(referenceBinding, 0);
}
}
return referenceBinding;
}
private ReferenceBinding findLocalType(char[] name_str) {
if (this._srcModel.getBinding().isLocalType()) {
if (CharOperation.equals(this._srcModel.getBinding().constantPoolName(), name_str))
return this._srcModel.getBinding();
}
if (this._srcModel instanceof RoleModel) {
Iterator<RoleModel> localTypes = ((RoleModel)this._srcModel).localTypes();
while (localTypes.hasNext()) {
RoleModel local = localTypes.next();
if (CharOperation.equals(local.getBinding().constantPoolName(), name_str)) {
return local.getBinding();
}
}
}
return null;
}
public MethodBinding findMethodBinding(ReferenceBinding class_rb, char[] name, char[] descriptor){
boolean isDecapsWrapper = false;
if (CharOperation.prefixEquals(IOTConstants.OT_DECAPS, name)) {
// accessors for decapsulation: strip prefix and prepend it after we have found the method:
isDecapsWrapper = true;
name = CharOperation.subarray(name, IOTConstants.OT_DECAPS.length, -1);
}
MethodBinding foundMethod = doFindMethodBinding(class_rb, name, descriptor);
if (foundMethod != null && isDecapsWrapper) {
foundMethod = new MethodBinding(foundMethod, class_rb); // OTRE adds the accessor to the exact base class, even if method is inherited
foundMethod.selector = CharOperation.concat(IOTConstants.OT_DECAPS, name);
}
return foundMethod;
}
private MethodBinding doFindMethodBinding(ReferenceBinding class_rb, char[] name, char[] descriptor){
MethodBinding[] mbs = class_rb.getMethods(name);
if(mbs != Binding.NO_METHODS) {
for (int i = 0; i < mbs.length; i++) {
MethodBinding binding = mbs[i];
if(binding!=null){
if(isEqual(binding, name,descriptor))
return binding;
}
}
// TODO(SH): currently this may happen, if a role file is not recompiled which
// required e.g., a getter access$n, while a setter access$n is being generated.
if (isSynthMethodName(name))
throw new InternalCompilerError("synthetic method "+new String(name)+" has unexpected signature"); //$NON-NLS-1$ //$NON-NLS-2$
}
if ( isSynthMethodName(name)
|| SyntheticBaseCallSurrogate.isBaseCallSurrogateName(name))
{
// for normal access methods class_rb should not be a BinaryTypeBinding,
// because in that case the above loop should have found the method
// (access$n are stored like normal methods).
if (class_rb.isBinaryBinding()) {
if (SyntheticBaseCallSurrogate.isBaseCallSurrogateName(name)) { // surrogate might be inherited
ReferenceBinding current = class_rb;
while ((current = current.superclass()) != null) {
MethodBinding candidate = doFindMethodBinding(current, name, descriptor);
if (candidate != null)
return candidate;
}
}
// TODO(SH): but when T has been compiled only with T.R1 while T.R2
// requires a synth.method, than this method will be missing!
} else {
SourceTypeBinding stb = (SourceTypeBinding)class_rb.erasure();
SyntheticMethodBinding[] accessMethods = stb.syntheticMethods();
if (accessMethods != null) {
for (int i=0; i<accessMethods.length; i++) {
if (CharOperation.equals(accessMethods[i].selector, name))
return accessMethods[i];
}
}
}
}
if (SyntheticRoleFieldAccess.isRoleFieldAccess(AccSynthetic, name)) {
if (class_rb.isBinaryBinding())
return null; // should have been found within methods
SourceTypeBinding sourceType = (SourceTypeBinding)class_rb.erasure();
SyntheticMethodBinding[] synthetics = sourceType.syntheticMethods();
if (synthetics == null)
return null;
for (SyntheticMethodBinding methodBinding : synthetics) {
if (CharOperation.equals(methodBinding.selector, name))
return methodBinding;
}
}
int modifiers = isFakedOTREMethod(name);
if (modifiers != 0)
{
// These methods will be generated by the OTRE,
// may safely be faked during compilation:
MethodBinding fakedMethod = createMethodFromSignature(
class_rb,
modifiers,
name,
descriptor);
class_rb.addMethod(fakedMethod);
return fakedMethod;
}
// since Eclipse 3.0 and for JDK >= 1.2 the declaring class is changed to the
// declared receiver (see SourceTypeBinding.getUpdatedMethodBinding()).
// need to search super class/interfaces to really find the method.
ReferenceBinding currentType = class_rb.superclass();
if (currentType != null) {
MethodBinding mb = findMethodBinding(currentType, name, descriptor);
if (mb != null)
return mb;
}
ReferenceBinding[] superIfcs = class_rb.superInterfaces();
if (superIfcs != null) {
for (int i = 0; i < class_rb.superInterfaces().length; i++) {
MethodBinding mb = findMethodBinding(superIfcs[i], name, descriptor);
if (mb != null) {
if (!class_rb.isInterface())
return new MethodBinding(mb, class_rb); // need a class method!
return mb;
}
}
}
return null;
}
boolean isSynthMethodName(char[] name) {
return
CharOperation.prefixEquals(TypeConstants.SYNTHETIC_ACCESS_METHOD_PREFIX, name)
|| CharOperation.prefixEquals(TypeConstants.SYNTHETIC_SWITCH_ENUM_TABLE, name)
|| CharOperation.equals(CalloutImplementorDyn.OT_ACCESS, name)
|| CharOperation.equals(CalloutImplementorDyn.OT_ACCESS_STATIC, name);
}
/** Detect methods that will be generated by the OTRE. If match return the assumed modifiers */
static int isFakedOTREMethod(char[] name) {
if (!CharOperation.prefixEquals(IOTConstants.OT_DOLLAR_NAME, name))
return 0;
if (CharOperation.prefixEquals(IOTConstants.OT_GETFIELD, name))
return AccPublic|AccStatic;
if (CharOperation.prefixEquals(IOTConstants.OT_SETFIELD, name))
return AccPublic|AccStatic;
if (CharOperation.prefixEquals(IOTConstants.ADD_ROLE, name))
return AccPublic;
if (CharOperation.prefixEquals(IOTConstants.REMOVE_ROLE, name))
return AccPublic;
if (CharOperation.prefixEquals(IOTConstants.ADD_REMOVE_ROLE, name))
return AccPublic;
// The next two are not searched in order to avoid receiver type o.o.Team.
// We want the tsub to always try to invoke its direct super, which may
// have more callin bindings than where known to the original dispatch method.
if (CharOperation.equals(CallinImplementorDyn.OT_CALL_AFTER, name))
return AccPublic;
if (CharOperation.equals(CallinImplementorDyn.OT_CALL_BEFORE, name))
return AccPublic;
if (CharOperation.equals(CalloutImplementorDyn.OT_ACCESS, name))
return AccPublic;
if (CharOperation.equals(CalloutImplementorDyn.OT_ACCESS_STATIC, name))
return AccPublic;
return 0;
}
/** Stolen mainly from BinaryTypeBinding.createMethod. */
private MethodBinding createMethodFromSignature(
ReferenceBinding declaringClass,
int methodModifiers,
char[] methodSelector,
char[] methodSignature)
{
int numOfParams = 0;
char nextChar;
int index = 0; // first character is always '(' so skip it
while ((nextChar = methodSignature[++index]) != ')') {
if (nextChar != '[') {
numOfParams++;
if (nextChar == 'L')
while ((nextChar = methodSignature[++index]) != ';'){/*empty*/}
}
}
// Ignore synthetic argument for member types.
int startIndex = 0;
TypeBinding[] parameters = Binding.NO_PARAMETERS;
int size = numOfParams - startIndex;
if (size > 0) {
parameters = new TypeBinding[size];
index = 1;
int end = 0; // first character is always '(' so skip it
for (int i = 0; i < numOfParams; i++) {
while ((nextChar = methodSignature[++end]) == '['){/*empty*/}
if (nextChar == 'L')
while ((nextChar = methodSignature[++end]) != ';'){/*empty*/}
if (i >= startIndex) // skip the synthetic arg if necessary
parameters[i - startIndex] = this._environment.getTypeFromSignature(methodSignature, index, end, false/*GENERIC*/, this._srcModel.getBinding(),
null, ITypeAnnotationWalker.EMPTY_ANNOTATION_WALKER); // no missing type info available
index = end + 1;
}
}
return new MethodBinding(
methodModifiers,
methodSelector,
this._environment.getTypeFromSignature(methodSignature, index + 1, -1, false/*GENERIC*/, this._srcModel.getBinding(), // index is currently pointing at the ')'
null, ITypeAnnotationWalker.EMPTY_ANNOTATION_WALKER),
parameters,
Binding.NO_EXCEPTIONS,
declaringClass);
}
private FieldBinding findFieldBinding(TypeBinding class_tb, char[] name, char[] descriptor)
{
if(class_tb instanceof ReferenceBinding)
{
ReferenceBinding class_rb = (ReferenceBinding) class_tb;
return findFieldByName(class_rb, name);
}
else if(class_tb instanceof ArrayBinding)
{
if(!CharOperation.equals(name, TypeConstants.LENGTH))
{
assert(false);
}
return ArrayBinding.ArrayLength;
}
else
{
//no fields on basetypes
assert(false);
return null;
}
}
public FieldBinding findFieldByName(ReferenceBinding clazz, char[] name)
{
char[] prefix = TypeConstants.SYNTHETIC_ENCLOSING_INSTANCE_PREFIX;
if (CharOperation.prefixEquals(prefix, name))
{
TypeBinding original = clazz.original();
if (original instanceof NestedTypeBinding)
{
if( original.isMemberType()
|| original.isLocalType())
{
NestedTypeBinding ntb = (NestedTypeBinding)original;
SyntheticArgumentBinding[] sab = ntb.syntheticEnclosingInstances();
for (int i=0; i<sab.length; i++) {
if (CharOperation.equals(name, sab[i].name))
return sab[i].matchingField;
}
}
}
// no name adjustment or synthetics needed at the reading (source) side.
}
// either regular field or synthetic in a BinaryTypeBinding:
return clazz.getField(name, true);
}
public static FieldBinding findFieldByBinding(ReferenceBinding clazz, FieldBinding refField)
{
char[] thisPrefix = TypeConstants.SYNTHETIC_ENCLOSING_INSTANCE_PREFIX;
char[] classPrefix = TypeConstants.SYNTHETIC_CLASS;
char[] name = refField.name;
if (CharOperation.prefixEquals(thisPrefix, name))
{
int distance = refField.declaringClass.depth()
- ((ReferenceBinding)refField.type).depth();
if (clazz instanceof NestedTypeBinding)
{
{
NestedTypeBinding mtb = (NestedTypeBinding)clazz;
ReferenceBinding dstFieldType = clazz;
while (distance-- > 0) {
dstFieldType = dstFieldType.enclosingType();
}
return mtb.addSyntheticFieldForInnerclass(dstFieldType);
}
} else { // BinaryTypeBinding
int depth = clazz.depth() - distance;
name = CharOperation.concat(
thisPrefix,
String.valueOf(depth).toCharArray());
}
} else if (CharOperation.prefixEquals(classPrefix, name))
{
// assume the synthetic field is present, just create a new binding.
return new FieldBinding(refField.name, refField.type, 0, clazz, null);
}
// directly find field in clazz or superclass(es)
ReferenceBinding current = clazz;
while (current != null) {
FieldBinding f = current.getField(name, true);
if (f != null) return f;
current = current.superclass();
}
return null;
}
/**
* compare the MethodBinding with an MethodRef entry from ConstantPool
* @param binding the binding wich is to be comared with the ConstantPool-Entry
* @param name the ConstantPool name of a Method
* @param descriptor the ConstantPool signature of a Method
* @return true if binding and signature means the same Method
*/
private boolean isEqual(MethodBinding binding, char[] name, char[] descriptor){
if(new String(binding.selector).compareTo(new String(name))!=0)
return false;
char[] signature = binding.signature(); // erasure
if (CharOperation.equals(signature, descriptor))
return true;
if (binding.isConstructor()) {
// chop off synthetic enclosing instance argument:
// 1. try to chop off enclosing team only:
int separatorPosMethod = CharOperation.indexOf('$', signature);
int separatorPosDescriptor = CharOperation.indexOf('$', descriptor);
// 2. chop off full arg until ';'
if (separatorPosMethod == -1 && separatorPosDescriptor == -1) {
separatorPosMethod = CharOperation.indexOf(';', signature);
separatorPosDescriptor = CharOperation.indexOf(';', descriptor);
}
if (separatorPosMethod > 0 && separatorPosDescriptor > 0) {
TypeBinding type1 = this._environment.getTypeFromSignature(signature, 1, separatorPosMethod, false/*GENERIC*/, this._srcModel.getBinding(),
null, ITypeAnnotationWalker.EMPTY_ANNOTATION_WALKER);
TypeBinding type2 = this._environment.getTypeFromSignature(descriptor, 1, separatorPosDescriptor, false/*GENERIC*/, this._srcModel.getBinding(),
null, ITypeAnnotationWalker.EMPTY_ANNOTATION_WALKER);
if (!type1.isTeam() || !type2.isTeam())
return false;
if (!type1.isCompatibleWith(type2))
return false;
signature = CharOperation.subarray(signature, separatorPosMethod, -1);
descriptor = CharOperation.subarray(descriptor, separatorPosDescriptor, -1);
}
}
return false;
}
/** Answer an iterator over all strings and integers in the constant pool,
* which are addressed with a single byte offset
* (non-wide indices, requiring ldc, not ldcw).
* @param nConstants number of constants in the src constant pool.
*/
public Iterator<ConstantPoolObject> getNonWideConstantIterator(final int nConstants) {
return new Iterator<ConstantPoolObject> () {
int cur = Math.min(256, nConstants);
@Override
public boolean hasNext() {
while (--this.cur >= 0) {
int entryType = getConstantPoolEntryType(this.cur);
switch (entryType) {
case StringTag:
case IntegerTag:
case FloatTag:
case ClassTag:
return true;
// note: No need to handle long,
// which is stored using ldc2_w of which no non-wide version exists
// No need to handle char which is inlined using bipush or sipush
}
}
return false;
}
@Override
public ConstantPoolObject next() {
return readConstantPoolObject(this.cur, 2);
}
@Override
public void remove() {
throw new InternalCompilerError("method not meant to be invoked."); //$NON-NLS-1$
}
};
}
}
//Markus Witte}