Bug 460525 - Evaluating PlayedBy attribute may cause bad processing
order
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java
index f58cb49..6da45e7 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java
@@ -64,6 +64,7 @@
 import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
 import org.eclipse.jdt.internal.compiler.util.Util;
 import org.eclipse.objectteams.otdt.core.compiler.IOTConstants;
+import org.eclipse.objectteams.otdt.internal.core.compiler.bytecode.AbstractAttribute;
 import org.eclipse.objectteams.otdt.internal.core.compiler.control.Config;
 import org.eclipse.objectteams.otdt.internal.core.compiler.control.Dependencies;
 import org.eclipse.objectteams.otdt.internal.core.compiler.control.ITranslationStates;
@@ -807,8 +808,8 @@
 					this.fields[i].setAnnotations(createAnnotations(binaryField.getAnnotations(), this.environment, missingTypeNames));
 				}
 			}
-				}
-			}
+		}
+	}
 }
 //{ObjectTeams: some fields are indeed value parameters:
 private SyntheticArgumentBinding[] valueParameters = NO_SYNTH_ARGUMENTS;
@@ -2220,8 +2221,18 @@
 }
 //{ObjectTeams:
 public ReferenceBinding baseclass () {
-    if (this.baseclass == null)
+	if (this.baseclass == null) {
+    	if (this.roleModel != null) {
+    		// check if evaluation of a PlayedBy attribute had to be deferred:
+    		AbstractAttribute attribute = this.roleModel.getAttribute(IOTConstants.PLAYEDBY_NAME);
+    		if (attribute != null) {
+    			attribute.evaluate(this, this.environment, null);
+    			this.roleModel.removeAttribute(attribute);
+    			return baseclass();
+    		}
+    	}
         return null;
+    }
     if (this.baseclass instanceof UnresolvedReferenceBinding)
         this.baseclass = ((UnresolvedReferenceBinding) this.baseclass).resolve(this.environment, false);
     return this.baseclass;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/SingleValueAttribute.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/SingleValueAttribute.java
index 8b08afa..500b18d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/SingleValueAttribute.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/SingleValueAttribute.java
@@ -1,7 +1,7 @@
 /**********************************************************************
  * This file is part of "Object Teams Development Tooling"-Software
  *
- * Copyright 2004, 2006 Fraunhofer Gesellschaft, Munich, Germany,
+ * Copyright 2004, 2015 Fraunhofer Gesellschaft, Munich, Germany,
  * for its Fraunhofer Institute for Computer Architecture and Software
  * Technology (FIRST), Berlin, Germany and Technical University Berlin,
  * Germany.
@@ -10,7 +10,6 @@
  * 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: SingleValueAttribute.java 23416 2010-02-03 19:59:31Z stephan $
  *
  * Please visit http://www.eclipse.org/objectteams for updates and contact.
  *
@@ -23,6 +22,7 @@
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.ClassFile;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileStruct;
+import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding;
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
 import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
 import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
@@ -66,7 +66,6 @@
  *
  * </ul>
  * @author stephan
- * @version $Id: SingleValueAttribute.java 23416 2010-02-03 19:59:31Z stephan $
  */
 public class SingleValueAttribute
         extends AbstractAttribute
@@ -200,6 +199,11 @@
             	ReferenceBinding currentType = staticPart;
             	ITeamAnchor anchor = null; // accumulate anchor path here
             	while (i<anchorPath.length) {
+            		if (currentType instanceof BinaryTypeBinding && ((BinaryTypeBinding) currentType).version == 0) {
+            			// necessary type on the path is not fully initialized (version is about the last field to be assigned in cachePartsFrom()).
+            			roleType.roleModel.addAttribute(this);
+            			return; // defer evaluation
+            		}
             		FieldBinding f = currentType.getField(anchorPath[i], true);
             		if (f == null || !(f.type instanceof ReferenceBinding))
             			return; // not a valid anchor path.
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/model/ModelElement.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/model/ModelElement.java
index c55a855..fd6a9b6 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/model/ModelElement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/model/ModelElement.java
@@ -1,7 +1,7 @@
 /**********************************************************************
  * This file is part of "Object Teams Development Tooling"-Software
  *
- * Copyright 2004, 2010 Fraunhofer Gesellschaft, Munich, Germany,
+ * Copyright 2004, 2015 Fraunhofer Gesellschaft, Munich, Germany,
  * for its Fraunhofer Institute for Computer Architecture and Software
  * Technology (FIRST), Berlin, Germany and Technical University Berlin,
  * Germany.
@@ -36,14 +36,10 @@
 
 
     /** Add an OT-specific bytecode attribute. */
-    public void addAttribute (AbstractAttribute attr)
-    {
-        if (this._attributes == null)
-        {
+    public void addAttribute (AbstractAttribute attr) {
+        if (this._attributes == null) {
             this._attributes = new AbstractAttribute[]{attr};
-        }
-        else
-        {
+        } else {
             int len = this._attributes.length;
             AbstractAttribute[] newAttrs = new AbstractAttribute[len+1];
             System.arraycopy(this._attributes, 0, newAttrs, 0, len);
@@ -93,6 +89,22 @@
 		}
     	return null;
     }
+
+    public void removeAttribute(AbstractAttribute attr) {
+    	if (this._attributes == null) return;
+    	int newLength = this._attributes.length-1;
+		AbstractAttribute[] newAttributes = new AbstractAttribute[newLength];
+		int i = 0;
+		for (AbstractAttribute anAttr : this._attributes) {
+			if (anAttr != attr) {
+				if (i == newLength)
+					return; // trying to insert the last item means: not found, so just don't change
+				newAttributes[i++] = anAttr;
+			}
+		}
+		this._attributes = newAttributes;
+    }
+
     /**
      * Write all OT-specific attributes of a given type binding to the given class file
      * @param type the element whose attributes should be written
diff --git a/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/rolesandteams/FileStructure.java b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/rolesandteams/FileStructure.java
index 40905e5..4755c2c 100644
--- a/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/rolesandteams/FileStructure.java
+++ b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/rolesandteams/FileStructure.java
@@ -1,13 +1,12 @@
 /**********************************************************************
  * This file is part of "Object Teams Development Tooling"-Software
  * 
- * Copyright 2004, 2010 IT Service Omikron GmbH and others.
+ * Copyright 2004, 2015 IT Service Omikron GmbH and others.
  * 
  * 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$
  * 
  * Please visit http://www.eclipse.org/objectteams for updates and contact.
  * 
@@ -2232,4 +2231,42 @@
             customOptions,
             null/*no custom requestor*/);
     }
+    
+    // Bug 460525 - Evaluating PlayedBy attribute may cause bad processing order
+    public void testBug460525() {
+    	compileOrder = new String[][] {
+			    			new String[] {"pb/BaseTeam.java", "pt/TopTeam.java", "pt/TopTeam/Mid/InnerRole.java"},
+			    			new String[] {"pt/Main.java"}
+    					};
+    	runConformTest(
+    		new String[] {
+    			"pb/BaseTeam.java",
+    				"package pb;\n" +
+    				"public team class BaseTeam {\n" +
+    				"	public class BaseRole {}\n" +
+    				"}\n",
+    			"pt/TopTeam.java",
+    				"package pt;\n" +
+    				"import base pb.BaseTeam;\n" +
+    				"public team class TopTeam {\n" +
+    				"	public team class Mid playedBy BaseTeam {\n" +
+    				"		public void mTest(BaseRole<@base> r) {}\n" +
+    				"	}\n" +
+    				"}\n",
+    			"pt/TopTeam/Mid/InnerRole.java",
+    				"team package pt.TopTeam.Mid;\n" +
+    				"public class InnerRole playedBy BaseRole<@Mid.base> {}\n",
+
+				// Compiling this class triggered:
+				// TopTeam.createFields() -> InnerRole.cachePartsFrom() -> InnerRole.evaluateOTAttributes() -> TopTeam.getField() -> NPE
+    			"pt/Main.java",
+    				"package pt;\n" +
+    				"public class Main {\n" +
+    				"	final TopTeam t = new TopTeam();\n" +
+    				"	void test(final Mid<@t> m, InnerRole<@m> i) {\n" +
+    				"		m.mTest(i);\n" + // need this call to force resolving of InnerRole.baseclass()
+    				"	}\n" +
+    				"}\n"
+    		});
+    }
 }