Bug 401415 - Can't show sources from installed plug-ins for some
teams/roles in o.e.objectteams.otdt.jdt.ui

OTModel:
- fix reading of CTF(set) under OTDRE (otmodel)
- include OT_CLASS_FLAGS in BinaryType.getFlags() via CFR.getModifiers
- use flag to create BinaryRoleType if needed
- strip __OT__ in one more ctor of BinaryType
- BinaryType.equals(): ignore __OT__ difference in parent classfile
- retrench some signatures for BinaryMethod, to make them selectable
- minor cleanup in ClassFileInfo

Improved source mapping for roles
- buffer lookup: don't directly consult the outermost enclosing type
- pass flags where known
- include team name for source lookup of role file

Outline:
- support double-click opening of role file
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java
index eb424c1..a1e6d99 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java
@@ -1029,6 +1029,14 @@
 	} else {
 		modifiers = this.accessFlags;
 	}
+//{ObjectTeams:
+	for (AbstractAttribute attribute : getOTAttributes()) {
+		if (attribute.nameEquals(IOTConstants.OT_CLASS_FLAGS)) {
+			modifiers |= ((WordValueAttribute) attribute).classFlagsToModifiers();
+			break;
+		}
+	}
+// SH}
 	return modifiers;
 }
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/WordValueAttribute.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/WordValueAttribute.java
index d4c5c9f..5d3fdde 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/WordValueAttribute.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/WordValueAttribute.java
@@ -245,8 +245,8 @@
 		}
 	}
 
-	private static WeavingScheme weavingSchemeFromCompilerVersion(int version) {
-		if ((version & OTDRE_FLAG) != 0)
+	public WeavingScheme weavingSchemeFromCompilerVersion() {
+		if ((this._value & OTDRE_FLAG) != 0)
 			return WeavingScheme.OTDRE;
 		return WeavingScheme.OTRE;
 	}
@@ -316,12 +316,7 @@
         {
             checkBindingMismatch(binding, 0);
             BinaryTypeBinding type = (BinaryTypeBinding)binding;
-            if ((this._value & OT_CLASS_ROLE) != 0)
-            	type.modifiers |= ExtraCompilerModifiers.AccRole;
-            if ((this._value & OT_CLASS_TEAM) != 0)
-            	type.modifiers |= ExtraCompilerModifiers.AccTeam;
-            if ((this._value & OT_CLASS_FLAG_HAS_TSUPER) != 0)
-            	type.modifiers |= ExtraCompilerModifiers.AccOverriding;
+            type.modifiers |= classFlagsToModifiers();
             if ((this._value & OT_CLASS_ROLE_LOCAL) != 0)
             	type.setIsRoleLocal();
             if ((this._value & (OT_CLASS_ROLE_FILE|OT_CLASS_PURELY_COPIED)) != 0)
@@ -347,9 +342,9 @@
         	checkBindingMismatch(binding, 0);
             BinaryTypeBinding type = (BinaryTypeBinding)binding;
         	if (type.isRole())
-        		type.roleModel.setCompilerVersion(this._value, weavingSchemeFromCompilerVersion(this._value));
+        		type.roleModel.setCompilerVersion(this._value, weavingSchemeFromCompilerVersion());
         	if (type.isTeam())
-        		type.getTeamModel().setCompilerVersion(this._value, weavingSchemeFromCompilerVersion(this._value));
+        		type.getTeamModel().setCompilerVersion(this._value, weavingSchemeFromCompilerVersion());
         	if (this._value < IOTConstants.OTVersion.getCompilerVersionMin())
         		environment.problemReporter.incompatibleOTJByteCodeVersion(((BinaryTypeBinding)binding).getFileName(), getBytecodeVersionString(this._value));
         	if ((type.isRole() || type.isTeam())
@@ -372,6 +367,17 @@
         }
     }
 
+	public int classFlagsToModifiers() {
+		int modifiers = 0;
+		if ((this._value & OT_CLASS_ROLE) != 0)
+			modifiers |= ExtraCompilerModifiers.AccRole;
+		if ((this._value & OT_CLASS_TEAM) != 0)
+			modifiers |= ExtraCompilerModifiers.AccTeam;
+		if ((this._value & OT_CLASS_FLAG_HAS_TSUPER) != 0)
+			modifiers |= ExtraCompilerModifiers.AccOverriding;
+		return modifiers;
+	}
+
 
     /** can only transfer some flags once we have the method binding */
     @Override
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryMethod.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryMethod.java
index a8bfec9..6a4f6a6 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryMethod.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryMethod.java
@@ -14,9 +14,12 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
+import java.util.Arrays;
+
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.jdt.core.Flags;
 import org.eclipse.jdt.core.IAnnotation;
+import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.ILocalVariable;
 import org.eclipse.jdt.core.IMemberValuePair;
 import org.eclipse.jdt.core.IMethod;
@@ -64,6 +67,27 @@
 	if (paramTypes == null) {
 		this.parameterTypes= CharOperation.NO_STRINGS;
 	} else {
+//{ObjectTeams: retrench some signatures
+		IType type = (IType) parent.getAncestor(IJavaElement.TYPE);
+		try {
+			if (paramTypes.length >= 6 && Flags.isRole(type.getFlags())) {
+				if (paramTypes[0].equals("Lorg.objectteams.IBoundBase2;")) //$NON-NLS-1$
+					paramTypes = Arrays.copyOfRange(paramTypes, 6, paramTypes.length);
+			} else if (paramTypes.length >= 2 && paramTypes[0].equals("I")) { //$NON-NLS-1$
+				IType outerType = type.getDeclaringType();
+				if (outerType != null) {
+					if (paramTypes[1].charAt(0) == Signature.C_RESOLVED
+							? Signature.toString(paramTypes[1]).equals(outerType.getFullyQualifiedName('$'))
+							: Signature.toString(paramTypes[1]).equals(outerType.getElementName())) {
+						// we're taking a guess that this might be a static role method, but getFlags() should not be called here
+						paramTypes = Arrays.copyOfRange(paramTypes, 2, paramTypes.length);
+					}
+				}
+			}
+		} catch (JavaModelException e) {
+			// ignore
+		}
+// SH}
 		this.parameterTypes= paramTypes;
 	}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryType.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryType.java
index dc7c301..e8591dd 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryType.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryType.java
@@ -33,7 +33,6 @@
 import org.eclipse.jdt.internal.compiler.env.IBinaryAnnotation;
 import org.eclipse.jdt.internal.compiler.env.IBinaryType;
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
-import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
 import org.eclipse.jdt.internal.core.JavaModelManager.PerProjectInfo;
 import org.eclipse.jdt.internal.core.hierarchy.TypeHierarchy;
@@ -62,14 +61,9 @@
 	// ((IBinaryType) getElementInfo()).getEnclosingTypeName();
 	private boolean enclosingNameSet = false;
 	private char[] storedEnclosingTypeName = null;
-	private boolean isRole = false;
 
 	protected BinaryType(char[] enclosingTypeName, JavaElement parent, String name) {
 		this(parent, name);
-		if (name.startsWith(IOTConstants.OT_DELIM)) {
-			this.isRole = true;
-			this.name = this.name.substring(IOTConstants.OT_DELIM_LEN);
-		}
 		this.storedEnclosingTypeName = enclosingTypeName;
 		this.enclosingNameSet = true;
 	}
@@ -77,7 +71,6 @@
 	void updateEnclosingTypeName(@NonNull char[] enclosingTypeName) {
 		if (!this.enclosingNameSet && this.storedEnclosingTypeName == null) {
 			if (this.name.startsWith(IOTConstants.OT_DELIM)) {
-				this.isRole = true;
 				this.name = this.name.substring(IOTConstants.OT_DELIM_LEN);
 			}
 			this.storedEnclosingTypeName = enclosingTypeName;
@@ -87,7 +80,7 @@
 // SH}
 
 protected BinaryType(JavaElement parent, String name) {
-	super(parent, name);
+	super(parent, name.startsWith(IOTConstants.OT_DELIM) ? name.substring(IOTConstants.OT_DELIM_LEN) : name);
 }
 /*
  * Remove my cached children from the Java Model
@@ -200,6 +193,22 @@
 @Override
 public boolean equals(Object o) {
 	if (!(o instanceof BinaryType)) return false;
+//{ObjectTeams:
+	// note: typeNames are already normalized, what's not normalized is the containing ClassFile
+	BinaryType yourType = (BinaryType) o;
+	String myName = getClassFile().getElementName();
+	String yourName = yourType.getClassFile().getElementName();
+	if (myName.contains(IOTConstants.OT_DELIM) != yourName.contains(IOTConstants.OT_DELIM)) {
+		myName = myName.contains(IOTConstants.OT_DELIM) ? myName.substring(IOTConstants.OT_DELIM_LEN) : myName;
+		yourName = yourName.contains(IOTConstants.OT_DELIM) ? yourName.substring(IOTConstants.OT_DELIM_LEN) : yourName;
+		if (myName.equals(yourName)) {
+			if (this.occurrenceCount != yourType.occurrenceCount)
+				return false;
+			// skip different ClassFiles:
+			return getPackageFragment().equals(yourType.getPackageFragment());
+		}
+	}
+// SH}
 	return super.equals(o);
 }
 
@@ -386,10 +395,7 @@
 @Override
 public int getFlags() throws JavaModelException {
 	IBinaryType info = (IBinaryType) getElementInfo();
-	return info.getModifiers() & ~ClassFileConstants.AccSuper
-//{ObjectTeams: do we know this is a role?
-		| (this.isRole ? ExtraCompilerModifiers.AccRole : 0);
-// SH}
+	return info.getModifiers() & ~ClassFileConstants.AccSuper;
 }
 
 @Override
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java
index d7cc7ec..9aaffb9 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java
@@ -506,6 +506,10 @@
 protected IBuffer openBuffer(IProgressMonitor pm, Object info) throws JavaModelException {
 	// Check the cache for the top-level type first
 	IType outerMostEnclosingType = getOuterMostEnclosingType();
+//{ObjectTeams:
+	if (Flags.isRole(getType().getFlags()))
+		outerMostEnclosingType = getType(); // revert to direct type to account for role files
+// SH}
 	IBuffer buffer = getBufferManager().getBuffer(outerMostEnclosingType.getClassFile());
 	if (buffer == null) {
 		SourceMapper mapper = getSourceMapper();
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFileInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFileInfo.java
index 129acc0..07eee8c 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFileInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFileInfo.java
@@ -30,6 +30,7 @@
 import org.eclipse.jdt.internal.compiler.env.IBinaryMethod;
 import org.eclipse.jdt.internal.compiler.env.IBinaryNestedType;
 import org.eclipse.jdt.internal.compiler.env.IBinaryType;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions.WeavingScheme;
 import org.eclipse.jdt.internal.compiler.lookup.TagBits;
 import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
@@ -41,6 +42,7 @@
 import org.eclipse.objectteams.otdt.internal.core.compiler.bytecode.AbstractAttribute;
 import org.eclipse.objectteams.otdt.internal.core.compiler.bytecode.CallinMethodMappingsAttribute;
 import org.eclipse.objectteams.otdt.internal.core.compiler.bytecode.CalloutMappingsAttribute;
+import org.eclipse.objectteams.otdt.internal.core.compiler.bytecode.WordValueAttribute;
 import org.eclipse.objectteams.otdt.internal.core.util.FieldData;
 import org.eclipse.objectteams.otdt.internal.core.util.MethodData;
 
@@ -271,24 +273,22 @@
 	// If the current type is an inner type, innerClasses returns
 	// an extra entry for the current type.  This entry must be removed.
 	// Can also return an entry for the enclosing type of an inner type.
-//{ObjectTeams: is outer a team?
-	boolean isTeam = Flags.isTeam(typeInfo.getModifiers()); // note that OTModelManager.isTeam() may trigger getElementInfo.
-// SH}
 	IBinaryNestedType[] innerTypes = typeInfo.getMemberTypes();
 	if (innerTypes != null) {
 		IPackageFragment pkg = (IPackageFragment) type.getAncestor(IJavaElement.PACKAGE_FRAGMENT);
 		for (int i = 0, typeCount = innerTypes.length; i < typeCount; i++) {
 			IBinaryNestedType binaryType = innerTypes[i];
 			IClassFile parentClassFile= pkg.getClassFile(new String(ClassFile.unqualifiedName(binaryType.getName())) + SUFFIX_STRING_class);
-//{ObjectTeams: added first parameter:
-			IType innerType = new BinaryType(typeInfo.getName(), (JavaElement)parentClassFile, ClassFile.simpleName(binaryType.getName()));
-// SH}
-//{ObjectTeams: maybe wrap:
+//{ObjectTeams: various tweaks for roles
 			int flags = binaryType.getModifiers(); // note that innerType.getFlags() would trigger getElementInfo.
-			// TODO(SH): static is workaround for unavailabel synth.-flag
+			// TODO(SH): static is workaround for unavailable synth.-flag
 			if ((flags & (ClassFileConstants.AccStatic|ClassFileConstants.AccInterface)) == (ClassFileConstants.AccStatic|ClassFileConstants.AccInterface))
 				continue; // skip synthetic interfaces
-			if (isTeam)
+// almost orig (added first parameter):
+			IType innerType = new BinaryType(typeInfo.getName(), (JavaElement)parentClassFile, ClassFile.simpleName(binaryType.getName()));
+//
+			// maybe wrap:
+			if (Flags.isTeam(typeInfo.getModifiers())) // note that OTModelManager.isTeam() would trigger getElementInfo.
 				flags |= ExtraCompilerModifiers.AccRole;
 			String baseclassName = null;
 			String baseclassAnchor = null;
@@ -302,14 +302,14 @@
 					}
 				}
 			}
-			OTModelManager.getSharedInstance().addType(innerType, flags, baseclassName, baseclassAnchor, isTeam);
+			OTModelManager.getSharedInstance().addType(innerType, flags, baseclassName, baseclassAnchor, false); // role file considered irrelevant for binary types
 // SH}
 			childrenHandles.add(innerType);
 		}
 	}
 }
 //{ObjectTeams: retrieve method mappings from OT-attributes:
-private void evaluateAttribute(CalloutMappingsAttribute attr, IType type, List<IJavaElement> childrenHandles) {
+private void evaluateAttribute(CalloutMappingsAttribute attr, IType type, List<IJavaElement> childrenHandles, WeavingScheme scheme) {
 	for (int i=0; i<attr.getNumMappings(); i++) {
 		MappingElementInfo calloutInfo = new MappingElementInfo();
 		calloutInfo.setRoleMethod(new MethodData(
@@ -329,7 +329,7 @@
 			boolean isSetter = flags == CalloutMappingsAttribute.CALLOUT_SET;
 			String accessorSignature = attr.getBaseMethodSignatureAt(i);
 			String fieldType = isSetter
-					? Signature.getParameterTypes(accessorSignature)[1] // 0 is base object since accessor is static
+					? Signature.getParameterTypes(accessorSignature)[scheme == WeavingScheme.OTRE ? 1 : 0] // under OTRE: 0 is base object since accessor is static
 					: Signature.getReturnType(accessorSignature);
 			if (fieldType.indexOf('/') > -1)
 				fieldType = String.valueOf(ClassFile.translatedName(fieldType.toCharArray()));
@@ -550,12 +550,20 @@
 		generateMethodInfos(type, typeInfo, newElements, childrenHandles, typeParameterHandles);
 		generateInnerClassHandles(type, typeInfo, childrenHandles); // Note inner class are separate openables that are not opened here: no need to pass in newElements
 //{ObjectTeams: eval OT attrs?
-		if (typeInfo instanceof ClassFileReader)
+		if (typeInfo instanceof ClassFileReader) {
+			WeavingScheme scheme = WeavingScheme.OTDRE;
+			for (AbstractAttribute attr : ((ClassFileReader)typeInfo).getOTAttributes()) {
+				if (attr.nameEquals(IOTConstants.OT_COMPILER_VERSION)) {
+					scheme = ((WordValueAttribute) attr).weavingSchemeFromCompilerVersion();
+					break;
+				}
+			}
 			for (AbstractAttribute attr : ((ClassFileReader)typeInfo).getOTAttributes())
 				if (attr.nameEquals(IOTConstants.CALLIN_METHOD_MAPPINGS))
 					evaluateAttribute((CallinMethodMappingsAttribute)attr, type, childrenHandles);
 				else if (attr.nameEquals(IOTConstants.CALLOUT_MAPPINGS))
-					evaluateAttribute((CalloutMappingsAttribute)attr, type, childrenHandles);
+					evaluateAttribute((CalloutMappingsAttribute)attr, type, childrenHandles, scheme);
+		}
 // SH}
 	}
 
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMapper.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMapper.java
index 039200a..8cfb0ec 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMapper.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMapper.java
@@ -41,6 +41,7 @@
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Status;
 import org.eclipse.jdt.core.Flags;
 import org.eclipse.jdt.core.IField;
 import org.eclipse.jdt.core.IJavaElement;
@@ -73,6 +74,8 @@
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
 import org.eclipse.jdt.internal.compiler.util.Util;
 import org.eclipse.jdt.internal.core.util.ReferenceInfoAdapter;
+import org.eclipse.objectteams.otdt.core.TypeHelper;
+import org.eclipse.objectteams.otdt.core.compiler.IOTConstants;
 
 /**
  * A SourceMapper maps source code in a ZIP file to binary types or
@@ -826,7 +829,12 @@
 				this.types[this.typeDepth] = getType(new String(typeInfo.name));
 			}
 		} else {
+//{ObjectTeams: pass modifiers, so we can dispatch between role parts:
+/* orig:
 			this.types[this.typeDepth] = getType(new String(typeInfo.name));
+  :giro */
+			this.types[this.typeDepth] = getType(new String(typeInfo.name), typeInfo.modifiers);
+// SH}
 		}
 		this.typeNameRanges[this.typeDepth] =
 			new SourceRange(typeInfo.nameSourceStart, typeInfo.nameSourceEnd - typeInfo.nameSourceStart + 1);
@@ -1164,7 +1172,22 @@
 	public char[] findSource(IType type, String simpleSourceFileName) {
 		PackageFragment pkgFrag = (PackageFragment) type.getPackageFragment();
 		String name = org.eclipse.jdt.internal.core.util.Util.concatWith(pkgFrag.names, simpleSourceFileName, '/');
+//ObjectTeams: RoFi?
+/* orig:
 		return internalFindSource((NamedMember) type, name);
+  :giro */
+		char[] source = internalFindSource((NamedMember) type, name);
+		try {
+			if (source == null && Flags.isRole(type.getFlags())) {
+				simpleSourceFileName = type.getDeclaringType().getElementName()+'/'+simpleSourceFileName;
+				name = org.eclipse.jdt.internal.core.util.Util.concatWith(pkgFrag.names, simpleSourceFileName, '/');
+				return internalFindSource((NamedMember) type, name);
+			}
+		} catch (JavaModelException e) {
+			JavaCore.getJavaCore().getLog().log(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, "couldn't access type "+type.getElementName(), e)); //$NON-NLS-1$
+		}
+		return source;
+// SH}
 	}
 
 	/**
@@ -1425,6 +1448,11 @@
 	 * as well.
 	 */
 	protected IType getType(String typeName) {
+//{ObjectTeams: additional parameter:
+		return getType(typeName, 0);
+	}
+	protected IType getType(String typeName, int modifiers) {
+// SH}
 		if (!(this.binaryTypeOrModule instanceof IType))
 			return null;
 		IType type = (IType) this.binaryTypeOrModule;
@@ -1441,7 +1469,15 @@
 		} else if (type.getElementName().equals(typeName))
 			return type;
 		else
+//{ObjectTeams: prefer class file of role class over synth interface
+		{
+			if (TypeHelper.isRole(modifiers) && !Flags.isInterface(modifiers) && !typeName.startsWith(IOTConstants.OT_DELIM))
+				typeName = IOTConstants.OT_DELIM+typeName;
+// orig:
 			return ((this.typeDepth <= 1) ? type : this.types[this.typeDepth - 1]).getType(typeName);
+// :giro
+		}
+// SH}
 	}
 
 	/**
diff --git a/org.eclipse.jdt.core/model/org/eclipse/objectteams/otdt/core/OTModelManager.java b/org.eclipse.jdt.core/model/org/eclipse/objectteams/otdt/core/OTModelManager.java
index 4257d54..b86407f 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/objectteams/otdt/core/OTModelManager.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/objectteams/otdt/core/OTModelManager.java
@@ -111,27 +111,30 @@
 			{
 			    case IJavaElement.COMPILATION_UNIT:
 			    case IJavaElement.CLASS_FILE:
-			    	if(isRoleFile)
-					{   //  could also be a teeam, which is handled inside the constructor
-			    		if (elem.isBinary())
-			    		{
-				        	MAPPING.addOTElement( result = new BinaryRoleType(elem,
-									parent,
-									typeDeclFlags,
-									baseClassName,
-									baseClassAnchor));
+			    	if (TypeHelper.isRole(typeDeclFlags)) {
+			    		if (elem.isBinary()) {
+			    			MAPPING.addOTElement( result = new BinaryRoleType(elem,
+			    					parent,
+			    					typeDeclFlags,
+			    					baseClassName,
+			    					baseClassAnchor));
+			    		} else {
+			    			if(isRoleFile) {
+								//  could also be a teeam, which is handled inside the constructor
+				    			MAPPING.addOTElement( result = new RoleFileType(elem,
+				    					parent,
+				    					typeDeclFlags,
+				    					baseClassName,
+				    					baseClassAnchor));
+							} else {
+								MAPPING.addOTElement( result = new RoleType(elem,
+				    					parent,
+				    					typeDeclFlags,
+				    					baseClassName,
+				    					baseClassAnchor));
+							}
 			    		}
-			    		else
-			    		{
-				        	MAPPING.addOTElement( result = new RoleFileType(elem,
-									parent,
-									typeDeclFlags,
-									baseClassName,
-									baseClassAnchor));
-			    		}
-					}
-			    	else if (TypeHelper.isTeam(typeDeclFlags))
-					{
+			    	} else if (TypeHelper.isTeam(typeDeclFlags)) {
 						MAPPING.addOTElement( result = new OTType(IOTJavaElement.TEAM, elem, null, typeDeclFlags) );
 					}
 					return result;
diff --git a/plugins/org.eclipse.objectteams.otdt.jdt.ui/src/org/eclipse/objectteams/otdt/internal/ui/javaeditor/JavaOutlinePageAdaptor.java b/plugins/org.eclipse.objectteams.otdt.jdt.ui/src/org/eclipse/objectteams/otdt/internal/ui/javaeditor/JavaOutlinePageAdaptor.java
index 0bf5592..daa4f02 100644
--- a/plugins/org.eclipse.objectteams.otdt.jdt.ui/src/org/eclipse/objectteams/otdt/internal/ui/javaeditor/JavaOutlinePageAdaptor.java
+++ b/plugins/org.eclipse.objectteams.otdt.jdt.ui/src/org/eclipse/objectteams/otdt/internal/ui/javaeditor/JavaOutlinePageAdaptor.java
@@ -17,9 +17,22 @@
  **********************************************************************/
 package org.eclipse.objectteams.otdt.internal.ui.javaeditor;
 
+import org.eclipse.jdt.core.Flags;
+import org.eclipse.jdt.core.IClassFile;
 import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.ITypeRoot;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.internal.ui.javaeditor.EditorUtility;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.swt.events.SelectionEvent;
 import org.eclipse.swt.widgets.Item;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.PartInitException;
 import org.eclipse.objectteams.otdt.core.IOTType;
+import org.eclipse.objectteams.otdt.core.OTModelManager;
+import org.eclipse.objectteams.otdt.core.ext.OTDTPlugin;
 import org.eclipse.objectteams.otdt.ui.Util;
 
 import base org.eclipse.jdt.internal.ui.javaeditor.JavaOutlinePage.JavaOutlineViewer;
@@ -48,11 +61,48 @@
 	}
 	protected class Viewer playedBy JavaOutlineViewer 
 	{
+		ISelection getSelection() -> ISelection getSelection();
+		Object getInput() -> Object getInput();
+
 		void unwrapOTType(Object element) <- replace void associate(Object element, Item item)
 			base when (element instanceof IOTType); 
 
 		callin void unwrapOTType(Object element) {
 			base.unwrapOTType(((IOTType)element).getCorrespondingJavaElement());
-		}		
+		}
+
+		void handleOpen(SelectionEvent event) <- replace void handleOpen(SelectionEvent event);
+
+		@SuppressWarnings("basecall")
+		callin void handleOpen(SelectionEvent event) {
+			ISelection selection = getSelection();
+			if (selection instanceof IStructuredSelection) {
+				Object firstElement = ((IStructuredSelection) selection).getFirstElement();
+				if (firstElement instanceof IJavaElement) {
+					IJavaElement selectedElement = (IJavaElement) firstElement;
+					IType selectedType = (IType) selectedElement.getAncestor(IJavaElement.TYPE);
+					try {
+						if (selectedType != null && Flags.isRole(selectedType.getFlags())) {
+							IClassFile selectedRoot = (IClassFile) selectedElement.getAncestor(IJavaElement.CLASS_FILE);
+							if (selectedRoot != null && OTModelManager.isRole((IType)selectedElement.getAncestor(IJavaElement.TYPE))) {
+								Object input = getInput();
+								if (input instanceof ITypeRoot) {
+									if (!selectedRoot.equals(input)) {
+										IEditorPart editor = EditorUtility.openInEditor(firstElement, true);
+										EditorUtility.revealInEditor(editor, selectedElement);
+										return;
+									}
+								}
+							}
+						}
+					} catch (PartInitException e) {
+						OTDTPlugin.logException("Failed to open element in editor", e); //$NON-NLS-1$
+					} catch (JavaModelException e) {
+						OTDTPlugin.logException("Failed access flags of type "+selectedElement.getElementName(), e); //$NON-NLS-1$
+					}
+				}
+			}
+			base.handleOpen(event);
+		}
 	}
 }