Bug 436759 [otdre] Finish implementation of OTDRE
- fix regression in test1126_nestingAndLayering4pf
  (avoid PrivateRoleMethodCall & static field accessors under OTDRE)
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java
index c2e277c..f3d99d8 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java
@@ -34,6 +34,7 @@
 import org.eclipse.jdt.internal.compiler.flow.FlowContext;
 import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions.WeavingScheme;
 import org.eclipse.jdt.internal.compiler.impl.Constant;
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
@@ -59,6 +60,7 @@
 import org.eclipse.objectteams.otdt.core.compiler.IOTConstants;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.CalloutMappingDeclaration;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.FieldAccessSpec;
+import org.eclipse.objectteams.otdt.internal.core.compiler.ast.MethodSpec.ImplementationStrategy;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.DependentTypeBinding;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.ITeamAnchor;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.RoleTypeBinding;
@@ -854,7 +856,7 @@
 					// realize decapsulation by simulating an inferred callout-to-field
 					field = closestField;
 					scope.problemReporter().decapsulation(this, field, scope);
-					accessAsCalloutToField(enclosingReceiver, field, index);
+					accessAsCalloutToField(enclosingReceiver, field, index, scope.compilerOptions().weavingScheme);
 					fixedByDecapsulation = true;
 				}
 		  }
@@ -924,12 +926,13 @@
 }
 
 //{ObjectTeams: replace this field reference with an accessor call (simulated as callout-to-field):
-private void accessAsCalloutToField(ReferenceBinding enclosingReceiver, FieldBinding baseclassField, int idx)
+private void accessAsCalloutToField(ReferenceBinding enclosingReceiver, FieldBinding baseclassField, int idx, WeavingScheme weaving)
 {
 	ReferenceBinding baseClass = baseclassField.declaringClass;
 
 	// manually create and add binding as if it were a callout to field:
-	final MethodBinding fakedAccessorBinding = FieldModel.getDecapsulatingFieldAccessor(baseClass, baseclassField, true);
+	ImplementationStrategy strategy = weaving == WeavingScheme.OTDRE ? ImplementationStrategy.DYN_ACCESS : ImplementationStrategy.DECAPS_WRAPPER;
+	final MethodBinding fakedAccessorBinding = FieldModel.getDecapsulatingFieldAccessor(baseClass, baseclassField, true, strategy);
 	baseClass.addMethod(fakedAccessorBinding);
 
 	// record the need to have the OTRE create the accessor:
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
index 9623091..f77eaad 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
@@ -66,6 +66,7 @@
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions.WeavingScheme;
 import org.eclipse.jdt.internal.compiler.parser.Parser;
 import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
 import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
@@ -77,6 +78,7 @@
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.RoleFileCache;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.TypeAnchorReference;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.TypeValueParameter;
+import org.eclipse.objectteams.otdt.internal.core.compiler.ast.MethodSpec.ImplementationStrategy;
 import org.eclipse.objectteams.otdt.internal.core.compiler.control.*;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.AnchorMapping;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.SyntheticBaseCallSurrogate;
@@ -2351,12 +2353,16 @@
 			ReferenceBinding originalRole = field.declaringClass;
 			if (field.copyInheritanceSrc != null)
 				originalRole = field.copyInheritanceSrc.declaringClass;
-			inner = FieldModel.getDecapsulatingFieldAccessor(this, field, true/*isGetter*/);
-			((SourceTypeBinding) enclosingType()).addSyntheticRoleMethodBridge(this, originalRole, inner, SyntheticMethodBinding.RoleMethodBridgeOuter);
-			if (!field.isFinal()) { // no setter for final (includes all static role fields)
-								    // otherwise we would have to handle different signatures (w/ w/o role arg), which we currently don't
-				inner = FieldModel.getDecapsulatingFieldAccessor(this, field, false/*isGetter*/);
+			ImplementationStrategy strategy = this.scope.compilerOptions().weavingScheme == WeavingScheme.OTDRE
+												? ImplementationStrategy.DYN_ACCESS : ImplementationStrategy.DECAPS_WRAPPER;
+			if (strategy != ImplementationStrategy.DYN_ACCESS) {
+				inner = FieldModel.getDecapsulatingFieldAccessor(this, field, true/*isGetter*/, strategy);
 				((SourceTypeBinding) enclosingType()).addSyntheticRoleMethodBridge(this, originalRole, inner, SyntheticMethodBinding.RoleMethodBridgeOuter);
+				if (!field.isFinal()) { // no setter for final (includes all static role fields)
+									    // otherwise we would have to handle different signatures (w/ w/o role arg), which we currently don't
+					inner = FieldModel.getDecapsulatingFieldAccessor(this, field, false/*isGetter*/, strategy);
+					((SourceTypeBinding) enclosingType()).addSyntheticRoleMethodBridge(this, originalRole, inner, SyntheticMethodBinding.RoleMethodBridgeOuter);
+				}
 			}
 		}
 // SH}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/FieldAccessSpec.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/FieldAccessSpec.java
index 7a94687..6fcd91a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/FieldAccessSpec.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/FieldAccessSpec.java
@@ -228,16 +228,24 @@
     		// because several callouts to the same field could exist.
     		// RoleTypeCreator.maybeWrapQualifiedRoleType(MessageSend,BlockScope)
     		// will wrap the type using a faked _OT$base receiver.
-    		return FieldModel.getDecapsulatingFieldAccessor(baseType, this.resolvedField, true);
+    		return FieldModel.getDecapsulatingFieldAccessor(baseType, this.resolvedField, true, this.implementationStrategy);
 		} else {
     		TypeBinding declaredFieldType = this.hasSignature ?
 					this.parameters[0] :
 					this.fieldType;
-    		TypeBinding[] argTypes = this.resolvedField.isStatic() ?
+			int access;
+			TypeBinding[] argTypes;
+			if (this.implementationStrategy == ImplementationStrategy.DYN_ACCESS) {
+				access = ClassFileConstants.AccPublic;
+				argTypes = new TypeBinding[]{declaredFieldType};
+			} else {
+				access = ClassFileConstants.AccPublic|ClassFileConstants.AccStatic;
+				argTypes = this.resolvedField.isStatic() ?
     									new TypeBinding[]{declaredFieldType} :
     									new TypeBinding[]{baseType, declaredFieldType};
+			}
 			return new MethodBinding(
-    				ClassFileConstants.AccPublic|ClassFileConstants.AccStatic,
+    					access,
 						accessorSelector,
 						TypeBinding.VOID,
 						argTypes,
@@ -267,8 +275,8 @@
     	if (this.resolvedMethod == null)
     		return this.parameters; // empty; FIXME(SH): handle "set" access
     	TypeBinding[] methodParams = super.resolvedParameters();
-    	if (this.resolvedField.isStatic())
-    		return methodParams; // no base argument when accessing a static field
+    	if (this.resolvedField.isStatic() || this.implementationStrategy == ImplementationStrategy.DYN_ACCESS)
+    		return methodParams; // no base argument when accessing a static field, or in OTDRE mode
 		TypeBinding[] result = new TypeBinding[methodParams.length-1];
     	System.arraycopy(methodParams, 1, result, 0, result.length);
     	return result;
@@ -329,7 +337,7 @@
 		if (this.calloutModifier == TerminalTokens.TokenNameget)
 			return true; // no parameter
 		int argumentPosition = 0; // safer against AIOOBE
-		if (this.resolvedField != null && !this.resolvedField.isStatic())
+		if (this.resolvedField != null && !this.resolvedField.isStatic() && this.implementationStrategy != ImplementationStrategy.DYN_ACCESS)
 			argumentPosition = 1;
 		TypeBinding accessorParamType = null;
 		if (this.resolvedMethod != null)
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/BytecodeTransformer.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/BytecodeTransformer.java
index a758b2e..d241b00 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/BytecodeTransformer.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/BytecodeTransformer.java
@@ -45,6 +45,7 @@
 import org.eclipse.objectteams.otdt.internal.core.compiler.bytecode.ConstantPoolObjectReader.IncompatibleBytecodeException;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lifting.ArrayTranslations;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lifting.Lifting;
+import org.eclipse.objectteams.otdt.internal.core.compiler.mappings.CalloutImplementorDyn;
 import org.eclipse.objectteams.otdt.internal.core.compiler.model.MethodModel;
 import org.eclipse.objectteams.otdt.internal.core.compiler.model.RoleModel;
 import org.eclipse.objectteams.otdt.internal.core.compiler.model.TeamModel;
@@ -161,6 +162,10 @@
         	dstMethod.binding.bytecodeMissing= true;
        		return;
         }
+        
+		if (CharOperation.equals(CalloutImplementorDyn.OT_ACCESS, dstMethod.selector)
+			||CharOperation.equals(CalloutImplementorDyn.OT_ACCESS_STATIC, dstMethod.selector))
+        	return;
 
         byte[] srcConstantPool  = null;
         int    offset           = -1;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/ConstantPoolObjectReader.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/ConstantPoolObjectReader.java
index e652076..39a6940 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/ConstantPoolObjectReader.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/ConstantPoolObjectReader.java
@@ -55,6 +55,7 @@
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.SyntheticBaseCallSurrogate;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.SyntheticRoleFieldAccess;
 import org.eclipse.objectteams.otdt.internal.core.compiler.mappings.CallinImplementorDyn;
+import org.eclipse.objectteams.otdt.internal.core.compiler.mappings.CalloutImplementorDyn;
 import org.eclipse.objectteams.otdt.internal.core.compiler.model.MethodModel;
 import org.eclipse.objectteams.otdt.internal.core.compiler.model.RoleModel;
 import org.eclipse.objectteams.otdt.internal.core.compiler.model.TypeModel;
@@ -487,7 +488,9 @@
 	boolean isSynthMethodName(char[] name) {
 		return 
 			CharOperation.prefixEquals(TypeConstants.SYNTHETIC_ACCESS_METHOD_PREFIX, name)
-			|| CharOperation.prefixEquals(TypeConstants.SYNTHETIC_SWITCH_ENUM_TABLE, name);
+			|| CharOperation.prefixEquals(TypeConstants.SYNTHETIC_SWITCH_ENUM_TABLE, name)
+			|| CharOperation.equals(CalloutImplementorDyn.OT_ACCESS, name)
+			|| CharOperation.equals(CalloutImplementorDyn.OT_ACCESS_STATIC, name);
 	}
 
 	/** Detect methods that will be generated by the OTRE. If match return the assumed modifiers */
@@ -507,6 +510,10 @@
 			return AccPublic;
 		if (CharOperation.equals(CallinImplementorDyn.OT_CALL_BEFORE, name))
 			return AccPublic;
+		if (CharOperation.equals(CalloutImplementorDyn.OT_ACCESS, name))
+			return AccPublic;
+		if (CharOperation.equals(CalloutImplementorDyn.OT_ACCESS_STATIC, name))
+			return AccPublic;
 		return 0;
 	}
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CalloutImplementor.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CalloutImplementor.java
index 2530885..44dd1f0 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CalloutImplementor.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/mappings/CalloutImplementor.java
@@ -68,6 +68,7 @@
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.CalloutMappingDeclaration;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.FieldAccessSpec;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.MethodSpec;
+import org.eclipse.objectteams.otdt.internal.core.compiler.ast.MethodSpec.ImplementationStrategy;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.ParameterMapping;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.PotentialLowerExpression;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.PrivateRoleMethodCall;
@@ -558,7 +559,9 @@
 							CastExpression.DO_WRAP);
 
 		Expression baseAccess = null;
-		if (calloutDecl.baseMethodSpec.isPrivate() && baseType.isRole()) {
+		if (calloutDecl.baseMethodSpec.isPrivate() && baseType.isRole()
+				&& calloutDecl.baseMethodSpec.implementationStrategy != ImplementationStrategy.DYN_ACCESS)
+		{
     		// tricky case: callout to a private role method (base-side)
     		// requires the indirection via two wrapper methods (privateBridgeMethod)
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/model/FieldModel.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/model/FieldModel.java
index 16d29eb..7c0a4ab 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/model/FieldModel.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/model/FieldModel.java
@@ -20,10 +20,10 @@
  **********************************************************************/
 package org.eclipse.objectteams.otdt.internal.core.compiler.model;
 
+import static org.eclipse.objectteams.otdt.core.compiler.IOTConstants.ANCHOR_USAGE_RANKS;
+import static org.eclipse.objectteams.otdt.core.compiler.IOTConstants.AccSynthIfc;
 import static org.eclipse.objectteams.otdt.core.compiler.IOTConstants.OT_GETFIELD;
 import static org.eclipse.objectteams.otdt.core.compiler.IOTConstants.OT_SETFIELD;
-import static org.eclipse.objectteams.otdt.core.compiler.IOTConstants.AccSynthIfc;
-import static org.eclipse.objectteams.otdt.core.compiler.IOTConstants.ANCHOR_USAGE_RANKS;
 
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
@@ -37,6 +37,7 @@
 import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
 import org.eclipse.objectteams.otdt.core.exceptions.InternalCompilerError;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.CalloutMappingDeclaration;
+import org.eclipse.objectteams.otdt.internal.core.compiler.ast.MethodSpec.ImplementationStrategy;
 import org.eclipse.objectteams.otdt.internal.core.compiler.bytecode.AnchorUsageRanksAttribute;
 import org.eclipse.objectteams.otdt.internal.core.compiler.bytecode.WordValueAttribute;
 import org.eclipse.objectteams.otdt.internal.core.compiler.model.MethodModel.FakeKind;
@@ -153,22 +154,33 @@
 	 */
 	public static MethodBinding getDecapsulatingFieldAccessor(ReferenceBinding baseType,
 												         		  FieldBinding     resolvedField,
-												         		  boolean 		   isGetter)
+												         		  boolean 		   isGetter,
+												         		  ImplementationStrategy strategy)
 	{
 		FieldModel model = FieldModel.getModel(resolvedField);
 		MethodBinding accessor = isGetter ? model._decapsulatingGetter : model._decapsulatingSetter;
 		if (accessor != null)
 			return accessor;
 		
-		TypeBinding[] argTypes = resolvedField.isStatic() 
+		TypeBinding[] argTypes;
+		int access;
+		if (strategy == ImplementationStrategy.DYN_ACCESS) {
+			argTypes = isGetter 
+							? new TypeBinding[0] 
+							: new TypeBinding[]{resolvedField.type};
+			access = ClassFileConstants.AccPublic;
+		} else {
+			argTypes = resolvedField.isStatic() 
 									? (isGetter 
 											? new TypeBinding[0] 
 											: new TypeBinding[]{resolvedField.type})
 									: (isGetter
 											? new TypeBinding[]{baseType}
 											: new TypeBinding[]{baseType, resolvedField.type});
+			access = ClassFileConstants.AccPublic|ClassFileConstants.AccStatic;
+		}
 		accessor = new MethodBinding(
-					ClassFileConstants.AccPublic|ClassFileConstants.AccStatic,
+					access,
 					CharOperation.concat(isGetter ? OT_GETFIELD : OT_SETFIELD, resolvedField.name),
 					isGetter ? resolvedField.type : TypeBinding.VOID,
 					argTypes,