blob: 29a4cc48f2e473a7e4edbecd8874957798bf5e86 [file] [log] [blame]
/**********************************************************************
* This file is part of "Object Teams Development Tooling"-Software
*
* Copyright 2005, 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: SwitchOnBaseTypeGenerator.java 23417 2010-02-03 20:13:55Z 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.statemachine.transformer;
import org.eclipse.jdt.internal.compiler.ast.CastExpression;
import org.eclipse.jdt.internal.compiler.ast.Expression;
import org.eclipse.jdt.internal.compiler.ast.IfStatement;
import org.eclipse.jdt.internal.compiler.ast.Statement;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.TagBits;
import org.eclipse.objectteams.otdt.core.compiler.IOTConstants;
import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.WeakenedTypeBinding;
import org.eclipse.objectteams.otdt.internal.core.compiler.model.RoleModel;
import org.eclipse.objectteams.otdt.internal.core.compiler.util.AstGenerator;
import org.eclipse.objectteams.otdt.internal.core.compiler.util.Sorting;
/**
* Creates an instanceof cascade as needed for lifting and for base predicate checks.
*
* @author stephan
* @version $Id: SwitchOnBaseTypeGenerator.java 23417 2010-02-03 20:13:55Z stephan $
*/
public abstract class SwitchOnBaseTypeGenerator implements IOTConstants {
/**
* Create the statement for one base type in the big cascade.
*
* @param role the most suitable role for the detected base type.
* @param gen use for AST-generation
* @return the generated statement or null
*/
protected abstract Statement createCaseStatement(RoleModel role, AstGenerator gen);
/**
* Create a statement for handling an ambiguous base class.
*/
protected abstract Statement createStatementForAmbiguousBase(AstGenerator gen);
/**
* Hook into createSwitchStatement(), which should create a default branch, if needed.
*
* @param staticRoleType expected role type.
* @param gen use for AST-generation
* @return the generated statement or null
*/
protected abstract Statement createDefaultStatement(ReferenceBinding staticRoleType, AstGenerator gen);
/**
* Create the instanceof cascade based on a given base object.
* Note that the previous two methods are hooks which should create the actual
* statements for the cascade template.
*
* @param teamType the team context
* @param staticRoleType we know we are about to lift to this role type or better
* @param caseObjects one role model for each bound and relevant subtype of staticRoleType
* @param gen use for AST-generation
* @return the assembled statement
*/
protected Statement createSwitchStatement(
ReferenceBinding teamType,
ReferenceBinding staticRoleType,
RoleModel[] caseObjects,
AstGenerator gen)
{
boolean hasBindingAmbiguity = teamType.getTeamModel().ambigousLifting.size() > 0;
if (caseObjects.length == 1 && ((teamType.tagBits & TagBits.HasAbstractRelevantRole) == 0) && !hasBindingAmbiguity) {
// avoid instanceof alltogether.
return createCaseStatement(caseObjects[0], gen);
}
ReferenceBinding staticBaseType = staticRoleType.baseclass();
RoleModel[] rolesToSort = new RoleModel[caseObjects.length];
System.arraycopy(caseObjects, 0, rolesToSort, 0, caseObjects.length);
caseObjects = Sorting.sortRoles(rolesToSort);
Statement[] stmts = new Statement[2];
Expression baseArg = gen.singleNameReference(baseVarName());
if (staticRoleType.baseclass() instanceof WeakenedTypeBinding)
baseArg = gen.castExpression(
baseArg,
gen.typeReference(((WeakenedTypeBinding)staticRoleType.baseclass()).getStrongType()),
CastExpression.RAW);
char[] LOCAL_BASE_NAME = "_OT$local$base".toCharArray(); //$NON-NLS-1$
stmts[0] = gen.localVariable(LOCAL_BASE_NAME, gen.baseclassReference(staticBaseType), baseArg);
IfStatement prevIf = null;
/*
* if (_OT$local$base instanceof MySubBaseA)
* <action for MySubRoleA playedBy MySubBaseA>
* else if (_OT$local$base instanceof MySubBaseB)
* <action for MySubRoleB playedBy MySubBaseB>
* ...
* This relies on most specific types to be handled first
*/
for (int idx = caseObjects.length-1; idx >= 0; idx--) {
RoleModel object = caseObjects[idx];
Statement s = (teamType.getTeamModel().isAmbiguousLifting(staticRoleType, object.getBaseTypeBinding()))
? createStatementForAmbiguousBase(gen)
: createCaseStatement(object, gen);
if (object.getBaseTypeBinding().equals(staticBaseType) && idx == 0 && !hasBindingAmbiguity) {
// shortcut if last type matches the static type: no need for a final instanceof check
if (prevIf == null)
stmts[1] = s;
else
prevIf.elseStatement = s;
return gen.block(stmts); // don't generate default.
} else {
if (s != null) {
Expression condition = gen.instanceOfExpression(gen.singleNameReference(LOCAL_BASE_NAME),
gen.baseclassReference(object.getBaseTypeBinding()));
IfStatement is = gen.ifStatement(condition, s);
if (prevIf == null)
stmts[1] = is; // this is the root "if"
else
prevIf.elseStatement = is; // hook into existing "if"
prevIf = is;
}
}
}
/*
* ...
* else
* <default action>
*/
prevIf.elseStatement = createDefaultStatement(staticRoleType, gen);
return gen.block(stmts);
}
/** What name should be used to address the base object? */
char[] baseVarName() {
return BASE; // default: "base" (predicate method argument)
}
}