Bug 138377 - [patch] [console] [source lookup] Clicking on Java stack
trace hyperlink in console is unusably slow again
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/OpenTypeAction.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/OpenTypeAction.java
index 4364f16..681fc3c 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/OpenTypeAction.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/OpenTypeAction.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2009 IBM Corporation and others.
+ * Copyright (c) 2000, 2012 IBM Corporation 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
@@ -16,6 +16,7 @@
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.OperationCanceledException;
 import org.eclipse.core.runtime.Status;
 import org.eclipse.debug.core.DebugException;
 import org.eclipse.debug.core.model.IDebugElement;
@@ -95,7 +96,7 @@
 				if (source == null) {
 					//resort to looking through the workspace projects for the
 					//type as the source locators failed.
-					source = findTypeInWorkspace(type.getName());
+					source = findTypeInWorkspace(type.getName(), false);
 				}
 			}
 		}
@@ -133,10 +134,15 @@
 	 * or <code>null</code> if none.
 	 * 
 	 * @param typeName fully qualified type name
+	 * @param findOnlyUniqueMatch
+	 *            if <code>true</code>, this method only returns a type iff
+	 *            there's only a single match in the workspace, and
+	 *            <code>null</code> otherwise. If <code>false</code>, it returns
+	 *            the first match.
 	 * @return type or <code>null</code>
-	 * @throws JavaModelException
+	 * @throws CoreException if search failed
 	 */
-	public static IType findTypeInWorkspace(String typeName) throws CoreException {
+	public static IType findTypeInWorkspace(String typeName, boolean findOnlyUniqueMatch) throws CoreException {
 		int dot= typeName.lastIndexOf('.');
 		char[][] qualifications;
 		String simpleName;
@@ -149,6 +155,14 @@
 		}
 		char[][] typeNames= new char[][] { simpleName.toCharArray() };
 		
+		if (findOnlyUniqueMatch) {
+			return findUniqueTypeInWorkspace(qualifications, typeNames);
+		}
+		return findAnyTypeInWorkspace(qualifications, typeNames);
+	}
+
+	private static IType findAnyTypeInWorkspace(char[][] qualifications,
+			char[][] typeNames) throws JavaModelException {
 		class ResultException extends RuntimeException {
 			private static final long serialVersionUID= 1L;
 			private final IType fType;
@@ -170,6 +184,26 @@
 		return null;
 	}
 	
+	private static IType findUniqueTypeInWorkspace(char[][] qualifications,
+			char[][] typeNames) throws JavaModelException {
+		final IType[] result = { null };
+		TypeNameMatchRequestor requestor= new TypeNameMatchRequestor() {
+			public void acceptTypeNameMatch(TypeNameMatch match) {
+				if (result[0] == null) {
+					result[0]= match.getType();
+				} else {
+					throw new OperationCanceledException();
+				}
+			}
+		};
+		try {
+			new SearchEngine().searchAllTypeNames(qualifications, typeNames, SearchEngine.createWorkspaceScope(), requestor, IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH, null);
+		} catch (OperationCanceledException e) {
+			return null;
+		}
+		return result[0];
+	}
+	
 	
 	protected void typeHierarchyError() {
 		showErrorMessage(ActionMessages.ObjectActionDelegate_Unable_to_display_type_hierarchy__The_selected_source_element_is_not_contained_in_the_workspace__1); 
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/console/JavaStackTraceHyperlink.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/console/JavaStackTraceHyperlink.java
index 7a6b4a5..b669ddb 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/console/JavaStackTraceHyperlink.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/console/JavaStackTraceHyperlink.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * Copyright (c) 2000, 2012 IBM Corporation 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
@@ -39,14 +39,15 @@
 import org.eclipse.ui.texteditor.ITextEditor;
 
 /**
- * A hyperlink from a stack trace line of the form "*(*.java:*)"
+ * A hyper-link from a stack trace line of the form "*(*.java:*)"
  */
 public class JavaStackTraceHyperlink implements IHyperlink {
 	
 	private TextConsole fConsole;
 
 	/**
-	 * Constructor for JavaStackTraceHyperlink.
+	 * Constructor
+	 * @param console the {@link TextConsole} this link detector is attached to
 	 */
 	public JavaStackTraceHyperlink(TextConsole console) {
 		fConsole = console;
@@ -90,6 +91,7 @@
 	 * Starts a search for the type with the given name. Reports back to 'searchCompleted(...)'.
 	 * 
 	 * @param typeName the type to search for
+	 * @param lineNumber the line number to open the editor on
 	 */
 	protected void startSourceSearch(final String typeName, final int lineNumber) {
 		Job search = new Job(ConsoleMessages.JavaStackTraceHyperlink_2) {
@@ -98,12 +100,14 @@
 				ILaunch launch = getLaunch();
 				Object result = null;
 				try {
-					if (launch != null) {
+					// search for the type in the workspace
+					result = OpenTypeAction.findTypeInWorkspace(typeName, true);
+					if (result == null && launch != null) {
 						result = JavaDebugUtils.resolveSourceElement(JavaDebugUtils.generateSourceName(typeName), getLaunch());
 					}
 					if (result == null) {
-						// search for the type in the workspace
-						result = OpenTypeAction.findTypeInWorkspace(typeName);
+						// search for any type in the workspace
+						result = OpenTypeAction.findTypeInWorkspace(typeName, false);
 					}
 					searchCompleted(result, typeName, lineNumber, null);
 				} catch (CoreException e) {
@@ -116,6 +120,14 @@
 		search.schedule();
 	}
 	
+	/**
+	 * Reported back to from {@link JavaStackTraceHyperlink#startSourceSearch(String, int)} when results are found
+	 * 
+	 * @param source the source object
+	 * @param typeName the fully qualified type name
+	 * @param lineNumber the line number in the type
+	 * @param status the error status or <code>null</code> if none
+	 */
 	protected void searchCompleted(final Object source, final String typeName, final int lineNumber, final IStatus status) {
 		UIJob job = new UIJob("link search complete") { //$NON-NLS-1$
 			@Override
@@ -173,10 +185,10 @@
 	}
 
 	/**
-	 * Returns the launch associated with this hyperlink, or
+	 * Returns the launch associated with this hyper-link, or
 	 *  <code>null</code> if none
 	 * 
-	 * @return the launch associated with this hyperlink, or
+	 * @return the launch associated with this hyper-link, or
 	 *  <code>null</code> if none
 	 */
 	private ILaunch getLaunch() {
@@ -189,7 +201,8 @@
 
 	/**
 	 * Returns the fully qualified name of the type to open
-	 *  
+	 * 
+	 * @param linkText the complete text of the link to be parsed
 	 * @return fully qualified type name
 	 * @exception CoreException if unable to parse the type name
 	 */
@@ -234,6 +247,8 @@
 	/**
 	 * Returns the line number associated with the stack trace or -1 if none.
 	 * 
+	 * @param linkText the complete text of the link to be parsed
+	 * @return the line number for the stack trace or -1 if one cannot be computed or has not been provided
 	 * @exception CoreException if unable to parse the number
 	 */
 	protected int getLineNumber(String linkText) throws CoreException {
@@ -267,6 +282,7 @@
 	/**
 	 * Returns this link's text
 	 * 
+	 * @return the complete text of the link, never <code>null</code>
 	 * @exception CoreException if unable to retrieve the text
 	 */
 	protected String getLinkText() throws CoreException {