Buggy code:
public class IndexBasedHierarchyBuilder extends HierarchyBuilder implements SuffixConstants { public static final int MAXTICKS = 800 ; protected Map cuToHandle ; protected IJavaSearchScope scope ; protected Map binariesFromIndexMatches ; static class Queue { public char [ ] [ ] names = new char [ 10 ] [ ] ; public int start = 0 ; public int end = - 1 ; public void add ( char [ ] name ) { } public char [ ] retrieve ( ) { } public String toString ( ) { } } public IndexBasedHierarchyBuilder ( TypeHierarchy hierarchy , IJavaSearchScope scope ) throws JavaModelException { } public void build ( boolean computeSubtypes ) { } private void buildForProject ( JavaProject project , ArrayList potentialSubtypes , ICompilationUnit [ ] workingCopies , HashSet localTypes , IProgressMonitor monitor ) throws JavaModelException { } private void buildFromPotentialSubtypes ( String [ ] allPotentialSubTypes , HashSet localTypes , IProgressMonitor monitor ) { } protected org . eclipse . jdt . internal . compiler . env . ICompilationUnit createCompilationUnitFromPath ( Openable handle , IFile file ) { } protected IBinaryType createInfoFromClassFile ( Openable classFile , IResource file ) { } protected IBinaryType createInfoFromClassFileInJar ( Openable classFile ) { } private String [ ] determinePossibleSubTypes ( final HashSet localTypes , IProgressMonitor monitor ) { } public static void searchAllPossibleSubTypes ( IType type , IJavaSearchScope scope , final Map binariesFromIndexMatches , final IPathRequestor pathRequestor , int waitingPolicy , IProgressMonitor progressMonitor ) { final IndexBasedHierarchyBuilder . Queue queue = new IndexBasedHierarchyBuilder . Queue ( ) ; final HashtableOfObject foundSuperNames = new HashtableOfObject ( 5 ) ; IndexManager indexManager = JavaModelManager . getJavaModelManager ( ) . getIndexManager ( ) ; IndexQueryRequestor searchRequestor = new IndexQueryRequestor ( ) { public boolean acceptIndexMatch ( String documentPath , SearchPattern indexRecord , SearchParticipant participant , AccessRuleSet access ) { SuperTypeReferencePattern record = ( ( SuperTypeReferencePattern ) ( indexRecord ) ) ; boolean isLocalOrAnonymous = ( record . enclosingTypeName ) == ( IIndexConstants . ONE_ZERO ) ; pathRequestor . acceptPath ( documentPath , isLocalOrAnonymous ) ; char [ ] typeName = record . simpleName ; <START_BUG> int suffix = documentPath . toLowerCase ( ) . indexOf ( SuffixConstants . SUFFIX_STRING_class ) ; <END_BUG> if ( suffix != ( - 1 ) ) { HierarchyBinaryType binaryType = ( ( HierarchyBinaryType ) ( binariesFromIndexMatches . get ( documentPath ) ) ) ; if ( binaryType == null ) { char [ ] enclosingTypeName = record . enclosingTypeName ; if ( isLocalOrAnonymous ) { int lastSlash = documentPath . lastIndexOf ( '//' ) ; int lastDollar = documentPath . lastIndexOf ( '$' ) ; if ( lastDollar == ( - 1 ) ) { enclosingTypeName = null ; typeName = documentPath . substring ( ( lastSlash + 1 ) , suffix ) . toCharArray ( ) ; } else { enclosingTypeName = documentPath . substring ( ( lastSlash + 1 ) , lastDollar ) . toCharArray ( ) ; typeName = documentPath . substring ( ( lastDollar + 1 ) , suffix ) . toCharArray ( ) ; } } binaryType = new HierarchyBinaryType ( record . modifiers , record . pkgName , typeName , enclosingTypeName , record . typeParameterSignatures , record . classOrInterface ) ; binariesFromIndexMatches . put ( documentPath , binaryType ) ; } binaryType . recordSuperType ( record . superSimpleName , record . superQualification , record . superClassOrInterface ) ; } if ( ( ! isLocalOrAnonymous ) && ( ! ( foundSuperNames . containsKey ( typeName ) ) ) ) { foundSuperNames . put ( typeName , typeName ) ; queue . add ( typeName ) ; } return true ; } } ; int superRefKind ; try { superRefKind = ( type . isClass ( ) ) ? SuperTypeReferencePattern . ONLY_SUPER_CLASSES : SuperTypeReferencePattern . ALL_SUPER_TYPES ; } catch ( JavaModelException e ) { superRefKind = SuperTypeReferencePattern . ALL_SUPER_TYPES ; } SuperTypeReferencePattern pattern = new SuperTypeReferencePattern ( null , null , superRefKind , ( ( SearchPattern . R_EXACT_MATCH ) | ( SearchPattern . R_CASE_SENSITIVE ) ) ) ; MatchLocator . setFocus ( pattern , type ) ; SubTypeSearchJob job = new SubTypeSearchJob ( pattern , new JavaSearchParticipant ( ) , scope , searchRequestor ) ; int ticks = 0 ; queue . add ( type . getElementName ( ) . toCharArray ( ) ) ; try { while ( ( queue . start ) <= ( queue . end ) ) { if ( ( progressMonitor != null ) && ( progressMonitor . isCanceled ( ) ) ) return ; char [ ] currentTypeName = queue . retrieve ( ) ; if ( CharOperation . equals ( currentTypeName , IIndexConstants . OBJECT ) ) currentTypeName = null ; pattern . superSimpleName = currentTypeName ; indexManager . performConcurrentJob ( job , waitingPolicy , null ) ; if ( ( progressMonitor != null ) && ( ( ++ ticks ) <= ( IndexBasedHierarchyBuilder . MAXTICKS ) ) ) progressMonitor . worked ( 1 ) ; if ( currentTypeName == null ) break ; } } finally { job . finished ( ) ; } } }

Fix:
int suffix = documentPath . toLowerCase ( ) . lastIndexOf ( SuffixConstants . SUFFIX_STRING_class ) ;