implement dispatching of static base-calls for otredyn
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CallinImplementorDyn.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CallinImplementorDyn.java
index 45de236..7364920 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CallinImplementorDyn.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CallinImplementorDyn.java
@@ -89,7 +89,10 @@
 	static final char[] OT_CALL_AFTER   = "_OT$callAfter".toCharArray(); //$NON-NLS-1$
 	static final char[] OT_CALL_REPLACE = "_OT$callReplace".toCharArray(); //$NON-NLS-1$
 	// used for base calls:
-	public static final char[] OT_CALL_NEXT     = "_OT$callNext".toCharArray(); //$NON-NLS-1$
+	public static final char[] OT_CALL_NEXT        = "_OT$callNext".toCharArray(); //$NON-NLS-1$
+	//  - both the team version (II[Object;) and the base version (I[Object;)
+	public static final char[] OT_CALL_ORIG_STATIC = "_OT$callOrigStatic".toCharArray(); //$NON-NLS-1$
+	
 	// for decapsulation:
 	public static final char[] OT_ACCESS 		= "_OT$access".toCharArray(); //$NON-NLS-1$
 	public static final char[] OT_ACCESS_STATIC = "_OT$accessStatic".toCharArray(); //$NON-NLS-1$
@@ -268,6 +271,7 @@
 		List<CallinMappingDeclaration> replaceMappings = new ArrayList<CallinMappingDeclaration>();
 		List<CallinMappingDeclaration> afterMappings = new ArrayList<CallinMappingDeclaration>();
 		
+		boolean hasReplaceStatic = false;
 		for (RoleModel role : aTeam.getRoles(false)) {
 			TypeDeclaration roleDecl = role.getAst(); // FIXME(SH): this breaks incremental compilation: all roles must be present as AST!!
 			if (roleDecl == null) continue; // FIXME(SH): check if this is OK
@@ -277,8 +281,10 @@
 						CallinMappingDeclaration callinDecl = (CallinMappingDeclaration) mappingDecl;
 						switch (callinDecl.callinModifier) {
 							case TerminalTokens.TokenNamebefore: 	beforeMappings.add(callinDecl); 	break;
-							case TerminalTokens.TokenNamereplace: 	replaceMappings.add(callinDecl); 	break;
 							case TerminalTokens.TokenNameafter: 	afterMappings.add(callinDecl); 		break;
+							case TerminalTokens.TokenNamereplace: 	replaceMappings.add(callinDecl);
+																	hasReplaceStatic |= callinDecl.isStaticReplace();
+																	break;
 						}
 					}
 				}
@@ -291,6 +297,8 @@
 		if (replaceMappings.size() > 0) {
 			generateDispatchMethod(OT_CALL_REPLACE, true,  false, replaceMappings, aTeam);
 			generateCallNext(replaceMappings, aTeam);
+			if (hasReplaceStatic)
+				generateCallOrigStatic(replaceMappings, aTeam);
 		}
 	}
 
@@ -820,6 +828,57 @@
 		AstEdit.addMethod(teamDecl, decl);
 	}
 
+	private void generateCallOrigStatic(List<CallinMappingDeclaration> callinDecls, TeamModel aTeam) {
+		// public Object _OT$callOrigStatic(int callinId, int boundMethodId, Object[] args)
+		// this team method delegates to the corresponding _OT$callOrigStatic(int,Object[])
+		// of the appropriate base classes.
+		final TypeDeclaration teamDecl = aTeam.getAst();
+		if (teamDecl == null) return;
+		final AstGenerator gen = new AstGenerator(teamDecl);
+		Argument[] args = new Argument[] {
+				gen.argument(CALLIN_ID, 		gen.typeReference(TypeBinding.INT)),
+				gen.argument(BOUND_METHOD_ID, 	gen.typeReference(TypeBinding.INT)),
+				gen.argument(ARGUMENTS, 		gen.qualifiedArrayTypeReference(TypeConstants.JAVA_LANG_OBJECT, 1))
+		};
+		Expression[] passThroughArgs = new Expression[] {
+				gen.singleNameReference(BOUND_METHOD_ID),
+				gen.singleNameReference(ARGUMENTS)
+		};
+		MethodDeclaration decl = gen.method(teamDecl.compilationResult,
+											AccPublic,
+											gen.qualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT),
+											OT_CALL_ORIG_STATIC,
+											args);
+		
+		SwitchStatement swStat = new SwitchStatement();
+		swStat.expression = gen.singleNameReference(CALLIN_ID);											// switch(callinId) { ...
+		List<Statement> swStatements = new ArrayList<Statement>(); 
+		for (CallinMappingDeclaration mapping : callinDecls) {
+			for (MethodSpec baseSpec : mapping.baseMethodSpecs) {
+				MethodBinding baseMethod = baseSpec.resolvedMethod;
+				if (baseMethod.isStatic()) {
+					swStatements.add(gen.caseStatement(gen.intLiteral(baseSpec.getCallinId(aTeam))));			// case baseSpecCallinId:
+					Expression result = gen.fakeMessageSend(gen.baseNameReference(baseMethod.declaringClass),	// 		return BaseClass._OT$callOrigStatic(boundMethodId, args);
+															OT_CALL_ORIG_STATIC, 
+															passThroughArgs,
+															baseMethod.declaringClass,
+															mapping.scope.getJavaLangObject());
+					swStatements.add(gen.returnStatement(result));
+				}
+			}
+		}																								// } // end-switch
+		if (swStatements.size() == 0)
+			return; // don't add useless method
+		
+		swStat.statements = swStatements.toArray(new Statement[swStatements.size()]);
+		decl.statements = new Statement[] {
+			swStat,
+			gen.returnStatement(gen.nullLiteral()) // shouldn't happen
+		};
+		decl.hasParsedStatements = true;
+		AstEdit.addMethod(teamDecl, decl);
+	}
+
 	boolean checkLiftingProblem(TypeDeclaration teamDecl, CallinMappingDeclaration callinDecl, ReferenceBinding roleType) {
 		int iProblem = teamDecl.getTeamModel().canLiftingFail(roleType);
 		if (iProblem != 0) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/util/AstGenerator.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/util/AstGenerator.java
index b249b3c..4eea29a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/util/AstGenerator.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/util/AstGenerator.java
@@ -27,6 +27,7 @@
 
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.CompilationResult;
+import org.eclipse.jdt.internal.compiler.CompilationResult.CheckPoint;
 import org.eclipse.jdt.internal.compiler.ast.*;
 import org.eclipse.jdt.internal.compiler.ast.Expression.DecapsulationState;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
@@ -34,11 +35,13 @@
 import org.eclipse.jdt.internal.compiler.flow.FlowContext;
 import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
 import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
 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.BlockScope;
 import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
 import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
 import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
 import org.eclipse.jdt.internal.compiler.lookup.Scope;
@@ -735,6 +738,33 @@
 		return messageSend;
 	}
 
+	/** Create a message send to a method that will be created by the otre. */
+	public MessageSend fakeMessageSend(Expression receiver, char[] selector, Expression[] parameters, 
+									   final ReferenceBinding receiverType, final TypeBinding resolvedReturn) 
+	{
+		MessageSend messageSend = new MessageSend() {
+			@Override
+			public TypeBinding resolveType(BlockScope scope) {
+				ReferenceContext referenceContext = scope.referenceContext();
+				CheckPoint cp = referenceContext.compilationResult().getCheckPoint(referenceContext);
+				super.resolveType(scope);
+				referenceContext.compilationResult().rollBack(cp);
+				this.binding = new MethodBinding(ClassFileConstants.AccStatic|ClassFileConstants.AccPublic, this.selector, 
+												 resolvedReturn, this.binding.parameters, Binding.NO_EXCEPTIONS, receiverType);
+				return this.resolvedType = resolvedReturn;
+			}
+		};
+		messageSend.sourceStart = this.sourceStart;
+		messageSend.sourceEnd   = this.sourceEnd;
+		messageSend.statementEnd = this.sourceEnd;
+		messageSend.nameSourcePosition = this.pos;
+		messageSend.receiver = receiver;
+		messageSend.selector = selector;
+		messageSend.arguments = parameters;
+		messageSend.constant = Constant.NotAConstant;
+		return messageSend;
+	}
+
 	public AllocationExpression allocation(TypeReference typeRef, Expression[] arguments) {
 		AllocationExpression result = new AllocationExpression();
 		result.sourceStart = this.sourceStart;