blob: f2de85d9bd19d77a1402f8ca29318d65150b91d3 [file] [log] [blame]
/**********************************************************************
* This file is part of "Object Teams Development Tooling"-Software
*
* Copyright 2007 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: RoleModel.java 16291 2007-09-09 14:58:47Z 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.control;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
import org.eclipse.objectteams.otdt.internal.core.compiler.model.RoleModel;
import org.eclipse.objectteams.otdt.internal.core.compiler.model.TypeModel;
import static org.eclipse.objectteams.otdt.internal.core.compiler.control.ITranslationStates.*;
/**
* Handle translation states of compilation units and types.
*
* @author stephan
* @since OTDT 1.1.3
*/
public class StateHelper
{
// === categorizing states: ===
static boolean isRequiredState(int state) {
if (state <= STATE_LENV_DONE_FIELDS_AND_METHODS)
return true;
switch (state) {
case STATE_NONE:
case STATE_ROLES_LINKED:
case STATE_ROLE_FEATURES_COPIED:
case STATE_ROLE_HIERARCHY_ANALYZED:
case STATE_FULL_LIFTING:
case STATE_FAULT_IN_TYPES:
case STATE_METHODS_CREATED:
case STATE_STATEMENTS_TRANSFORMED: // detects and marks local types
case STATE_CALLINS_TRANSFORMED:
case STATE_METHODS_VERIFIED:
case STATE_RESOLVED:
case STATE_CODE_ANALYZED:
case STATE_BYTE_CODE_PREPARED:
case STATE_BYTE_CODE_GENERATED:
return true;
default:
return false;
}
}
static boolean isCUDState(int state, int[] exceptions)
{
if (exceptions != null)
for (int exception : exceptions)
if (state == exception)
return false;
switch (state) {
case STATE_BINDINGS_BUILT:
case STATE_LENV_BUILD_TYPE_HIERARCHY:
case STATE_LENV_CHECK_AND_SET_IMPORTS:
case STATE_LENV_CONNECT_TYPE_HIERARCHY:
case STATE_LENV_DONE_FIELDS_AND_METHODS:
case STATE_ROLES_LINKED:
case STATE_ROLE_FILES_LINKED:
case STATE_METHODS_PARSED:
case STATE_METHODS_VERIFIED:
case STATE_RESOLVED:
case STATE_CODE_ANALYZED:
case STATE_BYTE_CODE_GENERATED:
return true;
default: return false;
}
}
// === query elements for their state: ===
static boolean unitHasState(CompilationUnitDeclaration unit, int state)
{
if (unit.types == null)
return false;
for (TypeDeclaration type : unit.types) {
if (!StateHelper.hasState(type.binding, state))
return false;
}
unit.state.setState(state);
return true;
}
/**
* does clazz have state (wrt its most appropriate model)?
*/
public static boolean hasState(ReferenceBinding clazz, int state) {
if (clazz == null)
return false;
return getState(clazz).getState() >= state;
}
/** Answer the minimal state among the given types. */
public static int minimalState(ReferenceBinding[] types)
{
int s = ITranslationStates.STATE_FINAL;
for (ReferenceBinding type : types) {
int s1= getState(type).getState();
if (s1 < s)
s = s1;
}
return s;
}
// === update element's state: ===
/** Recursively mark that `unit' has reached `state'.
* Also trigger any further translation that has been requested during processing.
*
* @param unit
* @param state
* @param markRoleUnits if true also mark CUD of any member RoFi.
*/
public static void setStateRecursive(CompilationUnitDeclaration unit, int state, boolean markRoleUnits)
{
int requested= ITranslationStates.STATE_NONE;
// update the unit:
unit.state.setState(state);
// descend to children:
TypeDeclaration[] types = unit.types;
if(types != null)
for (int t=0; t < types.length; t++) {
setStateRecursive(types[t], state, markRoleUnits);
if (types[t].isRole()) {
int roleRequest = types[t].getRoleModel()._state.fetchRequestedState();
if (roleRequest > requested)
requested= roleRequest;
}
}
LocalTypeBinding[] localTypes = unit.localTypes;
if(localTypes != null) {
for (int t=0; t < unit.localTypeCount; t++) {
if (localTypes[t].scope != null) {
ClassScope scope = localTypes[t].scope;
if (scope.referenceContext != null)
setStateRecursive(scope.referenceContext, state, markRoleUnits);
}
}
}
// handle requests:
unit.state.handleRequest(unit, requested);
}
/**
* record that decl and all contained types are in state `state'.
* make sure to reach all models of all types.
* @param markRoleUnit TODO
*/
public static void setStateRecursive(TypeDeclaration decl, int state, boolean markRoleUnit)
{
TypeModel model;
boolean processed = false;
if (decl.isTeam()) {
model = decl.getTeamModel();
model.setState(state);
processed = true;
}
if (decl.isRole()) {
boolean handlingRoleFileImports= decl.isRoleFile()
&& (state == STATE_LENV_CHECK_AND_SET_IMPORTS);
if (!handlingRoleFileImports || markRoleUnit) {
model = decl.getRoleModel();
model.setState(state);
if (decl.compilationUnit != null)
decl.compilationUnit.state.setState(state);
}
processed = true;
}
if (!processed) {
model = decl.getModel();
model.setState(state);
}
if (decl.memberTypes != null) {
for (int i = 0; i < decl.memberTypes.length; i++) {
setStateRecursive(decl.memberTypes[i], state, markRoleUnit);
}
}
}
// === manage current processing and pending requests: ===
/**
* Is the given type ready to process `state'?
* This is not the case if some processing already takes place
* - either directly
* - or via its enclosing team if state is a CUD state
* If current processing is less that `state'
* then schedule `state' as _requested.
*/
public static boolean isReadyToProcess(TypeModel model, int state) {
if (!model.isReadyToProcess(state))
return false;
if (model.isRole() && isCUDState(state, null)) {
ReferenceBinding role= model.getBinding();
if (role != null && role.enclosingType() != null)
return hasState(role.enclosingType(), state)
|| isReadyToProcess(role.enclosingType().getTeamModel(), state);
}
return true;
}
public static boolean isReadyToProcess(SourceTypeBinding type, int state) {
if (type.isRole() && !isReadyToProcess(type.roleModel, state))
return false;
if (type.isTeam() && !isReadyToProcess(type.getTeamModel(), state))
return false;
return isReadyToProcess(type.model, state);
}
public static boolean isDefinitelyReadyToProcess(ReferenceBinding type, ReferenceBinding requestingSite, int state) {
if (!(type instanceof SourceTypeBinding))
return false; // most treatment not needed for binary types
SourceTypeBinding sourceType = (SourceTypeBinding) type;
if (sourceType.outermostEnclosingType().erasure() == requestingSite.outermostEnclosingType().erasure()
|| CharOperation.equals(type.getFileName(), requestingSite.getFileName()))
return false; // could infinitely recurse to the same inclosing of kind
if (!StateHelper.isReadyToProcess(sourceType, state))
return false;
try {
StateMemento unitState = sourceType.scope.compilationUnitScope().referenceContext.state;
if (unitState.isReadyToProcess(state))
return true; // GOAL
} catch (NullPointerException npe) {
// be shy, if any enclosing thing was missing don't risk infinite recursion.
}
return false;
}
/** Signal that processing for `state' has begun
* (role- and team-models of type plus enclosing team).
* @param type
* @param state state according to ITranslationStates
* @param step sub-step according to LookupEnvironment
*/
public static boolean startProcessing(TypeDeclaration type, int state, int step)
{
if (type.isRole()) {
RoleModel roleModel = type.getRoleModel();
if (roleModel.getTeamModel()._state.isBlocking(roleModel.getTeamModel(), state, step))
return false; // processing a late role file.
roleModel._state.startProcessing(state, step);
}
if (type.isTeam())
type.getTeamModel()._state.startProcessing(state, step);
return true;
}
static StateMemento getState(ReferenceBinding type) {
TypeModel model = null;
if (type.isTeam())
model = type.getTeamModel();
else if (type.isRole())
model = type.roleModel;
if (model == null)
model = type.model;
return model._state;
}
}