blob: 6310517c7e0a2ed29326d574fb13ab57ce6d1206 [file] [log] [blame]
/**********************************************************************
* This file is part of "Object Teams Development Tooling"-Software
*
* Copyright 2004, 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: TSuperHelper.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 static org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.AccProtected;
import static org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers.AccRole;
import static org.eclipse.objectteams.otdt.core.compiler.IOTConstants.AccSynthIfc;
import static org.eclipse.objectteams.otdt.core.compiler.IOTConstants.MARKER_ARG_NAME;
import static org.eclipse.objectteams.otdt.core.compiler.IOTConstants.OT_DELIM_NAME;
import static org.eclipse.objectteams.otdt.core.compiler.IOTConstants.TSUPER_OT_NAME;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Argument;
import org.eclipse.jdt.internal.compiler.ast.CastExpression;
import org.eclipse.jdt.internal.compiler.ast.Expression;
import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
import org.eclipse.jdt.internal.compiler.ast.Statement;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
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.SourceTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.objectteams.otdt.core.compiler.OTNameUtils;
import org.eclipse.objectteams.otdt.internal.core.compiler.ast.TSuperMessageSend;
import org.eclipse.objectteams.otdt.internal.core.compiler.control.ITranslationStates;
import org.eclipse.objectteams.otdt.internal.core.compiler.control.StateHelper;
import org.eclipse.objectteams.otdt.internal.core.compiler.model.TeamModel;
/**
* This class is repsonsible for so-called marker interfaces by which copied methods
* are marked as tsuper-version.
*
* Note that this class is not intended for instantiation, but as a library of static methods.
*
* @author stephan
* @version $Id: TSuperHelper.java 23416 2010-02-03 19:59:31Z stephan $
*
*/
public class TSuperHelper {
/**
* Get the name of the interface marking methods inherited from `superTeam'
* @param superTeam
* @return marker ifc name.
*/
public static char[] getTSuperMarkName(ReferenceBinding superTeam) {
char[] name = superTeam.sourceName();
while ((superTeam = superTeam.enclosingType()) != null)
name = CharOperation.concat(superTeam.sourceName(), OT_DELIM_NAME, name);
return CharOperation.concat(TSUPER_OT_NAME, name);
}
// ==== Actual TSuper Marker Interfaces ===
/**
* @param teamModel
* @param superTeam
*/
public static void addMarkerInterface(TeamModel teamModel, ReferenceBinding superTeam) {
TypeDeclaration teamDeclaration = teamModel.getAst();
TypeDeclaration markerInterface = createMarkerInterface(teamDeclaration, superTeam);
teamModel.markerInterface = markerInterface;
markerInterface.getRoleModel().setState(ITranslationStates.STATE_LENV_DONE_FIELDS_AND_METHODS);
}
/**
* Only create one marker interface per team during copy inheritance.
* Other marker types should be retrieved using scope.getType(name);
*/
private static TypeDeclaration createMarkerInterface(TypeDeclaration teamTypeDeclaration, ReferenceBinding superteam) {
char[] superMarkName = TSuperHelper.getTSuperMarkName(superteam);
if (teamTypeDeclaration.memberTypes != null)
for (int i = 0; i < teamTypeDeclaration.memberTypes.length; i++) {
if (CharOperation.equals(teamTypeDeclaration.memberTypes[i].name, superMarkName))
return teamTypeDeclaration.memberTypes[i];
}
return AstConverter.createNestedType(
superMarkName,
AccSynthIfc | AccRole | AccProtected,
false, /* not a nested type */
false, /* not purely copied */
teamTypeDeclaration,
null /* no tsuper role */);
}
public static TypeBinding getMarkerInterface(Scope scope, ReferenceBinding superteam) {
return scope.getType(TSuperHelper.getTSuperMarkName(superteam));
}
private static TypeReference markerTypeRef(ReferenceBinding superTeam, AstGenerator gen) {
return gen.singleTypeReference(TSuperHelper.getTSuperMarkName(superTeam));
}
public static boolean isMarkerInterface(TypeBinding type) {
if (type.isWildcard()) // wildcards don't even have a name!
return false;
if ( type instanceof ReferenceBinding
&& type.isValidBinding())
return OTNameUtils.isTSuperMarkerInterface(((ReferenceBinding)type).internalName());
return false;
}
// ==== Marker Arguments: ====
/**
* Is the expression the casted null of a marker arg?
* @param expression
* @return the answer
*/
public static boolean isMarkerArg(Expression expression) {
if (!(expression instanceof CastExpression))
return false;
CastExpression cast = (CastExpression)expression;
if (!(cast.type instanceof SingleTypeReference))
return false;
return OTNameUtils.isTSuperMarkerInterface(((SingleTypeReference)cast.type).token);
}
/**
* Is the given method a tsuper-version (recognized by having
* a marker arg at last position) ?
*
* @param method
* @return the answer
*/
public static boolean isTSuper(MethodBinding method) {
TypeBinding[] params = method.parameters;
if (params.length > 0) {
TypeBinding lastParam = params[params.length-1];
if (lastParam != null)
return isMarkerInterface(lastParam);
}
return false;
}
/**
* Create and add a marker arg which marks a tsuper message send
* "Qualification.tsuper.m(args)" -> "args, TSuper_OT_QualifyingTeam"
*
* @param qualifyingType may be null.
* @param tsuperCall
* @param arguments
* @param scope
* @return argument expressions, either new, or unchanged or null (error).
*/
public static Expression[] addMarkerArgument(ReferenceBinding qualifyingType, Statement tsuperCall, Expression[] arguments, BlockScope scope) {
if(scope == null)
return null; // see 2.3.20-otjld-illegal-constructor-call-10
int sStart = tsuperCall.sourceStart;
int sEnd = tsuperCall.sourceEnd;
SourceTypeBinding roleType = scope.enclosingSourceType();
if (!roleType.isSourceRole()) {
scope.problemReporter().tsuperOutsideRole(
(AbstractMethodDeclaration)scope.methodScope().referenceContext,
tsuperCall,
roleType);
return arguments; // unchanged.
}
ReferenceBinding[] tsuperRoleBindings = roleType.roleModel.getTSuperRoleBindings();
if (tsuperRoleBindings.length == 0) {
scope.problemReporter().tsuperCallWithoutTsuperRole(roleType, tsuperCall);
return null;
}
ReferenceBinding superTeam;
if (qualifyingType == null) {
superTeam = tsuperRoleBindings[0].enclosingType();
} else {
TSuperMessageSend tsuperMsg = (TSuperMessageSend)tsuperCall;
ReferenceBinding superRole = (ReferenceBinding)tsuperMsg.tsuperReference.resolveType(scope);
superTeam = superRole.enclosingType();
if (superTeam == null)
return null;
}
AstGenerator gen = new AstGenerator(sStart, sEnd);
CastExpression cast = createMarkerArgExpr(superTeam, gen);
Expression[] newArgs;
if(arguments == null){
newArgs = new Expression[] {cast};
} else {
newArgs = new Expression[arguments.length+1];
System.arraycopy(arguments,0, newArgs,0, arguments.length);
newArgs[newArgs.length-1] = cast;
}
return newArgs;
}
public static CastExpression createMarkerArgExpr(ReferenceBinding superTeam, AstGenerator gen) {
return gen.castExpression(
gen.nullLiteral(),
markerTypeRef(superTeam, gen),
CastExpression.RAW);
}
/**
* Augments the method signature with a special parameter
* (adds an additional parameter at end of parameter list).
* The type of the new parameter is the MarkerInterface-Type.
* <code>public method(String str)</code>
* will be augmented to
* <code>public method(String str, TSuper__OT__XYZ __OT__marker )</code>
* where XYZ is the name of the direct superteam.
* @param methodDeclaration the method of which Parameters will be augmented
* @param origin superTeam used for part of the marker type's name
*/
public static void addMarkerArg(AbstractMethodDeclaration methodDeclaration, ReferenceBinding origin) {
AstGenerator gen = new AstGenerator(methodDeclaration.sourceStart, methodDeclaration.sourceEnd);
TypeReference marker = gen.singleTypeReference(TSuperHelper.getTSuperMarkName(origin));
int argPos = 0;
if(methodDeclaration.arguments==null){
methodDeclaration.arguments = new Argument[1];
} else{
int argumentlength = methodDeclaration.arguments.length;
if(argumentlength == 0){
methodDeclaration.arguments = new Argument[1];
} else{
Argument[] arguments = new Argument[argumentlength+1];
System.arraycopy(methodDeclaration.arguments,0, arguments,0, argumentlength);
methodDeclaration.arguments=arguments;
argPos = argumentlength;
}
}
methodDeclaration.arguments[argPos] =
new Argument(MARKER_ARG_NAME,0,marker,0);
methodDeclaration.isTSuper = true;
if (methodDeclaration.binding != null) {
TypeBinding[] oldParams = methodDeclaration.binding.parameters;
TypeBinding[] newParams = new TypeBinding[oldParams.length+1];
System.arraycopy(oldParams, 0, newParams, 0, oldParams.length);
newParams[oldParams.length] = marker.resolveType(methodDeclaration.scope);
methodDeclaration.binding.parameters = newParams;
methodDeclaration.binding.resetSignature();
}
}
public static boolean isTSubOf(ReferenceBinding class1, ReferenceBinding other) {
if (!class1.isRole() || !other.isRole())
return false;
if ( StateHelper.hasState(other, ITranslationStates.STATE_LENV_CONNECT_TYPE_HIERARCHY)
&& StateHelper.hasState(class1, ITranslationStates.STATE_LENV_CONNECT_TYPE_HIERARCHY)
&& StateHelper.hasState(class1.enclosingType(), ITranslationStates.STATE_LENV_CONNECT_TYPE_HIERARCHY))
{
return class1.roleModel.hasTSuperRole(other);
}
if (!CharOperation.equals(class1.sourceName(), other.sourceName()))
return false;
return class1.enclosingType().superclass() == other.enclosingType()
|| isTSubOf(class1.enclosingType(), other.enclosingType());
}
// UNUSED but commit this code at least once to facility retrieval should it be needed later.
// /**
// * Convert a marker interface back to the team being represented.
// * @param marker
// * @param environment
// * @return team reference binding
// */
// public static ReferenceBinding markerToTeam(ReferenceBinding site, ReferenceBinding marker) {
// int compoundLen = marker.compoundName.length;
// // this will hold the compound name of the outermost type:
// char[][] compoundName = new char[compoundLen][];
// System.arraycopy(marker.compoundName, 0, compoundName, 0, compoundLen);
//
// // extract the pure name of the marker interface:
// char[][] splitName = CharOperation.splitOn('$', compoundName[compoundLen-1]);
// String name = new String(splitName[splitName.length-1]);
//
// // parse the name:
// int start = TSUPER_OT_LEN;
// ReferenceBinding clazz = null;
// int end = 0;
// while (end != -1) {
// end = name.indexOf(OT_DELIM, start); // additional delim-separator?
// String element = null;
// if (end == -1)
// element = name.substring(start); // get the last element
// else
// element = name.substring(start, end);
// if (clazz == null) {
// // retrieve the outermost type:
// compoundName[compoundLen-1] = element.toCharArray();
// //clazz = environment.getType(compoundName);
// clazz = findType(site, element.toCharArray());
// } else {
// // retrieve member types:
// clazz = clazz.getMemberType(element.toCharArray());
// if (clazz.isSynthInterface())
// clazz = clazz.roleModel.getClassPartBinding();
// }
// start=end+OT_DELIM_LEN;
// }
// return clazz;
// }
//
// private static ReferenceBinding findType(ReferenceBinding site, char[] name) {
// ReferenceBinding currentLevel = site;
// do {
// ReferenceBinding currentSuper = currentLevel;
// do {
// if (CharOperation.equals(currentSuper.internalName(), name))
// return currentSuper;
// currentSuper = currentSuper.superclass();
// } while (currentSuper != null);
// currentLevel = currentLevel.enclosingType();
// } while (currentLevel != null);
// return null;
// }
}