| /********************************************************************** |
| * 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; |
| } |
| } |