search: matching2 improvements
diff --git a/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/core/DLTKLanguageManager.java b/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/core/DLTKLanguageManager.java
index cba1f7e..805c6e1 100644
--- a/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/core/DLTKLanguageManager.java
+++ b/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/core/DLTKLanguageManager.java
@@ -18,6 +18,7 @@
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.Platform;
+import org.eclipse.dltk.annotations.Nullable;
 import org.eclipse.dltk.ast.parser.ISourceParser;
 import org.eclipse.dltk.ast.parser.SourceParserManager;
 import org.eclipse.dltk.codeassist.ICompletionEngine;
@@ -364,6 +365,7 @@
 	/**
 	 * @since 2.0
 	 */
+	@Nullable
 	public static ISearchPatternProcessor getSearchPatternProcessor(
 			String natureId) {
 		final ISearchFactory factory = getSearchFactory(natureId);
diff --git a/core/plugins/org.eclipse.dltk.core/search/org/eclipse/dltk/core/search/matching2/AbstractMatchingPredicate.java b/core/plugins/org.eclipse.dltk.core/search/org/eclipse/dltk/core/search/matching2/AbstractMatchingPredicate.java
index 98e8f61..35121c4 100644
--- a/core/plugins/org.eclipse.dltk.core/search/org/eclipse/dltk/core/search/matching2/AbstractMatchingPredicate.java
+++ b/core/plugins/org.eclipse.dltk.core/search/org/eclipse/dltk/core/search/matching2/AbstractMatchingPredicate.java
@@ -11,6 +11,8 @@
  *******************************************************************************/
 package org.eclipse.dltk.core.search.matching2;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.regex.Pattern;
 
 import org.eclipse.dltk.compiler.CharOperation;
@@ -111,8 +113,45 @@
 
 	@Override
 	public String toString() {
-		return getClass().getSimpleName() + "("
-				+ (namePattern != null ? new String(namePattern) : "*") + ")";
+		final StringBuilder sb = new StringBuilder();
+		sb.append(getClass().getSimpleName());
+		sb.append("(");
+		sb.append(namePattern != null ? new String(namePattern) : "*");
+		final List<String> options = new ArrayList<String>();
+		collectToStringOptions(options);
+		if (!options.isEmpty()) {
+			sb.append(":");
+			boolean first = true;
+			for (String option : options) {
+				if (!first) {
+					sb.append(',');
+				}
+				sb.append(option);
+				first = false;
+			}
+		}
+		sb.append(")");
+		return sb.toString();
+	}
+
+	protected void collectToStringOptions(List<String> options) {
+	}
+
+	public MatchLevel resolvePotentialMatch(E node) {
+		return MatchLevel.INACCURATE_MATCH;
+	}
+
+	public boolean contains(IMatchingPredicate<E> predicate) {
+		return false;
+	}
+
+	/**
+	 * Calls {@link #matchName(String)} and upgrades
+	 * {@link MatchLevel#POSSIBLE_MATCH} to the specified value.
+	 */
+	protected MatchLevel matchName(String name, MatchLevel upgraded) {
+		final MatchLevel level = matchName(name);
+		return level == MatchLevel.POSSIBLE_MATCH ? upgraded : level;
 	}
 
 }
diff --git a/core/plugins/org.eclipse.dltk.core/search/org/eclipse/dltk/core/search/matching2/FalseMatchingPredicate.java b/core/plugins/org.eclipse.dltk.core/search/org/eclipse/dltk/core/search/matching2/FalseMatchingPredicate.java
index 768a9ef..7ea6e66 100644
--- a/core/plugins/org.eclipse.dltk.core/search/org/eclipse/dltk/core/search/matching2/FalseMatchingPredicate.java
+++ b/core/plugins/org.eclipse.dltk.core/search/org/eclipse/dltk/core/search/matching2/FalseMatchingPredicate.java
@@ -11,11 +11,18 @@
  *******************************************************************************/
 package org.eclipse.dltk.core.search.matching2;
 
-
 public final class FalseMatchingPredicate<E> implements IMatchingPredicate<E> {
 
 	public MatchLevel match(E node) {
 		return null;
 	}
 
+	public MatchLevel resolvePotentialMatch(E node) {
+		return null;
+	}
+
+	public boolean contains(IMatchingPredicate<E> predicate) {
+		return predicate.getClass() == getClass();
+	}
+
 }
diff --git a/core/plugins/org.eclipse.dltk.core/search/org/eclipse/dltk/core/search/matching2/IMatchingPredicate.java b/core/plugins/org.eclipse.dltk.core/search/org/eclipse/dltk/core/search/matching2/IMatchingPredicate.java
index 0b48d53..9d839ed 100644
--- a/core/plugins/org.eclipse.dltk.core/search/org/eclipse/dltk/core/search/matching2/IMatchingPredicate.java
+++ b/core/plugins/org.eclipse.dltk.core/search/org/eclipse/dltk/core/search/matching2/IMatchingPredicate.java
@@ -11,8 +11,6 @@
  *******************************************************************************/
 package org.eclipse.dltk.core.search.matching2;
 
-
-
 public interface IMatchingPredicate<E> {
 
 	/**
@@ -23,4 +21,21 @@
 	 */
 	MatchLevel match(E node);
 
+	/**
+	 * Answers whether this predicate completely contains another predicate.
+	 * 
+	 * @since 5.0
+	 */
+	public boolean contains(IMatchingPredicate<E> predicate);
+
+	/**
+	 * Resolves the potential matching after the node was enhanced with the
+	 * additional information. This method is called for the nodes, for which
+	 * {@link MatchLevel#POSSIBLE_MATCH} was previously returned from
+	 * {@link #match(Object)}.
+	 * 
+	 * @since 5.0
+	 */
+	MatchLevel resolvePotentialMatch(E node);
+
 }
diff --git a/core/plugins/org.eclipse.dltk.core/search/org/eclipse/dltk/core/search/matching2/MatchLevel.java b/core/plugins/org.eclipse.dltk.core/search/org/eclipse/dltk/core/search/matching2/MatchLevel.java
index 70b43e4..18f03f3 100644
--- a/core/plugins/org.eclipse.dltk.core/search/org/eclipse/dltk/core/search/matching2/MatchLevel.java
+++ b/core/plugins/org.eclipse.dltk.core/search/org/eclipse/dltk/core/search/matching2/MatchLevel.java
@@ -11,6 +11,8 @@
  *******************************************************************************/
 package org.eclipse.dltk.core.search.matching2;
 
+import org.eclipse.dltk.core.search.SearchMatch;
+
 public enum MatchLevel {
 	// /**
 	// * 0%
@@ -30,5 +32,16 @@
 	/**
 	 * 100%
 	 */
-	ACCURATE_MATCH
+	ACCURATE_MATCH;
+
+	public int toSearchMatchAccuracy() {
+		switch (this) {
+		case ACCURATE_MATCH:
+			return SearchMatch.A_ACCURATE;
+		case INACCURATE_MATCH:
+			return SearchMatch.A_INACCURATE;
+		default:
+			return -1;
+		}
+	}
 }
diff --git a/core/plugins/org.eclipse.dltk.core/search/org/eclipse/dltk/core/search/matching2/MatchingNodeSet.java b/core/plugins/org.eclipse.dltk.core/search/org/eclipse/dltk/core/search/matching2/MatchingNodeSet.java
index 327a431..1ca7d74 100644
--- a/core/plugins/org.eclipse.dltk.core/search/org/eclipse/dltk/core/search/matching2/MatchingNodeSet.java
+++ b/core/plugins/org.eclipse.dltk.core/search/org/eclipse/dltk/core/search/matching2/MatchingNodeSet.java
@@ -156,6 +156,7 @@
 		for (E node : nodes) {
 			result.append("\n\t"); //$NON-NLS-1$
 			result.append(matchingNodes.get(node));
+			result.append(' ');
 			result.append(describeNode(node));
 		}
 		result.append("\nPossible matches:"); //$NON-NLS-1$
diff --git a/core/plugins/org.eclipse.dltk.core/search/org/eclipse/dltk/core/search/matching2/OrMatchingPredicate.java b/core/plugins/org.eclipse.dltk.core/search/org/eclipse/dltk/core/search/matching2/OrMatchingPredicate.java
index 163f521..c02b982 100644
--- a/core/plugins/org.eclipse.dltk.core/search/org/eclipse/dltk/core/search/matching2/OrMatchingPredicate.java
+++ b/core/plugins/org.eclipse.dltk.core/search/org/eclipse/dltk/core/search/matching2/OrMatchingPredicate.java
@@ -12,7 +12,10 @@
 package org.eclipse.dltk.core.search.matching2;
 
 import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
 import java.util.List;
+import java.util.Queue;
 
 public class OrMatchingPredicate<E> implements IMatchingPredicate<E> {
 
@@ -32,8 +35,29 @@
 		return null;
 	}
 
+	public MatchLevel resolvePotentialMatch(E node) {
+		for (IMatchingPredicate<E> predicate : predicates) {
+			final MatchLevel level = predicate.resolvePotentialMatch(node);
+			if (level != null) {
+				return level;
+			}
+		}
+		return null;
+	}
+
 	public IMatchingPredicate<E> optimize() {
-		// TODO merge if possible
+		final Queue<IMatchingPredicate<E>> queue = new LinkedList<IMatchingPredicate<E>>(
+				predicates);
+		for (IMatchingPredicate<E> predicate; (predicate = queue.poll()) != null;) {
+			for (Iterator<IMatchingPredicate<E>> i = predicates.iterator(); i
+					.hasNext();) {
+				final IMatchingPredicate<E> next = i.next();
+				if (predicate != next && predicate.contains(next)) {
+					i.remove();
+					queue.remove(next);
+				}
+			}
+		}
 		if (predicates.isEmpty()) {
 			return new FalseMatchingPredicate<E>();
 		} else if (predicates.size() == 1) {
@@ -43,4 +67,9 @@
 		}
 	}
 
+	public boolean contains(IMatchingPredicate<E> predicate) {
+		// TODO Auto-generated method stub
+		return false;
+	}
+
 }
diff --git a/core/plugins/org.eclipse.dltk.core/search/org/eclipse/dltk/internal/core/search/DLTKSearchDocument.java b/core/plugins/org.eclipse.dltk.core/search/org/eclipse/dltk/internal/core/search/DLTKSearchDocument.java
index 06df29d..84586c6 100644
--- a/core/plugins/org.eclipse.dltk.core/search/org/eclipse/dltk/internal/core/search/DLTKSearchDocument.java
+++ b/core/plugins/org.eclipse.dltk.core/search/org/eclipse/dltk/internal/core/search/DLTKSearchDocument.java
@@ -59,7 +59,7 @@
 	}
 
 	public String toString() {
-		return "SearchDocument for " + getPath(); //$NON-NLS-1$
+		return "SearchDocument(" + getPath() + ')'; //$NON-NLS-1$
 	}
 
 	public boolean isExternal() {
diff --git a/core/plugins/org.eclipse.dltk.core/search/org/eclipse/dltk/internal/core/search/matching/TypeReferencePattern.java b/core/plugins/org.eclipse.dltk.core/search/org/eclipse/dltk/internal/core/search/matching/TypeReferencePattern.java
index f17e688..8fb6f1b 100644
--- a/core/plugins/org.eclipse.dltk.core/search/org/eclipse/dltk/internal/core/search/matching/TypeReferencePattern.java
+++ b/core/plugins/org.eclipse.dltk.core/search/org/eclipse/dltk/internal/core/search/matching/TypeReferencePattern.java
@@ -17,7 +17,7 @@
 
 public class TypeReferencePattern extends AndPattern implements IIndexConstants {
 
-	protected char[] qualification;
+	public char[] qualification;
 	public char[] simpleName;
 
 	protected char[] currentCategory;
diff --git a/core/tests/org.eclipse.dltk.core.tests/src/org/eclipse/dltk/core/tests/model/TestSearchResults.java b/core/tests/org.eclipse.dltk.core.tests/src/org/eclipse/dltk/core/tests/model/TestSearchResults.java
index fd0ca2a..0bf30eb 100644
--- a/core/tests/org.eclipse.dltk.core.tests/src/org/eclipse/dltk/core/tests/model/TestSearchResults.java
+++ b/core/tests/org.eclipse.dltk.core.tests/src/org/eclipse/dltk/core/tests/model/TestSearchResults.java
@@ -12,6 +12,8 @@
 package org.eclipse.dltk.core.tests.model;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 
 import junit.framework.Assert;
@@ -113,4 +115,12 @@
 	public String toString() {
 		return matches.toString();
 	}
+
+	public void sortByOffset() {
+		Collections.sort(matches, new Comparator<SearchMatch>() {
+			public int compare(SearchMatch o1, SearchMatch o2) {
+				return o1.getOffset() - o2.getOffset();
+			}
+		});
+	}
 }