Java tutorial
/********************************************************************** * This file is part of "Object Teams Development Tooling"-Software * * Copyright 2003, 2006 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 * $Id: TypeAnalyzer.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.util; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; import org.eclipse.jdt.internal.compiler.ast.Expression; import org.eclipse.jdt.internal.compiler.ast.ExpressionContext; import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding; import org.eclipse.jdt.internal.compiler.lookup.Binding; import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; import org.eclipse.jdt.internal.compiler.lookup.InferenceContext18; import org.eclipse.jdt.internal.compiler.lookup.InvocationSite; import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; import org.eclipse.jdt.internal.compiler.lookup.MemberTypeBinding; import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; import org.eclipse.jdt.internal.compiler.lookup.MethodScope; import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; import org.eclipse.jdt.internal.compiler.lookup.ProblemFieldBinding; import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons; import org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding; 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.TypeBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; 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.ast.TypeAnchorReference; 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.lookup.DependentTypeBinding; import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.ITeamAnchor; import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.RoleTypeBinding; import org.eclipse.objectteams.otdt.internal.core.compiler.model.TeamModel; /** * Utility class for analyzing, and generating types. * Handles bindings, names and references. * * @author stephan <i>stephan@cs.tu-berlin.de</i> * @version $Id: TypeAnalyzer.java 23416 2010-02-03 19:59:31Z stephan $ */ public class TypeAnalyzer { public static final int EXACT_MATCH_ONLY = 1; public static final int NEEDING_ADJUSTMENT_ONLY = 2; public static final int ANY_MATCH = 3; /** * Given a method in a super Team, check wether the method declaration * from the sub Team is "the same method", which means, that role type * adjustments are taken into consideration. * These kinds of comparison are supported: * <dt> * <dt>EXACT_MATCH_ONLY * <dd> these mathods are the same even in plain Java * <dt>NEEDING_ADJUSTMENT_ONLY * <dd> only answer "true" if any parameter needs weakening * <dt>ANY_MATCH * <dd> answer "true" if either kind of match is encountered. * </dt> * @param superTeam * @param superMeth * @param subTeam * @param subMeth * @param matchKind one of the above constants. * @return the answer */ public static boolean isEqualMethodSignature(ReferenceBinding superTeam, MethodBinding superMeth, ReferenceBinding subTeam, MethodBinding subMeth, int matchKind) { if (subMeth.parameters.length != superMeth.parameters.length) return false; TypeBinding[] params = subMeth.parameters; boolean needAdjustment = false; for (int i = 0; i < params.length; i++) { TypeBinding param = params[i]; TypeBinding superTypeBind = superMeth.parameters[i]; if (TypeBinding.equalsEquals(param, superTypeBind)) continue; if (areTypesMatchable(param, subTeam, superTypeBind, superTeam, matchKind)) { needAdjustment = true; } else { return false; } } if (matchKind == NEEDING_ADJUSTMENT_ONLY) return needAdjustment; return true; } /** * Answer, whether two reference bindings are views of the same role * possibly seen from different teams. */ public static boolean isSameRole(ReferenceBinding r1, ReferenceBinding r2) { if (TypeBinding.equalsEquals(r1, r2)) return true; if (r1 == null || r2 == null) return false; if (!(r1.isRole() && r2.isRole())) return false; ReferenceBinding t1 = r1.enclosingType(); ReferenceBinding t2 = r2.enclosingType(); if (TypeBinding.equalsEquals(t1, t2) || t1 == null || t2 == null) return false; // not two different teams: no other chance.. if (!(t1.isCompatibleWith(t2) || t2.isCompatibleWith(t1))) return false; // not sub/super teams. return CharOperation.equals(r1.internalName(), r2.internalName()); } /** does role refine the extends clause of its tsuper role? */ public static boolean refinesExtends(ReferenceBinding role, ReferenceBinding tsuperRole) { return !isSameRole(role.superclass(), tsuperRole.superclass()); } /** * Answer, whether two type are the same, when regarding a class and an * interface part of a role as identical. */ public static boolean isSameType(ReferenceBinding site, TypeBinding t1, TypeBinding t2) { if (TypeBinding.equalsEquals(t1, t2)) return true; if (t1 == null || t2 == null) return false; if (t1.isArrayType()) { if (!t2.isArrayType() || (t1.dimensions() != t2.dimensions())) return false; t1 = t1.leafComponentType(); t2 = t2.leafComponentType(); } else if (t2.isArrayType()) { return false; } if (t1.isBaseType()) return TypeBinding.equalsEquals(t1, t2); if (t2.isBaseType()) return false; ReferenceBinding r1 = (ReferenceBinding) t1; ReferenceBinding r2 = (ReferenceBinding) t2; if (r1.isDirectRole() && r2.isDirectRole()) { r2 = (ReferenceBinding) TeamModel.strengthenRoleType(site, r2); return TypeBinding.equalsEquals(r1.roleModel.getInterfacePartBinding(), r2.roleModel.getInterfacePartBinding()); } return false; } /** * Are type compatible possibly performing role type adjustment? * @param currentType * @param subTeam * @param tsuperType * @param superTeam * @param matchKind * @return the answer */ public static boolean areTypesMatchable(TypeBinding currentType, ReferenceBinding subTeam, TypeBinding tsuperType, ReferenceBinding superTeam, int matchKind) { // be very defensive: if (currentType instanceof ProblemReferenceBinding) { TypeBinding closestMatch = ((ProblemReferenceBinding) currentType).closestMatch(); if (closestMatch == null) return CharOperation.equals(currentType.sourceName(), tsuperType.sourceName()); currentType = closestMatch; } if (tsuperType instanceof ProblemReferenceBinding) { TypeBinding closestMatch = ((ProblemReferenceBinding) tsuperType).closestMatch(); if (closestMatch == null) return CharOperation.equals(currentType.sourceName(), tsuperType.sourceName()); tsuperType = closestMatch; } // if it's array-types, compare dimension and extract leafComponentType if ((currentType instanceof ArrayBinding) || (tsuperType instanceof ArrayBinding)) { if (!(tsuperType instanceof ArrayBinding) || !(currentType instanceof ArrayBinding)) return false; ArrayBinding currentArray = (ArrayBinding) currentType; ArrayBinding superArray = (ArrayBinding) tsuperType; if (currentArray.dimensions() != superArray.dimensions()) return false; currentType = currentArray.leafComponentType(); tsuperType = superArray.leafComponentType(); } // guaranteed to be scalar now if (currentType instanceof ReferenceBinding) { if (currentType instanceof DependentTypeBinding) currentType = ((DependentTypeBinding) currentType).getRealType(); if (!(tsuperType instanceof ReferenceBinding)) return false; if (tsuperType instanceof DependentTypeBinding) tsuperType = ((DependentTypeBinding) tsuperType).getRealType(); if (currentType.isParameterizedType() || tsuperType.isParameterizedType()) { // at least one type parameterized: get erasure(s) if (currentType.isParameterizedType()) { if (tsuperType.isParameterizedType()) { // both parameterized: check parameters: ParameterizedTypeBinding currentParameterized = ((ParameterizedTypeBinding) currentType); ParameterizedTypeBinding tsuperParameterized = ((ParameterizedTypeBinding) tsuperType); if (!CharOperation.equals(currentParameterized.genericTypeSignature, tsuperParameterized.genericTypeSignature)) return false; } else if (!tsuperType.isRawType()) { return false; // mismatch generic vs. non-generic } } else if (!currentType.isRawType()) { return false; // mismatch non-generic vs. generic } currentType = currentType.erasure(); tsuperType = tsuperType.erasure(); } if (currentType.isTypeVariable() && tsuperType.isTypeVariable()) return TypeBinding.equalsEquals(currentType, tsuperType); char[][] tname1 = compoundNameOfReferenceType((ReferenceBinding) tsuperType, true, true); char[][] tname2 = compoundNameOfReferenceType((ReferenceBinding) currentType, true, true); if (CharOperation.equals(tname1, tname2)) { if (TypeBinding.notEquals(tsuperType, currentType) && tsuperType.isValidBinding()) // don't complain about different missing types throw new InternalCompilerError( "different bindings for the same type??" + currentType + ':' + tsuperType); //$NON-NLS-1$ return true; } if (matchKind == EXACT_MATCH_ONLY) { return false; } else { tname1 = splitTypeNameRelativeToTeam((ReferenceBinding) tsuperType, superTeam); tname2 = splitTypeNameRelativeToTeam((ReferenceBinding) currentType, subTeam); if (!CharOperation.equals(tname1, tname2)) return false; } } else if (currentType instanceof BaseTypeBinding) { if (TypeBinding.notEquals(currentType, tsuperType)) return false; } else { throw new InternalCompilerError("matching of unexpected type kind: " + currentType); //$NON-NLS-1$ } return true; } /** * Extract a compound type name relativ to a given Team. * This means, if tb is a (transitiv) member type of team, * cut off the Team and return only remaining part. * If tb is not a (transitiv) member of team, return the * full compound name of outer/inner classes but not containing * the package. * * For features inherited from an indirect super team allow * the team prefix to relate to that super team. * * @param tb the type to represent * @param teamBinding the Team * @return non-null array of at least one component */ public static char[][] splitTypeNameRelativeToTeam(ReferenceBinding tb, TypeBinding teamBinding) { char[][] qname = new char[][] { tb.internalName() }; // move out until we find the source team: while (tb instanceof MemberTypeBinding) { tb = ((MemberTypeBinding) tb).enclosingType; if (tb.isTeam()) { if (TypeBinding.equalsEquals(tb, teamBinding)) return qname; else if (teamBinding.isCompatibleWith(tb)) return qname; } else { // prepend one component to qname: char[][] qn2 = new char[qname.length + 1][]; System.arraycopy(qname, 0, qn2, 1, qname.length); qn2[0] = tb.internalName(); qname = qn2; } } return qname; } /** * Split the qualified name of a member type into a compound name. * (the field compoundName merges Outer$Inner into one element * of the compound, which is not what we want here). * @param tb * @param includePackage should the package name(s) be included? * @param createTeamAnchor should a possible team anchor be included in the compound name? * TODO(SH) saying yes here causes as to create old syntax AST. * @return non-null array of at least one component */ public static char[][] compoundNameOfReferenceType(ReferenceBinding tb, boolean includePackage, boolean createTeamAnchor) { if (tb instanceof ProblemReferenceBinding) { ReferenceBinding closestMatch = (ReferenceBinding) tb.closestMatch(); if (closestMatch != null) tb = closestMatch; } if (!tb.isValidBinding()) { // no further processing possible if (includePackage) return tb.compoundName; int l = tb.compoundName.length; return new char[][] { tb.compoundName[l - 1] }; } if (tb instanceof UnresolvedReferenceBinding) { LookupEnvironment env = Config.getLookupEnvironment(); if (env == null) throw new InternalCompilerError("No lookup environment configured"); //$NON-NLS-1$ tb = ((UnresolvedReferenceBinding) tb).resolve(env, false); } if (createTeamAnchor && tb instanceof DependentTypeBinding && ((DependentTypeBinding) tb).hasExplicitAnchor()) { DependentTypeBinding roleTypeBinding = (DependentTypeBinding) tb; // for role types the prefix is a variable not a type: ITeamAnchor[] path = roleTypeBinding._teamAnchor.getBestNamePath(); // If anchor is a field, prepend a team anchor with "Outer.this" // for the type containing the anchor field. char[] declaringClass = null; int prefixLen = 0; if (roleTypeBinding._teamAnchor instanceof FieldBinding) { declaringClass = ((FieldBinding) (roleTypeBinding)._teamAnchor).declaringClass.internalName(); prefixLen = 2; } char[][] names = new char[path.length + 1 + prefixLen][]; if (declaringClass != null) { // do prepend names[0] = declaringClass; names[1] = "this".toCharArray(); //$NON-NLS-1$ } for (int i = 0; i < path.length; i++) { names[i + prefixLen] = path[i].internalName(); } names[path.length + prefixLen] = tb.internalName(); return names; } char[][] packName = includePackage && (tb.getPackage() != null) ? tb.getPackage().compoundName : new char[0][]; char[][] outerName = (tb.enclosingType() != null) ? compoundNameOfReferenceType(tb.enclosingType(), false, createTeamAnchor) : new char[0][]; char[][] result = new char[packName.length + outerName.length + 1][]; System.arraycopy(packName, 0, result, 0, packName.length); System.arraycopy(outerName, 0, result, packName.length, outerName.length); result[result.length - 1] = tb.internalName(); return result; } /** * Try to interpret a type name as a local type of a role. * Take the constantPoolName and chop off the team name which prefixes this name. * * @param teamBinding * @param compoundName * @return non-null char-array */ public static char[] constantPoolNameRelativeToTeam(ReferenceBinding teamBinding, char[] compoundName) { char[] teamName = teamBinding.constantPoolName(); if (!CharOperation.prefixEquals(teamName, compoundName)) return compoundName; assert (compoundName[teamName.length] == '$'); return CharOperation.subarray(compoundName, teamName.length + 1, -1); } /** * Compare two types trying to interpret type names as local types of roles, where * the constantPoolName must be investigated but the team name prefix chopped off. * * @param teamBinding enclosing team of the first type * @param role the first type itself * @param typeName relative name of the second type (ie., team prefix is already copped off). * @return the answer */ public static boolean equalRoleLocal(ReferenceBinding teamBinding, ReferenceBinding role, char[] typeName) { // TODO (SH) during CopyInheritanc constantPoolName is still null. // but do we need to map names of local types in accessor signatures?? if (role.constantPoolName() == null) return false; char[] relativeName = constantPoolNameRelativeToTeam(teamBinding, role.constantPoolName()); return CharOperation.equals(typeName, relativeName); } /** * Given a reference (read from source code) and a binding (read from * a resolved super-role) create a weakened type reference, i.e., if * the type is a role-type, create a new reference from the binding. * Precondition: both types are identical except for implicit inheritance. * @param origRef This reference may or may not need to be changed. * In any case use its source positions. * @param binding this specifies the type we need to refer to. * @return either origRef or a fresh reference */ public static TypeReference weakenTypeReferenceFromBinding(MethodScope scope, TypeReference origRef, TypeBinding origBinding, TypeBinding binding) { if (!((binding instanceof ReferenceBinding) || (binding instanceof ArrayBinding))) return origRef; binding = binding.erasure(); origBinding = origBinding.erasure(); if (binding instanceof RoleTypeBinding) if (TypeBinding.equalsEquals(origBinding, ((RoleTypeBinding) binding).getRealType())) return origRef; if (TypeBinding.equalsEquals(origBinding, binding)) return origRef; AstGenerator gen = new AstGenerator(origRef.sourceStart, origRef.sourceEnd); return gen.typeReference(binding); } /** * Find a method in a super role * @param subTeam the Team containing subMethod * @param subMethod a method to match * @param superRole where to look * @param superTeam enclosing Team of superRole * @return a method or null */ public static MethodBinding findMethodInSuperRole(ReferenceBinding subTeam, MethodBinding subMethod, ReferenceBinding superRole, ReferenceBinding superTeam, int matchKind) { MethodBinding[] superMethods = superRole.methods(); for (int i = 0; i < superMethods.length; i++) { if (isEqualMethodSignature(superTeam, superMethods[i], subTeam, subMethod, matchKind)) return superMethods[i]; } return null; } public static boolean isOrgObjectteamsTeam(ReferenceBinding type) { if (type == null) return false; return CharOperation.equals(type.compoundName, IOTConstants.ORG_OBJECTTEAMS_TEAM); } public static boolean isOrgObjectteamsTeam(CompilationUnitDeclaration unit) { if (unit != null && unit.currentPackage != null && unit.types != null && unit.types.length > 0) { return CharOperation.equals(IOTConstants.ORG_OBJECTTEAMS, unit.currentPackage.tokens) && CharOperation.equals(IOTConstants.TEAM, unit.types[0].name); } return false; } public static boolean isVariableRef(Expression e) { return (e.bits & Binding.VARIABLE) != 0; } /** * Find a fied in a type searching superclasses and enclosing classes. * Note, that this method indeed finds private fields even via a super-class of type. * * @param type where to look * @param token name of the field to look for * @param isStaticScope is the field reference within a static scope? * @param allowOuter is it legal to find the field in an enclosing type? * @param requiredState when navigating to supertypes, is a certain state required for those? * (this does not apply to `type' itself and its enclosing). * @return a field or null */ public static FieldBinding findField(ReferenceBinding type, char[] token, boolean isStaticScope, boolean allowOuter, int requiredState) { while (type != null) { // loop inner->outer ReferenceBinding currentType = type; while (currentType != null) { // loop sub->super FieldBinding foundVar = currentType.getField(token, /*resolve*/true); if (foundVar != null) { if (isStaticScope && !foundVar.isStatic()) return new ProblemFieldBinding(foundVar, currentType, token, ProblemReasons.NonStaticReferenceInStaticContext); return foundVar; } currentType = currentType.superclass(); if (currentType != null && requiredState != -1) Dependencies.ensureBindingState(currentType, requiredState); } if (!allowOuter) return null; isStaticScope = type.isStatic(); type = type.enclosingType(); } return null; } public static FieldBinding findField(ReferenceBinding type, char[] token, boolean isStaticScope, boolean allowOuter) { return findField(type, token, isStaticScope, allowOuter, -1); } /** * Find a method in type or one of its super types. * @param scope where the method shall be invoked from * @param type where to search * @param selector name of the method * @param params params */ public static MethodBinding findMethod(Scope scope, ReferenceBinding type, char[] selector, TypeBinding[] params) { return findMethod(scope, type, selector, params, /*decapsulationAllowed*/false, null); } /** * Find a method in type or one of its super types. * @param scope where the method shall be invoked from * @param type where to search * @param selector name of the method * @param params params * @param decapsulationAllowed whether or not invisible methods should be found, too * @param site invocation site if available */ public static @Nullable MethodBinding findMethod(final Scope scope, ReferenceBinding type, char[] selector, TypeBinding[] params, boolean decapsulationAllowed, @Nullable InvocationSite site) { if (type == null || scope == null) return null; if (site == null) { final Expression[] fakeArguments = new Expression[params.length]; for (int i = 0; i < params.length; i++) { fakeArguments[i] = new SingleNameReference(("fakeArg" + i).toCharArray(), 0L); //$NON-NLS-1$ fakeArguments[i].resolvedType = params[i]; } site = new InvocationSite() { @Override public int sourceStart() { return 0; } @Override public int sourceEnd() { return 0; } @Override public void setFieldIndex(int depth) { /* nop */ } @Override public void setDepth(int depth) { /* nop */ } @Override public void setActualReceiverType(ReferenceBinding receiverType) { /* nop */ } @Override public boolean receiverIsImplicitThis() { return false; } @Override public boolean isTypeAccess() { return false; } @Override public boolean isSuperAccess() { return false; } @Override public boolean isQualifiedSuper() { return false; } @Override public boolean checkingPotentialCompatibility() { return false; } @Override public void acceptPotentiallyCompatibleMethods(MethodBinding[] methods) { /* nop */ } @Override public TypeBinding invocationTargetType() { return scope.getJavaLangObject(); } @Override public ExpressionContext getExpressionContext() { return ExpressionContext.ASSIGNMENT_CONTEXT; } @Override public TypeBinding[] genericTypeArguments() { return null; } @Override public InferenceContext18 freshInferenceContext(Scope someScope) { return new InferenceContext18(someScope, fakeArguments, this, null); } }; } return scope.getMethod(type, selector, params, site); } /** Find a method with identical parameters after erasing. */ public static MethodBinding findCompatibleMethod(ReferenceBinding site, MethodBinding template) { methods: for (MethodBinding existingMethod : site.getMethods(template.selector)) { if (existingMethod.parameters.length != template.parameters.length) continue; for (int j = 0; j < template.parameters.length; j++) { if (TypeBinding.notEquals(existingMethod.parameters[j].erasure(), template.parameters[j].erasure())) continue methods; } return existingMethod; } return null; } /** * Look for the method declaration matching the given selector and length of argument list. * @param typeDeclaration * @param selector * @param nArgs * @return a method or null */ public static AbstractMethodDeclaration findMethodDecl(TypeDeclaration typeDeclaration, char[] selector, int nArgs) { if (typeDeclaration.methods == null) return null; AbstractMethodDeclaration[] methods = typeDeclaration.methods; for (int i = 0; i < methods.length; i++) { if (CharOperation.equals(methods[i].selector, selector)) { if (methods[i].arguments == null) { if (nArgs == 0) return methods[i]; } else if (methods[i].arguments.length == nArgs) { return methods[i]; } } } return null; } /** * Find a method just by its selector. * Looks up the superclass/interfaces hierarchy. * * @param typeBinding * @param selector * @return first matching method */ public static MethodBinding getMethod(ReferenceBinding typeBinding, char[] selector) { if (typeBinding == null) return null; MethodBinding[] foundMethods = typeBinding.getMethods(selector); if (foundMethods != Binding.NO_METHODS) return foundMethods[0]; MethodBinding foundMethod = getMethod(typeBinding.superclass(), selector); if (foundMethod != null) return foundMethod; ReferenceBinding[] superInterfaces = typeBinding.superInterfaces(); for (int i = 0; i < superInterfaces.length; i++) { foundMethod = getMethod(superInterfaces[i], selector); if (foundMethod != null) return foundMethod; } return null; } /** * When comparing two role types, allow the teams to be super/sub teams * in either direction. * * TODO (SH): check: * (1) does this method hide relevant incompatibilities? * (2) do we need to apply this method in other places, too? * * @param one * @param two * @return the answer */ public static boolean areRoleTypesEqual(RoleTypeBinding one, RoleTypeBinding two) { if (!CharOperation.equals(one.sourceName(), two.sourceName())) return false; ReferenceBinding teamOne = one._staticallyKnownTeam; ReferenceBinding teamTwo = two._staticallyKnownTeam; if (teamOne.isRole() && teamTwo.isRole()) { ReferenceBinding outerOne = teamOne.enclosingType(); ReferenceBinding outerTwo = teamTwo.enclosingType(); if (TypeBinding.notEquals(outerOne, outerTwo)) { // raise nested teams to same level. if (outerOne.isCompatibleWith(outerTwo)) { teamTwo = (ReferenceBinding) TeamModel.strengthenRoleType(outerOne, teamTwo); } else if (outerTwo.isCompatibleWith(outerOne)) { teamOne = (ReferenceBinding) TeamModel.strengthenRoleType(outerTwo, teamOne); } } // in order to compare two team-as-role types take their interface parts: teamOne = teamOne.roleModel.getInterfacePartBinding(); teamTwo = teamTwo.roleModel.getInterfacePartBinding(); } if (teamOne.isCompatibleWith(teamTwo)) return true; if (teamTwo.isCompatibleWith(teamOne)) return true; return false; } /* * This is the structure of confined types as seen by the compiler: * * predefined: * IConfined .superclass = null * Team.IConfined .superclass = null, superinterface = IConfined * Team.Confined .superclass = null * Team.__OT__Confined.superclass = null, superinterface = Team.Confined * * client code: * TX.IConfined .superclass = OTC, superinterface = Team.IConfined * TX.Confined .superclass = OTC, superinterface = Team.Confined * TX.__OT__Confined .superclass = OTC, superinterface = TX.Confined * TX.R .superclass = OTC, superinterface = TX.IMyIFC * TX.__OT__R .superclass = OTC, superinterface = TX.R * (OTX = __OT__Confined, resolving to TX.__OT__Confined except for itself) * * Class-files have to differ from this view: * For JVM-compatibility all superinterfaces must store Object as their superclass. * These interfaces are marked using OTClassFlags attribute. * */ public static boolean isTopConfined(ReferenceBinding type) { char[][] compoundName = type.compoundName; if (compoundName.length == 3 && (CharOperation.equals(compoundName, IOTConstants.ORG_OBJECTTEAMS_ICONFINED) || CharOperation.equals(compoundName, IOTConstants.ORG_OBJECTTEAMS_ITEAM_ICONFINED) || CharOperation.equals(compoundName, IOTConstants.ORG_OBJECTTEAMS_TEAM_CONFINED) || CharOperation.equals(compoundName, IOTConstants.ORG_OBJECTTEAMS_TEAM_OTCONFINED))) { return true; } char[] name = type.internalName(); return type.isRole() && (CharOperation.equals(name, IOTConstants.ICONFINED) || CharOperation.equals(name, IOTConstants.OTCONFINED) || CharOperation.equals(name, IOTConstants.CONFINED)); } public static boolean isConfined(TypeBinding type) { if (type == null || !type.isRole()) return false; ReferenceBinding currentType = (ReferenceBinding) type; while (currentType != null) { if (currentType.id == TypeIds.T_JavaLangObject) return false; currentType = currentType.superclass(); } return true; } public static boolean isPredefinedRole(ReferenceBinding type) { char[] name = type.internalName(); if (CharOperation.equals(name, IOTConstants.ROFI_CACHE)) return true; if (!type.isRole()) return false; return CharOperation.equals(name, IOTConstants.ICONFINED) || CharOperation.equals(name, IOTConstants.OTCONFINED) || CharOperation.equals(name, IOTConstants.CONFINED) || CharOperation.equals(name, IOTConstants.ILOWERABLE) || CharOperation.equals(name, IOTConstants.IBOUNDBASE) || CharOperation.equals(name, IOTConstants.IBOUNDBASE2); } public static boolean extendsOTConfined(TypeDeclaration type) { if (type.superclass instanceof QualifiedTypeReference) return CharOperation.equals(((QualifiedTypeReference) type.superclass).tokens, IOTConstants.ORG_OBJECTTEAMS_TEAM_OTCONFINED); if (type.superclass instanceof SingleTypeReference) return CharOperation.equals(((SingleTypeReference) type.superclass).token, IOTConstants.OTCONFINED); return false; } /** * When asking for a field should synthetic fields be searched? * @param scope site of usage, if this is a generated methods, searching synthetics is OK * @param receiverType class containing the field * @param fieldName * @return the answer */ public static boolean isSearchingForSyntheticField(MethodScope scope, TypeBinding receiverType, char[] fieldName) { return CharOperation.prefixEquals(TypeConstants.SYNTHETIC_ENCLOSING_INSTANCE_PREFIX, fieldName) && scope != null && ((AbstractMethodDeclaration) scope.referenceContext).isGenerated && receiverType instanceof ReferenceBinding && ((ReferenceBinding) receiverType).isRole(); } public static boolean isSourceTypeWithErrors(ReferenceBinding type) { if (type instanceof SourceTypeBinding) { SourceTypeBinding sourceType = (SourceTypeBinding) type; if (sourceType.scope != null) return sourceType.scope.referenceContext.hasErrors(); } return false; } // _OT$base.Types need stripping: public static char[] stripTypeName(char[] typeName) { if (CharOperation.prefixEquals(IOTConstants._OT_BASE, typeName)) typeName = CharOperation.subarray(typeName, IOTConstants.OT_DOLLAR_LEN, -1); return typeName; } public static boolean sameOrContained(ReferenceBinding binding, ReferenceBinding targetEnclosingType) { while (binding != null) { if (TypeBinding.equalsEquals(binding, targetEnclosingType)) return true; binding = binding.enclosingType(); } return false; } /** Does the unit contain any role class with a base class reference that could potentially represent an anchored type? */ public static boolean containsAnchoredBaseclass(CompilationUnitDeclaration parsedUnit) { if (parsedUnit.types == null) return false; for (TypeDeclaration type : parsedUnit.types) if (containsAnchoredBaseclass(type)) return true; return false; } private static boolean containsAnchoredBaseclass(TypeDeclaration type) { TypeReference baseRef = type.baseclass; if (baseRef instanceof ParameterizedSingleTypeReference) { TypeReference[] typeArguments = ((ParameterizedSingleTypeReference) baseRef).typeArguments; return typeArguments != null && typeArguments.length > 0 && typeArguments[0] instanceof TypeAnchorReference; } else if (baseRef instanceof QualifiedTypeReference) { return true; } TypeDeclaration[] members = type.memberTypes; if (members != null) for (TypeDeclaration member : members) if (containsAnchoredBaseclass(member)) return true; return false; } }