Initial implementation for  Bug 321411 -  [hierarchy] Replace OTTypeHierarchy with adapting the original TypeHierarchy
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyBuilder.java
index b516c02..1dea119 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyBuilder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyBuilder.java
@@ -119,6 +119,20 @@
 			this.hierarchy.addRootClass(focusType);
 		}
 	}
+	/** Wrapper method as hook for OTTypeHierarchies. */
+	public void hookableConnect(
+			ReferenceBinding focusType,
+			ReferenceBinding typeBinding,
+			IGenericType type,
+			IType typeHandle,
+			boolean isPhantom,
+			IType superclassHandle,
+			IType[] tsuperclassHandles,
+			boolean[] arePhantoms,
+			IType[] superinterfaceHandles) 
+	{
+		connect(type, typeHandle, superclassHandle, superinterfaceHandles);
+	}
 	/**
 	 * Connect the supplied type to its superclass & superinterfaces.
 	 * The superclass & superinterfaces are the identical binary or source types as
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyResolver.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyResolver.java
index 0628bea..0a64b30 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyResolver.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyResolver.java
@@ -37,8 +37,11 @@
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.Status;
 import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.Signature;
 import org.eclipse.jdt.core.compiler.CharOperation;
@@ -169,9 +172,14 @@
 			this.lookupEnvironment.buildTypeBindings(unit, accessRestriction);
 
 			org.eclipse.jdt.core.ICompilationUnit cu = ((SourceTypeElementInfo)sourceType).getHandle().getCompilationUnit();
+//{ObjectTeams: swap order so rememberAllTypes catches also copy-inherited roles:
+/* orig:
 			rememberAllTypes(unit, cu, false);
-
+ */
 			this.lookupEnvironment.completeTypeBindings(unit, true/*build constructor only*/);
+// :giro
+			rememberAllTypes(unit, cu, false);
+// SH}
 		} catch (AbortCompilation e) {
 			// missing 'java.lang' package: ignore
 		}
@@ -429,7 +437,12 @@
 	this.typeBindings[this.typeIndex] = typeBinding;
 }
 private void remember(IType type, ReferenceBinding typeBinding) {
+//{ObjectTeams: for phantom roles avoid hitting the JME (phantom has no info) but proceed into else as to record what we have
+/* orig:
 	if (((CompilationUnit)type.getCompilationUnit()).isOpen()) {
+  :giro */
+	if (((CompilationUnit)type.getCompilationUnit()).isOpen() && !isPurelyCopiedRole(typeBinding)) {
+// SH}
 		try {
 			IGenericType genericType = (IGenericType)((JavaElement)type).getElementInfo();
 			remember(genericType, typeBinding);
@@ -483,6 +496,13 @@
 	}
 
 }
+//{ObjectTeams: helper for above:
+private boolean isPurelyCopiedRole(ReferenceBinding typeBinding) {
+	if (typeBinding == null || typeBinding.roleModel == null)
+		return false;
+	return typeBinding.roleModel.isPurelyCopied();
+}
+// SH}
 /*
  * Remembers all type bindings defined in the given parsed unit, adding local/anonymous types if specified.
  */
@@ -628,6 +648,24 @@
 				typeBinding = typeBinding.roleModel.getClassPartBinding();
 			}
 		}
+		if (typeBinding.isSynthInterface())
+			continue; // don't report synthetic ifc parts
+		
+		// prepare additional info to pass to the builder (viz. the OTTypeHierarchies team)
+		IType[] tsuperClasses = new IType[0];
+		boolean[] arePhantoms = new boolean[0]; // one flag for each role in tsuperClasses
+		if (typeBinding.isSourceRole()) {
+			ReferenceBinding[] tsuperBindings = typeBinding.roleModel.getTSuperRoleBindings();
+			if (tsuperBindings.length > 0) {
+				tsuperClasses = new IType[tsuperBindings.length];
+				arePhantoms = new boolean[tsuperBindings.length];
+				for (int i = 0; i < tsuperBindings.length; i++) {
+					tsuperClasses[i] = getHandle(tsuperBindings[i]);
+					arePhantoms[i] = tsuperBindings[i].roleModel.isPurelyCopied();
+				}
+			}
+		}
+		boolean isPhantom = typeBinding.roleModel != null && typeBinding.roleModel.isPurelyCopied();
 // SH}
 		if (typeBinding.isInterface()){ // do not connect interfaces to Object
 			superclass = null;
@@ -636,7 +674,12 @@
 		}
 		IType[] superinterfaces = findSuperInterfaces(suppliedType, typeBinding);
 
+//{ObjectTeams: also announce tsuper classes and info about phantomness:
+/* orig:
 		this.builder.connect(suppliedType, this.builder.getHandle(suppliedType, typeBinding), superclass, superinterfaces);
+  :giro */
+		this.builder.hookableConnect(this.focusType, typeBinding, suppliedType, this.builder.getHandle(suppliedType, typeBinding), isPhantom, superclass, tsuperClasses, arePhantoms, superinterfaces);
+// SH}
 	}
 	// add java.lang.Object only if the super class is not missing
 	if (objectIndex > -1 && (!this.hasMissingSuperClass || this.focusType == null)) {
@@ -644,6 +687,17 @@
 		this.builder.connect(objectType, this.builder.getHandle(objectType, this.typeBindings[objectIndex]), null, null);
 	}
 }
+//{ObjectTeams: 
+private IType getHandle(ReferenceBinding typeBinding) {
+	for (int t = this.typeIndex; t >= 0; t--) {
+		if (this.typeBindings[t] == typeBinding) {
+			 return this.builder.getHandle(this.typeModels[t], typeBinding);
+		}
+	}
+	JavaCore.getPlugin().getLog().log(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, "Inconsistency between typeIndex and typeBindings")); //$NON-NLS-1$
+	return null;
+}
+// SH}
 private void reset(){
 	this.lookupEnvironment.reset();
 
@@ -1013,61 +1067,17 @@
 //	if (superclass != null && superclass.id == TypeIds.T_JavaLangObject && subType.isHierarchyInconsistent()) return false;
 	if (subTypeOfType(superclass, typeBinding)) return true;
 	ReferenceBinding[] superInterfaces = subType.superInterfaces();
+// {ObjectTeams: check implicit inheritance:
+	if (subType.isSourceRole())
+		for (ReferenceBinding tsuperBinding : subType.roleModel.getTSuperRoleBindings())
+			if (subTypeOfType(tsuperBinding, typeBinding)) 
+				return true;
+// SH}
 	if (superInterfaces != null) {
-// {OTDTUI: Subtype check for roles and non-roles:
-	  if (subType.isRole())
-	  {
-		// Role interface -> check superinterfaces
-		if (subType.isRegularInterface())
-		{
-			for (int i = 0, length = superInterfaces.length; i < length; i++)
-			{
-				if (subTypeOfType(superInterfaces[i], typeBinding)) return true;
-			}
-		}
-		// Interface part of roles -> check superinterfaces, class part
-		else if (subType.isSynthInterface())
-		{
-			for (int i = 0, length = superInterfaces.length; i < length; i++)
-			{
-				if (superInterfaces[i].isSynthInterface())
-				{
-					// Ignore (tsuper's) synthetic.
-					// I don't know why ak skipped them in earlier revisions,
-					// but it seems like we don't need to consider implicit
-					// inheritance here.
-					continue;
-				}
-				if (subTypeOfType(superInterfaces[i], typeBinding)) return true;
-			}
-			if (typeBinding.isClass())
-			{
-				ReferenceBinding classPart = subType.roleModel.getClassPartBinding();
-				if (subTypeOfType(classPart, typeBinding)) return true;
-			}
-		}
-		// role class -> check superinterfaces
-		else
-		{
-			if (typeBinding.isInterface())
-			{
-				for (int i = 0, length = superInterfaces.length; i < length; i++)
-				{
-					if (subTypeOfType(superInterfaces[i], typeBinding)) return true;
-				}
-			}
-		}
-	  }
-		// non role types -> check superinterfaces
-	  else {
-// orig:
 		for (int i = 0, length = superInterfaces.length; i < length; i++) {
 			ReferenceBinding superInterface = (ReferenceBinding) superInterfaces[i].erasure();
 			if (subTypeOfType(superInterface, typeBinding)) return true;
 		}
-// :giro
-	  }
-// mkr}
 	}
 	return false;
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/IndexBasedHierarchyBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/IndexBasedHierarchyBuilder.java
index bf54a70..ff59b38 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/IndexBasedHierarchyBuilder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/IndexBasedHierarchyBuilder.java
@@ -24,6 +24,7 @@
 import org.eclipse.jdt.internal.compiler.env.AccessRuleSet;
 import org.eclipse.jdt.internal.compiler.env.IBinaryType;
 import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
+import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
 import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
 import org.eclipse.jdt.internal.compiler.util.HashtableOfObject;
 import org.eclipse.jdt.internal.compiler.util.HashtableOfObjectToInt;
@@ -38,6 +39,8 @@
 import org.eclipse.jdt.internal.core.search.matching.SuperTypeReferencePattern;
 import org.eclipse.jdt.internal.core.util.HandleFactory;
 import org.eclipse.jdt.internal.core.util.Util;
+import org.eclipse.objectteams.otdt.core.IRoleType;
+import org.eclipse.objectteams.otdt.core.OTModelManager;
 
 public class IndexBasedHierarchyBuilder extends HierarchyBuilder implements SuffixConstants {
 	public static final int MAXTICKS = 800; // heuristic so that there still progress for deep hierachies
@@ -487,6 +490,9 @@
 					&& !foundSuperNames.containsKey(typeName)){
 				foundSuperNames.put(typeName, typeName);
 				queue.add(typeName);
+//{ObjectTeams: check if we need additional traversal role->enclosing team in order to cover implicit inheritance, too.
+				reportIndexMatch(record, queue, foundSuperNames);
+// SH}
 			}
 			return true;
 		}
@@ -509,6 +515,12 @@
 
 	int ticks = 0;
 	queue.add(type.getElementName().toCharArray());
+//{ObjectTeams: additional traversal role->enclosing team in order to cover implicit inheritance, too.
+	while (OTModelManager.isRole(type)) {
+		type = ((IRoleType)OTModelManager.getOTElement(type)).getTeamJavaType();
+		queue.add(type.getElementName().toCharArray());
+	}
+// SH}	
 	try {
 		while (queue.start <= queue.end) {
 			if (progressMonitor != null && progressMonitor.isCanceled()) return;
@@ -544,4 +556,25 @@
 		job.finished();
 	}
 }
+//{ObjectTeams: additional traversal role->enclosing team in order to cover implicit inheritance, too.
+static void reportIndexMatch(SuperTypeReferencePattern record, Queue q, HashtableOfObject foundSuperNames) {
+	if ((record.modifiers & ExtraCompilerModifiers.AccRole) != 0) {
+		char[][] enclosingNames = CharOperation.splitOn('$', record.enclosingTypeName);
+		char[] teamSimpleName;
+		if (enclosingNames.length > 0) {
+			teamSimpleName = enclosingNames[enclosingNames.length-1];
+		} else {
+			char[][] packageNames = CharOperation.splitOn('$', record.pkgName);
+			if (packageNames.length > 0)
+				teamSimpleName = packageNames[packageNames.length-1];
+			else
+				return; // no success (enclosing team name not found)
+		}
+		if (!foundSuperNames.containsKey(teamSimpleName)) {
+			q.add(teamSimpleName);
+			foundSuperNames.put(teamSimpleName, teamSimpleName);
+		}
+	}
+}
+// SH}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/TypeHierarchy.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/TypeHierarchy.java
index 742d915..dd4003d 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/TypeHierarchy.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/TypeHierarchy.java
@@ -33,6 +33,7 @@
 import org.eclipse.jdt.internal.core.*;
 import org.eclipse.jdt.internal.core.util.Messages;
 import org.eclipse.jdt.internal.core.util.Util;
+import org.eclipse.objectteams.otdt.core.IOTType;
 
 /**
  * @see ITypeHierarchy
@@ -154,6 +155,10 @@
  * Creates a TypeHierarchy on the given type.
  */
 public TypeHierarchy(IType type, ICompilationUnit[] workingCopies, IJavaSearchScope scope, boolean computeSubtypes) {
+//{ObjectTeams: always unwrap OTTypes, hierarchy only stores plain java types (SourceType, BinaryType):
+	if (type instanceof IOTType)
+		type = (IType) ((IOTType) type).getCorrespondingJavaElement();
+// SH}
 	this.focusType = type == null ? null : (IType) ((JavaElement) type).unresolved(); // unsure the focus type is unresolved (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=92357)
 	this.workingCopies = workingCopies;
 	this.computeSubtypes = computeSubtypes;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/DiskIndex.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/DiskIndex.java
index cc256b6..dba3104 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/DiskIndex.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/DiskIndex.java
@@ -51,7 +51,7 @@
 /* orig:
 public static final String SIGNATURE= "INDEX VERSION 1.126"; //$NON-NLS-1$
   :giro */
-public static final String SIGNATURE= "INDEX VERSION 1.126 OT1"; //$NON-NLS-1$
+public static final String SIGNATURE= "INDEX VERSION 1.126 OT2"; //$NON-NLS-1$
 // SH}
 private static final char[] SIGNATURE_CHARS = SIGNATURE.toCharArray();
 public static boolean DEBUG = false;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeReferencePattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeReferencePattern.java
index 8d568e9..76a6bac 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeReferencePattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeReferencePattern.java
@@ -116,7 +116,12 @@
 	int simpleLength = simpleName == null ? 0 : simpleName.length;
 	int enclosingLength = enclosingTypeName == null ? 0 : enclosingTypeName.length;
 	int packageLength = packageName == null ? 0 : packageName.length;
+//{ObjectTeams: one more char for modifiers
+/* orig:
 	char[] result = new char[superLength + superQLength + simpleLength + enclosingLength + typeParametersLength + packageLength + 9];
+  :giro */
+	char[] result = new char[superLength + superQLength + simpleLength + enclosingLength + typeParametersLength + packageLength + 10];
+// SH}
 	int pos = 0;
 	if (superLength > 0) {
 		System.arraycopy(superSimpleName, 0, result, pos, superLength);
@@ -150,7 +155,13 @@
 	result[pos++] = SEPARATOR;
 	result[pos++] = superClassOrInterface;
 	result[pos++] = classOrInterface;
+//{ObjectTeams: expand to also cover AccRole:
+/* orig:
 	result[pos] = (char) modifiers;
+  :giro */
+	result[pos++] = (char) modifiers;
+	result[pos] = (char) (modifiers>>16);
+// SH}
 	return result;
 }
 
@@ -232,7 +243,12 @@
 
 	this.superClassOrInterface = key[slash + 1];
 	this.classOrInterface = key[slash + 2];
+//{ObjectTeams: expanded to also cover AccRole:
+/* orig:
 	this.modifiers = key[slash + 3]; // implicit cast to int type
+   :giro */
+	this.modifiers = key[slash + 3] + (key[slash + 4]<<16);
+// SH}
 }
 public SearchPattern getBlankPattern() {
 	return new SuperTypeReferencePattern(R_EXACT_MATCH | R_CASE_SENSITIVE);