blob: ee1844784e454d46d991671bb8744bda91b818a3 [file] [log] [blame]
/**********************************************************************
* This file is part of "Object Teams Development Tooling"-Software
*
* Copyright 2004, 2010 Fraunhofer Gesellschaft, Munich, Germany,
* for its Fraunhofer Institute for Computer Architecture and Software
* Technology (FIRST), Berlin, Germany and Technical University Berlin,
* Germany.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
* $Id: FieldModel.java 23416 2010-02-03 19:59:31Z stephan $
*
* 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
**********************************************************************/
package org.eclipse.objectteams.otdt.internal.core.compiler.model;
import static org.eclipse.objectteams.otdt.core.compiler.IOTConstants.ANCHOR_USAGE_RANKS;
import static org.eclipse.objectteams.otdt.core.compiler.IOTConstants.AccSynthIfc;
import static org.eclipse.objectteams.otdt.core.compiler.IOTConstants.OT_GETFIELD;
import static org.eclipse.objectteams.otdt.core.compiler.IOTConstants.OT_SETFIELD;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.lookup.Binding;
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.Scope;
import org.eclipse.jdt.internal.compiler.lookup.TagBits;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.objectteams.otdt.core.compiler.IOTConstants;
import org.eclipse.objectteams.otdt.core.exceptions.InternalCompilerError;
import org.eclipse.objectteams.otdt.internal.core.compiler.ast.CalloutMappingDeclaration;
import org.eclipse.objectteams.otdt.internal.core.compiler.ast.MethodSpec.ImplementationStrategy;
import org.eclipse.objectteams.otdt.internal.core.compiler.bytecode.AnchorUsageRanksAttribute;
import org.eclipse.objectteams.otdt.internal.core.compiler.bytecode.WordValueAttribute;
import org.eclipse.objectteams.otdt.internal.core.compiler.mappings.CalloutImplementorDyn;
import org.eclipse.objectteams.otdt.internal.core.compiler.model.MethodModel.FakeKind;
/**
* Store additional information for a field.
* + Modifiers (in the case of static final in a synthetic role interface).
*
* @author stephan
* @version $Id: FieldModel.java 23416 2010-02-03 19:59:31Z stephan $
*/
public class FieldModel extends ModelElement {
public static FieldModel getModel(FieldDeclaration decl) {
FieldModel model = decl.model;
if (model == null) {
if (decl.binding != null && decl.binding.model != null)
model = decl.binding.model;
else
model = new FieldModel(decl);
}
return model;
}
public static FieldModel getModel(FieldBinding binding) {
FieldModel model = binding.model;
if (model == null)
model = new FieldModel(binding);
return model;
}
private FieldDeclaration _decl = null;
private FieldBinding _binding = null;
/** A flat encoding of a type anchor for this fields declared type .*/
public char[] typeAnchor = null;
public boolean hasResolveAnchorStarted = false;
/** Flag for transfering a bit from generated AST to binding. */
public boolean _clearPrivateModifier = false;
/** Faked _OT$base fields store here, in which super-role a real base field can be found. */
public ReferenceBinding actualDeclaringClass;
// store inferred callouts to avoid duplicate generation: // FIXME(SH): should be per adapting role
public CalloutMappingDeclaration _setterCallout= null;
public CalloutMappingDeclaration _getterCallout= null;
private MethodBinding _decapsulatingGetter = null;
private MethodBinding _decapsulatingSetter = null;
private FieldModel(FieldDeclaration decl) {
this._decl = decl;
decl.model = this;
}
private FieldModel(FieldBinding binding) {
this._binding = binding;
binding.model = this;
}
public void setBinding(FieldBinding fieldBinding) {
if (this._binding != null)
assert this._binding == fieldBinding;
this._binding = fieldBinding;
fieldBinding.model = this;
if (this._clearPrivateModifier)
fieldBinding.tagBits |= TagBits.ClearPrivateModifier;
}
public FieldDeclaration getAST() {
return this._decl;
}
/**
* Return the class that really (in the Java-view) declares the given field,
* considering whether f is a faked covariant _OT$base field.
*/
public static ReferenceBinding getActualDeclaringClass(FieldBinding f) {
if ((f.otBits & IOTConstants.IsFakedField) != 0)
if (f.model != null)
return f.model.actualDeclaringClass;
return f.declaringClass;
}
/** Given that this is the model of a fake strong base field, return the original field from the super role. */
public FieldBinding getOriginalFromFake() {
ReferenceBinding superRole = this.actualDeclaringClass;
FieldBinding fieldBinding = superRole.getField(this._binding.name, true);
if (fieldBinding == null)
throw new InternalCompilerError("Expected base field not found in super Role "+new String(superRole.readableName())); //$NON-NLS-1$
return fieldBinding;
}
/** After inserting a field into a role interface create an attribute to store its source modifiers. */
public static boolean checkCreateModifiersAttribute(TypeDeclaration type, FieldDeclaration field)
{
if ((type.modifiers & AccSynthIfc) != 0) {
if ((field.modifiers & ClassFileConstants.AccPublic) == 0) {
FieldModel model = getModel(field);
model.addAttribute(WordValueAttribute.modifiersAttribute(field.modifiers));
// if no binding is present yet remember this bit for transfer in FieldBinding().
model._clearPrivateModifier = true;
return true;
}
}
return false;
}
/** Record that the rank'th type parameter is anchored to this field. */
public void addUsageRank(int rank) {
AnchorUsageRanksAttribute attr = (AnchorUsageRanksAttribute) getAttribute(ANCHOR_USAGE_RANKS);
attr.addUsageRank(rank);
}
/** Create a faked method binding for a getAccessor to a given base field.
* @param isGetter select getter or setter
*/
public static MethodBinding getDecapsulatingFieldAccessor(Scope scope,
ReferenceBinding baseType,
FieldBinding resolvedField,
boolean isGetter,
ImplementationStrategy strategy)
{
FieldModel model = FieldModel.getModel(resolvedField);
MethodBinding accessor = isGetter ? model._decapsulatingGetter : model._decapsulatingSetter;
if (accessor != null)
return accessor;
if (strategy == ImplementationStrategy.DYN_ACCESS) {
accessor = CalloutImplementorDyn.ensureAccessor(scope, baseType, resolvedField.isStatic());
} else {
TypeBinding[] argTypes = resolvedField.isStatic()
? (isGetter
? new TypeBinding[0]
: new TypeBinding[]{resolvedField.type})
: (isGetter
? new TypeBinding[]{baseType}
: new TypeBinding[]{baseType, resolvedField.type});
accessor = new MethodBinding(
ClassFileConstants.AccPublic|ClassFileConstants.AccStatic,
CharOperation.concat(isGetter ? OT_GETFIELD : OT_SETFIELD, resolvedField.name),
isGetter ? resolvedField.type : TypeBinding.VOID,
argTypes,
Binding.NO_EXCEPTIONS,
baseType);
baseType.addMethod(accessor);
}
MethodModel.getModel(accessor)._fakeKind = FakeKind.BASE_FIELD_ACCESSOR;
if (isGetter)
model._decapsulatingGetter = accessor;
else
model._decapsulatingSetter = accessor;
return accessor;
}
/** Retrieve the array of ranks as read from bytecode. Returns null if no such attribute found. */
public static int[] getAnchorUsageRanks(FieldBinding field) {
if (field.model == null)
return null;
AnchorUsageRanksAttribute attr = (AnchorUsageRanksAttribute) field.model.getAttribute(ANCHOR_USAGE_RANKS);
return attr.getRanks();
}
/** Is the given field accessed via an inferred callout-to-field? */
public static boolean isCalloutAccessed(FieldBinding fieldBinding) {
FieldModel model = fieldBinding.model;
if (model == null)
return false;
return model._setterCallout != null || model._getterCallout != null;
}
}