Bug 468116: [otdre] weaving access to indirectly inherited base method
fails in OT/Equinox settings

- test (was already passing)
- change data in OTSpecialAccessAttribute to register more base classes
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/OTSpecialAccessAttribute.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/OTSpecialAccessAttribute.java
index 1892da1..4e2433f 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/OTSpecialAccessAttribute.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/OTSpecialAccessAttribute.java
@@ -31,6 +31,7 @@
 import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
 import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
 import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
 import org.eclipse.jdt.internal.compiler.parser.TerminalTokens;
 import org.eclipse.objectteams.otdt.core.compiler.IOTConstants;
 import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.RoleTypeBinding;
@@ -117,7 +118,16 @@
 														this.method.declaringClass.attributeName(),
 														this.method.selector
 													}, sep);
-				writeName(this.boundBaseclass.attributeName()); // where to weave into
+				char[] weaveIntoClasses = this.boundBaseclass.attributeName();
+				if (OTSpecialAccessAttribute.this._weavingScheme == WeavingScheme.OTDRE) {
+					// for OTDRE pass all classes to weave from boundBaseclass up to the actual declaring class (:-separated)
+					ReferenceBinding someClass = this.boundBaseclass.getRealClass();
+					if (someClass != null && TypeBinding.notEquals(someClass, this.method.declaringClass)) {
+						while ((someClass = someClass.superclass()) != null && TypeBinding.notEquals(someClass, this.method.declaringClass))
+							weaveIntoClasses = CharOperation.concat(weaveIntoClasses, someClass.attributeName(), ':');
+					}
+				}
+				writeName(weaveIntoClasses);
 				writeName(encodedName);
 				writeName(this.method.signature());
 			}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmClassVisitor.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmClassVisitor.java
index 46c01bc..c235796 100644
--- a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmClassVisitor.java
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmClassVisitor.java
@@ -25,6 +25,7 @@
 import org.eclipse.objectteams.otredyn.bytecode.asm.Attributes.CallinBindingsAttribute.MultiBinding;

 import org.eclipse.objectteams.otredyn.bytecode.asm.Attributes.CallinPrecedenceAttribute;

 import org.eclipse.objectteams.otredyn.bytecode.asm.Attributes.OTSpecialAccessAttribute;

+import org.eclipse.objectteams.otredyn.bytecode.asm.Attributes.OTSpecialAccessAttribute.DecapsMethod;

 import org.objectweb.asm.AnnotationVisitor;

 import org.objectweb.asm.Attribute;

 import org.objectweb.asm.ClassVisitor;

@@ -110,11 +111,12 @@
 				int[] baseFlags = multiBindings[i].getBaseFlags();

 				boolean handleCovariantReturn = multiBindings[i].isHandleCovariantReturn();

 				for (int j = 0; j < baseMethodNames.length; j++) {

+					String declaringBaseClassName = declaringBaseClassNames[j];

 					Binding binding = new Binding(clazz, roleClassName, callinLabel, baseClassName, 

-												  baseMethodNames[j], baseMethodSignatures[j], declaringBaseClassNames[j],

+												  baseMethodNames[j], baseMethodSignatures[j], declaringBaseClassName,

 												  callinModifier, callinIds[j], baseFlags[j], handleCovariantReturn);

 					clazz.addBinding(binding);

-					clazz.boundBaseClasses.add(declaringBaseClassNames[j].replace('/', '.'));

+					clazz.boundBaseClasses.add(declaringBaseClassName.replace('/', '.'));

 				}

 			}

 		} else if (attribute.type.equals(Attributes.ATTRIBUTE_CALLIN_PRECEDENCE)) {

@@ -123,7 +125,12 @@
 		} else if (attribute.type.equals(Attributes.ATTRIBUTE_OT_CLASS_FLAGS)) {

 			clazz.setOTClassFlags(((OTClassFlagsAttribute)attribute).flags);

 		} else if (attribute.type.equals(Attributes.ATTRIBUTE_OT_SPECIAL_ACCESS)) {

-			((OTSpecialAccessAttribute)attribute).registerAt(clazz);

+			OTSpecialAccessAttribute accessAttribute = (OTSpecialAccessAttribute)attribute;

+			accessAttribute.registerAt(clazz);

+			for (DecapsMethod method : accessAttribute.methods) {

+				for (String weaveInto : method.weaveIntoClasses)

+					clazz.boundBaseClasses.add(weaveInto);

+			}

 		} else if (attribute.type.equals(Attributes.ATTRIBUTE_ROLE_BASE_BINDINGS)) {

 			for (String base : ((RoleBaseBindingsAttribute) attribute).bases) {

 				clazz.boundBaseClasses.add(base.replace('/', '.'));

diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/Attributes.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/Attributes.java
index 031df64..571eed6 100644
--- a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/Attributes.java
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/Attributes.java
@@ -286,11 +286,13 @@
 			}

 		}

 		class DecapsMethod {

-			String baseclass, name, desc;

+			String[] weaveIntoClasses;

+			String declaringClass, name, desc;

 			int perTeamAccessId;

 			boolean isStatic;

-			DecapsMethod(String baseclass, String name, String desc, int id, boolean isStatic) {

-				this.baseclass = baseclass;

+			DecapsMethod(String weaveIntoClasses, String declaringClass, String name, String desc, int id, boolean isStatic) {

+				this.weaveIntoClasses = weaveIntoClasses.split(":");

+				this.declaringClass = declaringClass;

 				this.name = name;

 				this.desc = desc;

 				this.perTeamAccessId = id;

@@ -346,11 +348,11 @@
 			String methodDesc  = cr.readUTF8(off+4, buf);

 			int accessId = cr.readUnsignedShort(off+6);

 			boolean isStatic = false;

-			String baseClass;

+			String declaringClass;

 			String methodName;

 			if (encodedName.charAt(0) == '<') {

 				// constructor

-				baseClass = className;

+				declaringClass = className;

 				methodName = encodedName;

 				isStatic = true; // use static accessor

 			} else {

@@ -359,10 +361,10 @@
 					pos = encodedName.indexOf('!');

 					isStatic = true;

 				}

-				baseClass = encodedName.substring(0, pos);

+				declaringClass = encodedName.substring(0, pos);

 				methodName = encodedName.substring(pos+1);

 			}

-			this.methods.add(new DecapsMethod(baseClass, methodName, methodDesc, accessId, isStatic));

+			this.methods.add(new DecapsMethod(className, declaringClass, methodName, methodDesc, accessId, isStatic));

 		}

 		private void readFieldAccess(ClassReader cr, int off, char[] buf) {

 			int accessId = cr.readUnsignedShort(off);

@@ -382,11 +384,11 @@
 				// FIXME(SH): the following may need adaptation for OT/Equinox or other multi-classloader settings:

 				// bypassing the identifier provider (we don't have a Class<?> yet):

 				// String boundClassIdentifier = provider.getBoundClassIdentifier(clazz, dMethod.baseclass);

-				AbstractBoundClass baseclass = repo.getBoundClass(dMethod.baseclass, dMethod.baseclass.replace('.', '/'), clazz.getClassLoader());

+				AbstractBoundClass baseclass = repo.getBoundClass(dMethod.declaringClass, dMethod.declaringClass.replace('.', '/'), clazz.getClassLoader());

 				// register the target method:

 				baseclass.getMethod(dMethod.name, dMethod.desc, false/*covariantReturn*/, dMethod.isStatic);

 				clazz.recordAccessId(dMethod.perTeamAccessId);

-				clazz.addBinding(new Binding(clazz, dMethod.baseclass, dMethod.name, dMethod.desc, dMethod.perTeamAccessId, IBinding.BindingType.METHOD_ACCESS));

+				clazz.addBinding(new Binding(clazz, dMethod.declaringClass, dMethod.name, dMethod.desc, dMethod.perTeamAccessId, IBinding.BindingType.METHOD_ACCESS));

 			}

 

 			for (DecapsField dField: this.fields) {

diff --git a/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/calloutbinding/OverridingAccessRestrictions.java b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/calloutbinding/OverridingAccessRestrictions.java
index fa04665..1c0bcc2 100644
--- a/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/calloutbinding/OverridingAccessRestrictions.java
+++ b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/calloutbinding/OverridingAccessRestrictions.java
@@ -1613,4 +1613,36 @@
 			"C1::printStr1(): C1.str\n" +
 			"T1.R1::getStr1(): C1.str");
     }
+    public void testX() throws Exception {
+    	runConformTest(
+    		new String[] {
+				"pt/MyTeam.java",
+				"package pt;\n" +
+				"public team class MyTeam {\n" +
+				"	protected class R playedBy p3.C3 {\n" +
+				"		protected void rm() -> void mc();\n" +
+				"	}\n" +
+				"	void test(p3.C3 as R r) {\n" +
+				"		r.rm();\n" +
+				"	}\n" +
+				"	public static void main(String... args) {\n" +
+				"		new MyTeam().test(new p3.C3());\n" +
+				"	}\n" +
+				"}\n",
+    			"p1/C1.java",
+    			"package p1;\n" +
+    			"public class C1 {\n" +
+    			"	protected void mc() {\n" +
+    			"		System.out.print(13);\n" +
+    			"	}\n" +
+    			"}\n",
+    			"p2/C2.java",
+    			"package p2;\n" +
+    			"public class C2 extends p1.C1 {}\n",
+    			"p3/C3.java",
+    			"package p3;\n" +
+    			"public class C3 extends p2.C2 {}\n",
+    		},
+    		"13");
+    }
 }