Initial implementation for  Bug 321411 -  [hierarchy] Replace OTTypeHierarchy with adapting the original TypeHierarchy
diff --git a/plugins/org.eclipse.objectteams.otdt/.classpath b/plugins/org.eclipse.objectteams.otdt/.classpath
index 304e861..9b7e6c5 100644
--- a/plugins/org.eclipse.objectteams.otdt/.classpath
+++ b/plugins/org.eclipse.objectteams.otdt/.classpath
@@ -2,6 +2,7 @@
 <classpath>
 	<classpathentry kind="src" path="src"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+	<classpathentry kind="con" path="OTRE"/>
 	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
 	<classpathentry kind="output" path="bin"/>
 </classpath>
diff --git a/plugins/org.eclipse.objectteams.otdt/.project b/plugins/org.eclipse.objectteams.otdt/.project
index a40a654..7bcffe8 100644
--- a/plugins/org.eclipse.objectteams.otdt/.project
+++ b/plugins/org.eclipse.objectteams.otdt/.project
@@ -6,7 +6,7 @@
 	</projects>
 	<buildSpec>
 		<buildCommand>
-			<name>org.eclipse.jdt.core.javabuilder</name>
+			<name>org.eclipse.objectteams.otdt.builder.OTJBuilder</name>
 			<arguments>
 			</arguments>
 		</buildCommand>
@@ -24,5 +24,6 @@
 	<natures>
 		<nature>org.eclipse.pde.PluginNature</nature>
 		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>org.eclipse.objectteams.otdt.OTJavaNature</nature>
 	</natures>
 </projectDescription>
diff --git a/plugins/org.eclipse.objectteams.otdt/META-INF/MANIFEST.MF b/plugins/org.eclipse.objectteams.otdt/META-INF/MANIFEST.MF
index 664f29d..70aeb3c 100644
--- a/plugins/org.eclipse.objectteams.otdt/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.objectteams.otdt/META-INF/MANIFEST.MF
@@ -3,9 +3,12 @@
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.objectteams.otdt;singleton:=true
 Bundle-Version: 0.7.1.qualifier
+Bundle-ClassPath: otdtcoreext.jar
 Bundle-Activator: org.eclipse.objectteams.otdt.core.ext.OTDTPlugin
 Bundle-Vendor: %providerName
 Bundle-Localization: plugin
+Export-Package: org.eclipse.objectteams.otdt.core.ext,
+ org.eclipse.objectteams.otdt.core.hierarchy
 Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.4.0,4.0.0)",
  org.eclipse.core.resources,
  org.eclipse.jdt.core;bundle-version="[3.6.0.v_OTDT_r070,3.6.0.v_OTDT_r080)",
@@ -13,8 +16,7 @@
  org.eclipse.debug.core,
  org.eclipse.osgi,
  org.eclipse.objectteams.otequinox.branding,
- org.eclipse.objectteams.runtime;bundle-version="[0.7.0,0.8.0)"
-Bundle-ActivationPolicy: lazy
-Bundle-ClassPath: otdtcoreext.jar
-Export-Package: org.eclipse.objectteams.otdt.core.ext
+ org.eclipse.objectteams.runtime;bundle-version="[0.7.0,0.8.0)",
+ org.eclipse.objectteams.otequinox
 Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Bundle-ActivationPolicy: lazy
diff --git a/plugins/org.eclipse.objectteams.otdt/plugin.xml b/plugins/org.eclipse.objectteams.otdt/plugin.xml
index 84bc547..b1df675 100644
--- a/plugins/org.eclipse.objectteams.otdt/plugin.xml
+++ b/plugins/org.eclipse.objectteams.otdt/plugin.xml
@@ -50,4 +50,19 @@
 	 		id="OTRE"
             class="org.eclipse.objectteams.otdt.core.ext.OTREContainerInitializer"/>
    </extension>
+   <extension
+         point="org.eclipse.objectteams.otequinox.aspectBindings">
+      <aspectBinding
+            icon="platform:/plugin/org.eclipse.objectteams.otdt.ui/icons/ot/calloutbinding_obj.gif">
+         <basePlugin
+               icon="platform:/plugin/org.eclipse.pde.ui/icons/obj16/plugin_obj.gif"
+               id="org.eclipse.jdt.core">
+         </basePlugin>
+         <team
+               activation="ALL_THREADS"
+               class="org.eclipse.objectteams.otdt.core.hierarchy.OTTypeHierarchies"
+               icon="platform:/plugin/org.eclipse.objectteams.otdt.ui/icons/ot/team_obj.gif">
+         </team>
+      </aspectBinding>
+   </extension>
 </plugin>
diff --git a/plugins/org.eclipse.objectteams.otdt/src/org/eclipse/objectteams/otdt/core/hierarchy/OTTypeHierarchies.java b/plugins/org.eclipse.objectteams.otdt/src/org/eclipse/objectteams/otdt/core/hierarchy/OTTypeHierarchies.java
new file mode 100644
index 0000000..4de99fb
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otdt/src/org/eclipse/objectteams/otdt/core/hierarchy/OTTypeHierarchies.java
@@ -0,0 +1,667 @@
+/**********************************************************************
+ * This file is part of "Object Teams Development Tooling"-Software
+ * 
+ * Copyright 2010 GK Software AG
+ * 
+ * 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.
+ * 
+ * Contributors:
+ * 	  Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otdt.core.hierarchy;
+
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.internal.compiler.env.IGenericType;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.core.JavaModelStatus;
+import org.eclipse.objectteams.otdt.core.IOTType;
+import org.eclipse.objectteams.otdt.core.OTModelManager;
+
+// both base type and directly used:
+import org.eclipse.jdt.core.IType;
+
+import base org.eclipse.jdt.internal.core.BinaryType;
+import base org.eclipse.jdt.internal.core.SourceType;
+import base org.eclipse.jdt.internal.core.hierarchy.HierarchyBuilder;
+import base org.eclipse.jdt.internal.core.hierarchy.TypeHierarchy;
+import base org.eclipse.objectteams.otdt.core.PhantomType;
+import base org.eclipse.objectteams.otdt.internal.core.OTType;
+
+/**
+ * Adapt the regular Java TypeHierarchy as to handle implicit inheritance, too.
+ * 
+ * 
+ * @author stephan
+ */
+@SuppressWarnings("restriction")
+public team class OTTypeHierarchies {
+	
+	/** How does a given type relate to the focus type? */
+	enum FocusRelation {
+		/** a type is a subtype of the focus type. */
+		BELOW, 
+		/** a type is the focus type itself. */
+		EQUAL, 
+		/** a type is a supertype of the focus type. */
+		ABOVE, 
+		/** a type is neither sub- nor supertype of the focus type. */
+		UNRELATED;
+
+		public static FocusRelation compute(ReferenceBinding focusType, ReferenceBinding typeBinding) {
+			if (focusType.isRole())
+				focusType = focusType.getRealType();
+			if (typeBinding.isRole())
+				typeBinding = typeBinding.getRealType();
+			if (focusType.equals(typeBinding))				return EQUAL;
+			if (focusType.isCompatibleWith(typeBinding))	return ABOVE;
+			if (typeBinding.isCompatibleWith(focusType))	return BELOW;
+			return UNRELATED;
+		}
+	}
+	
+	private static final IType[] NO_TYPE = new IType[0];
+
+	// === singleton infrastructure: ===
+	
+	private static OTTypeHierarchies instance;
+	public OTTypeHierarchies() {
+		instance = this;
+	}
+	/** Get the singleton instance of this team, which was created and activated by OT/Equinox. */
+	public static OTTypeHierarchies getInstance() { return instance; }
+	
+	
+	/** 
+	 * The stateful part of this team, implemented as a nested team.
+	 */
+	protected team class OTTypeHierarchy playedBy TypeHierarchy 
+	{
+		// === "Imports" (callout) from plain TypeHierarchy: ===
+		
+		@SuppressWarnings("decapsulation") IType getFocusType() 	-> get IType focusType;
+		ConnectedType getSuperclass(IType type) 					-> IType getSuperclass(IType type);
+		ConnectedType[] getAllSuperclassesUnfiltered(IType type) 	-> IType[] getAllSuperclasses(IType type);
+		IType[] getSuperInterfaces(IType type) 						-> IType[] getSuperInterfaces(IType type);
+		IType[] getAllSuperInterfaces(IType type) 					-> IType[] getAllSuperInterfaces(IType type);
+		
+		
+		// === Adapt TypeHierarchy (callin bindings): ===
+
+		precedence unwrapping, filtering1, superlinearize; // order: outer callins unwrap and filter, inner callin performs computation
+		precedence filtering2, tsuperadding;
+
+		// --- considure implicit inheritance for some queries: ----
+		
+		// make getSuperclass() traverse the superclass linearization of the focus type:
+	superlinearize: 
+		ConnectedType getSuperclassLinearized(ConnectedType type) <- replace IType getSuperclass(IType type);
+		
+		// augment original queries to capture tsub-types, too:
+		@SuppressWarnings("decapsulation")
+		addTSubs <- replace getSubtypesForType; // adjust internal method as to capture calls from getAllSubtypes(IType), too.
+	tsuperadding:
+		addTSubs <- replace getSubclasses;
+
+		// --- filtering (duplicates and phantoms) and unwrapping (OTTypes): ---
+		
+		// make some methods aware of our phantom mode:
+	filtering1: 
+		ConnectedType[] phantomFilterWrapper() 
+		<- replace 
+			IType[] getAllClasses(), 
+			IType[] getImplementingClasses(IType type), 
+			IType[] getAllSuperclasses(IType type) 
+					when (!this.phantomMode);
+		
+		// filter intermediate results only at these top-level queries:
+	filtering2: 	
+		filterDuplicatesAndPhantoms <- replace getSubclasses, getSubtypes, getAllSubtypes, getImplementingClasses; // includes unwrapping of OTTypes
+		
+		// all top-level queries unwrap and given OTTypes:
+	unwrapping:
+		ensureJavaType <- replace getAllSuperclasses, getAllSuperInterfaces, getAllSupertypes,
+							      getCachedFlags, getExtendingInterfaces, 
+								  getSuperclass, getSuperInterfaces, getSupertypes;
+
+		/**
+		 * This role adds to ITypes the capability of connecting to all direct and indirect tsuper types,
+		 * which includes linearization of all super types (implicit & explicit). 
+		 */
+		@SuppressWarnings("abstractrelevantrole")
+		protected abstract class ConnectedType  playedBy IType 
+		{
+			/** Is this type a phantom role? */
+			protected boolean isPhantom;
+
+			/** The direct tsuper types of this type. */
+			protected ConnectedType[] directTSupers;
+
+			/** All direct & indirect tsuper classes in a linearized form. All classes in this list have the same simple name. */
+			protected List<ConnectedType> allTSupersLinearized;
+
+			/** This type's relation to the focus type. */
+			private FocusRelation focusRelation;
+			
+			// the last item in allTSupersLinearized, used as a token for switching from implicit to explicit supers
+			private ConnectedType lastTSuper = null;
+			
+			/** the root of the tsuper chain through which this connected type was reached. */
+			protected ConnectedType tsuperChainRoot;
+			
+			/** All known direct tsub types of this type. */
+			protected Set<ConnectedType> knownTSubTypes;
+
+					
+			protected ConnectedType(IType type) {
+				this.tsuperChainRoot = this;
+			}
+
+			public void init(boolean isPhantom, ConnectedType[] tsuperclassHandles, FocusRelation focusRelation) {
+				this.isPhantom = isPhantom;
+				this.directTSupers = tsuperclassHandles;
+				this.focusRelation = focusRelation;			
+			}
+			
+			/** Combine indirect tsuper classes into the list of all linearized tsuper types. */
+			@SuppressWarnings("ambiguouslowering") // method contains takes an Object argument
+			public void combineTSupers(ConnectedType focusLayerType, ConnectedType[] tsuperclassHandles) {
+				this.tsuperChainRoot = focusLayerType.tsuperChainRoot;
+				if (this.allTSupersLinearized == null)
+					this.allTSupersLinearized = new LinkedList<ConnectedType>();
+				for (ConnectedType type : tsuperclassHandles)
+					if (!this.allTSupersLinearized.contains(type))
+						this.allTSupersLinearized.add(type);
+			}
+
+			/** Get the next type in the tsuper linearization. */
+			protected ConnectedType getTSuperType() {
+				if (this.focusRelation == FocusRelation.BELOW) {
+					// only follow the path towards the focus type:
+					if (this.directTSupers != null)
+						for (ConnectedType directTSuper : this.directTSupers)
+							if (directTSuper.focusRelation == FocusRelation.EQUAL || directTSuper.focusRelation == FocusRelation.BELOW)
+								return directTSuper;
+					return null; // no tsuper leading to focus
+				}
+				// shortcut if no tsupers:
+				if (this.allTSupersLinearized == null || this.allTSupersLinearized.size() == 0)
+					return null;
+				// when starting from the focus layer return the first tsuper role:
+				if (isInFocusLayer(this))
+					return this.allTSupersLinearized.get(0);
+				// when type is contained in the list of tsuperRoles return the next tsuper role from the list
+				for (int i = 0; i < this.allTSupersLinearized.size()-1; i++)
+					if (this.allTSupersLinearized.get(i) == this)
+						return this.allTSupersLinearized.get(i+1);
+				return null; // end reached
+			}
+			
+			/** Is this the last element in the list of tsuper roles? */
+			protected boolean isLastTSuper() {
+				if (this.allTSupersLinearized == null || this.allTSupersLinearized.size() == 0) // optimize: don's store empty list?
+					return false;
+				if (this.lastTSuper == null)
+					this.lastTSuper = this.allTSupersLinearized.get(this.allTSupersLinearized.size()-1);
+				return this.lastTSuper == this;
+			}
+			
+			/** If this is a phantom type, get the real tsuper class that this is derived (copied) from. */
+			protected ConnectedType getRealTSuper() throws JavaModelException {
+				if (!isPhantom)
+					return this;
+				if (this.allTSupersLinearized != null)
+					for(ConnectedType other : this.allTSupersLinearized)
+						if (!other.isPhantom)
+							return other;
+				throw new JavaModelException(new JavaModelStatus(JavaModelStatus.ERROR, this, "no non-phantom type found in allTSupersLinearized")); //$NON-NLS-1$
+			}
+			
+			/** Get all tsuper types yet respecting phantom mode. */
+			protected ConnectedType[] getAllTSuperTypes() 
+			{
+				if (this.focusRelation == FocusRelation.BELOW && this.directTSupers != null) {
+					// special handling for types below the focus: transitively collect tsupers:
+					ConnectedType direct = getTSuperType(); // only the one path towards focus
+					if (direct == null) 
+						return new ConnectedType[0];
+					ConnectedType[] indirect = direct.getAllTSuperTypes(); // NB: recursion may enter the focus cone
+					if (indirect == null) 
+						return new ConnectedType[] {direct};
+					// merge direct and indirect:
+					int len = indirect.length;
+					ConnectedType[] result = new ConnectedType[len+1];
+					result[0] = direct;
+					System.arraycopy(indirect, 0, result, 1, len);
+					return result;
+				}
+
+				int size;
+				if (this.allTSupersLinearized != null && (size = this.allTSupersLinearized.size()) > 0) 
+				{
+					// focus level => all types from the linearization:
+					if (isInFocusLayer(this))
+						return this.allTSupersLinearized.toArray(new ConnectedType[size]);
+					
+					// not focus, search in linearization for this type ...
+					int skip = 0;
+					boolean found = false;
+					while (skip < size)
+						if (this.allTSupersLinearized.get(skip++) == this) {
+							found = true;
+							break;
+						}
+					if (found) { // .. and take the tail after this type: 
+						if (skip < size) { // if found at last pos, there's no tail
+							ConnectedType[] result = new ConnectedType[size-skip];
+							for (int i=0; skip<size;)
+								result[i++] = this.allTSupersLinearized.get(skip++);
+							return result;
+						}
+					} else {
+						System.out.println("HERE "+this);
+						// not focus type but seemingly bottom of the lattice, take all known tsupers
+						return this.allTSupersLinearized.toArray(new ConnectedType[size]);
+					}
+				}
+				return new ConnectedType[0];
+			}
+			
+			/** Register a known tsub type of this type. */
+			protected void addTSubType(ConnectedType tsub) {
+				if (this.knownTSubTypes == null)
+					this.knownTSubTypes = new HashSet<ConnectedType>();
+				this.knownTSubTypes.add(tsub);
+			}
+		
+			toString => toString; // for debugging
+
+		}
+		// binding source variant of IType
+		protected class ConnectedSourceType extends ConnectedType playedBy SourceType { /*just class binding, no details*/ }
+		
+		// binding binary variant of IType
+		protected class ConnectedBinaryType extends ConnectedType playedBy BinaryType { /*just class binding, no details*/ }
+		
+		// binding binary variant of IType
+		protected class ConnectedPhantomType extends ConnectedType playedBy PhantomType { /*just class binding, no details*/ }
+
+		// binding binary variant of IType
+		protected class ConnectedOTType extends ConnectedType playedBy OTType { /*just class binding, no details*/ }
+
+		// === start main part of nested team OTTypeHierarchy ===
+		
+		/** Should the hierarchy show phantom roles? */
+		protected boolean phantomMode;
+
+		/**
+		 * Connect the found tsuper classes into the connected type for the given type. 
+		 */
+		protected void connectTSupers(IType as ConnectedType connectedType, 
+									  boolean isPhantom, 
+									  IType as ConnectedType tsuperclassHandles[], 
+									  boolean[] arePhantoms,
+									  FocusRelation focusRelation) 
+		{
+			connectedType.init(isPhantom, tsuperclassHandles, focusRelation);
+			
+			// connect tsuperclassHandles into the appropriate ConnectedType:
+			switch (focusRelation) {
+			case EQUAL:
+				connectedType.allTSupersLinearized = new LinkedList<ConnectedType>();
+				for (int i = 0; i < tsuperclassHandles.length; i++)
+					connectedType.allTSupersLinearized.add(tsuperclassHandles[i]);
+				break;
+			case ABOVE:
+				ConnectedType focusLayerType = connectedType.tsuperChainRoot;
+				focusLayerType.combineTSupers(focusLayerType, tsuperclassHandles);
+				connectedType.allTSupersLinearized = focusLayerType.allTSupersLinearized; // share the same list
+				break;
+			case BELOW:
+				// don't merge into focus' up-chain
+				break;
+			default: // UNRELATED
+//				if (isInFocusLayer(connectedType)) {
+//					connectedType.allTSupersLinearized = new LinkedList<ConnectedType>();
+//					for (int i = 0; i < tsuperclassHandles.length; i++)
+//						connectedType.allTSupersLinearized.add(tsuperclassHandles[i]);
+//				}
+				// otherwise shouldn't be relevant?
+			}
+			// connect each in tsuperclassHandles back to the tsuperChainRoot:
+			for (int i = 0; i < tsuperclassHandles.length; i++) {
+				if (focusRelation == FocusRelation.EQUAL || focusRelation == FocusRelation.ABOVE)
+					tsuperclassHandles[i].tsuperChainRoot = connectedType.tsuperChainRoot;
+				tsuperclassHandles[i].isPhantom = arePhantoms[i];
+				// and remember the type-tsub link:
+				tsuperclassHandles[i].addTSubType(connectedType);
+			}
+		}
+
+		boolean isInFocusLayer(IType type) {
+			IType focusType = getFocusType();
+			if (type.equals(focusType))
+				return true;
+			return focusType.getParent().equals(type.getParent()); // FIXME(SH) elaborate more
+		}
+		
+		boolean isStrictlyBelowFocusType(IType type) {
+			IType focusType = getFocusType();
+			if (focusType.equals(type))
+				return false;
+			return isBelowFocusType(focusType, type);
+		}
+
+		private boolean isBelowFocusType(IType focusType, IType type) {
+			if (focusType.equals(type))
+				return true;
+			return false;
+		}
+
+		/** Given that 'type' is element of a superclass linearization return the next super in the chain. */
+		@SuppressWarnings("basecall")
+		callin ConnectedType getSuperclassLinearized(ConnectedType type) {
+			// check for tsuper type in the computed list:
+			ConnectedType tsuperType = type.getTSuperType();
+			if (tsuperType != null)
+				return tsuperType;
+			// if type is the last in the list ... 
+			if (type.isLastTSuper()) {
+				// ...we're done with tsupers, start over with super of the focus level type:
+				return base.getSuperclassLinearized(type.tsuperChainRoot);
+			}
+			return base.getSuperclassLinearized(type);
+		}
+
+		// ==== handling for phantom mode: ====
+		
+		ConnectedType[] maybeSubstitutePhantoms(ConnectedType[] roles) throws JavaModelException {
+			if (this.phantomMode)
+				return roles;
+			ConnectedType[] substituted = new ConnectedType[roles.length];
+			for (int i = 0; i < roles.length; i++)
+				substituted[i] = roles[i].getRealTSuper();
+			return substituted;
+		}
+
+		protected ConnectedType[] filterPhantomRoles(ConnectedType[] roles) {
+			ConnectedType[] substituted = new ConnectedType[roles.length];
+			int n = 0;
+			for (int i = 0; i < roles.length; i++)
+				if (!roles[i].isPhantom)
+					substituted[n++] = roles[i];
+			if (n<roles.length)
+				System.arraycopy(substituted, 0, substituted=new ConnectedType[n], 0, n);
+			return substituted;
+		}
+
+		// wrappers for use in multiple callin bindings
+		callin ConnectedType[] phantomFilterWrapper() {
+			return filterPhantomRoles(base.phantomFilterWrapper());
+		}
+		
+		callin ConnectedType[] filterDuplicatesAndPhantoms(IType type) {
+			if (type instanceof IOTType) type = (IType) ((IOTType)type).getCorrespondingJavaElement();
+			return filterDupsAndPhants(base.filterDuplicatesAndPhantoms(type));
+		}
+
+		protected ConnectedType[] filterDupsAndPhants(ConnectedType[] unfiltered) {
+			if (unfiltered == null)
+				return unfiltered;
+			Set<ConnectedType> filtered = new HashSet<ConnectedType>();
+			for(ConnectedType type : unfiltered)
+				if (this.phantomMode || !type.isPhantom)
+					filtered.add(type);
+			return filtered.toArray(new ConnectedType[filtered.size()]);
+		}
+
+		callin void ensureJavaType(IType type) {
+			if (type instanceof IOTType) type = (IType) ((IOTType)type).getCorrespondingJavaElement();
+			base.ensureJavaType(type);
+		}
+		
+		// ==== adjusting some subtype queries for tsubs:
+		
+		callin ConnectedType[] addTSubs(ConnectedType type) {
+			ConnectedType[] res1 = base.addTSubs(type);
+			Set<ConnectedType> tsubs = type.knownTSubTypes;
+			
+			if (tsubs == null || tsubs.size() == 0)
+				return this.phantomMode ? res1 : filterDupsAndPhants(res1);
+		
+			Set<ConnectedType> result = new HashSet<ConnectedType>();
+			result.addAll(tsubs);
+			for (ConnectedType t1 : res1)
+				result.add(t1);
+			return result.toArray(new ConnectedType[result.size()]);
+		}
+		
+	
+		// ==== queries for clients (wrapped by methods of enclosing team, see there for documentation): ====
+		
+		protected IType[] getAllTSuperTypes(IType as ConnectedType type) {
+			ConnectedType[] result = type.getAllTSuperTypes();
+			return this.phantomMode ? result : filterPhantomRoles(result);  
+				// FIXME(SH) return without intermediate local var -> CCE
+				// like: return type.getAllTSuperTypes();
+		}
+
+		protected IType[] getDirectTSupers(IType as ConnectedType type) throws JavaModelException {
+			if (type.directTSupers == null)
+				return NO_TYPE;
+			return maybeSubstitutePhantoms(type.directTSupers);
+		}
+		
+		protected IType getPlainSuperclass(IType type) throws JavaModelException {
+			try {
+				OTTypeHierarchies.this.deactivate();
+				ConnectedType result = getSuperclass(type);
+				if (this.phantomMode || result == null)
+					return result;
+				return result.getRealTSuper();
+			} finally {
+				OTTypeHierarchies.this.activate();
+			}
+		}
+		
+		// sole purpose of this wrapper: array-lowering
+		protected IType[] getAllSuperclasses(IType type) {
+			return getAllSuperclassesUnfiltered(type);
+		}
+	}
+	
+	/**
+	 * This role adapts the HierarchyBuilder in order to record information about implicit inheritance, too. 
+	 */
+	protected class OTHierarchyBuilder playedBy HierarchyBuilder {
+
+		@SuppressWarnings("decapsulation")
+		OTTypeHierarchy getHierarchy() -> get TypeHierarchy hierarchy;
+
+		connectTSupers  <- before hookableConnect;
+
+		private void connectTSupers(ReferenceBinding focusType, ReferenceBinding typeBinding, IGenericType type, IType typeHandle, boolean isPhantom, 
+									IType superclassHandle, IType[] tsuperclassHandles, boolean[] arePhantoms, IType[] superinterfaceHandles) 
+		{
+			if (tsuperclassHandles!= null) {
+				FocusRelation focusRelation = FocusRelation.compute(focusType, typeBinding);
+				getHierarchy().connectTSupers(typeHandle, isPhantom, tsuperclassHandles, arePhantoms, focusRelation);
+			}
+		}
+	}
+
+	/**
+	 * API: Query all direct and indirect implicit superclasses of the given type.
+	 * If phantomMode is set to <code>false</code> any phantom roles will be filtered from the result.
+	 * 
+	 * @param otHierarchy a hierarchy that has been focused on the given type
+	 * @param type        the focus type whose super types are queried
+	 * @return a non-null array of ordered implicit super classes
+	 * @throws JavaModelException If the tsuper linearization is corrupt
+	 */
+	public IType[] getAllTSuperTypes(TypeHierarchy as OTTypeHierarchy otHierarchy, IType type) throws JavaModelException {
+		if (type instanceof IOTType) type = (IType) ((IOTType)type).getCorrespondingJavaElement();
+		return otHierarchy.getAllTSuperTypes(type);
+	}
+	
+	/**
+	 * API: Query all direct implicit superclasses of the given type.
+	 * If phantomMode is set to <code>false</code> any phantom roles will be translated to its real origin.
+	 * 
+	 * @param otHierarchy a hierarchy that has been focused on the given type
+	 * @param type        the focus type whose super types are queried
+	 * @return a non-null array of ordered implicit super classes
+	 * @throws JavaModelException If the tsuper linearization is corrupt
+	 */
+	public IType[] getTSuperTypes(TypeHierarchy as OTTypeHierarchy otHierarchy, IType type) throws JavaModelException {
+		if (type instanceof IOTType) type = (IType) ((IOTType)type).getCorrespondingJavaElement();
+		return otHierarchy.getDirectTSupers(type);
+	}
+	
+	/**
+	 * API: Query all direct, implicit and explicit superclasses of the given type.
+	 * If phantomMode is set to <code>false</code> any phantom roles will be substituted with their real origin.
+	 * 
+	 * @param otHierarchy a hierarchy that has been focused on the given type
+	 * @param type        the focus type whose super types are queried
+	 * @return a non-null array of ordered super classes.
+	 * @throws JavaModelException If the tsuper linearization is corrupt
+	 */
+	public IType[] getSuperclasses(TypeHierarchy as OTTypeHierarchy otHierarchy, IType type) throws JavaModelException {
+		if (type instanceof IOTType) type = (IType) ((IOTType)type).getCorrespondingJavaElement();
+		// have superclass (otherwise type == java.lang.Object?)
+		IType superclass = otHierarchy.getPlainSuperclass(type);
+		if (superclass == null)
+			return NO_TYPE;
+		
+		// check direct tsupers:
+		IType[] directTSupers = getTSuperTypes(otHierarchy, type);
+		if (directTSupers == null)
+			return new IType[] { superclass };
+		
+		// found both => merge
+		int count = directTSupers.length;
+		IType[] merged = new IType[count+1];
+		System.arraycopy(directTSupers, 0, merged, 0, count);
+		merged[count] = superclass;
+		return merged;
+	}
+	
+	/**
+	 * API: Query all direct and indirect, implicit and explicit superclasses of the given type.
+	 * If phantomMode is set to <code>false</code> any phantom roles will be filtered from the result.
+	 * 
+	 * @param otHierarchy a hierarchy that has been focused on the given type
+	 * @param type        the focus type whose super types are queried
+	 * @return a non-null array of ordered super classes.
+	 * @throws JavaModelException if accessing type failed
+	 */
+	public IType[] getAllSuperclasses(TypeHierarchy as OTTypeHierarchy otHierarchy, IType type) throws JavaModelException {
+		if (type.isInterface())
+			return NO_TYPE;
+		if (type instanceof IOTType) type = (IType) ((IOTType)type).getCorrespondingJavaElement();
+		return otHierarchy.getAllSuperclasses(type);
+	}
+	
+	/**
+	 * API: Query the explicit superclass of the given type.
+	 * 
+	 * @param otHierarchy a hierarchy that has been focused on the given type
+	 * @param type        the focus type whose super type is queried
+	 * @return the superclass
+	 * @throws JavaModelException If the tsuper linearization is corrupt
+	 */
+	public IType getExplicitSuperclass(TypeHierarchy as OTTypeHierarchy otHierarchy, IType type) throws JavaModelException {
+		if (type instanceof IOTType) type = (IType) ((IOTType)type).getCorrespondingJavaElement();
+		// have superclass (otherwise type == java.lang.Object?)
+		return otHierarchy.getPlainSuperclass(type);
+	}
+
+	/** Get ALL super types: classes and interfaces, explicit and implicit, direct and indirect. */
+	public IType[] getAllSupertypes(TypeHierarchy  as OTTypeHierarchy otHierarchy, IType type) {
+		if (type instanceof IOTType) type = (IType) ((IOTType)type).getCorrespondingJavaElement();
+		IType[] superclasses = otHierarchy.getAllSuperclasses(type);
+		IType[] superinterfaces = otHierarchy.getAllSuperInterfaces(type);
+		int l1 = superclasses.length, l2 = superinterfaces.length;
+		IType[] result = new IType[l1+l2];
+		System.arraycopy(superclasses, 0, result, 0, l1);
+		System.arraycopy(superinterfaces, 0, result, l1, l2);
+		return result;
+	}
+
+	/**
+	 * API: Query the superinterfaces of the given type, plus if it's a role interface the tsuper interfaces.
+	 * tsuper's direct superinterfaces are also counted as direct interfaces.
+	 * 
+	 * @param otHierarchy a hierarchy that has been focused on the given type
+	 * @param type        the focus type whose super types are queried
+	 * @return the superinterfaces
+	 * @throws JavaModelException If the tsuper linearization is corrupt
+	 */
+	public IType[] getSuperInterfaces(TypeHierarchy as OTTypeHierarchy otHierarchy, IType type) throws JavaModelException {
+		if (type instanceof IOTType) type = (IType) ((IOTType)type).getCorrespondingJavaElement();
+		IType[] superinterfaces = otHierarchy.getSuperInterfaces(type);
+		if (!OTModelManager.isRole(type))
+			return superinterfaces;
+		Set<IType> all = new HashSet<IType>();
+		for (IType iType : superinterfaces)
+			all.add(iType);
+		for (IType tsuperinterface : otHierarchy.getDirectTSupers(type)) {
+			if (type.isInterface()) // otherwise just traverse tsuper to find more super interfaces
+				all.add(tsuperinterface);
+			for (IType tsupersuper : otHierarchy.getSuperInterfaces(tsuperinterface))
+				all.add(tsupersuper);
+		}
+		return all.toArray(new IType[all.size()]);
+	}
+
+	/**
+	 * API: Query the superinterfaces of the given type: explicit & implicit, direct & indirect.
+	 * 
+	 * @param otHierarchy a hierarchy that has been focused on the given type
+	 * @param type        the focus type whose super types are queried
+	 * @return the superinterfaces
+	 * @throws JavaModelException If the tsuper linearization is corrupt
+	 */
+	public IType[] getAllSuperInterfaces(TypeHierarchy as OTTypeHierarchy otHierarchy, IType type) throws JavaModelException {
+		if (!OTModelManager.isRole(type))
+			return otHierarchy.getAllSuperInterfaces(type);
+		if (type instanceof IOTType) type = (IType) ((IOTType)type).getCorrespondingJavaElement();
+		Set<IType> all = new HashSet<IType>();
+		getAllSuperInterfaces2(otHierarchy, type, all);
+		return all.toArray(new IType[all.size()]);
+	}
+	// recursive helper for above
+	private void getAllSuperInterfaces2(OTTypeHierarchy otHierarchy, IType seed, Set<IType> collected) throws JavaModelException {
+		for (IType tsuperinterface : otHierarchy.getAllTSuperTypes(seed)) {
+			if (seed.isInterface()) { // otherwise just traverse tsuper to find more super interfaces
+				collected.add(tsuperinterface);
+			}
+			getAllSuperInterfaces2(otHierarchy, tsuperinterface, collected);
+		}
+		for (IType superinterface : otHierarchy.getAllSuperInterfaces(seed)) {
+			collected.add(superinterface);
+			getAllSuperInterfaces2(otHierarchy, superinterface, collected);
+		}
+	}
+	
+	/**
+	 * Configure whether the given hierarchy should consider phantom roles or not.
+	 * Depending on the query used, phantom roles will either be filtered out or replaced with their real origins.
+	 * In order for the phantom modes to be respected, the hierarchy must not be directly consulted but only
+	 * via the fassade methods of this team. 
+	 */
+	public void setPhantomMode(TypeHierarchy as OTTypeHierarchy otHierarchy, boolean mode) {
+		otHierarchy.phantomMode = mode;		
+	}
+}