blob: 35d6a2b26d9c59b746d37ef502815ac95ddb1eb2 [file] [log] [blame]
/**********************************************************************
* This file is part of "Object Teams Development Tooling"-Software
*
* Copyright 2004, 2019 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: RoleModel.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.jdt.internal.compiler.classfmt.ClassFileConstants.AccInterface;
import static org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.AccSynthetic;
import static org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers.AccOverriding;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ClassFile;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions.WeavingScheme;
import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.Binding;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
import org.eclipse.jdt.internal.compiler.lookup.ElementValuePair;
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.MethodScope;
import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.Scope;
import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.SyntheticMethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.TagBits;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
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.AbstractMethodMappingDeclaration;
import org.eclipse.objectteams.otdt.internal.core.compiler.ast.CallinMappingDeclaration;
import org.eclipse.objectteams.otdt.internal.core.compiler.bytecode.AbstractAttribute;
import org.eclipse.objectteams.otdt.internal.core.compiler.bytecode.CPTypeAnchorAttribute;
import org.eclipse.objectteams.otdt.internal.core.compiler.bytecode.CallinMethodMappingsAttribute;
import org.eclipse.objectteams.otdt.internal.core.compiler.bytecode.CalloutMappingsAttribute;
import org.eclipse.objectteams.otdt.internal.core.compiler.bytecode.OTSpecialAccessAttribute;
import org.eclipse.objectteams.otdt.internal.core.compiler.bytecode.OTSpecialAccessAttribute.CalloutToFieldDesc;
import org.eclipse.objectteams.otdt.internal.core.compiler.bytecode.RoleLocalTypesAttribute;
import org.eclipse.objectteams.otdt.internal.core.compiler.bytecode.SingleValueAttribute;
import org.eclipse.objectteams.otdt.internal.core.compiler.bytecode.WordValueAttribute;
import org.eclipse.objectteams.otdt.internal.core.compiler.control.Config;
import org.eclipse.objectteams.otdt.internal.core.compiler.control.Dependencies;
import org.eclipse.objectteams.otdt.internal.core.compiler.control.ITranslationStates;
import org.eclipse.objectteams.otdt.internal.core.compiler.lifting.Lifting;
import org.eclipse.objectteams.otdt.internal.core.compiler.lifting.Lifting.InstantiationPolicy;
import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.CallinCalloutBinding;
import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.RoleTypeBinding;
import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.SyntheticRoleFieldAccess;
import org.eclipse.objectteams.otdt.internal.core.compiler.mappings.CalloutImplementor;
import org.eclipse.objectteams.otdt.internal.core.compiler.statemachine.copyinheritance.CopyInheritance;
import org.eclipse.objectteams.otdt.internal.core.compiler.statemachine.copyinheritance.TypeLevel;
import org.eclipse.objectteams.otdt.internal.core.compiler.statemachine.transformer.RoleSplitter;
import org.eclipse.objectteams.otdt.internal.core.compiler.util.TypeAnalyzer;
/**
* This class augments and generalizes ReferenceBinding and MemberTypeDeclaration
* to take some additional information for role classes.
*
* These are the main tasks:
* <ul>
* <li>Store byte code from tsuper role before adjustment
* <li>Link to team, link ifc/class parts, link to tsuper role
* <li>record the need to create a concrete _OT$getBase() method.
* <li>Iterate through role hierarchies.
* </ul>
*
* @author stephan
* @version $Id: RoleModel.java 23416 2010-02-03 19:59:31Z stephan $
*/
public class RoleModel extends TypeModel
{
// Flag constants for tagBits:
// is parameterized type instantiated via tsuper-link?
public static final int IsViewedAsTSuper = ASTNode.Bit1;
// had the baseclass field/playedBy problems?
public static final int BaseclassHasProblems = ASTNode.Bit2;
// several issues making lifting impossible
public static final int HasLiftingProblem = ASTNode.Bit3;
// ========== Byte code related fields: ======================
// name to use for ClassFileReader when re-interpreting existing constant pool
public static final char[] NO_SOURCE_FILE = "<intermediate>".toCharArray(); //$NON-NLS-1$
/** Temporarily store the ClassFile to initialize offsets later. */
private ClassFile _classFile = null;
/** The full byte code of this class. */
private byte[] _classByteCode = null;
private int _headerOffset = 0;
/** Offsets into the constant pool */
private int[] _constantPoolOffsets = null;
/** A table of all offsets to methods within the byte code */
private HashMap <MethodBinding, Integer> _methodByteCodeOffsets = new HashMap<MethodBinding, Integer>();
// ========= Structure related fields: ============
/** The Team containing this role. */
private TeamModel _teamModel;
/**
* The corresponding roles from super-Teams.
* This is a list, because for each level of nesting a new super team arises:
* super, tsuper, tsuper-of-tsuper etc.
* Examples:
* a role T2M2R1 may have these tsupers: T2M1R1 and T1M2R1
* a role O2T2M2R1 has these: O2T2M1R1, O2T1M2R1 and O1T2M2R1
* All remaining roles R1 are indirect tsupers as they can be reached via any
* of the above.
*/
private ReferenceBinding[] _tsuperRoleBindings = new ReferenceBinding[2]; // 2 should suffice for human understandable programs ;-}
private int numTSuperRoles = 0;
/** this is set while role-splitting */
public TypeDeclaration _interfacePart = null;
/** this is set while role-splitting */
public TypeDeclaration _classPart = null;
private ReferenceBinding _interfaceBinding = null; // only internal cache
private ReferenceBinding _classBinding = null;
/** Record here all types which are defined local to a method (RoleModel). */
private LinkedList<RoleModel> _localTypes = new LinkedList<RoleModel>();
/** The known sub roles (including this) as determined by RoleHierarchyAnalyzer.analyze(). */
private RoleModel[] _subRoles = null;
/** bound roles store here the topmost bound (super)role, which determines the cache to use: */
public RoleModel _boundRootRole = null;
/** Collection of various flags. */
public int tagBits = 0;
/** will this role declare an abstract lower method? */
public boolean _abstractLower = false;
/** is this role refining the extends clause of its tsuper role? */
public boolean _refinesExtends = false;
/** does this bound role have a binding ambiguity prohibiting lifting? */
public boolean _hasBindingAmbiguity = false;
/** is the baseclass an (indirect) enclosing class? */
public boolean _playedByEnclosing = false;
/** map synthetic methods/fields of tsuper role to this role's */
private HashMap<Binding, Binding> _syntheticMap = new HashMap<Binding, Binding>();
/** is this role a local type? */
public boolean _isLocalType;
/** Remember which tsuper-features (methods & fields) have already been copied,
* so that we can come back and copy more features (copyGeneratedFeatures)
* without the risk of duplication.
*/
private HashSet<Binding> _copiedFeatureBindings = new HashSet<Binding>();
/** Signal if a more specific role exists with unchanged playedBy. */
public ReferenceBinding _supercededBy;
/**
* Constructor for use by BinaryTypeBinding only.
*/
public RoleModel (ReferenceBinding roleBinding)
{
super(roleBinding);
if (roleBinding.isLocalType())
this._isLocalType = true;
}
/**
* Constructor for use by MemberTypeDeclaration only.
*/
public RoleModel (TypeDeclaration roleAst)
{
super(roleAst);
if (!TeamModel.isOrgObjectteamsTeam(roleAst.enclosingType))
addAttribute(WordValueAttribute.compilerVersionAttribute());
if (roleAst.scope != null && roleAst.scope.parent instanceof MethodScope)
this._isLocalType = true;
}
public boolean hasState(int state) {
return this._state.getState() >= state;
}
/** @return old state */
@Override
public int setState(int state) {
// FIXME(SH): should perhaps also set state of role-CUDs??
// their state seems to skip many stages...
int oldState = super.setState(state); // may also run pending jobs
if ( oldState >= ITranslationStates.STATE_ROLE_FEATURES_COPIED
&& state < ITranslationStates.STATE_BYTE_CODE_GENERATED)
{
// we are past STATE_ROLE_FEATURES_COPIED, take care to add generated features.
// (This assumes, super team already has 'state').
if (this._ast != null)
CopyInheritance.copyGeneratedFeatures(this);
}
// TODO(SH): enable only if needed, currently such behavior triggered only in setStateRecursive(CUD,state)
// if ( this._currentlyProcessingState == ITranslationStates.STATE_NONE
// && this._requestedState > state)
// {
// this._currentlyProcessingState= this._requestedState;
// if (Dependencies.ensureRoleState(this, this._requestedState))
// this._requestedState= ITranslationStates.STATE_NONE;
// }
return oldState;
}
/**
* Override method from TypeModel:
* Also recurse into role local types.
*/
@Override
public void setMemberState(int state) {
super.setMemberState(state);
if ( state <= ITranslationStates.STATE_ROLES_SPLIT
|| state >= ITranslationStates.STATE_RESOLVED)
{
Iterator<RoleModel> localTypes = localTypes();
while (localTypes.hasNext()) {
RoleModel type = localTypes.next();
type.setState(state);
type.setMemberState(state);
}
}
}
@Override
public boolean isReadyToProcess(int state) {
if (!this._state.isReadyToProcess(state))
return false;
// check the other model, too:
RoleModel otherModel= null;
if (this._interfaceBinding != null)
otherModel= this._interfaceBinding.roleModel;
if (otherModel == null || otherModel == this) {
if (this._classBinding != null)
otherModel= this._classBinding.roleModel;
}
if (otherModel != null && otherModel != this)
return otherModel._state.isReadyToProcess(state);
return true;
}
@Override
public boolean isTeam() {
if (this._ast != null)
return this._ast.isTeam();
return this._binding.isTeam();
}
public TeamModel getTeamModelOfThis() {
// the class part has all the structure:
getClassPartAst(); // initialize
if (this._classPart != null && this._classPart.isTeam())
return this._classPart.getTeamModel();
getClassPartBinding(); // initialze
if (this._classBinding != null && this._classBinding.isTeam())
return this._classBinding.getTeamModel();
return null;
}
public static boolean isClass(ReferenceBinding memberType) {
if (!memberType.isRole())
return memberType.isClass();
ReferenceBinding realClass = memberType.getRealClass();
return realClass != null && realClass.isClass();
}
public static boolean isInterface(ReferenceBinding memberType) {
if (!memberType.isRole())
return memberType.isInterface();
// role can only be class or interface; test !class:
ReferenceBinding realClass = memberType.getRealClass();
return realClass == null || !realClass.isClass();
}
/** Is ifc the synthetic interface part of clazz? */
public static boolean isSynthIfcOfClass(ReferenceBinding ifc, ReferenceBinding clazz) {
if (ifc.isSynthInterface() && ifc.roleModel != null)
if (TypeBinding.equalsEquals(ifc.roleModel.getClassPartBinding(), clazz))
return true;
return false;
}
public static void setTagBit(ReferenceBinding role, int tagBit) {
role.roleModel.tagBits |= tagBit;
}
public static boolean hasTagBit(ReferenceBinding typeBinding, int tagBit) {
if (typeBinding.roleModel == null)
return false;
return (typeBinding.roleModel.tagBits & tagBit) != 0;
}
// ================= Byte code related methods =========================
/** Store byte code information of a method */
public void recordByteCode (
MethodBinding method,
byte[] code,
int offset,
int[] constantPoolOffsets)
{
this._methodByteCodeOffsets.put(method, new Integer(offset));
if (this._classByteCode == null) {
this._classByteCode = code;
this._constantPoolOffsets = constantPoolOffsets;
} else {
assert(this._classByteCode == code);
// when registering from IBinaryType, the code will not be modified any more.
}
}
/** Store byte code information of a method */
public static void maybeRecordByteCode(
AbstractMethodDeclaration method,
ClassFile file,
int codeAttributeOffset)
{
TypeDeclaration clazz = method.scope.referenceType();
if (clazz.isRole())
{
TypeDeclaration memberType = clazz;
RoleModel role = memberType.getRoleModel();
role.recordClassFile(method.binding, file, codeAttributeOffset);
}
}
/**
* Is this role expected to have byte code?
* Reasons for not having byte code originate in ignoreFurtherInvestigation
* and may be propagated via MethodBinding.bytecodeMissing.
* If no method with bytecode exists, no bytes have been recorded here.
*/
public boolean hasByteCode() {
if (this._classByteCode != null || this._classFile != null || this._classFilePath != null)
return true;
TypeDeclaration ast = this._ast;
if (ast == null)
ast = this._binding.isInterface() ? this._interfacePart : this._classPart;
if (ast == null) return false;
if (TypeModel.isIgnoreFurtherInvestigation(ast)) return false;
MethodBinding[] methods= ast.binding.methods();
for (MethodBinding methodBinding : methods) {
if (!methodBinding.bytecodeMissing)
return true;
}
return false;
}
/** Get the byte code of this role class.
* Must be registered with (maybe)recordByteCode
*/
public synchronized byte[] getByteCode ()
{
if (this._classByteCode == null) {
if (this._classFile == null && this._ast != null)
this._classFile = this._ast.compilationResult.findClassFile(this._binding);
if (this._classFile != null) // nullified once a class file is re-used for a different type
{
this._classByteCode = this._classFile.getBytes();
this._headerOffset = this._classFile.headerOffset;
} else {
// restore bytes from class file on disk:
try {
ClassFileReader reader = read();
if (reader == null) {
if (Config.getConfig().ignoreMissingBytecode)
return null;
throw new InternalCompilerError("Class file was not yet written to disk"); //$NON-NLS-1$
}
this._classByteCode = reader.getBytes();
this._headerOffset = reader.getHeaderOffset();
this._constantPoolOffsets = reader.getConstantPoolOffsets();
} catch (Exception e) {
throw new InternalCompilerError("cannot retrieve generated class file: "+e); //$NON-NLS-1$
}
}
}
assert(this._classByteCode != null);
return this._classByteCode;
}
/** Get the byte code offsets of this role's constant pool.
* Must be registered with (maybe)recordByteCode
*/
public int[] getConstantPoolOffsets()
{
if (this._constantPoolOffsets == null)
restoreCPOffsets();
return this._constantPoolOffsets;
}
/** Get the offset where in the byte code 'method' start.
* Must be registered with (maybe)recordByteCode
* @return method offset or -1 if source method has no byte code due to errors.
*/
public int getByteCodeOffset (MethodBinding method)
{
if (getByteCode() == null)
return -1;
Integer offset = this._methodByteCodeOffsets.get(method.original());
if (offset == null)
{
if(!method.bytecodeMissing)
throw new InternalCompilerError("Method has no byte code: "+method); // unexpectedly! //$NON-NLS-1$
return -1;
}
return offset.intValue() + this._headerOffset;
}
@Override
public synchronized void setClassFilePath(String classFilePath) {
super.setClassFilePath(classFilePath);
this._classFile = null; // don't use any more but retrieve using the class file path
if (isTeam())
getTeamModelOfThis().setClassFilePath(classFilePath);
}
/**
* Currently unusable, since bytecode may be needed any time again!
*/
public synchronized void forgetByteCode() {
this._methodByteCodeOffsets = new HashMap<MethodBinding, Integer>();
this._classFile = null;
this._classByteCode = null;
this._constantPoolOffsets = null;
}
private synchronized void recordClassFile(MethodBinding method, ClassFile file, int offset)
{
this._methodByteCodeOffsets.put(method, new Integer(offset));
if ( (this._classFile != null)
&& (this._classFile != file))
{
throw new InternalCompilerError("wrong ClassFile instance."); //$NON-NLS-1$
}
this._classFile = file;
}
private void restoreCPOffsets() {
try {
byte[] code = getByteCode();
if (code != null) {
ClassFileReader reader
= new ClassFileReader(code, NO_SOURCE_FILE); // not recording OT-attributes
this._constantPoolOffsets = reader.getConstantPoolOffsets();
}
} catch (ClassFormatException ex) {
throw new InternalCompilerError(ex.toString());
}
}
// =================== structure related methods: =================
/**
* Role name: for normal roles (with ifc part) strip of the __OT__.
* @return the name
*/
public char[] getName() {
return this._binding != null ?
this._binding.sourceName() :
this._ast.name;
}
/**
* Is this a real role from source code (not role nested)?
*/
public boolean isSourceRole() {
return this._ast != null ? this._ast.isSourceRole() : this._binding.isSourceRole();
}
/** Answer whether the role is purely copied (aka phantom role) are exists in source. */
public boolean isPurelyCopied() {
if (this._ast != null)
return this._ast.isPurelyCopied;
else
return (this._extraRoleFlags & IOTConstants.OT_CLASS_PURELY_COPIED) != 0;
}
// can be role file and/or purely copied
private int _extraRoleFlags = 0;
public boolean isRoleFile() {
if (this._ast == null)
return (this._extraRoleFlags & IOTConstants.OT_CLASS_ROLE_FILE) != 0;
return this._ast.isRoleFile();
}
public void setExtraRoleFlags(int flags) {
this._extraRoleFlags = flags;
// FIXME(SH): for role files also mark enclosing team (-> role files attribute)
}
public int getExtraRoleFlags() {
return this._extraRoleFlags;
}
public boolean isLocalType() {
if (this._binding != null)
return this._binding.isLocalType();
if (this._classBinding != null)
return this._classBinding.isLocalType();
if (this._ast != null && this._ast.scope != null)
return (this._ast.scope.parent.kind == Scope.METHOD_SCOPE);
return false;
}
public TypeDeclaration getInterfaceAst()
{
if (this._interfacePart != null)
return this._interfacePart;
if (this._ast == null)
return null; // neither class nor ifc ast present, must be binary.
if ( this._interfaceBinding != null
&& !this._ast.isInterface())
{
RoleModel interfaceModel = this._interfaceBinding.roleModel;
if (interfaceModel != null && interfaceModel != this) // model sharing didn't work
return interfaceModel.getInterfaceAst();
}
if ((this._ast.bits & ASTNode.IsLocalType) != 0)
return null;
assert this._ast.isInterface();
return this._ast;
}
public TypeDeclaration getClassPartAst()
{
if (this._classPart != null)
return this._classPart;
if (this._ast != null && !this._ast.isInterface())
return this._classPart = this._ast;
if (this._classBinding != null) {
RoleModel classRole = this._classBinding.roleModel;
if (classRole != null)
return this._classPart = classRole._ast;
}
return null;
}
public ReferenceBinding getInterfacePartBinding()
{
if (this._interfaceBinding == null) {
if (this._interfacePart != null)
this._interfaceBinding = this._interfacePart.binding;
else if (this._binding != null && this._binding.enclosingType() != null)
this._interfaceBinding = this._binding.enclosingType().getMemberType(
this._binding.sourceName()); // chop off OT_DELIM
// Sanity check:
if ( this._interfaceBinding != null && this._binding != null
&& this._interfaceBinding.isBinaryBinding() != this._binding.isBinaryBinding()) {
Scope scope = null;
if (!this._binding.isBinaryBinding())
scope = ((SourceTypeBinding)this._binding).scope;
else if (!this._interfaceBinding.isBinaryBinding())
scope = ((SourceTypeBinding)this._interfaceBinding).scope;
String message = "Mismatching binary/source class/interface parts: "+String.valueOf(this._binding.readableName())+" / "+String.valueOf(this._interfaceBinding.readableName()); //$NON-NLS-1$ //$NON-NLS-2$
if (scope != null) {
scope.problemReporter().mismatchingRoleParts(this._interfaceBinding, scope.referenceType());
} else
throw new InternalCompilerError(message);
}
}
return this._interfaceBinding;
}
public ReferenceBinding getClassPartBinding()
{
if (this._classBinding == null) {
if (this._binding == null) return null; // assuming error
if (!this._binding.isInterface())
this._classBinding = this._binding;
else if (this._binding.isSynthInterface()) {
if (this._classPart != null)
this._classBinding = this._classPart.binding;
if (this._classBinding == null)
this._classBinding = this._binding.enclosingType().getMemberType(
CharOperation.concat(IOTConstants.OT_DELIM_NAME, this._binding.internalName()));
}
}
return this._classBinding;
}
public void setTeamModel(TeamModel teamModel) {
this._teamModel = teamModel;
}
public TeamModel getTeamModel() {
if (this._teamModel == null) {
try {
if (this._binding != null)
this._teamModel = TeamModel.getEnclosingTeam(this._binding).getTeamModel();
else // ROFI: fallback if team model is required before a binding is created:
this._teamModel = this._ast.enclosingType.getTeamModel();
} catch (NullPointerException npe) {
throw new InternalCompilerError("Missing enclosing team for "+this+"\n" //$NON-NLS-1$ //$NON-NLS-2$
+(this._ast != null ? this._ast : this._binding));
}
}
return this._teamModel;
}
/**
* Retrieve the tsuper role with highest priority.
*
* Note, that more tsuper roles may exist due to team nesting.
* TODO (SH): need to check all callers, whether reading just the first
* tsuper role is OK!
*
* @return first tsuper role or null
*/
public ReferenceBinding getTSuperRoleBinding() {
return this._tsuperRoleBindings[this.numTSuperRoles > 0 ? this.numTSuperRoles-1 : 0];
}
/** Answer all direct tsuper roles of this role in ascending priority. */
public ReferenceBinding[] getTSuperRoleBindings() {
ReferenceBinding[] tsupers = new ReferenceBinding[this.numTSuperRoles];
System.arraycopy(this._tsuperRoleBindings, 0, tsupers, 0, this.numTSuperRoles);
return tsupers;
}
/** Does this role have any tsuper role, other than the predefined roles from Team? */
public boolean hasRelevantTSuperRole() {
return this.numTSuperRoles > 0
&& !TypeAnalyzer.isPredefinedRole(getBinding());
}
/**
* Is role some kind of tsuper role of current?
* It could be that any enclosing teams are role-and-tsuper-role.
* Then from there on inwards only role names are compared.
*/
public boolean hasTSuperRole(ReferenceBinding role) {
if (!role.isRole())
return false;
ReferenceBinding otherClass = null, otherIfc = null;
if(role.isInterface()) {
otherIfc = role;
otherClass = role.getRealClass();
} else {
otherIfc = role.getRealType();
otherClass = role;
}
Dependencies.ensureRoleState(this, ITranslationStates.STATE_LENV_CONNECT_TYPE_HIERARCHY);
for (int i = 0; i < this.numTSuperRoles; i++) {
ReferenceBinding other = this._tsuperRoleBindings[i].isInterface() ? otherIfc : otherClass;
if (TypeBinding.equalsEquals(this._tsuperRoleBindings[i], other))
return true;
if (this._tsuperRoleBindings[i].roleModel.hasTSuperRole(other))
return true;
}
ReferenceBinding outerRole = this._binding.enclosingType();
if (outerRole.isRole()) {
ReferenceBinding roleOuter = role.enclosingType();
if (!roleOuter.isRole())
return false;
if (!outerRole.roleModel.hasTSuperRole(roleOuter))
return false;
return CharOperation.equals(role.internalName(), this._binding.internalName());
}
return false;
}
@Override
public void setBinding (ReferenceBinding binding) {
this._binding = binding;
binding.roleModel = this;
}
// -------------- local types -----------------
/**
* An binary local type was requested during resolve.
* Maybe fix enclosingType and enter to _localTypes.
*
* @param local
*/
public void addBinaryLocalType (ReferenceBinding local) {
if (local instanceof BinaryTypeBinding) {
((BinaryTypeBinding)local).setEnclosingOfRoleLocal(this._binding);
}
this._localTypes.add(local.roleModel);
}
/**
* A local type was read from source code.
* Record it as part (though not member) of this role.
* @param local
*/
public void addLocalType (char[] constantPoolName, RoleModel local) {
this._localTypes.add(local);
local._isLocalType = true;
if (constantPoolName != null) {
if (this._ast != null) {
Scope scope = this._ast.scope;
if (scope != null) {
CompilationUnitScope cuScope = scope.compilationUnitScope();
cuScope.registerLocalType(constantPoolName, local.getAst());
}
}
}
if (this._attributes != null)
for (AbstractAttribute attribute : this._attributes)
if (attribute.nameEquals(IOTConstants.ROLE_LOCAL_TYPES))
return;
addAttribute(new RoleLocalTypesAttribute(this));
}
/**
* The method at [sourceStart-sourceEnd] was found to have errors.
* Purge all recorded local types contained in that method (based on source positions).
* @param sourceStart
* @param sourceEnd
*/
public void purgeLocalTypes(int sourceStart, int sourceEnd) {
Iterator<RoleModel> iterator = this._localTypes.iterator();
while (iterator.hasNext()) {
RoleModel role = iterator.next();
TypeDeclaration ast = role.getAst();
if (ast != null && sourceStart < ast.sourceStart && ast.declarationSourceEnd < sourceEnd) {
iterator.remove();
}
}
}
public void maybeAddLocalToEnclosing() {
ReferenceBinding enclosing= this._binding.enclosingType();
if (enclosing != null && enclosing.isRole()) {
enclosing.roleModel.addBinaryLocalType(this._binding);
}
}
/**
* Get source type bindings for all local types ready to
* write the RoleLocalTypesAttribute.
*
* @return a new non-null array
*/
public ReferenceBinding[] getLocalTypes() {
ReferenceBinding[] types = new ReferenceBinding[this._localTypes.size()];
int j = 0;
for (int i=0; i<types.length; i++) {
types[j] = this._localTypes.get(i).getBinding();
if (types[j] != null)
j++;
}
if (j != types.length)
System.arraycopy(types, 0,
types = new ReferenceBinding[j], 0,
j);
return types;
}
/**
* Get role models of all recorded local types of this role.
* Resolve these types if needed.
*/
public Iterator<RoleModel> localTypes() {
return this._localTypes.iterator();
}
/**
* Find a type by its compound name.
* First look in local types (including enclosing roles).
* Second use the environment for lookup.
* This method is needed since local types are not stored in the environment.
*
* @param environment
* @param compoundName
* @return type specified by compoundName
*/
@Override
public ReferenceBinding findType(LookupEnvironment environment, char[][] compoundName)
{
char[][] myName = CharOperation.splitOn('/', this._binding.constantPoolName());
if ( this._binding.isLocalType()
&& CharOperation.equals(compoundName, myName))
return this._binding;
Iterator<RoleModel> locals = localTypes();
while (locals.hasNext()) {
RoleModel role = locals.next();
char[][] roleName = CharOperation.splitOn('/', role.getBinding().constantPoolName());
if (CharOperation.equals(compoundName, roleName))
return role.getBinding();
}
if (this._binding.enclosingType().isRole())
return this._binding.enclosingType().roleModel.findType(environment, compoundName);
return environment.getType(compoundName);
}
/**
* Similar to the above, but comparison is made be relative names, ie., team names
* as prefix are chopped of. Instead of an environment the scope of this role is used.
*
* @param compoundName
* @return type as specified by compoundName
*/
public ReferenceBinding findTypeRelative(char[] compoundName)
{
ReferenceBinding teamBinding = TeamModel.getEnclosingTeam(this._binding);
if (this._binding.isLocalType())
{
if (TypeAnalyzer.equalRoleLocal(teamBinding, this._binding, compoundName))
return this._binding;
} else {
if (CharOperation.equals(this._binding.internalName(), compoundName))
return this._binding;
}
Iterator<RoleModel> locals = localTypes();
while (locals.hasNext())
{
RoleModel role = locals.next();
if (TypeAnalyzer.equalRoleLocal(teamBinding, role.getBinding(), compoundName))
return role.getBinding();
}
if (this._binding.enclosingType().isRole())
return this._binding.enclosingType().roleModel.findTypeRelative(compoundName);
if (this._ast != null)
return (ReferenceBinding)this._ast.scope.getType(compoundName);
return null;
}
private boolean hasCheckedBaseclass= false; // caching the result the below method
private boolean isBound; // --"--
/**
* @return is this role bound to a base type?
*/
public boolean isBound() {
if (this.hasCheckedBaseclass)
return this.isBound;
this.hasCheckedBaseclass= true;
if ( this._ast != null
&& this._ast.baseclass != null)
return this.isBound= true;
if (this._binding != null) {
if (this._binding.rawBaseclass() != null)
return this.isBound= true;
ReferenceBinding superRole = this._binding.superclass();
if ( superRole != null
&& superRole.isRole()
&& superRole.roleModel.isBound())
return this.isBound= true;
}
for (int i=0; i<this.numTSuperRoles; i++) {
if (this._tsuperRoleBindings[i].roleModel.isBound())
return this.isBound= true;
}
return this.isBound= false;
}
public boolean hasBaseclassProblem() {
if ((this.tagBits & BaseclassHasProblems) != 0)
return true;
ReferenceBinding binding = (this._classBinding != null) ? this._classBinding : this._binding;
if (binding.superclass() != null) {
ReferenceBinding superclass = binding.superclass();
if ( ( superclass.isRole()
&& superclass.isHierarchyInconsistent())
|| ( (superclass.roleModel != null)
&& (superclass.roleModel.hasBaseclassProblem())))
{
this.tagBits |= BaseclassHasProblems;
return true;
}
}
return false;
}
public static boolean isRoleWithBaseProblem(TypeDeclaration declaration) {
if (!declaration.isSourceRole())
return false;
return declaration.getRoleModel().hasBaseclassProblem();
}
public ReferenceBinding getBaseTypeBinding() {
return this._binding.baseclass();
}
/**
* Is current a direct supertype of model?
* Considers superClass and superInterfaces
*/
public boolean isSuperTypeOf(RoleModel model) {
if (this._binding.isSuperclassOf(model.getBinding()))
return true;
ReferenceBinding[] superInterfaces =
(model.getInterfacePartBinding() != null) ?
model.getInterfacePartBinding().superInterfaces():
model.getClassPartBinding().superInterfaces();
if (superInterfaces != null)
{
for (int i=0; i<superInterfaces.length; i++) {
if (TypeBinding.equalsEquals(superInterfaces[i], this._binding))
return true;
}
}
return false;
}
public RoleModel getExplicitSuperRole()
{
ReferenceBinding superClass = this._binding.superclass();
if(superClass.superclass() == null)
{
//superClass is java.lang.Object
return null;
}
return this._binding.superclass().roleModel;
}
public RoleModel getImplicitSuperRole()
{
if(getTSuperRoleBinding() == null)
{
return null;
}
return getTSuperRoleBinding().roleModel;
}
/**
* Give the most general role type on the path between this role
* and it's tsub version which is visible in 'scope'.
* @pre startRole.baseclass() != null
* @return non-null
*/
public static ReferenceBinding getTopmostBoundRole(BlockScope scope, ReferenceBinding startRole) {
ReferenceBinding current = startRole;
ReferenceBinding candidate = null;
while (current != null) {
if (!current.isRole())
return candidate;
if (current.baseclass() != null) // true at least in first iteration.
candidate = current;
else
return candidate;
current = current.roleModel.getTSuperRoleBinding();
}
return candidate;
}
public RoleModel getCopyInheritanceSource() {
if (!isPurelyCopied())
return this;
for (int i = 0; i < this._tsuperRoleBindings.length; i++) {
if (this._tsuperRoleBindings[i] != null) {
RoleModel model = this._tsuperRoleBindings[i].roleModel.getCopyInheritanceSource();
if (model != null)
return model;
}
}
throw new InternalCompilerError("Unable to find real tsuper role of phantom role "+this);
}
/**
* Store the known sub roles (including this) as determined by RoleHierarchyAnalyzer.analyze().
*
* @param subRoles
*/
public void setSubRoles(RoleModel[] subRoles) {
this._subRoles = subRoles;
}
/**
* Retrieve the known sub roles (including this) as determined by RoleHierarchyAnalyzer.analyze().
*/
public RoleModel[] getSubRoles() {
return this._subRoles;
}
RoleModel getSuperIfcRole(int idx) {
if (getInterfacePartBinding().superInterfaces() == null)
return null;
if (getInterfacePartBinding().superInterfaces().length <= idx)
return null;
ReferenceBinding ifc = getInterfacePartBinding().superInterfaces()[idx];
if (ifc.isSourceRole())
return ifc.roleModel;
return null;
}
int getNumSuperIfc () {
if (this._binding.superInterfaces() == null)
return 0;
return this._binding.superInterfaces().length;
}
public boolean isSynthInterface() {
int AccSynthIfc = AccInterface|AccSynthetic;
return (this._binding.modifiers & AccSynthIfc) == AccSynthIfc;
}
public boolean isRegularInterface() {
return this._binding.isRegularInterface();
}
public boolean equals(RoleModel other) {
if (other == null) return false;
if (this._interfaceBinding != null && other._interfaceBinding != null)
return TypeBinding.equalsEquals(this._interfaceBinding, other._interfaceBinding);
if (this._classBinding != null && other._classBinding != null)
return TypeBinding.equalsEquals(this._classBinding, other._classBinding);
return this._ast == other._ast;
}
/**
* Record the interface part of a copied role.
* @param roleIfcs map of interface indexed by name (String)
*/
public void recordIfcPart(HashMap<String,TypeDeclaration> roleIfcs) {
if (this._interfacePart == null) {
// defensively search the interface part's name:
String ifcName = null;
if (this._binding != null)
ifcName = new String(this._binding.sourceName());
else if (this._ast != null) {
if (RoleSplitter.isClassPartName(this._ast.name))
ifcName = new String(RoleSplitter.getInterfacePartName(this._ast.name));
}
// on incredibly broken code, ifcName may still be null (see TPX-423).
if (ifcName != null) {
this._interfacePart = roleIfcs.get(ifcName);
checkClassAndIfcParts();
} else {
assert this._ast == null || this._ast.ignoreFurtherInvestigation : "should only ever happen one erroneous code"; //$NON-NLS-1$
}
}
}
public void checkClassAndIfcParts() {
boolean hasError = false;
Scope scope = null;
char[] ifcName = null;
char[] className = null;
if (this._interfacePart != null && this._classPart != null) {
scope = this._classPart.scope;
ifcName = this._interfacePart.name;
className = this._classPart.name;
if (this._interfacePart.enclosingType != this._classPart.enclosingType)
hasError = true;
}
if (this._interfaceBinding != null && this._classBinding != null) {
// binding names contain more information:
ifcName = this._interfaceBinding.readableName();
className = this._classBinding.readableName();
if (TypeBinding.notEquals(this._interfaceBinding.enclosingType(), this._classBinding.enclosingType()))
hasError = true;
}
if (hasError) {
if (scope == null)
if (this._ast != null)
scope = this._ast.scope;
if (scope == null)
throw new InternalCompilerError("Multiple errors processing role "+toString()); //$NON-NLS-1$
scope.problemReporter().inconsistentlyResolvedRole(this._ast, ifcName, className);
}
}
/**
* Once team and tsuper role are known, record this information.
*/
public void connect(TeamModel teamModel, ReferenceBinding tsuperRole) {
setTeamModel(teamModel);
ReferenceBinding superTeamBinding = teamModel.getBinding().superclass();
if (superTeamBinding instanceof ParameterizedTypeBinding && !(tsuperRole instanceof ParameterizedTypeBinding)) {
LookupEnvironment env = Config.getLookupEnvironment();
if (env != null) {
tsuperRole = env.createParameterizedType(tsuperRole, null, superTeamBinding);
RoleModel.setTagBit(tsuperRole, RoleModel.IsViewedAsTSuper);
}
}
boolean tsuperAlreadyPresent = false;
for (int i = 0; i < this.numTSuperRoles; i++) {
if (TypeBinding.equalsEquals(this._tsuperRoleBindings[i], tsuperRole)) {
tsuperAlreadyPresent = true;
break;
}
}
if (!tsuperAlreadyPresent) {
if (this.numTSuperRoles == this._tsuperRoleBindings.length)
System.arraycopy(
this._tsuperRoleBindings, 0,
this._tsuperRoleBindings = new ReferenceBinding[2*this.numTSuperRoles], 0,
this.numTSuperRoles);
this._tsuperRoleBindings[this.numTSuperRoles++] = tsuperRole;
if (getAst() != null && getAst().isInterface())
TypeLevel.addImplicitInheritance(getAst(), tsuperRole);
int otClassFlags = IOTConstants.OT_CLASS_FLAG_HAS_TSUPER;
if (tsuperRole.roleModel.hasFinalFieldInit())
otClassFlags |= IOTConstants.OT_CLASS_HAS_FINAL_FIELD_INITS;
WordValueAttribute.addClassFlags(this, otClassFlags);
if (this._binding != null)
this._binding.modifiers |= AccOverriding;
}
// invoked from copy role we have at least this state:
this._state.inititalize(ITranslationStates.STATE_ROLES_SPLIT);
}
public boolean hasFinalFieldInit() {
AbstractAttribute attribute = getAttribute(IOTConstants.OT_CLASS_FLAGS);
if (attribute instanceof WordValueAttribute) {
if ((((WordValueAttribute) attribute).getValue() & IOTConstants.OT_CLASS_HAS_FINAL_FIELD_INITS) != 0)
return true;
}
if (this._classPart != null && this._classPart.fields != null) {
for (FieldDeclaration field : this._classPart.fields) {
if (field.initialization != null && field.isFinal())
return true;
}
}
return false;
}
@Override
protected String getKindString() {
return "Role"; //$NON-NLS-1$
}
/**
* @param srcMethod
* @param dstMethod
*/
public void addSyntheticMethodMapping(MethodBinding srcMethod, MethodBinding dstMethod) {
this._syntheticMap.put(srcMethod, dstMethod);
}
public MethodBinding mapSyntheticMethod (MethodBinding srcMethod) {
if (srcMethod instanceof SyntheticRoleFieldAccess) {
// matching by name
ReferenceBinding dstType = getBinding();
if (dstType.isBinaryBinding())
return null; // will be found within methods
SyntheticMethodBinding[] synthetics = ((SourceTypeBinding)dstType).syntheticMethods();
if (synthetics == null)
return null;
for (SyntheticMethodBinding methodBinding : synthetics) {
if (CharOperation.equals(methodBinding.selector, srcMethod.selector))
return methodBinding;
}
return null;
} else {
// matching by map
return (MethodBinding)this._syntheticMap.get(srcMethod);
}
}
/**
* @param srcField a synthetic field from tsuper
* @param newField the synthetic new field copy
*/
public void addSyntheticFieldMapping(FieldBinding srcField, FieldBinding newField) {
this._syntheticMap.put(srcField, newField);
}
public FieldBinding mapSyntheticField(FieldBinding srcField) {
return (FieldBinding)this._syntheticMap.get(srcField);
}
/**
* Record that the given method is only accessible using decapsulation.
* @param binding
*/
public int addInaccessibleBaseMethod(MethodBinding binding) {
// push out to the team to ensure early evaluation by the OTRE:
OTSpecialAccessAttribute specialAccess = getTeamModel().getSpecialAccessAttribute();
ReferenceBinding declaringClass = binding.declaringClass;
specialAccess.addAdaptedBaseClass(declaringClass);
ReferenceBinding baseclass = this._binding.baseclass();
boolean visibleInBaseClass = true;
if (getWeavingScheme() == WeavingScheme.OTDRE) {
TypeBinding declaringOriginal = declaringClass.original();
if (binding.isPrivate()) {
visibleInBaseClass = TypeBinding.equalsEquals(baseclass.original(), declaringOriginal);
} else if (binding.isDefault()) {
PackageBinding tgtPackage = declaringClass.fPackage;
ReferenceBinding currentType = baseclass;
while (currentType != null && TypeBinding.notEquals(currentType.original(), declaringOriginal)) {
if (tgtPackage != currentType.fPackage) {
visibleInBaseClass = false;
break;
}
currentType = currentType.superclass();
}
}
}
return specialAccess.addDecapsulatedMethodAccess(baseclass, binding, visibleInBaseClass);
}
/**
* Record that a given field is accessed using callout.
* @param field
* @param calloutModifier either TokenNameget or TokenNameset (from TerminalTokens).
* @return the accessId (per team) for this field
*/
public int addAccessedBaseField(FieldBinding field, int calloutModifier, CalloutToFieldDesc cpInheritanceSrc) {
// find appropriate target class
ReferenceBinding targetClass = field.declaringClass; // default: the class declaring the field (could be super of bound base)
if (!field.isStatic() && (field.isProtected() || field.isPublic()))
targetClass = getBaseTypeBinding(); // use the specific declared bound class (avoids weaving into possibly inaccessible super base)
// push out to the team to ensure early evaluation by the OTRE:
OTSpecialAccessAttribute specialAccess = getTeamModel().getSpecialAccessAttribute();
int accessId = specialAccess.addCalloutFieldAccess(field, targetClass, calloutModifier, cpInheritanceSrc);
specialAccess.addAdaptedBaseClass(field.declaringClass);
return accessId;
}
/**
* Record that a base call needs access to the base.super-method.
* @param baseMethod
*/
public void addMethodSuperAccess(MethodBinding baseMethod) {
OTSpecialAccessAttribute specialAccess = getTeamModel().getSpecialAccessAttribute();
specialAccess.addSuperMethodAccess(baseMethod);
}
/**
* Record that an inaccessible base is bound.
* @param baseclass
*/
public void markBaseClassDecapsulation(ReferenceBinding baseclass) {
// push out to the team to ensure early evaluation by the OTRE:
OTSpecialAccessAttribute specialAccess = getTeamModel().getSpecialAccessAttribute();
specialAccess.addBaseClassDecapsulation(baseclass);
}
/** Hook into attribute writing in order to insert callout mappings attribute. */
@Override
public int writeAttributes(ClassFile file) {
if (this._binding.callinCallouts != null) {
for (int i = 0; i < this._binding.callinCallouts.length; i++) {
if (this._binding.callinCallouts[i].type != CallinCalloutBinding.CALLIN) // callout or -override
{
addAttribute(new CalloutMappingsAttribute(this));
break;
}
}
}
return super.writeAttributes(file);
}
@Override
public CPTypeAnchorAttribute getTypeAnchors() {
return this._binding.model.getTypeAnchors();
}
public void setErrorFlag(boolean flag) {
if (this._ast != null)
this._ast.ignoreFurtherInvestigation = flag;
if (this._classPart != null)
this._classPart.ignoreFurtherInvestigation = flag;
if (this._interfacePart != null)
this._interfacePart.ignoreFurtherInvestigation = flag;
}
public void recordCopiedFeature(Binding feature) {
this._copiedFeatureBindings.add(feature);
}
public boolean hasAlreadyBeenCopied(Binding feature) {
return this._copiedFeatureBindings.contains(feature);
}
/** The Attributename of this role's baseclass as it is used in bytecode attributes.
* PRE: this is a bound role.
* @param includeAnchor should anchored types be encoded in full?
*/
public char[] getBaseclassAttributename(boolean includeAnchor) {
ReferenceBinding baseclass = getBinding().baseclass();
char[] baseName = baseclass.getRealClass().attributeName();
if (includeAnchor && RoleTypeBinding.isRoleWithExplicitAnchor(baseclass))
return CharOperation.concat(baseName,
CharOperation.concat(SingleValueAttribute.ANCHOR_DELIM,
CharOperation.append(((RoleTypeBinding)baseclass)._teamAnchor.getBestName(), '>')));
return baseName;
}
/* (non-Javadoc)
* @see org.eclipse.objectteams.otdt.internal.core.compiler.model.TypeModel#cleanup()
*/
@Override
public void cleanup()
{
super.cleanup();
this._copiedFeatureBindings = null;
}
public RoleModel getBoundRootRole() {
if (this._boundRootRole != null)
return this._boundRootRole;
if (this._binding.isInterface() && this._classBinding != null)
{
RoleModel classPart = this._classBinding.roleModel;
return classPart.getBoundRootRole();
}
return null;
}
public static int getDeclaredModifiers(ReferenceBinding typeBinding) {
if (!typeBinding.isRole() || typeBinding.roleModel == null)
return typeBinding.modifiers;
ReferenceBinding classPartBinding = typeBinding.roleModel.getClassPartBinding();
if (classPartBinding != null)
return classPartBinding.modifiers;
return typeBinding.modifiers;
}
public static boolean isRoleFromOuterEnclosing(SourceTypeBinding sourceType,
ReferenceBinding baseclass)
{
ReferenceBinding enclosingTeam = sourceType.enclosingType();
if (enclosingTeam == null || !enclosingTeam.isTeam())
return false;
if (TypeBinding.equalsEquals(enclosingTeam, baseclass.enclosingType()))
return false;
while (true) {
enclosingTeam = enclosingTeam.enclosingType();
if (enclosingTeam == null || !enclosingTeam.isTeam())
return false;
if (TypeBinding.equalsEquals(enclosingTeam, baseclass.enclosingType()))
return true;
}
}
public boolean hasCallins() {
if (this._attributes == null)
return false;
for (AbstractAttribute attribute : this._attributes)
if (attribute.nameEquals(IOTConstants.CALLIN_METHOD_MAPPINGS)) {
// don't report if all callins are inherited:
if (!((CallinMethodMappingsAttribute)attribute).isInherited())
return true;
}
return false;
}
/**
* After attributes are evaluated, each role class must check, whether it is
* supposed to implement method mappings inherited from a super interface.
*/
public void implementMethodBindingsFromSuperinterfaces() {
if (this._ast == null || this._ast.isInterface() || this._binding == null || this._binding.isLocalType())
return;
ReferenceBinding interfacePartBinding = getInterfacePartBinding();
if (interfacePartBinding == null) // paranoia
return;
ReferenceBinding[] superInterfaces = interfacePartBinding.superInterfaces();
if (superInterfaces == null) // paranoia (null seen in real life)
return;
for (ReferenceBinding superInterface : superInterfaces)
{
if (!superInterface.isRole())
continue;
if (superInterface.roleModel.getState() < ITranslationStates.STATE_LATE_ATTRIBUTES_EVALUATED-1)
continue; // not yet prepared
if (!Dependencies.ensureBindingState(superInterface, ITranslationStates.STATE_LATE_ATTRIBUTES_EVALUATED))
continue;
CallinCalloutBinding[] methodMappings = superInterface.callinCallouts;
if (methodMappings != null)
for (CallinCalloutBinding mapping : methodMappings)
if (mapping.isValidBinding() && mapping.isCallout())
new CalloutImplementor(this).generateFromBinding(mapping);
}
}
@Override
public void evaluateLateAttributes(int state) {
if (state == ITranslationStates.STATE_LATE_ATTRIBUTES_EVALUATED) {
for (ReferenceBinding tsuperRole : this.getTSuperRoleBindings())
Dependencies.ensureBindingState(tsuperRole, ITranslationStates.STATE_LATE_ATTRIBUTES_EVALUATED);
}
if (this._ast != null)
CopyInheritance.copyGeneratedFeatures(this);
super.evaluateLateAttributes(state);
}
public synchronized void releaseClassFile() {
this._classFile= null;
}
/**
* Starting with this role look for subtypes that are bound, returning all top-bound roles.
* @return non-null
*/
public ReferenceBinding[] getBoundDescendants() {
if (this._binding == null)
return new ReferenceBinding[0];
if (this._binding.baseclass() != null)
return new ReferenceBinding[]{this._binding};
ArrayList<ReferenceBinding> roles = new ArrayList<ReferenceBinding>();
for (ReferenceBinding knownRole: getTeamModel().getKnownRoles()) {
if (knownRole.baseclass() == null) continue; // not bound
if (!knownRole.isCompatibleWith(this._binding)) continue; // not compatible
if (knownRole.superclass().baseclass() != null) continue; // not top
if (knownRole.isClass()) continue; // only record ifc to avoid dupes
roles.add(knownRole);
}
return roles.toArray(new ReferenceBinding[roles.size()]);
}
/** recored here any unimplemented getBase method:
* <_OT$AnyBase base R> _OT$getBase() { throw new AbstractMethodError(); }
*/
public MethodBinding unimplementedGetBase;
/**
* If an unbound super role exists return its unimplemented getBase method.
*/
public MethodBinding getInheritedUnimplementedGetBase() {
ReferenceBinding classPartBinding = getClassPartBinding();
if (classPartBinding != null) {
ReferenceBinding superclass = classPartBinding.superclass();
while (superclass != null && superclass.isRole()) {
RoleModel superRole = superclass.roleModel;
if (superRole.unimplementedGetBase != null)
return superRole.unimplementedGetBase;
superclass = superclass.superclass();
}
}
return null;
}
public static Lifting.InstantiationPolicy getInstantiationPolicy(ReferenceBinding roleClassBinding) {
if ((roleClassBinding.getAnnotationTagBits() & TagBits.AnnotationInstantiation) != 0) {
for (AnnotationBinding annotation : roleClassBinding.getAnnotations()) {
if (annotation.getAnnotationType().id == IOTConstants.T_OrgObjectTeamsInstantiation) {
for (ElementValuePair pair : annotation.getElementValuePairs()) {
if (pair.value instanceof FieldBinding) {
String name = String.valueOf(((FieldBinding) pair.value).name);
try {
return InstantiationPolicy.valueOf(name);
} catch (IllegalArgumentException iae) {
return InstantiationPolicy.ERROR;
}
}
}
}
}
}
return InstantiationPolicy.ONDEMAND; // default
}
public static boolean areTypeParametersOfSameRole(TypeVariableBinding one, Binding two) {
if (!(two instanceof TypeVariableBinding))
return false;
Binding declaring1 = one.declaringElement;
Binding declaring2 = ((TypeVariableBinding)two).declaringElement;
if ( !(declaring1 instanceof ReferenceBinding)
|| !(declaring2 instanceof ReferenceBinding))
return false;
return TypeBinding.equalsEquals(((ReferenceBinding)declaring1).getRealType(), ((ReferenceBinding)declaring2).getRealType());
}
public void markCallinOverride(char[] name, RoleModel subRole) {
if (this._ast == null || this._ast.callinCallouts == null)
return;
for (AbstractMethodMappingDeclaration mapping : this._ast.callinCallouts) {
if (mapping instanceof CallinMappingDeclaration) {
CallinMappingDeclaration callin = (CallinMappingDeclaration) mapping;
if (callin.hasName() && CharOperation.equals(name, callin.name)) {
callin.isOverriddenInTeam = true;
this._ast.scope.problemReporter().callinOverriddenInTeam(callin, subRole);
}
}
}
}
}