HEAD - Merge v_408a_head with v_408a_thaw_402
diff --git a/buildnotes_jdt-core.html b/buildnotes_jdt-core.html
index eae1e96..7ca8f09 100644
--- a/buildnotes_jdt-core.html
+++ b/buildnotes_jdt-core.html
@@ -43,6 +43,9 @@
 <h2>
 What's new in this drop</h2>
 <ul>
+<li>Added new API to create a DOM AST while reconciling 
+	 <code>ICompilationUnit.reconcile(boolean, boolean, WorkingCopyOwner, IProgressMonitor)</code>.
+</li>
 </ul>
 
 <h3>Problem Reports Fixed</h3>
@@ -54,6 +57,8 @@
 The type AbstractStringBuilder is not visible
 <br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49259">49259</a>
 Task tags starting with TODO don't correctly display their priority in Tasks View
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49879">49879</a>
+java.lang.ClassCastException (SourceTypeBinding to a BinaryTypeBinding) in 30M6 within jdt.core.dom.TypeBinding.getKey(TypeBinding.java:411)
 
 <a name="v_408"></a>
 <p><hr><h1>
diff --git a/compiler/org/eclipse/jdt/internal/compiler/SourceElementParser.java b/compiler/org/eclipse/jdt/internal/compiler/SourceElementParser.java
index 675ece2..d0f64e3 100644
--- a/compiler/org/eclipse/jdt/internal/compiler/SourceElementParser.java
+++ b/compiler/org/eclipse/jdt/internal/compiler/SourceElementParser.java
@@ -17,6 +17,7 @@
 import org.eclipse.jdt.internal.compiler.lookup.*;
 import org.eclipse.jdt.internal.compiler.parser.*;
 import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.core.util.CommentRecorderParser;
 
 /**
  * A source element parser extracts structural and reference information
@@ -36,7 +37,7 @@
  *
  * Any (parsing) problem encountered is also provided.
  */
-public class SourceElementParser extends Parser {
+public class SourceElementParser extends CommentRecorderParser {
 	
 	ISourceElementRequestor requestor;
 	int fieldCount;
@@ -101,7 +102,32 @@
 }
 
 public void checkComment() {
-	super.checkComment();
+	if (this.currentElement != null && this.scanner.commentPtr >= 0) {
+		flushCommentsDefinedPriorTo(this.endStatementPosition); // discard obsolete comments during recovery
+	}
+	
+	int lastComment = this.scanner.commentPtr;
+	
+	if (this.modifiersSourceStart >= 0) {
+		// eliminate comments located after modifierSourceStart if positionned
+		while (lastComment >= 0 && Math.abs(this.scanner.commentStarts[lastComment]) > this.modifiersSourceStart) lastComment--;
+	}
+	if (lastComment >= 0) {
+		// consider all remaining leading comments to be part of current declaration
+		this.modifiersSourceStart = Math.abs(this.scanner.commentStarts[0]); 
+	
+		// check deprecation in last comment if javadoc (can be followed by non-javadoc comments which are simply ignored)	
+		while (lastComment >= 0 && this.scanner.commentStops[lastComment] < 0) lastComment--; // non javadoc comment have negative end positions
+		if (lastComment >= 0 && this.javadocParser != null) {
+			if (this.javadocParser.checkDeprecation(
+					this.scanner.commentStarts[lastComment],
+					this.scanner.commentStops[lastComment] - 1)) { //stop is one over,
+				checkAndSetModifiers(AccDeprecated);
+			}
+			this.javadoc = this.javadocParser.docComment;	// null if check javadoc is not activated 
+		}
+	}
+
 	if (this.reportReferenceInfo && this.javadocParser.checkDocComment && this.javadoc != null) {
 		// Report reference info in javadoc comment @throws/@exception tags
 		TypeReference[] thrownExceptions = this.javadoc.thrownExceptions;
@@ -1058,7 +1084,6 @@
 		return typeDeclaration.sourceEnd;
 	}
 }
-
 public void parseCompilationUnit(
 	ICompilationUnit unit, 
 	int start, 
diff --git a/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java b/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java
index 0ada7de..c78bc3d 100644
--- a/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java
+++ b/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java
@@ -183,10 +183,11 @@
 					int innerOffset = readOffset + 6;
 					int number_of_classes = u2At(innerOffset);
 					if (number_of_classes != 0) {
+						innerOffset+= 2;
 						this.innerInfos = new InnerClassInfo[number_of_classes];
 						for (int j = 0; j < number_of_classes; j++) {
 							this.innerInfos[j] = 
-								new InnerClassInfo(reference, this.constantPoolOffsets, innerOffset + 2); 
+								new InnerClassInfo(reference, this.constantPoolOffsets, innerOffset); 
 							if (this.classNameIndex == this.innerInfos[j].innerClassNameIndex) {
 								this.innerInfo = this.innerInfos[j];
 								this.innerInfoIndex = j;
@@ -341,8 +342,18 @@
 			 * attribute entry is a member class, but due to the bug:
 			 * http://dev.eclipse.org/bugs/show_bug.cgi?id=14592
 			 * we needed to add an extra check. So we check that innerNameIndex is different from 0 as well.
+			 * 
+			 * https://bugs.eclipse.org/bugs/show_bug.cgi?id=49879
+			 * From JavaMail 1.2, the class javax.mail.Folder contains an anonymous class in the
+			 * terminateQueue() method for which the inner attribute is boggus.
+			 * outerClassNameIdx is not 0, innerNameIndex is not 0, but the sourceName length is 0.
+			 * So I added this extra check to filter out this anonymous class from the 
+			 * member types.
 			 */
-			if (outerClassNameIdx != 0 && innerNameIndex != 0 && outerClassNameIdx == this.classNameIndex) {
+			if (outerClassNameIdx != 0
+				&& innerNameIndex != 0
+				&& outerClassNameIdx == this.classNameIndex
+				&& currentInnerInfo.getSourceName().length != 0) {
 				memberTypes[memberTypeIndex++] = currentInnerInfo;
 			}
 		}
diff --git a/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java b/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java
index 948ef1e..217cbf5 100644
--- a/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java
+++ b/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java
@@ -896,16 +896,7 @@
 	// AssignmentOperator ::= '^='
 	// AssignmentOperator ::= '|='
 
-	try {
-		this.intStack[++this.intPtr] = pos;
-	} catch (IndexOutOfBoundsException e) {
-		//this.intPtr is correct 
-		int oldStackLength = this.intStack.length;
-		int oldStack[] = this.intStack;
-		this.intStack = new int[oldStackLength + StackIncrement];
-		System.arraycopy(oldStack, 0, this.intStack, 0, oldStackLength);
-		this.intStack[this.intPtr] = pos;
-	}
+	pushOnIntStack(pos);
 }
 protected void consumeBinaryExpression(int op) {
 	// MultiplicativeExpression ::= MultiplicativeExpression '*' UnaryExpression
diff --git a/dom/org/eclipse/jdt/core/dom/AST.java b/dom/org/eclipse/jdt/core/dom/AST.java
index b3e764f..c740000 100644
--- a/dom/org/eclipse/jdt/core/dom/AST.java
+++ b/dom/org/eclipse/jdt/core/dom/AST.java
@@ -123,6 +123,38 @@
 	}
 
 	/**
+	 * Internal method.
+	 * <p>
+	 * This method converts the given internal compiler AST for the given source string
+	 * into a compilation unit. This method is not intended to be called by clients.
+	 * </p>
+	 * 
+	 * @param unit an internal AST node for a compilation unit declaration
+	 * @param source the string of the Java compilation unit
+	 * @param options compiler options
+	 * @param monitor the progress monitor used to report progress and request cancelation,
+	 *     or <code>null</code> if none
+	 * @return the compilation unit node
+	 */
+	public static CompilationUnit convertCompilationUnit(
+		org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration compilationUnitDeclaration,
+		char[] source,
+		Map options,
+		IProgressMonitor monitor) {
+		
+		ASTConverter converter = new ASTConverter(options, true, monitor);
+		AST ast = new AST();
+		BindingResolver resolver = new DefaultBindingResolver(compilationUnitDeclaration.scope);
+		ast.setBindingResolver(resolver);
+		converter.setAST(ast);
+	
+		CompilationUnit cu = converter.convert(compilationUnitDeclaration, source);
+		cu.setLineEndTable(compilationUnitDeclaration.compilationResult.lineSeparatorPositions);
+		resolver.storeModificationCount(ast.modificationCount());
+		return cu;
+	}
+
+	/**
 	 * Creates a new, empty abstract syntax tree using the given options.
 	 * <p>
 	 * Following option keys are significant:
diff --git a/dom/org/eclipse/jdt/core/dom/CompilationUnitResolver.java b/dom/org/eclipse/jdt/core/dom/CompilationUnitResolver.java
index d963d3d..c630bc4 100644
--- a/dom/org/eclipse/jdt/core/dom/CompilationUnitResolver.java
+++ b/dom/org/eclipse/jdt/core/dom/CompilationUnitResolver.java
@@ -405,7 +405,7 @@
 		try {
 			environment = new CancelableNameEnvironment(((JavaProject)javaProject), owner, monitor);
 			problemFactory = new CancelableProblemFactory(monitor);
-			CompilationUnitResolver compilationUnitVisitor =
+			CompilationUnitResolver resolver =
 				new CompilationUnitResolver(
 					environment,
 					getHandlingPolicy(),
@@ -415,30 +415,18 @@
 
 			String encoding = javaProject.getOption(JavaCore.CORE_ENCODING, true);
 
-			if (nodeSearcher != null) {
-				unit = 
-					compilationUnitVisitor.resolve(
-						new BasicCompilationUnit(
-							source,
-							packageName,
-							unitName,
-							encoding),
-						nodeSearcher,
-						true, // method verification
-						true, // analyze code
-						true); // generate code					
-			} else {
-				unit = 
-					compilationUnitVisitor.resolve(
-						new BasicCompilationUnit(
-							source,
-							packageName,
-							unitName,
-							encoding),
-						true, // method verification
-						true, // analyze code
-						true); // generate code					
-			}
+			unit = 
+				resolver.resolve(
+					null, // no existing compilation unit declaration
+					new BasicCompilationUnit(
+						source,
+						packageName,
+						unitName,
+						encoding),
+					nodeSearcher,
+					true, // method verification
+					true, // analyze code
+					true); // generate code					
 			return unit;
 		} finally {
 			if (environment != null) {
@@ -494,110 +482,16 @@
 		}
 	}
 
-	/*
-	 * Internal API used to resolve a given compilation unit. Can run a subset of the compilation process
-	 */
-	public CompilationUnitDeclaration resolve(
-			org.eclipse.jdt.internal.compiler.env.ICompilationUnit compilationUnit,
+	private CompilationUnitDeclaration resolve(
+			CompilationUnitDeclaration unit,
+			org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit,
 			NodeSearcher nodeSearcher,
 			boolean verifyMethods,
 			boolean analyzeCode,
 			boolean generateCode) {
 
-		CompilationUnitDeclaration unit = null;
 		try {
 
-			this.parseThreshold = 0; // will request a diet parse
-			beginToCompile(new org.eclipse.jdt.internal.compiler.env.ICompilationUnit[] { compilationUnit});
-			// process all units (some more could be injected in the loop by the lookup environment)
-			unit = this.unitsToProcess[0];
-
-			int searchPosition = nodeSearcher.position;
-			if (searchPosition >= 0 && searchPosition <= compilationUnit.getContents().length) {
-				unit.traverse(nodeSearcher, unit.scope);
-				
-				org.eclipse.jdt.internal.compiler.ast.ASTNode node = nodeSearcher.found;
-				
-	 			if (node != null) {
-					org.eclipse.jdt.internal.compiler.ast.TypeDeclaration enclosingTypeDeclaration = nodeSearcher.enclosingType;
-	  				if (node instanceof AbstractMethodDeclaration) {
-						((AbstractMethodDeclaration)node).parseStatements(this.parser, unit);
-	 				} else if (enclosingTypeDeclaration != null) {
-						if (node instanceof org.eclipse.jdt.internal.compiler.ast.Initializer) {
-		 					((org.eclipse.jdt.internal.compiler.ast.Initializer) node).parseStatements(this.parser, enclosingTypeDeclaration, unit);
-	 					} else if (node instanceof org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) {  					
-							((org.eclipse.jdt.internal.compiler.ast.TypeDeclaration)node).parseMethod(this.parser, unit);
-						} 				
-	 				}
-	 			}
-			}
-			if (unit.scope != null) {
-				// fault in fields & methods
-				unit.scope.faultInTypes();
-				if (unit.scope != null && verifyMethods) {
-					// http://dev.eclipse.org/bugs/show_bug.cgi?id=23117
- 					// verify inherited methods
-					unit.scope.verifyMethods(this.lookupEnvironment.methodVerifier());
-				}
-				// type checking
-				unit.resolve();		
-
-				// flow analysis
-				if (analyzeCode) unit.analyseCode();
-		
-				// code generation
-				if (generateCode) unit.generateCode();
-			}
-			if (this.unitsToProcess != null) this.unitsToProcess[0] = null; // release reference to processed unit declaration
-			this.requestor.acceptResult(unit.compilationResult.tagAsAccepted());
-			return unit;
-		} catch (AbortCompilation e) {
-			this.handleInternalException(e, unit);
-			return null;
-		} catch (Error e) {
-			this.handleInternalException(e, unit, null);
-			throw e; // rethrow
-		} catch (RuntimeException e) {
-			this.handleInternalException(e, unit, null);
-			throw e; // rethrow
-		} finally {
-			// No reset is performed there anymore since,
-			// within the CodeAssist (or related tools),
-			// the compiler may be called *after* a call
-			// to this resolve(...) method. And such a call
-			// needs to have a compiler with a non-empty
-			// environment.
-			// this.reset();
-		}
-	}
-	/*
-	 * Internal API used to resolve a given compilation unit. Can run a subset of the compilation process
-	 */
-	public CompilationUnitDeclaration resolve(
-			org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit, 
-			boolean verifyMethods,
-			boolean analyzeCode,
-			boolean generateCode) {
-				
-		return resolve(
-			null,
-			sourceUnit,
-			verifyMethods,
-			analyzeCode,
-			generateCode);
-	}
-
-	/*
-	 * Internal API used to resolve a given compilation unit. Can run a subset of the compilation process
-	 */
-	public CompilationUnitDeclaration resolve(
-			CompilationUnitDeclaration unit, 
-			org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit, 
-			boolean verifyMethods,
-			boolean analyzeCode,
-			boolean generateCode) {
-				
-		try {
 			if (unit == null) {
 				// build and record parsed units
 				this.parseThreshold = 0; // will request a full parse
@@ -611,7 +505,31 @@
 				// binding resolution
 				this.lookupEnvironment.completeTypeBindings();
 			}
-			this.parser.getMethodBodies(unit);
+
+			if (nodeSearcher == null) {
+				this.parser.getMethodBodies(unit); // no-op if method bodies have already been parsed
+			} else {
+				int searchPosition = nodeSearcher.position;
+				if (searchPosition >= 0 && searchPosition <= sourceUnit.getContents().length) {
+					unit.traverse(nodeSearcher, unit.scope);
+					
+					org.eclipse.jdt.internal.compiler.ast.ASTNode node = nodeSearcher.found;
+					
+		 			if (node != null) {
+						org.eclipse.jdt.internal.compiler.ast.TypeDeclaration enclosingTypeDeclaration = nodeSearcher.enclosingType;
+		  				if (node instanceof AbstractMethodDeclaration) {
+							((AbstractMethodDeclaration)node).parseStatements(this.parser, unit);
+		 				} else if (enclosingTypeDeclaration != null) {
+							if (node instanceof org.eclipse.jdt.internal.compiler.ast.Initializer) {
+			 					((org.eclipse.jdt.internal.compiler.ast.Initializer) node).parseStatements(this.parser, enclosingTypeDeclaration, unit);
+		 					} else if (node instanceof org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) {  					
+								((org.eclipse.jdt.internal.compiler.ast.TypeDeclaration)node).parseMethod(this.parser, unit);
+							} 				
+		 				}
+		 			}
+				}
+			}
+			
 			if (unit.scope != null) {
 				// fault in fields & methods
 				unit.scope.faultInTypes();
@@ -651,4 +569,40 @@
 			// this.reset();
 		}
 	}
+	/*
+	 * Internal API used to resolve a given compilation unit. Can run a subset of the compilation process
+	 */
+	public CompilationUnitDeclaration resolve(
+			org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit, 
+			boolean verifyMethods,
+			boolean analyzeCode,
+			boolean generateCode) {
+				
+		return resolve(
+			null, /* no existing compilation unit declaration*/
+			sourceUnit,
+			null/*no node searcher*/, 
+			verifyMethods,
+			analyzeCode,
+			generateCode);
+	}
+
+	/*
+	 * Internal API used to resolve a given compilation unit. Can run a subset of the compilation process
+	 */
+	public CompilationUnitDeclaration resolve(
+			CompilationUnitDeclaration unit, 
+			org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit, 
+			boolean verifyMethods,
+			boolean analyzeCode,
+			boolean generateCode) {
+		
+		return resolve(
+			unit, 
+			sourceUnit, 
+			null/*no node searcher*/, 
+			verifyMethods, 
+			analyzeCode, 
+			generateCode);
+	}
 }
diff --git a/model/org/eclipse/jdt/core/ICompilationUnit.java b/model/org/eclipse/jdt/core/ICompilationUnit.java
index 45645b8..0503c0c 100644
--- a/model/org/eclipse/jdt/core/ICompilationUnit.java
+++ b/model/org/eclipse/jdt/core/ICompilationUnit.java
@@ -11,6 +11,7 @@
 package org.eclipse.jdt.core;
 
 import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jdt.core.dom.CompilationUnit;
 
 /**
  * Represents an entire Java compilation unit (<code>.java</code> source file).
@@ -460,6 +461,8 @@
  * <li> The original Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
  * </ul>
  * @since 3.0
+ * @deprecated Use reconcile(boolean, boolean, WorkingCopyOwner, IProgressMonitor) instead
+ * TODO (jerome) remove after M8
  */
 void reconcile(boolean forceProblemDetection, IProgressMonitor monitor) throws JavaModelException;
 /**
@@ -498,9 +501,59 @@
  * <li> The original Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
  * </ul>
  * @since 3.0
+ * @deprecated Use reconcile(boolean, boolean, WorkingCopyOwner, IProgressMonitor) instead
+ * TODO (jerome) remove after M8
  */
 void reconcile(boolean forceProblemDetection, WorkingCopyOwner owner, IProgressMonitor monitor) throws JavaModelException;
 /**
+ * Reconciles the contents of this working copy, sends out a Java delta
+ * notification indicating the nature of the change of the working copy since
+ * the last time it was either reconciled or made consistent 
+ * (see <code>IOpenable#makeConsistent()</code>), and returns a
+ * compilation unit AST if requested.
+ * <p>
+ * It performs the reconciliation by locally caching the contents of 
+ * the working copy, updating the contents, then creating a delta 
+ * over the cached contents and the new contents, and finally firing
+ * this delta.
+ * <p>
+ * The boolean argument allows to force problem detection even if the
+ * working copy is already consistent.
+ * </p><p>
+ * This functionality allows to specify a working copy owner which is used during problem detection.
+ * All references contained in the working copy are resolved against other units; for which corresponding 
+ * owned working copies are going to take precedence over their original compilation units. 
+ * If <code>null</code> is passed in, then the primary working copy owner is used.
+ * </p><p>
+ * Compilation problems found in the new contents are notified through the
+ * <code>IProblemRequestor</code> interface which was passed at
+ * creation, and no longer as transient markers.
+ * </p><p>
+ * Note: Since 3.0 added/removed/changed inner types generate change deltas.</p>
+ * </p><p>
+ * If requested, a DOM AST representing the compilation unit is returned. Its bindings are computed 
+ * only if the problem requestor is active, or if the problem detection is forced. 
+ * This method returns <code>null</code> if the creation of the DOM AST was not requested, or 
+ * if the working copy was already consistent.
+ * </p>
+ *
+ * @param forceProblemDetection boolean indicating whether problem should be recomputed
+ *   even if the source hasn't changed.
+ * @param owner the owner of working copies that take precedence over the original compilation units,
+ *   or <code>null</code> if the primary working copy owner should be used
+ * @param monitor a progress monitor
+ * @return the compilation unit AST or <code>null</code> if not requested, 
+ *   or if the working copy was consistent.
+ * 
+ * @throws JavaModelException if the contents of the original element
+ *		cannot be accessed. Reasons include:
+ * <ul>
+ * <li> The original Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * </ul>
+ * @since 3.0
+ */
+CompilationUnit reconcile(boolean createAST, boolean forceProblemDetection, WorkingCopyOwner owner, IProgressMonitor monitor) throws JavaModelException;
+/**
  * Restores the contents of this working copy to the current contents of
  * this working copy's original element. Has no effect if this element
  * is not a working copy.
diff --git a/search/org/eclipse/jdt/internal/core/index/impl/Int.java b/model/org/eclipse/jdt/internal/core/ASTHolderCUInfo.java
similarity index 74%
rename from search/org/eclipse/jdt/internal/core/index/impl/Int.java
rename to model/org/eclipse/jdt/internal/core/ASTHolderCUInfo.java
index 25d1344..819a6d1 100644
--- a/search/org/eclipse/jdt/internal/core/index/impl/Int.java
+++ b/model/org/eclipse/jdt/internal/core/ASTHolderCUInfo.java
@@ -8,14 +8,10 @@
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
+package org.eclipse.jdt.internal.core;
 
-public class Int {
-	public int value;
-	/**
-	 * Int constructor comment.
-	 */
-	public Int(int i) {
-		value= i;
-	}
+import org.eclipse.jdt.core.dom.CompilationUnit;
+
+public class ASTHolderCUInfo extends CompilationUnitElementInfo {
+	CompilationUnit ast;
 }
diff --git a/model/org/eclipse/jdt/internal/core/ClassFileWorkingCopy.java b/model/org/eclipse/jdt/internal/core/ClassFileWorkingCopy.java
index 7784e80..b35b0a5 100644
--- a/model/org/eclipse/jdt/internal/core/ClassFileWorkingCopy.java
+++ b/model/org/eclipse/jdt/internal/core/ClassFileWorkingCopy.java
@@ -31,6 +31,7 @@
 import org.eclipse.jdt.core.ISourceRange;
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.dom.CompilationUnit;
 
 /**
  * A working copy on an <code>IClassFile</code>.
@@ -504,6 +505,18 @@
 	}
 
 	/**
+	 * @see ICompilationUnit#reconcile(boolean, boolean, WorkingCopyOwner, IProgressMonitor)
+	 */
+	public CompilationUnit reconcile(
+		boolean createAST,
+		boolean forceProblemDetection,
+		WorkingCopyOwner owner,
+		IProgressMonitor monitor)
+		throws JavaModelException {
+		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
+	}
+	
+	/**
 	 * @see ICompilationUnit#reconcile(boolean, IProgressMonitor)
 	 */
 	public void reconcile(
diff --git a/model/org/eclipse/jdt/internal/core/CompilationUnit.java b/model/org/eclipse/jdt/internal/core/CompilationUnit.java
index abbb589..eb2b92c 100644
--- a/model/org/eclipse/jdt/internal/core/CompilationUnit.java
+++ b/model/org/eclipse/jdt/internal/core/CompilationUnit.java
@@ -17,6 +17,7 @@
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.compiler.*;
 import org.eclipse.jdt.core.compiler.IProblem;
+import org.eclipse.jdt.core.dom.AST;
 import org.eclipse.jdt.core.jdom.IDOMNode;
 import org.eclipse.jdt.internal.compiler.ASTVisitor;
 import org.eclipse.jdt.internal.compiler.IProblemFactory;
@@ -107,10 +108,11 @@
 	JavaModelManager.PerWorkingCopyInfo perWorkingCopyInfo = getPerWorkingCopyInfo();
 	boolean computeProblems = perWorkingCopyInfo != null && perWorkingCopyInfo.isActive();
 	IProblemFactory problemFactory = new DefaultProblemFactory();
+	Map options = getJavaProject().getOptions(true);
 	SourceElementParser parser = new SourceElementParser(
 		requestor, 
 		problemFactory, 
-		new CompilerOptions(getJavaProject().getOptions(true)),
+		new CompilerOptions(options),
 		true/*report local declarations*/);
 	requestor.parser = parser;
 	CompilationUnitDeclaration unit = parser.parseCompilationUnit(new org.eclipse.jdt.internal.compiler.env.ICompilationUnit() {
@@ -141,6 +143,11 @@
 		perWorkingCopyInfo.endReporting();
 	}
 	
+	if (info instanceof ASTHolderCUInfo) {
+		org.eclipse.jdt.core.dom.CompilationUnit cu = AST.convertCompilationUnit(unit, contents, options, pm);
+		((ASTHolderCUInfo) info).ast = cu;
+	}
+	
 	return unitInfo.isStructureKnown();
 }
 /*
@@ -920,7 +927,10 @@
  * @see IOpenable#makeConsistent(IProgressMonitor)
  */
 public void makeConsistent(IProgressMonitor monitor) throws JavaModelException {
-	if (isConsistent()) return;
+	makeConsistent(false/*don't create AST*/, monitor);
+}
+public org.eclipse.jdt.core.dom.CompilationUnit makeConsistent(boolean createAST, IProgressMonitor monitor) throws JavaModelException {
+	if (isConsistent()) return null;
 		
 	// close
 	JavaModelManager manager = JavaModelManager.getJavaModelManager();
@@ -928,7 +938,16 @@
 	manager.removeInfoAndChildren(this);
 	
 	// create a new info and make it the current info
-	openWhenClosed(createElementInfo(), monitor);
+	if (createAST) {
+		ASTHolderCUInfo info = new ASTHolderCUInfo();
+		openWhenClosed(info, monitor);
+		org.eclipse.jdt.core.dom.CompilationUnit result = info.ast;
+		info.ast = null;
+		return result;
+	} else {
+		openWhenClosed(createElementInfo(), monitor);
+		return null;
+	}
 }
 /**
  * @see ISourceManipulation#move(IJavaElement, IJavaElement, String, boolean, IProgressMonitor)
@@ -1010,14 +1029,31 @@
  * @deprecated
  */
 public IMarker[] reconcile() throws JavaModelException {
-	reconcile(false, null);
+	reconcile(false/*don't force problem detection*/, null/*use primary owner*/, null/*no progress monitor*/);
 	return null;
 }
 /**
  * @see ICompilationUnit#reconcile(boolean, IProgressMonitor)
  */
 public void reconcile(boolean forceProblemDetection, IProgressMonitor monitor) throws JavaModelException {
-	reconcile(forceProblemDetection, DefaultWorkingCopyOwner.PRIMARY, monitor);
+	reconcile(forceProblemDetection, null/*use primary owner*/, monitor);
+}
+/**
+ * @see ICompilationUnit#reconcile(boolean, boolean, WorkingCopyOwner, IProgressMonitor)
+ */
+public org.eclipse.jdt.core.dom.CompilationUnit reconcile(
+	boolean createAST,
+	boolean forceProblemDetection,
+	WorkingCopyOwner workingCopyOwner,
+	IProgressMonitor monitor)
+	throws JavaModelException {
+	
+	if (!isWorkingCopy()) return null; // Reconciling is not supported on non working copies
+	if (workingCopyOwner == null) workingCopyOwner = DefaultWorkingCopyOwner.PRIMARY;
+	
+	ReconcileWorkingCopyOperation op = new ReconcileWorkingCopyOperation(this, createAST, forceProblemDetection, workingCopyOwner);
+	op.runOperation(monitor);
+	return op.ast;
 }
 /**
  * @see ICompilationUnit#reconcile(boolean, WorkingCopyOwner, IProgressMonitor)
@@ -1028,10 +1064,7 @@
 	IProgressMonitor monitor)
 	throws JavaModelException {
 
-	if (!isWorkingCopy()) return; // Reconciling is not supported on non working copies
-	
-	ReconcileWorkingCopyOperation op = new ReconcileWorkingCopyOperation(this, forceProblemDetection, workingCopyOwner);
-	op.runOperation(monitor);
+	reconcile(false/*don't create AST*/, forceProblemDetection, workingCopyOwner, monitor);
 }
 /**
  * @see ISourceManipulation#rename(String, boolean, IProgressMonitor)
diff --git a/model/org/eclipse/jdt/internal/core/ReconcileWorkingCopyOperation.java b/model/org/eclipse/jdt/internal/core/ReconcileWorkingCopyOperation.java
index 0eeb9f7..1874b66 100644
--- a/model/org/eclipse/jdt/internal/core/ReconcileWorkingCopyOperation.java
+++ b/model/org/eclipse/jdt/internal/core/ReconcileWorkingCopyOperation.java
@@ -10,9 +10,13 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
+import java.util.Map;
+
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.dom.AST;
+import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
 import org.eclipse.jdt.internal.core.util.Util;
 
 /**
@@ -20,11 +24,14 @@
  */
 public class ReconcileWorkingCopyOperation extends JavaModelOperation {
 		
+	boolean createAST;
 	boolean forceProblemDetection;
 	WorkingCopyOwner workingCopyOwner;
+	org.eclipse.jdt.core.dom.CompilationUnit ast;
 	
-	public ReconcileWorkingCopyOperation(IJavaElement workingCopy, boolean forceProblemDetection, WorkingCopyOwner workingCopyOwner) {
+	public ReconcileWorkingCopyOperation(IJavaElement workingCopy, boolean creatAST, boolean forceProblemDetection, WorkingCopyOwner workingCopyOwner) {
 		super(new IJavaElement[] {workingCopy});
+		this.createAST = creatAST;
 		this.forceProblemDetection = forceProblemDetection;
 		this.workingCopyOwner = workingCopyOwner;
 	}
@@ -33,45 +40,45 @@
 	 * 	of the original compilation unit fails
 	 */
 	protected void executeOperation() throws JavaModelException {
-		if (progressMonitor != null){
-			if (progressMonitor.isCanceled()) return;
-			progressMonitor.beginTask(Util.bind("element.reconciling"), 10); //$NON-NLS-1$
+		if (this.progressMonitor != null){
+			if (this.progressMonitor.isCanceled()) return;
+			this.progressMonitor.beginTask(Util.bind("element.reconciling"), 2); //$NON-NLS-1$
 		}
 	
 		CompilationUnit workingCopy = getWorkingCopy();
 		boolean wasConsistent = workingCopy.isConsistent();
-		JavaElementDeltaBuilder deltaBuilder = null;
-	
 		try {
-			// create the delta builder (this remembers the current content of the cu)
-			if (!wasConsistent){
-				deltaBuilder = new JavaElementDeltaBuilder(workingCopy);
+			if (!wasConsistent) {
+				// create the delta builder (this remembers the current content of the cu)
+				JavaElementDeltaBuilder deltaBuilder = new JavaElementDeltaBuilder(workingCopy);
 				
 				// update the element infos with the content of the working copy
-				workingCopy.makeConsistent(progressMonitor);
+				this.ast = workingCopy.makeConsistent(this.createAST, this.progressMonitor);
 				deltaBuilder.buildDeltas();
-		
-			}
-	
-			if (progressMonitor != null) progressMonitor.worked(2);
+
+				if (progressMonitor != null) progressMonitor.worked(2);
 			
-			// force problem detection? - if structure was consistent
-			if (forceProblemDetection && wasConsistent){
-				if (progressMonitor != null && progressMonitor.isCanceled()) return;
-		
-				IProblemRequestor problemRequestor = workingCopy.getPerWorkingCopyInfo();
-				if (problemRequestor != null && problemRequestor.isActive()){
-					problemRequestor.beginReporting();
-					CompilationUnitProblemFinder.process(workingCopy, this.workingCopyOwner, problemRequestor, progressMonitor);
-					problemRequestor.endReporting();
-				}
-			}
-			
-			// register the deltas
-			if (deltaBuilder != null){
+				// register the deltas
 				if (deltaBuilder.delta != null) {
 					addReconcileDelta(workingCopy, deltaBuilder.delta);
 				}
+			} else {
+				// force problem detection? - if structure was consistent
+				if (forceProblemDetection) {
+					IProblemRequestor problemRequestor = workingCopy.getPerWorkingCopyInfo();
+					if (problemRequestor != null && problemRequestor.isActive()){
+						problemRequestor.beginReporting();
+						CompilationUnitDeclaration unit = CompilationUnitProblemFinder.process(workingCopy, this.workingCopyOwner, problemRequestor, this.progressMonitor);
+						problemRequestor.endReporting();
+						if (progressMonitor != null) progressMonitor.worked(1);
+						if (this.createAST && unit != null) {
+							char[] contents = workingCopy.getContents();
+							Map options = workingCopy.getJavaProject().getOptions(true);
+							this.ast = AST.convertCompilationUnit(unit, contents, options, this.progressMonitor);
+							if (progressMonitor != null) progressMonitor.worked(1);
+						}
+					}
+				}
 			}
 		} finally {
 			if (progressMonitor != null) progressMonitor.done();
diff --git a/model/org/eclipse/jdt/internal/core/hierarchy/IndexBasedHierarchyBuilder.java b/model/org/eclipse/jdt/internal/core/hierarchy/IndexBasedHierarchyBuilder.java
index 4868df4..2993f9a 100644
--- a/model/org/eclipse/jdt/internal/core/hierarchy/IndexBasedHierarchyBuilder.java
+++ b/model/org/eclipse/jdt/internal/core/hierarchy/IndexBasedHierarchyBuilder.java
@@ -387,7 +387,7 @@
 	IProgressMonitor progressMonitor) {
 
 	/* embed constructs inside arrays so as to pass them to (inner) collector */
-	final Queue awaitings = new Queue();
+	final Queue queue = new Queue();
 	final HashtableOfObject foundSuperNames = new HashtableOfObject(5);
 
 	IndexManager indexManager = JavaModelManager.getJavaModelManager().getIndexManager();
@@ -418,12 +418,12 @@
 			}
 			if (!foundSuperNames.containsKey(typeName)){
 				foundSuperNames.put(typeName, typeName);
-				awaitings.add(typeName);
+				queue.add(typeName);
 			}
 			return true;
 		}		
 	};
-	
+
 	SuperTypeReferencePattern pattern =
 		new SuperTypeReferencePattern(null, null, false, SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE);
 	pattern.focus = type;
@@ -432,36 +432,29 @@
 		new JavaSearchParticipant(null), // java search only
 		scope, 
 		searchRequestor);
-	
-	/* initialize entry result cache */
-	pattern.entryResults = new HashMap();
-	/* iterate all queued names */
+
 	int ticks = 0;
-	awaitings.add(type.getElementName().toCharArray());
-	while (awaitings.start <= awaitings.end){
-		if (progressMonitor != null && progressMonitor.isCanceled()) return;
+	queue.add(type.getElementName().toCharArray());
+	try {
+		while (queue.start <= queue.end) {
+			if (progressMonitor != null && progressMonitor.isCanceled()) return;
 
-		char[] currentTypeName = awaitings.retrieve();
+			// all subclasses of OBJECT are actually all types
+			char[] currentTypeName = queue.retrieve();
+			if (CharOperation.equals(currentTypeName, IIndexConstants.OBJECT))
+				currentTypeName = null;
 
-		/* all subclasses of OBJECT are actually all types */
-		if (CharOperation.equals(currentTypeName, IIndexConstants.OBJECT)){
-			currentTypeName = null;
-		}			
-		/* search all index references to a given supertype */
-		pattern.superSimpleName = currentTypeName;
-		indexManager.performConcurrentJob(
-			job, 
-			waitingPolicy, 
-			null); // don't pass a sub progress monitor as this is too costly for deep hierarchies
-		if (progressMonitor != null && ++ticks <= MAXTICKS) {
-			progressMonitor.worked(1);
+			// search all index references to a given supertype
+			pattern.superSimpleName = currentTypeName;
+			indexManager.performConcurrentJob(job, waitingPolicy, null); // no sub progress monitor since its too costly for deep hierarchies
+			if (progressMonitor != null && ++ticks <= MAXTICKS)
+				progressMonitor.worked(1);
+
+			// in case, we search all subtypes, no need to search further
+			if (currentTypeName == null) break;
 		}
-		/* in case, we search all subtypes, no need to search further */
-		if (currentTypeName == null) break;
+	} finally {
+		job.finished();
 	}
-	/* close all cached index inputs */
-	job.closeAll();
-	/* flush entry result cache */
-	pattern.entryResults = null;
 }
 }
diff --git a/model/org/eclipse/jdt/internal/core/util/InnerClassesAttribute.java b/model/org/eclipse/jdt/internal/core/util/InnerClassesAttribute.java
index 46e7a23..3ce5827 100644
--- a/model/org/eclipse/jdt/internal/core/util/InnerClassesAttribute.java
+++ b/model/org/eclipse/jdt/internal/core/util/InnerClassesAttribute.java
@@ -37,16 +37,16 @@
 		throws ClassFormatException {
 		super(classFileBytes, constantPool, offset);
 		this.numberOfClasses = u2At(classFileBytes, 6, offset);
-		int readOffset = 8;
 		int length = this.numberOfClasses;
 		this.entries = NO_ENTRIES;
 		if (length != 0) {
+			int readOffset = 8;
 			this.entries = new IInnerClassesAttributeEntry[length];
+			for (int i = 0; i < length; i++) {
+				this.entries[i] = new InnerClassesAttributeEntry(classFileBytes, constantPool, offset + readOffset);
+				readOffset += 8;
+			}		
 		}
-		for (int i = 0; i < length; i++) {
-			this.entries[i] = new InnerClassesAttributeEntry(classFileBytes, constantPool, offset + readOffset);
-			readOffset += 8;
-		}		
 	}
 
 	/**
diff --git a/model/org/eclipse/jdt/internal/core/util/Util.java b/model/org/eclipse/jdt/internal/core/util/Util.java
index 4c04177..c625bc4 100644
--- a/model/org/eclipse/jdt/internal/core/util/Util.java
+++ b/model/org/eclipse/jdt/internal/core/util/Util.java
@@ -30,8 +30,6 @@
 import org.eclipse.jdt.internal.core.Assert;
 import org.eclipse.jdt.internal.core.JavaModelManager;
 import org.eclipse.jdt.internal.core.PackageFragmentRoot;
-import org.eclipse.jdt.internal.core.index.impl.IndexedFile;
-import org.eclipse.jdt.internal.core.index.impl.WordEntry;
 import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.text.edits.MalformedTreeException;
 import org.eclipse.text.edits.TextEdit;
@@ -1517,32 +1515,6 @@
 			quickSort(sortedCollection, left, original_right);
 		}
 	}
-	private static void quickSort(IndexedFile[] list, int left, int right) {
-		int original_left= left;
-		int original_right= right;
-		String mid= list[(left + right) / 2].path;
-		do {
-			while (list[left].path.compareTo(mid) < 0) {
-				left++;
-			}
-			while (mid.compareTo(list[right].path) < 0) {
-				right--;
-			}
-			if (left <= right) {
-				IndexedFile tmp= list[left];
-				list[left]= list[right];
-				list[right]= tmp;
-				left++;
-				right--;
-			}
-		} while (left <= right);
-		if (original_left < right) {
-			quickSort(list, original_left, right);
-		}
-		if (left < original_right) {
-			quickSort(list, left, original_right);
-		}
-	}
 	private static void quickSort(int[] list, int left, int right) {
 		int original_left= left;
 		int original_right= right;
@@ -1662,32 +1634,6 @@
 			quickSort(sortedCollection, left, original_right);
 		}
 	}
-	private static void quickSort(WordEntry[] list, int left, int right) {
-		int original_left= left;
-		int original_right= right;
-		char[] mid= list[(left + right) / 2].fWord;
-		do {
-			while (compare(list[left].fWord, mid) < 0) {
-				left++;
-			}
-			while (compare(mid, list[right].fWord) < 0) {
-				right--;
-			}
-			if (left <= right) {
-				WordEntry tmp= list[left];
-				list[left]= list[right];
-				list[right]= tmp;
-				left++;
-				right--;
-			}
-		} while (left <= right);
-		if (original_left < right) {
-			quickSort(list, original_left, right);
-		}
-		if (left < original_right) {
-			quickSort(list, left, original_right);
-		}
-	}
 
 	/**
 	 * Sort the strings in the given collection in reverse alphabetical order.
@@ -1818,10 +1764,6 @@
 		if (objects.length > 1)
 			quickSort(objects, 0, objects.length - 1);
 	}
-	public static void sort(IndexedFile[] list) {
-		if (list.length > 1)
-			quickSort(list, 0, list.length - 1);
-	}
 	public static void sort(int[] list) {
 		if (list.length > 1)
 			quickSort(list, 0, list.length - 1);
@@ -1851,10 +1793,6 @@
 		if (strings.length > 1)
 			quickSort(strings, 0, strings.length - 1);
 	}
-	public static void sort(WordEntry[] list) {
-		if (list.length > 1)
-			quickSort(list, 0, list.length - 1);
-	}
 
 	/**
 	 * Sorts an array of Comparable objects, returning a new array
@@ -2038,10 +1976,11 @@
 	 * for the character. 
 	 *
 	 * @param      str   a string to be written.
+	 * @return     the number of bytes written to the stream.
 	 * @exception  IOException  if an I/O error occurs.
 	 * @since      JDK1.0
 	 */
-	public static void writeUTF(OutputStream out, char[] str) throws IOException {
+	public static int writeUTF(OutputStream out, char[] str) throws IOException {
 		int strlen= str.length;
 		int utflen= 0;
 		for (int i= 0; i < strlen; i++) {
@@ -2071,5 +2010,6 @@
 				out.write(0x80 | ((c >> 0) & 0x3F));
 			}
 		}
+		return utflen + 2; // the number of bytes written to the stream
 	}	
 }
diff --git a/notes/porting_guide.html b/notes/porting_guide.html
index 3ab3b35..8813b91 100644
--- a/notes/porting_guide.html
+++ b/notes/porting_guide.html
@@ -208,11 +208,11 @@
           <li>The equivalent functionality is now provided on ICompilationUnit
             directly:
             <ul>
-              <li>public void reconcile(boolean,IProgressMonitor)</li>
+              <li>public void reconcile(boolean,boolean,WorkingCopyOwner,IProgressMonitor)</li>
             </ul>
           </li>
           <li>Replace wc.reconcile() with ((ICompilationUnit)
-            wc).reconcile(false, null)</li>
+            wc).reconcile(false,false,null,null)</li>
           <li>Note: The former method always returned null; the replacement
             method does not return a result.</li>
         </ul>
@@ -221,7 +221,7 @@
         <ul>
           <li>The method is now declared on ICompilationUnit directly.</li>
           <li>Replace wc.reconcile(b,monitor) with ((ICompilationUnit)
-            wc).reconcile(b.monitor)</li>
+            wc).reconcile(false,b,null,monitor)</li>
         </ul>
       </li>
       <li>public void restore() has been deprecated.
diff --git a/search/org/eclipse/jdt/core/search/FieldDeclarationMatch.java b/search/org/eclipse/jdt/core/search/FieldDeclarationMatch.java
new file mode 100644
index 0000000..263ad57
--- /dev/null
+++ b/search/org/eclipse/jdt/core/search/FieldDeclarationMatch.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.search;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.internal.core.search.matching.JavaSearchMatch;
+
+public class FieldDeclarationMatch extends JavaSearchMatch {
+
+	public FieldDeclarationMatch(IJavaElement element, int accuracy, int sourceStart, int sourceEnd, SearchParticipant participant, IResource resource) {
+		super(element, accuracy, sourceStart, sourceEnd, participant, resource);
+	}
+
+}
diff --git a/search/org/eclipse/jdt/core/search/FieldReferenceMatch.java b/search/org/eclipse/jdt/core/search/FieldReferenceMatch.java
new file mode 100644
index 0000000..39ddb4a
--- /dev/null
+++ b/search/org/eclipse/jdt/core/search/FieldReferenceMatch.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.search;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.internal.core.search.matching.JavaSearchMatch;
+
+public class FieldReferenceMatch extends JavaSearchMatch {
+
+	public FieldReferenceMatch(IJavaElement element, int accuracy, int sourceStart, int sourceEnd, SearchParticipant participant, IResource resource) {
+		super(element, accuracy, sourceStart, sourceEnd, participant, resource);
+	}
+
+}
diff --git a/search/org/eclipse/jdt/core/search/LocalVariableDeclarationMatch.java b/search/org/eclipse/jdt/core/search/LocalVariableDeclarationMatch.java
new file mode 100644
index 0000000..3150629
--- /dev/null
+++ b/search/org/eclipse/jdt/core/search/LocalVariableDeclarationMatch.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.search;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.internal.core.search.matching.JavaSearchMatch;
+
+public class LocalVariableDeclarationMatch extends JavaSearchMatch {
+
+	public LocalVariableDeclarationMatch(IJavaElement element, int accuracy, int sourceStart, int sourceEnd, SearchParticipant participant, IResource resource) {
+		super(element, accuracy, sourceStart, sourceEnd, participant, resource);
+	}
+
+}
diff --git a/search/org/eclipse/jdt/core/search/LocalVariableReferenceMatch.java b/search/org/eclipse/jdt/core/search/LocalVariableReferenceMatch.java
new file mode 100644
index 0000000..fcdb69d
--- /dev/null
+++ b/search/org/eclipse/jdt/core/search/LocalVariableReferenceMatch.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.search;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.internal.core.search.matching.JavaSearchMatch;
+
+public class LocalVariableReferenceMatch extends JavaSearchMatch {
+
+	public LocalVariableReferenceMatch(IJavaElement element, int accuracy, int sourceStart, int sourceEnd, SearchParticipant participant, IResource resource) {
+		super(element, accuracy, sourceStart, sourceEnd, participant, resource);
+	}
+
+}
diff --git a/search/org/eclipse/jdt/core/search/MethodDeclarationMatch.java b/search/org/eclipse/jdt/core/search/MethodDeclarationMatch.java
new file mode 100644
index 0000000..25565b9
--- /dev/null
+++ b/search/org/eclipse/jdt/core/search/MethodDeclarationMatch.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.search;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.internal.core.search.matching.JavaSearchMatch;
+
+public class MethodDeclarationMatch extends JavaSearchMatch {
+
+	public MethodDeclarationMatch(IJavaElement element, int accuracy, int sourceStart, int sourceEnd, SearchParticipant participant, IResource resource) {
+		super(element, accuracy, sourceStart, sourceEnd, participant, resource);
+	}
+
+}
diff --git a/search/org/eclipse/jdt/core/search/MethodReferenceMatch.java b/search/org/eclipse/jdt/core/search/MethodReferenceMatch.java
new file mode 100644
index 0000000..990bd33
--- /dev/null
+++ b/search/org/eclipse/jdt/core/search/MethodReferenceMatch.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.search;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.internal.core.search.matching.JavaSearchMatch;
+
+public class MethodReferenceMatch extends JavaSearchMatch {
+
+	public MethodReferenceMatch(IJavaElement element, int accuracy, int sourceStart, int sourceEnd, SearchParticipant participant, IResource resource) {
+		super(element, accuracy, sourceStart, sourceEnd, participant, resource);
+	}
+
+}
diff --git a/search/org/eclipse/jdt/core/search/PackageDeclarationMatch.java b/search/org/eclipse/jdt/core/search/PackageDeclarationMatch.java
new file mode 100644
index 0000000..dfd0971
--- /dev/null
+++ b/search/org/eclipse/jdt/core/search/PackageDeclarationMatch.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.search;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.internal.core.search.matching.JavaSearchMatch;
+
+public class PackageDeclarationMatch extends JavaSearchMatch {
+
+	public PackageDeclarationMatch(IJavaElement element, int accuracy, int sourceStart, int sourceEnd, SearchParticipant participant, IResource resource) {
+		super(element, accuracy, sourceStart, sourceEnd, participant, resource);
+	}
+
+}
diff --git a/search/org/eclipse/jdt/core/search/PackageReferenceMatch.java b/search/org/eclipse/jdt/core/search/PackageReferenceMatch.java
new file mode 100644
index 0000000..ff7c546
--- /dev/null
+++ b/search/org/eclipse/jdt/core/search/PackageReferenceMatch.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.search;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.internal.core.search.matching.JavaSearchMatch;
+
+public class PackageReferenceMatch extends JavaSearchMatch {
+
+	public PackageReferenceMatch(IJavaElement element, int accuracy, int sourceStart, int sourceEnd, SearchParticipant participant, IResource resource) {
+		super(element, accuracy, sourceStart, sourceEnd, participant, resource);
+	}
+
+}
diff --git a/search/org/eclipse/jdt/core/search/SearchDocument.java b/search/org/eclipse/jdt/core/search/SearchDocument.java
index 36d5ec0..76308be 100644
--- a/search/org/eclipse/jdt/core/search/SearchDocument.java
+++ b/search/org/eclipse/jdt/core/search/SearchDocument.java
@@ -18,8 +18,7 @@
 	protected String documentPath;
 	protected SearchParticipant participant;
 	public org.eclipse.jdt.internal.core.index.Index index;
-	public org.eclipse.jdt.internal.core.index.impl.IndexedFile indexedFile; // temporary placeholder for the index during indexing
-	
+
 	public SearchDocument(String documentPath, SearchParticipant participant) {
 		this.documentPath = documentPath;
 		this.participant = participant;
diff --git a/search/org/eclipse/jdt/core/search/SearchEngine.java b/search/org/eclipse/jdt/core/search/SearchEngine.java
index 62c6a74..0af948c 100644
--- a/search/org/eclipse/jdt/core/search/SearchEngine.java
+++ b/search/org/eclipse/jdt/core/search/SearchEngine.java
@@ -281,20 +281,8 @@
 	public static SearchPattern createAndSearchPattern(final SearchPattern leftPattern, final SearchPattern rightPattern) {
 		return new AndPattern(0/*no kind*/, 0/*no rule*/) {
 			SearchPattern current = leftPattern;
-			public void decodeIndexKey(char[] key) {
-				current.decodeIndexKey(key);
-			}
-			public char[] encodeIndexKey() {
-				return current.encodeIndexKey();
-			}
-			public SearchPattern getBlankPattern() {
-				return current.getBlankPattern();
-			}
-			public char[][] getMatchCategories() {
-				return current.getMatchCategories();
-			}
-			public int getMatchRule() {
-				return current.getMatchRule();
+			public SearchPattern currentPattern() {
+				return current;
 			}
 			protected boolean hasNextQuery() {
 				if (current == leftPattern) {
@@ -303,9 +291,6 @@
 				}
 				return false; 
 			}
-			public boolean matchesDecodedPattern(SearchPattern decodedPattern) {
-				return current.matchesDecodedPattern(decodedPattern);
-			}
 			protected void resetQuery() {
 				current = leftPattern;
 			}
diff --git a/search/org/eclipse/jdt/core/search/SearchParticipant.java b/search/org/eclipse/jdt/core/search/SearchParticipant.java
index 13c7d38..4f1b6b2 100644
--- a/search/org/eclipse/jdt/core/search/SearchParticipant.java
+++ b/search/org/eclipse/jdt/core/search/SearchParticipant.java
@@ -36,9 +36,8 @@
 	}
 	// A service provided for participants. Its called from indexDocument(SearchDocument document, IPath indexPath)
 	public static void removeAllIndexEntries(SearchDocument document) {
-// is no-op until new index implementation
-//		if (document.index != null)
-//			document.index.remove(document.getPath());
+		if (document.index != null)
+			document.index.remove(document.getPath());
 	}
 
 	/**
diff --git a/search/org/eclipse/jdt/core/search/SearchPattern.java b/search/org/eclipse/jdt/core/search/SearchPattern.java
index ac4e04b..08e2df1 100644
--- a/search/org/eclipse/jdt/core/search/SearchPattern.java
+++ b/search/org/eclipse/jdt/core/search/SearchPattern.java
@@ -54,12 +54,19 @@
 	public static final int R_CASE_SENSITIVE = 4;
 
 
-	public boolean mustResolve = true;
-	
+	public final int kind;
+	public final boolean isCaseSensitive;
+	public final int matchMode;
+
+	/* focus element (used for reference patterns*/
+	public IJavaElement focus;
+
 	public SearchPattern(int patternKind, int matchRule) {
-		super(patternKind, matchRule);
+		this.kind = patternKind;
+		this.isCaseSensitive = (matchRule & R_CASE_SENSITIVE) != 0;
+		this.matchMode = matchRule - (this.isCaseSensitive ? R_CASE_SENSITIVE : 0);
 	}
-	
+
 	/**
 	 * Constructor pattern are formed by [declaringQualification.]type[(parameterTypes)]
 	 * e.g. java.lang.Object()
@@ -1092,31 +1099,40 @@
 				return null;
 		}
 	}
-	
+	public static char[] encodeIndexKey(char[] key, int matchMode) {
+		return key; // null means match all words
+
+//		switch(matchMode) {
+//			case SearchPattern.R_EXACT_MATCH :
+//			case  SearchPattern.R_PREFIX_MATCH :
+//			case  SearchPattern.R_PATTERN_MATCH :
+//				return key;
+//			case  SearchPattern.R_REGEXP_MATCH:
+//				// TODO (jerome) implement
+//				return key;
+//		}
+	}
 	/**
-	 * Decoded the given index key into the given record.
+	 * Decode the given index key.
 	 */
 	public void decodeIndexKey(char[] key) {
-		// override as necessary
+		// called from findIndexMatches(), override as necessary
 	}
-
-	/**
-	 * Returns a key to find in relevant index categories. The key will be matched according to some match rule.
-	 * These potential matches will be further narrowed by the match locator, but precise
-	 * match locating can be expensive, and index query should be as accurate as possible
-	 * so as to eliminate obvious false hits.
-	 */
-	public char[] encodeIndexKey() {
-		return null; // override as necessary
-	}
-
 	/**
 	 * TODO (jerome) spec
 	 */
 	public SearchPattern getBlankPattern() {
-		return null; // override as necessary
+		return null; // called from findIndexMatches(), override as necessary
 	}
-
+	/**
+	 * Returns a key to find in relevant index categories, if null then all words are matched.
+	 * The key will be matched according to some match rule. These potential matches
+	 * will be further narrowed by the match locator, but precise match locating can be expensive,
+	 * and index query should be as accurate as possible so as to eliminate obvious false hits.
+	 */
+	public char[] getIndexKey() {
+		return null; // called from queryIn(), override as necessary
+	}
 	/**
 	 * Returns an array of index categories to consider for this index query.
 	 * These potential matches will be further narrowed by the match locator, but precise
@@ -1124,9 +1140,8 @@
 	 * so as to eliminate obvious false hits.
 	 */
 	public char[][] getMatchCategories() {
-		return CharOperation.NO_CHAR_CHAR; // override as necessary
+		return CharOperation.NO_CHAR_CHAR; // called from queryIn(), override as necessary
 	}
-	
 	/**
 	 * Returns the rule to apply for matching index keys. Can be exact match, prefix match, pattern match or regexp match.
 	 * Rule can also be combined with a case sensitivity flag.
@@ -1134,14 +1149,12 @@
 	public int getMatchRule() {
 		return this.matchMode + (this.isCaseSensitive ? SearchPattern.R_CASE_SENSITIVE : 0);
 	}
-	
 	/**
 	 * TODO (jerome) spec
 	 */
-	public boolean matchesDecodedPattern(SearchPattern decodedPattern) {
-		return false; // override as necessary
+	public boolean matchesDecodedKey(SearchPattern decodedPattern) {
+		return true; // called from findIndexMatches(), override as necessary if index key is encoded
 	}
-
 	/**
 	 * Returns whether the given name matches the given pattern.
 	 */
@@ -1164,7 +1177,6 @@
 		}
 		return false;
 	}
-
 	public String toString() {
 		return "SearchPattern"; //$NON-NLS-1$
 	}
diff --git a/search/org/eclipse/jdt/core/search/TypeDeclarationMatch.java b/search/org/eclipse/jdt/core/search/TypeDeclarationMatch.java
new file mode 100644
index 0000000..9da82f0
--- /dev/null
+++ b/search/org/eclipse/jdt/core/search/TypeDeclarationMatch.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.search;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.internal.core.search.matching.JavaSearchMatch;
+
+public class TypeDeclarationMatch extends JavaSearchMatch {
+
+	public TypeDeclarationMatch(IJavaElement element, int accuracy, int sourceStart, int sourceEnd, SearchParticipant participant, IResource resource) {
+		super(element, accuracy, sourceStart, sourceEnd, participant, resource);
+	}
+
+}
diff --git a/search/org/eclipse/jdt/core/search/TypeReferenceMatch.java b/search/org/eclipse/jdt/core/search/TypeReferenceMatch.java
new file mode 100644
index 0000000..6c59237
--- /dev/null
+++ b/search/org/eclipse/jdt/core/search/TypeReferenceMatch.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.search;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.internal.core.search.matching.JavaSearchMatch;
+
+public class TypeReferenceMatch extends JavaSearchMatch {
+
+	public TypeReferenceMatch(IJavaElement enclosingElement, int accuracy,	int sourceStart, int sourceEnd, SearchParticipant participant, IResource resource) {
+		super(enclosingElement, accuracy, sourceStart, sourceEnd, participant, resource);
+	}
+}
diff --git a/search/org/eclipse/jdt/internal/core/index/DiskIndex.java b/search/org/eclipse/jdt/internal/core/index/DiskIndex.java
new file mode 100644
index 0000000..95a9a2f
--- /dev/null
+++ b/search/org/eclipse/jdt/internal/core/index/DiskIndex.java
@@ -0,0 +1,799 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core.index;
+
+import java.io.*;
+
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.internal.core.util.*;
+import org.eclipse.jdt.internal.compiler.util.HashtableOfIntValues;
+import org.eclipse.jdt.internal.compiler.util.HashtableOfObject;
+
+public class DiskIndex {
+
+String fileName;
+
+private int headerInfoOffset;
+private int numberOfChunks;
+private int sizeOfLastChunk;
+private int[] chunkOffsets;
+private int documentReferenceSize; // 1, 2 or more bytes... depends on # of document names
+private HashtableOfIntValues categoryOffsets;
+
+private int cacheUserCount;
+private String[][] cachedChunks; // decompressed chunks of document names
+private HashtableOfObject categoryTables; // category name -> HashtableOfObject(words -> int[] of document #'s) or offset if not read yet
+
+public static final String SIGNATURE= "INDEX FILE 0.011"; //$NON-NLS-1$
+public static boolean DEBUG = false;
+
+private static final int RE_INDEXED = -1;
+private static final int DELETED = -2;
+
+private static final int CHUNK_SIZE = 100;
+
+class IntList {
+
+int size;
+int[] elements;
+
+IntList(int[] elements) {
+	this.elements = elements;
+	this.size = elements.length;
+}
+void add(int newElement) {
+	if (this.size == this.elements.length) {
+		int newSize = this.size * 3;
+		if (newSize < 7) newSize = 7;
+		System.arraycopy(this.elements, 0, this.elements = new int[newSize], 0, this.size);
+	}
+	this.elements[this.size++] = newElement;
+}
+int[] asArray() {
+	int[] result = new int[this.size];
+	System.arraycopy(this.elements, 0, result, 0, this.size);
+	return result;
+}	
+}
+
+
+DiskIndex(String fileName) {
+	this.fileName = fileName;
+
+	// clear cached items
+	this.headerInfoOffset = -1;
+	this.numberOfChunks = -1;
+	this.sizeOfLastChunk = -1;
+	this.chunkOffsets = null;
+	this.documentReferenceSize = -1;
+	this.cacheUserCount = -1;
+	this.cachedChunks = null;
+	this.categoryTables = null;
+	this.categoryOffsets = null;
+}
+SimpleSet addDocumentNames(String substring, MemoryIndex memoryIndex) throws IOException {
+	// must skip over documents which have been added/changed/deleted in the memory index
+	SimpleSet results = new SimpleSet();
+	String[] docNames = readAllDocumentNames();
+	if (substring == null) {
+		if (memoryIndex == null) {
+			for (int i = 0, l = docNames.length; i < l; i++)
+				results.add(docNames[i]);
+		} else {
+			SimpleLookupTable docsToRefs = memoryIndex.docsToReferences;
+			for (int i = 0, l = docNames.length; i < l; i++) {
+				String docName = docNames[i];
+				if (!docsToRefs.containsKey(docName))
+					results.add(docName);
+			}
+		}
+	} else {
+		if (memoryIndex == null) {
+			for (int i = 0, l = docNames.length; i < l; i++)
+				if (docNames[i].startsWith(substring, 0))
+					results.add(docNames[i]);
+		} else {
+			SimpleLookupTable docsToRefs = memoryIndex.docsToReferences;
+			for (int i = 0, l = docNames.length; i < l; i++) {
+				String docName = docNames[i];
+				if (docName.startsWith(substring, 0) && !docsToRefs.containsKey(docName))
+					results.add(docName);
+			}
+		}
+	}
+	return results;
+}
+private void addQueryResult(HashtableOfObject results, char[] word, HashtableOfObject wordsToDocNumbers, MemoryIndex memoryIndex) throws IOException {
+	// must skip over documents which have been added/changed/deleted in the memory index
+	EntryResult result = (EntryResult) results.get(word);
+	if (memoryIndex == null) {
+		if (result == null)
+			results.put(word, new EntryResult(word, wordsToDocNumbers));
+		else
+			result.addDocumentTable(wordsToDocNumbers);
+	} else {
+		SimpleLookupTable docsToRefs = memoryIndex.docsToReferences;
+		if (result == null)
+			result = new EntryResult(word, null);
+		int[] docNumbers = readDocumentNumbers(wordsToDocNumbers.get(word));
+		for (int i = 0, l = docNumbers.length; i < l; i++) {
+			String docName = readDocumentName(docNumbers[i]);
+			if (!docsToRefs.containsKey(docName))
+				result.addDocumentName(docName);
+		}
+		if (!result.isEmpty())
+			results.put(word, result);
+	}
+}
+HashtableOfObject addQueryResults(char[][] categories, char[] key, int matchRule, MemoryIndex memoryIndex) throws IOException {
+	// assumes sender has called startQuery() & will call stopQuery() when finished
+	HashtableOfObject results = new HashtableOfObject(13);
+	if (this.categoryOffsets == null)
+		return results; // file is empty
+
+	if (matchRule == SearchPattern.R_EXACT_MATCH + SearchPattern.R_CASE_SENSITIVE) {
+		for (int i = 0, l = categories.length; i < l; i++) {
+			HashtableOfObject wordsToDocNumbers = readCategoryTable(categories[i], false);
+			if (wordsToDocNumbers != null && wordsToDocNumbers.containsKey(key))
+				addQueryResult(results, key, wordsToDocNumbers, memoryIndex);
+		}
+	} else {
+		for (int i = 0, l = categories.length; i < l; i++) {
+			HashtableOfObject wordsToDocNumbers = readCategoryTable(categories[i], false);
+			if (wordsToDocNumbers != null) {
+				char[][] words = wordsToDocNumbers.keyTable;
+				for (int j = 0, m = words.length; j < m; j++) {
+					char[] word = words[j];
+					if (word != null && Index.isMatch(key, word, matchRule))
+						addQueryResult(results, word, wordsToDocNumbers, memoryIndex);
+				}
+			}
+		}
+	}
+	return results;
+}
+private String[] computeDocumentNames(String[] onDiskNames, int[] positions, SimpleLookupTable indexedDocuments, MemoryIndex memoryIndex) {
+	int onDiskLength = onDiskNames.length;
+	Object[] docNames = memoryIndex.docsToReferences.keyTable;
+	Object[] referenceTables = memoryIndex.docsToReferences.valueTable;
+	if (onDiskLength == 0) {
+		// disk index was empty, so add every indexed document
+		for (int i = 0, l = referenceTables.length; i < l; i++)
+			if (referenceTables[i] != null)
+				indexedDocuments.put(docNames[i], null); // remember each new document
+
+		String[] newDocNames = new String[indexedDocuments.elementSize];
+		int count = 0;
+		Object[] added = indexedDocuments.keyTable;
+		for (int i = 0, l = added.length; i < l; i++)
+			if (added[i] != null)
+				newDocNames[count++] = (String) added[i];
+		Util.sort(newDocNames);
+		for (int i = 0, l = newDocNames.length; i < l; i++)
+			indexedDocuments.put(newDocNames[i], new Integer(i));
+		return newDocNames;
+	}
+
+	// initialize positions as if each document will remain in the same position
+	for (int i = 0; i < onDiskLength; i++)
+		positions[i] = i;
+
+	// find out if the memory index has any new or deleted documents, if not then the names & positions are the same
+	int numDeletedDocNames = 0;
+	int numReindexedDocNames = 0;
+	nextPath : for (int i = 0, l = docNames.length; i < l; i++) {
+		String docName = (String) docNames[i];
+		if (docName != null) {
+			for (int j = 0; j < onDiskLength; j++) {
+				if (docName.equals(onDiskNames[j])) {
+					if (referenceTables[i] == null) {
+						positions[j] = DELETED;
+						numDeletedDocNames++;
+					} else {
+						positions[j] = RE_INDEXED;
+						numReindexedDocNames++;
+					}
+					continue nextPath;
+				}
+			}
+			if (referenceTables[i] != null)
+				indexedDocuments.put(docName, null); // remember each new document, skip deleted documents which were never saved
+		}
+	}
+
+	String[] newDocNames = onDiskNames;
+	if (numDeletedDocNames > 0 || indexedDocuments.elementSize > 0) {
+		// some new documents have been added or some old ones deleted
+		newDocNames = new String[onDiskLength + indexedDocuments.elementSize - numDeletedDocNames];
+		int count = 0;
+		for (int i = 0; i < onDiskLength; i++)
+			if (positions[i] >= RE_INDEXED)
+				newDocNames[count++] = onDiskNames[i]; // keep each unchanged document
+		Object[] added = indexedDocuments.keyTable;
+		for (int i = 0, l = added.length; i < l; i++)
+			if (added[i] != null)
+				newDocNames[count++] = (String) added[i]; // add each new document
+		Util.sort(newDocNames);
+		for (int i = 0, l = newDocNames.length; i < l; i++)
+			if (indexedDocuments.containsKey(newDocNames[i]))
+				indexedDocuments.put(newDocNames[i], new Integer(i)); // remember the position for each new document
+	}
+
+	// need to be able to look up an old position (ref# from a ref[]) and map it to its new position
+	// if its old position == DELETED then its forgotton
+	// if its old position == ReINDEXED then its also forgotten but its new position is needed to map references
+	int count = -1;
+	for (int i = 0; i < onDiskLength;) {
+		switch(positions[i]) {
+			case DELETED :
+				i++; // skip over deleted... references are forgotten
+				break;
+			case RE_INDEXED :
+				String newName = newDocNames[++count];
+				if (newName.equals(onDiskNames[i])) {
+					indexedDocuments.put(newName, new Integer(count)); // the reindexed docName that was at position i is now at position count
+					i++;
+				}
+				break;
+			default :
+				if (newDocNames[++count].equals(onDiskNames[i]))
+					positions[i++] = count; // the unchanged docName that was at position i is now at position count
+		}
+	}
+	return newDocNames;
+}
+private void copyQueryResults(HashtableOfObject categoryToWords, int newPosition) throws IOException {
+	char[][] categoryNames = categoryToWords.keyTable;
+	Object[] wordSets = categoryToWords.valueTable;
+	for (int i = 0, l = categoryNames.length; i < l; i++) {
+		char[] categoryName = categoryNames[i];
+		if (categoryName != null) {
+			SimpleWordSet wordSet = (SimpleWordSet) wordSets[i];
+			HashtableOfObject wordsToDocs = (HashtableOfObject) this.categoryTables.get(categoryName);
+			if (wordsToDocs == null)
+				this.categoryTables.put(categoryName, wordsToDocs = new HashtableOfObject(wordSet.elementSize));
+
+			char[][] words = wordSet.words;
+			for (int j = 0, m = words.length; j < m; j++) {
+				char[] word = words[j];
+				if (word != null) {
+					Object o = wordsToDocs.get(word);
+					if (o == null) {
+						wordsToDocs.put(word, new int[] {newPosition});
+					} else if (o instanceof IntList) {
+						((IntList) o).add(newPosition);
+					} else {
+						IntList list = new IntList((int[]) o);
+						list.add(newPosition);
+						wordsToDocs.put(word, list);
+					}
+				}
+			}
+		}
+	}
+}
+File getIndexFile() {
+	if (this.fileName == null) return null;
+
+	return new File(this.fileName);
+}
+void initialize(boolean reuseExistingFile) throws IOException {
+	File indexFile = getIndexFile();
+	if (indexFile.exists()) {
+		if (reuseExistingFile) {
+			RandomAccessFile file = new RandomAccessFile(this.fileName, "r"); //$NON-NLS-1$
+			try {
+				String signature = file.readUTF();
+				if (!signature.equals(SIGNATURE))
+					throw new IOException(Util.bind("exception.wrongFormat")); //$NON-NLS-1$
+
+				this.headerInfoOffset = file.readInt();
+				if (this.headerInfoOffset > 0) // file is empty if its not set
+					readHeaderInfo(file);
+			} finally {
+				file.close();
+			}
+			return;
+		}
+		if (!indexFile.delete()) {
+			if (DEBUG)
+				System.out.println("initialize - Failed to delete index " + this.fileName); //$NON-NLS-1$
+			throw new IOException("Failed to delete index " + this.fileName); //$NON-NLS-1$
+		}
+	}
+	if (indexFile.createNewFile()) {
+		RandomAccessFile file = new RandomAccessFile(this.fileName, "rw"); //$NON-NLS-1$
+		try {
+			file.writeUTF(SIGNATURE);
+			file.writeInt(-1); // file is empty
+		} finally {
+			file.close();
+		}
+	} else {
+		if (DEBUG)
+			System.out.println("initialize - Failed to create new index " + this.fileName); //$NON-NLS-1$
+		throw new IOException("Failed to create new index " + this.fileName); //$NON-NLS-1$
+	}
+}
+private void initializeFrom(DiskIndex diskIndex, File newIndexFile) throws IOException {
+	if (newIndexFile.exists() && !newIndexFile.delete()) { // delete the temporary index file
+		if (DEBUG)
+			System.out.println("initializeFrom - Failed to delete temp index " + this.fileName); //$NON-NLS-1$
+	} else if (!newIndexFile.createNewFile()) {
+		if (DEBUG)
+			System.out.println("initializeFrom - Failed to create temp index " + this.fileName); //$NON-NLS-1$
+		throw new IOException("Failed to create temp index " + this.fileName); //$NON-NLS-1$
+	}
+
+	int size = diskIndex.categoryOffsets == null ? 7 : diskIndex.categoryOffsets.elementSize;
+	this.categoryOffsets = new HashtableOfIntValues(size);
+	this.categoryTables = new HashtableOfObject(size);
+}
+private void mergeCategories(DiskIndex onDisk, int[] positions, DataOutputStream stream) throws IOException {
+	// at this point, this.categoryTables contains the names -> wordsToDocs added in copyQueryResults()
+	char[][] oldNames = onDisk.categoryOffsets.keyTable;
+	for (int i = 0, l = oldNames.length; i < l; i++) {
+		char[] oldName = oldNames[i];
+		if (oldName != null && !this.categoryTables.containsKey(oldName))
+			this.categoryTables.put(oldName, null);
+	}
+
+	char[][] categoryNames = this.categoryTables.keyTable;
+	for (int i = 0, l = categoryNames.length; i < l; i++)
+		if (categoryNames[i] != null)
+			mergeCategory(categoryNames[i], onDisk, positions, stream);
+}
+private void mergeCategory(char[] categoryName, DiskIndex onDisk, int[] positions, DataOutputStream stream) throws IOException {
+	HashtableOfObject wordsToDocs = (HashtableOfObject) this.categoryTables.get(categoryName);
+	if (wordsToDocs == null)
+		wordsToDocs = new HashtableOfObject(3);
+
+	HashtableOfObject oldWordsToDocs = onDisk.readCategoryTable(categoryName, true);
+	if (oldWordsToDocs != null) {
+		char[][] oldWords = oldWordsToDocs.keyTable;
+		Object[] oldArrayOffsets = oldWordsToDocs.valueTable;
+		nextWord: for (int i = 0, l = oldWords.length; i < l; i++) {
+			char[] oldWord = oldWords[i];
+			if (oldWord != null) {
+				int[] oldDocNumbers = (int[]) oldArrayOffsets[i];
+				int length = oldDocNumbers.length;
+				int[] mappedNumbers = new int[length];
+				int count = 0;
+				for (int j = 0; j < length; j++) {
+					int pos = positions[oldDocNumbers[j]];
+					if (pos > RE_INDEXED) // forget any reference to a document which was deleted or re_indexed
+						mappedNumbers[count++] = pos;
+				}
+				if (count < length) {
+					if (count == 0) continue nextWord; // skip words which no longer have any references
+					System.arraycopy(mappedNumbers, 0, mappedNumbers = new int[count], 0, count);
+				}
+
+				Object o = wordsToDocs.get(oldWord);
+				if (o == null) {
+					wordsToDocs.put(oldWord, mappedNumbers);
+				} else {
+					IntList list = null;
+					if (o instanceof IntList) {
+						list = (IntList) o;
+					} else {
+						list = new IntList((int[]) o);
+						wordsToDocs.put(oldWord, list);
+					}
+					for (int j = 0; j < count; j++)
+						list.add(mappedNumbers[j]);
+				}
+			}
+		}
+		onDisk.categoryTables.put(categoryName, null); // flush cached table
+	}
+	writeCategoryTable(categoryName, wordsToDocs, stream);
+}
+DiskIndex mergeWith(MemoryIndex memoryIndex) throws IOException {
+ 	// assume write lock is held
+	// compute & write out new docNames
+	String[] docNames = readAllDocumentNames();
+	int previousLength = docNames.length;
+	int[] positions = new int[previousLength]; // keeps track of the position of each document in the new sorted docNames
+	SimpleLookupTable indexedDocuments = new SimpleLookupTable(3); // for each new/changed document in the memoryIndex
+	docNames = computeDocumentNames(docNames, positions, indexedDocuments, memoryIndex);
+	if (docNames.length == 0) {
+		if (previousLength == 0) return this; // nothing to do... memory index contained deleted documents that had never been saved
+
+		// index is now empty since all the saved documents were removed
+		DiskIndex newDiskIndex = new DiskIndex(this.fileName);
+		newDiskIndex.initialize(false);
+		return newDiskIndex;
+	}
+
+	DiskIndex newDiskIndex = new DiskIndex(this.fileName + ".tmp"); //$NON-NLS-1$
+	File newIndexFile = newDiskIndex.getIndexFile();
+	try {
+		newDiskIndex.initializeFrom(this, newIndexFile);
+		DataOutputStream stream = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(newIndexFile, false)));
+		int offsetToHeader = -1;
+		try {
+			newDiskIndex.writeAllDocumentNames(docNames, stream);
+			docNames = null; // free up the space
+
+			// add each new/changed doc to empty category tables using its new position #
+			if (indexedDocuments.elementSize > 0) {
+				Object[] names = indexedDocuments.keyTable;
+				Object[] integerPositions = indexedDocuments.valueTable;
+				for (int i = 0, l = names.length; i < l; i++)
+					if (names[i] != null)
+						newDiskIndex.copyQueryResults(
+							(HashtableOfObject) memoryIndex.docsToReferences.get(names[i]),
+							((Integer) integerPositions[i]).intValue());
+			}
+			indexedDocuments = null; // free up the space
+
+			// merge each category table with the new ones & write them out
+			if (previousLength == 0)
+				newDiskIndex.writeCategories(stream);
+			else
+				newDiskIndex.mergeCategories(this, positions, stream);
+			offsetToHeader = stream.size();
+			newDiskIndex.writeHeaderInfo(stream);
+			positions = null; // free up the space
+		} finally {
+			stream.close();
+		}
+		newDiskIndex.writeOffsetToHeader(offsetToHeader);
+
+		// rename file by deleting previous index file & renaming temp one
+		File old = getIndexFile();
+		if (!old.delete()) {
+			if (DEBUG)
+				System.out.println("mergeWith - Failed to delete " + this.fileName); //$NON-NLS-1$
+			throw new IOException("Failed to delete index file " + this.fileName); //$NON-NLS-1$
+		}
+		if (!newIndexFile.renameTo(old)) {
+			if (DEBUG)
+				System.out.println("mergeWith - Failed to rename " + this.fileName); //$NON-NLS-1$
+			throw new IOException("Failed to rename index file " + this.fileName); //$NON-NLS-1$
+		}
+	} catch (IOException e) {
+		if (newIndexFile.exists() && !newIndexFile.delete())
+			if (DEBUG)
+				System.out.println("mergeWith - Failed to delete temp index " + newDiskIndex.fileName); //$NON-NLS-1$
+		throw e;
+	}
+
+	newDiskIndex.fileName = this.fileName;
+	return newDiskIndex;
+}
+private synchronized String[] readAllDocumentNames() throws IOException {
+	if (this.numberOfChunks <= 0)
+		return new String[0];
+
+	DataInputStream stream = new DataInputStream(new BufferedInputStream(new FileInputStream(getIndexFile())));
+	try {
+		stream.skip(this.chunkOffsets[0]);
+		int lastIndex = this.numberOfChunks - 1;
+		String[] docNames = new String[lastIndex * CHUNK_SIZE + sizeOfLastChunk];
+		for (int i = 0; i < this.numberOfChunks; i++)
+			readChunk(docNames, stream, i * CHUNK_SIZE, i < lastIndex ? CHUNK_SIZE : sizeOfLastChunk);
+		return docNames;
+	} finally {
+		stream.close();
+	}
+}
+private synchronized HashtableOfObject readCategoryTable(char[] categoryName, boolean cacheDocNumbers) throws IOException {
+	// result will be null if categoryName is unknown
+	int offset = this.categoryOffsets.get(categoryName);
+	if (offset == HashtableOfIntValues.NO_VALUE)
+		return null;
+
+	if (this.categoryTables == null) {
+		this.categoryTables = new HashtableOfObject(this.categoryOffsets.elementSize);
+	} else {
+		HashtableOfObject cachedTable = (HashtableOfObject) this.categoryTables.get(categoryName);
+		if (cachedTable != null)
+			return cachedTable;
+	}
+
+	DataInputStream stream = new DataInputStream(new BufferedInputStream(new FileInputStream(getIndexFile())));
+	HashtableOfObject categoryTable = null;
+	char[][] matchingWords = null;
+	int count = 0;
+	int firstOffset = -1;
+	try {
+		stream.skip(offset);
+		int size = stream.readInt();
+		categoryTable = new HashtableOfObject(size);
+		if (cacheDocNumbers)
+			matchingWords = new char[size][];
+		for (int i = 0; i < size; i++) {
+			char[] word = Util.readUTF(stream);
+			int arrayOffset = stream.readInt();
+			if (arrayOffset > 0) {
+				if (matchingWords != null) {
+					if (count == 0)
+						firstOffset = arrayOffset;
+					matchingWords[count++] = word;
+				}
+				categoryTable.put(word, new Integer(arrayOffset)); // offset to array in the file
+			} else {
+				categoryTable.put(word, new int[] {-arrayOffset}); // stored a 1 element array by negating the documentNumber
+			}
+		}
+		this.categoryTables.put(categoryName, categoryTable);
+	} finally {
+		stream.close();
+	}
+
+	if (count > 0) {
+		stream = new DataInputStream(new BufferedInputStream(new FileInputStream(getIndexFile())));
+		try {
+			stream.skip(firstOffset);
+			for (int i = 0; i < count; i++) // each array follows the previous one
+				categoryTable.put(matchingWords[i], readDocumentArray(stream));
+		} finally {
+			stream.close();
+		}
+	}
+	return categoryTable;
+}
+private void readChunk(String[] docNames, DataInputStream stream, int index, int size) throws IOException {
+	String current = stream.readUTF();
+	docNames[index++] = current;
+	for (int i = 1; i < size; i++) {
+		int start = stream.readUnsignedByte(); // number of identical characters at the beginning
+		int end = stream.readUnsignedByte(); // number of identical characters at the end
+		String next = stream.readUTF();
+		if (start > 0) {
+			if (end > 0) {
+				int length = current.length();
+				next = current.substring(0, start) + next + current.substring(length - end, length);
+			} else {
+				next = current.substring(0, start) + next;
+			}
+		} else if (end > 0) {
+			int length = current.length();
+			next = next + current.substring(length - end, length);
+		}
+		docNames[index++] = next;
+		current = next;
+	}
+}
+private int[] readDocumentArray(DataInputStream stream) throws IOException {
+	int arraySize = stream.readShort();
+	if (arraySize == 0x7FFF)
+		arraySize = stream.readInt();
+	int[] result = new int[arraySize];
+	for (int i = 0; i < arraySize; i++) {
+		switch (this.documentReferenceSize) {
+			case 1 :
+				result[i] = stream.readUnsignedByte();
+				break;
+			case 2 :
+				result[i] = stream.readUnsignedShort();
+				break;
+			default :
+				result[i] = stream.readInt();
+				break;
+		}
+	}
+	return result;
+}
+synchronized String readDocumentName(int docNumber) throws IOException {
+	if (this.cachedChunks == null)
+		this.cachedChunks = new String[this.numberOfChunks][];
+
+	int chunkNumber = docNumber / CHUNK_SIZE;
+	String[] chunk = this.cachedChunks[chunkNumber];
+	if (chunk == null) {
+		DataInputStream stream = new DataInputStream(new BufferedInputStream(new FileInputStream(getIndexFile())));
+		try {
+			stream.skip(this.chunkOffsets[chunkNumber]);
+			int size = chunkNumber == this.numberOfChunks - 1 ? this.sizeOfLastChunk : CHUNK_SIZE;
+			chunk = new String[size];
+			readChunk(chunk, stream, 0, size);
+		} finally {
+			stream.close();
+		}
+		this.cachedChunks[chunkNumber] = chunk;
+	}
+	return chunk[docNumber - (chunkNumber * CHUNK_SIZE)];
+}
+synchronized int[] readDocumentNumbers(Object arrayOffset) throws IOException {
+	// arrayOffset is either a cached array of docNumbers or an Integer offset in the file
+	if (arrayOffset instanceof int[])
+		return (int[]) arrayOffset;
+
+	DataInputStream stream = new DataInputStream(new BufferedInputStream(new FileInputStream(getIndexFile())));
+	try {
+		stream.skip(((Integer) arrayOffset).intValue());
+		return readDocumentArray(stream);
+	} finally {
+		stream.close();
+	}
+}
+private void readHeaderInfo(RandomAccessFile file) throws IOException {
+	file.seek(this.headerInfoOffset);
+
+	// must be same order as writeHeaderInfo()
+	this.numberOfChunks = file.readInt();
+	this.sizeOfLastChunk = file.readUnsignedByte();
+	this.documentReferenceSize = file.readUnsignedByte();
+
+	this.chunkOffsets = new int[this.numberOfChunks];
+	for (int i = 0; i < this.numberOfChunks; i++)
+		this.chunkOffsets[i] = file.readInt();
+
+	int size = file.readInt();
+	this.categoryOffsets = new HashtableOfIntValues(size);
+	for (int i = 0; i < size; i++)
+		this.categoryOffsets.put(Util.readUTF(file), file.readInt()); // cache offset to category table
+	this.categoryTables = new HashtableOfObject(size);
+}
+synchronized void startQuery() {
+	this.cacheUserCount++;
+}
+synchronized void stopQuery() {
+	if (--this.cacheUserCount < 0) {
+		// clear cached items
+		this.cacheUserCount = -1;
+		this.cachedChunks = null;
+		this.categoryTables = null;
+	}
+}
+private void writeAllDocumentNames(String[] sortedDocNames, DataOutputStream stream) throws IOException {
+	if (sortedDocNames.length == 0)
+		throw new IllegalArgumentException();
+
+	// assume the file was just created by initializeFrom()
+	// in order, write: SIGNATURE & headerInfoOffset place holder, then each compressed chunk of document names
+	stream.writeUTF(SIGNATURE);
+	this.headerInfoOffset = stream.size();
+	stream.writeInt(-1); // will overwrite with correct value later
+
+	int size = sortedDocNames.length;
+	this.numberOfChunks = (size / CHUNK_SIZE) + 1;
+	this.sizeOfLastChunk = size % CHUNK_SIZE;
+	if (this.sizeOfLastChunk == 0) {
+		this.numberOfChunks--;
+		this.sizeOfLastChunk = CHUNK_SIZE;
+	}
+	this.documentReferenceSize = size <= 0x7F ? 1 : (size <= 0x7FFF ? 2 : 4); // number of bytes used to encode a reference
+
+	this.chunkOffsets = new int[this.numberOfChunks];
+	int lastIndex = this.numberOfChunks - 1;
+	for (int i = 0; i < this.numberOfChunks; i++) {
+		this.chunkOffsets[i] = stream.size();
+
+		int chunkSize = i == lastIndex ? this.sizeOfLastChunk : CHUNK_SIZE;
+		int chunkIndex = i * CHUNK_SIZE;
+		String current = sortedDocNames[chunkIndex];
+		stream.writeUTF(current);
+		for (int j = 1; j < chunkSize; j++) {
+			String next = sortedDocNames[chunkIndex + j];
+			int len1 = current.length();
+			int len2 = next.length();
+			int max = len1 < len2 ? len1 : len2;
+			int start = 0; // number of identical characters at the beginning (also the index of first character that is different)
+			while (current.charAt(start) == next.charAt(start)) {
+				start++;
+				if (max == start) break; // current is 'abba', next is 'abbab'
+			}
+			if (start > 255) start = 255;
+
+			int end = 0; // number of identical characters at the end
+			while (current.charAt(--len1) == next.charAt(--len2)) {
+				end++;
+				if (len2 == start) break; // current is 'abbba', next is 'abba'
+			}
+			if (end > 255) end = 255;
+			stream.writeByte(start);
+			stream.writeByte(end);
+
+			int last = next.length() - end;
+			stream.writeUTF(start < last ? next.substring(start, last) : ""); //$NON-NLS-1$
+			current = next;
+		}
+	}
+}
+private void writeCategories(DataOutputStream stream) throws IOException {
+	char[][] categoryNames = this.categoryTables.keyTable;
+	Object[] tables = this.categoryTables.valueTable;
+	for (int i = 0, l = categoryNames.length; i < l; i++)
+		if (categoryNames[i] != null)
+			writeCategoryTable(categoryNames[i], (HashtableOfObject) tables[i], stream);
+}
+private void writeCategoryTable(char[] categoryName, HashtableOfObject wordsToDocs, DataOutputStream stream) throws IOException {
+	// append the file with the document number arrays & remember the offsets
+	Object[] values = wordsToDocs.valueTable;
+	for (int i = 0, l = values.length; i < l; i++) {
+		Object o = values[i];
+		if (o != null) {
+			int[] documentNumbers = o instanceof int[] ? (int[]) o : ((IntList) o).asArray();
+			int length = documentNumbers.length;
+			if (length == 1) {
+				values[i] = new Integer(-documentNumbers[0]); // store an array of 1 element by negating the documentNumber (can be zero)
+			} else {
+				values[i] = new Integer(stream.size());
+				writeDocumentNumbers(documentNumbers, stream);
+			}
+		}
+	}
+
+	// append the file with the arrays followed by the words & offsets
+	this.categoryOffsets.put(categoryName, stream.size()); // remember the offset to the start of the table
+	this.categoryTables.put(categoryName, null); // flush cached table
+	stream.writeInt(wordsToDocs.elementSize);
+	char[][] words = wordsToDocs.keyTable;
+	for (int i = 0, l = words.length; i < l; i++) {
+		if (words[i] != null) {
+			Util.writeUTF(stream, words[i]);
+			stream.writeInt(((Integer) values[i]).intValue()); // offset in the file of the array of document numbers
+		}
+	}
+}
+private void writeDocumentNumbers(int[] documentNumbers, DataOutputStream stream) throws IOException {
+	int length = documentNumbers.length;
+	if (length < 0x7FFF) {
+		if (length == 0)
+			throw new IllegalArgumentException();
+		stream.writeShort(length);
+	} else {
+		stream.writeShort(0x7FFF);
+		stream.writeInt(length);
+	}
+	Util.sort(documentNumbers);
+	for (int i = 0; i < length; i++) {
+		switch (this.documentReferenceSize) {
+			case 1 :
+				stream.writeByte(documentNumbers[i]);
+				break;
+			case 2 :
+				stream.writeShort(documentNumbers[i]);
+				break;
+			default :
+				stream.writeInt(documentNumbers[i]);
+				break;
+		}
+	}
+}
+private void writeHeaderInfo(DataOutputStream stream) throws IOException {
+	stream.writeInt(this.numberOfChunks);
+	stream.writeByte(this.sizeOfLastChunk);
+	stream.writeByte(this.documentReferenceSize);
+
+	// apend the file with chunk offsets
+	for (int i = 0; i < this.numberOfChunks; i++)
+		stream.writeInt(this.chunkOffsets[i]);
+
+	// append the file with the category offsets... # of name -> offset pairs, followed by each name & an offset to its word->doc# table
+	stream.writeInt(this.categoryOffsets.elementSize);
+	char[][] categoryNames = this.categoryOffsets.keyTable;
+	int[] offsets = this.categoryOffsets.valueTable;
+	for (int i = 0, l = categoryNames.length; i < l; i++) {
+		if (categoryNames[i] != null) {
+			Util.writeUTF(stream, categoryNames[i]);
+			stream.writeInt(offsets[i]);
+		}
+	}
+}
+private void writeOffsetToHeader(int offsetToHeader) throws IOException {
+	if (offsetToHeader > 0) {
+		RandomAccessFile file = new RandomAccessFile(this.fileName, "rw"); //$NON-NLS-1$
+		try {
+			file.seek(this.headerInfoOffset); // offset to position in header
+			file.writeInt(offsetToHeader);
+			this.headerInfoOffset = offsetToHeader; // update to reflect the correct offset
+		} finally {
+			file.close();
+		}
+	}
+}
+}
+	
\ No newline at end of file
diff --git a/search/org/eclipse/jdt/internal/core/index/EntryResult.java b/search/org/eclipse/jdt/internal/core/index/EntryResult.java
index d901054..d783953 100644
--- a/search/org/eclipse/jdt/internal/core/index/EntryResult.java
+++ b/search/org/eclipse/jdt/internal/core/index/EntryResult.java
@@ -10,56 +10,60 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.index;
 
-import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.util.HashtableOfObject;
+import org.eclipse.jdt.internal.core.util.SimpleSet;
 
 public class EntryResult {
-	private char[] word;
-	private int[]  fileRefs;
-	
-public EntryResult(char[] word, int[] refs) {
-	this.word = word;
-	this.fileRefs = refs;
-}
-public boolean equals(Object anObject){
-	
-	if (this == anObject) {
-	    return true;
-	}
-	if ((anObject != null) && (anObject instanceof EntryResult)) {
-		EntryResult anEntryResult = (EntryResult) anObject;
-		if (!CharOperation.equals(this.word, anEntryResult.word)) return false;
 
-		int length;
-		int[] refs, otherRefs;
-		if ((length = (refs = this.fileRefs).length) != (otherRefs = anEntryResult.fileRefs).length) return false;
-		for (int i =  0; i < length; i++){
-			if (refs[i] != otherRefs[i]) return false;
-		}
-		return true;
-	}
-	return false;
-	
+private char[] word;
+private HashtableOfObject[] documentTables;
+private SimpleSet documentNames;
+
+public EntryResult(char[] word, HashtableOfObject table) {
+	this.word = word;
+	if (table != null)
+		this.documentTables = new HashtableOfObject[] {table};
 }
-public int[] getFileReferences() {
-	return fileRefs;
+public void addDocumentName(String documentName) {
+	if (this.documentNames == null)
+		this.documentNames = new SimpleSet();
+	this.documentNames.add(documentName);
+}
+public void addDocumentTable(HashtableOfObject table) {
+	if (this.documentTables == null) {
+		this.documentTables = new HashtableOfObject[] {table};
+		return;
+	}
+
+	int length = this.documentTables.length;
+	System.arraycopy(this.documentTables, 0, this.documentTables = new HashtableOfObject[length + 1], 0, length);
+	this.documentTables[length] = table;
 }
 public char[] getWord() {
-	return word;
+	return this.word;
 }
-public int hashCode(){
-	return CharOperation.hashCode(word);
-}
-public String toString(){
-	StringBuffer buffer = new StringBuffer(word.length * 2);
-	buffer.append("EntryResult: word="); //$NON-NLS-1$
-	buffer.append(word);
-	buffer.append(", refs={"); //$NON-NLS-1$
-	for (int i = 0; i < fileRefs.length; i++){
-		if (i > 0) buffer.append(',');
-		buffer.append(' ');
-		buffer.append(fileRefs[i]);
+public String[] getDocumentNames(Index index) throws java.io.IOException {
+	if (this.documentTables != null) {
+		for (int i = 0, l = this.documentTables.length; i < l; i++) {
+			Object offset = this.documentTables[i].get(word);
+			int[] numbers = index.diskIndex.readDocumentNumbers(offset);
+			for (int j = 0, k = numbers.length; j < k; j++)
+				addDocumentName(index.diskIndex.readDocumentName(numbers[j]));
+		}
 	}
-	buffer.append(" }"); //$NON-NLS-1$
-	return buffer.toString();
+
+	if (this.documentNames == null)
+		return new String[0];
+
+	String[] names = new String[this.documentNames.elementSize];
+	int count = 0;
+	Object[] values = this.documentNames.values;
+	for (int i = 0, l = values.length; i < l; i++)
+		if (values[i] != null)
+			names[count++] = (String) values[i];
+	return names;
+}
+public boolean isEmpty() {
+	return this.documentTables == null && this.documentNames == null;
 }
 }
diff --git a/search/org/eclipse/jdt/internal/core/index/Index.java b/search/org/eclipse/jdt/internal/core/index/Index.java
index 1448293..d227ff1 100644
--- a/search/org/eclipse/jdt/internal/core/index/Index.java
+++ b/search/org/eclipse/jdt/internal/core/index/Index.java
@@ -12,46 +12,173 @@
 
 import java.io.*;
 
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.internal.compiler.util.HashtableOfObject;
+import org.eclipse.jdt.internal.core.util.*;
+import org.eclipse.jdt.internal.core.search.indexing.ReadWriteMonitor;
 
 /**
- * An IIndex is the interface used to generate an index file, and to make queries on
- * this index.
+ * An <code>Index</code> maps document names to their referenced words in various categories.
+ * 
+ * Queries can search a single category or several at the same time.
+ * 
+ * Indexes are not synchronized structures and should only be queried/updated one at a time.
  */
 
-public abstract class Index {
-	/**
-	 * Associates the category and key with the document.
-	 */
-	public abstract void addIndexEntry(char[] category, char[] key, SearchDocument document);
-	/**
-	 * Returns the document name for the given number.
-	 */
-	protected abstract String getDocumentName(int number);
-	/**
-	 * Returns the index file on the disk.
-	 */
-	public abstract File getIndexFile();
-	/**
-	 * Ansers true if has some changes to save.
-	 */
-	public abstract boolean hasChanged();
-	/**
-	 * Returns the entries containing the given key in a group of categories.
-	 * The matchRule dictates whether its an exact, prefix or pattern match, as well as
-	 * case sensitive or insensitive.
-	 */
-	public abstract EntryResult[] query(char[][] categories, char[] key, int matchRule);
-	/**
-	 * Returns the document names that contain the given substring, if null returns all of them.
-	 */
-	public abstract String[] queryDocumentNames(String substring) throws IOException;
-	/**
-	 * Removes the corresponding document from the index.
-	 */
-	public abstract void remove(String documentName);
-	/**
-	 * Saves the index on the disk.
-	 */
-	public abstract void save() throws IOException;
+public class Index {
+
+public String printableName;
+public ReadWriteMonitor monitor;
+
+protected DiskIndex diskIndex;
+protected MemoryIndex memoryIndex;
+
+/**
+ * Returns the path represented by pathString converted back to a path relative to the local file system.
+ *
+ * @param pathString the path to convert:
+ * <ul>
+ *		<li>an absolute IPath (relative to the workspace root) if the path represents a resource in the 
+ *			workspace
+ *		<li>a relative IPath (relative to the workspace root) followed by JAR_FILE_ENTRY_SEPARATOR
+ *			followed by an absolute path (relative to the jar) if the path represents a .class file in
+ *			an internal jar
+ *		<li>an absolute path (relative to the file system) followed by JAR_FILE_ENTRY_SEPARATOR
+ *			followed by an absolute path (relative to the jar) if the path represents a .class file in
+ *			an external jar
+ * </ul>
+ * @return the converted path:
+ * <ul>
+ *		<li>the original pathString if the path represents a resource in the workspace
+ *		<li>an absolute path (relative to the file system) followed by JAR_FILE_ENTRY_SEPARATOR
+ *			followed by an absolute path (relative to the jar) if the path represents a .class file in
+ *			an external or internal jar
+ * </ul>
+ */
+public static String convertPath(String pathString) {
+	int index = pathString.indexOf(IJavaSearchScope.JAR_FILE_ENTRY_SEPARATOR);
+	if (index == -1) return pathString;
+	
+	Path jarPath = new Path(pathString.substring(0, index));
+	return (jarPath.isAbsolute() ? jarPath.toOSString() : jarPath.makeAbsolute().toString())
+		+ pathString.substring(index, pathString.length());
 }
+public static boolean isMatch(char[] pattern, char[] word, int matchRule) {
+	if (pattern == null) return true;
+
+	switch(matchRule) {
+		case SearchPattern.R_EXACT_MATCH :
+			return CharOperation.equals(pattern, word, false);
+		case SearchPattern.R_PREFIX_MATCH :
+			return CharOperation.prefixEquals(pattern, word, false);
+		case SearchPattern.R_PATTERN_MATCH :
+			return CharOperation.match(pattern, word, false);
+		case SearchPattern.R_EXACT_MATCH + SearchPattern.R_CASE_SENSITIVE :
+			return CharOperation.equals(pattern, word);
+		case SearchPattern.R_PREFIX_MATCH + SearchPattern.R_CASE_SENSITIVE :
+			return CharOperation.prefixEquals(pattern, word);
+		case SearchPattern.R_PATTERN_MATCH + SearchPattern.R_CASE_SENSITIVE :
+			return CharOperation.match(pattern, word, true);
+	}
+	return false;
+}
+
+
+public Index(String fileName, String printableName, boolean reuseExistingFile) throws IOException {
+	this.printableName = printableName;
+	this.monitor = new ReadWriteMonitor();
+
+	this.memoryIndex = new MemoryIndex();
+	this.diskIndex = new DiskIndex(fileName);
+	this.diskIndex.initialize(reuseExistingFile);
+}
+public void addIndexEntry(char[] category, char[] key, SearchDocument document) {
+	this.memoryIndex.addIndexEntry(category, key, document);
+}
+public File getIndexFile() {
+	if (this.diskIndex == null) return null;
+
+	return this.diskIndex.getIndexFile();
+}
+public boolean hasChanged() {
+	return this.memoryIndex.hasChanged();
+}
+/**
+ * Returns the entries containing the given key in a group of categories, or null if no matches are found.
+ * The matchRule dictates whether its an exact, prefix or pattern match, as well as case sensitive or insensitive.
+ * If the key is null then all entries in specified categories are returned.
+ */
+public EntryResult[] query(char[][] categories, char[] key, int matchRule) throws IOException {
+	if (this.memoryIndex.shouldMerge() && monitor.exitReadEnterWrite()) {
+		try {
+			save();
+		} finally {
+			monitor.exitWriteEnterRead();
+		}
+	}
+
+	HashtableOfObject results;
+	if (this.memoryIndex.hasChanged()) {
+		results = this.diskIndex.addQueryResults(categories, key, matchRule, this.memoryIndex);
+		this.memoryIndex.addQueryResults(categories, key, matchRule, results);
+	} else {
+		results = this.diskIndex.addQueryResults(categories, key, matchRule, null);
+	}
+	if (results.elementSize == 0) return null;
+
+	EntryResult[] entryResults = new EntryResult[results.elementSize];
+	int count = 0;
+	Object[] values = results.valueTable;
+	for (int i = 0, l = values.length; i < l; i++) {
+		EntryResult result = (EntryResult) values[i];
+		if (result != null)
+			entryResults[count++] = result;
+	}
+	return entryResults;
+}
+/**
+ * Returns the document names that contain the given substring, if null then returns all of them.
+ */
+public String[] queryDocumentNames(String substring) throws IOException {
+	SimpleSet results;
+	if (this.memoryIndex.hasChanged()) {
+		results = this.diskIndex.addDocumentNames(substring, this.memoryIndex);
+		this.memoryIndex.addDocumentNames(substring, results);
+	} else {
+		results = this.diskIndex.addDocumentNames(substring, null);
+	}
+	if (results.elementSize == 0) return null;
+
+	String[] documentNames = new String[results.elementSize];
+	int count = 0;
+	Object[] paths = results.values;
+	for (int i = 0, l = paths.length; i < l; i++)
+		if (paths[i] != null)
+			documentNames[count++] = (String) paths[i];
+	return documentNames;
+}
+public void remove(String documentName) {
+	this.memoryIndex.remove(documentName);
+}
+public void save() throws IOException {
+	// must own the write lock of the monitor
+	if (!hasChanged()) return;
+
+	this.diskIndex = this.diskIndex.mergeWith(this.memoryIndex);
+	this.memoryIndex = new MemoryIndex();
+}
+public void startQuery() throws IOException {
+	if (this.diskIndex != null)
+		this.diskIndex.startQuery();
+}
+public void stopQuery() throws IOException {
+	if (this.diskIndex != null)
+		this.diskIndex.stopQuery();
+}
+public String toString() {
+	if (this.printableName != null) return this.printableName;
+	return super.toString();
+}
+}
\ No newline at end of file
diff --git a/search/org/eclipse/jdt/internal/core/index/MemoryIndex.java b/search/org/eclipse/jdt/internal/core/index/MemoryIndex.java
new file mode 100644
index 0000000..05b2b40
--- /dev/null
+++ b/search/org/eclipse/jdt/internal/core/index/MemoryIndex.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core.index;
+
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.internal.core.util.*;
+import org.eclipse.jdt.internal.compiler.util.HashtableOfObject;
+
+public class MemoryIndex {
+
+public int NUM_CHANGES = 100; // number of separate document changes... used to decide when to merge
+
+SimpleLookupTable docsToReferences; // document paths -> HashtableOfObject(category names -> set of words)
+
+MemoryIndex() {
+	this.docsToReferences = new SimpleLookupTable();
+}
+void addDocumentNames(String substring, SimpleSet results) {
+	// assumed the disk index already skipped over documents which have been added/changed/deleted
+	Object[] paths = this.docsToReferences.keyTable;
+	Object[] referenceTables = this.docsToReferences.valueTable;
+	if (substring == null) { // add all new/changed documents
+		for (int i = 0, l = referenceTables.length; i < l; i++)
+			if (referenceTables[i] != null)
+				results.add(paths[i]);
+	} else {
+		for (int i = 0, l = referenceTables.length; i < l; i++)
+			if (referenceTables[i] != null && ((String) paths[i]).startsWith(substring, 0))
+				results.add(paths[i]);
+	}
+}
+void addIndexEntry(char[] category, char[] key, SearchDocument document) {
+	// assumed a document was removed before its reindexed
+	String documentName = document.getPath();
+	HashtableOfObject referenceTable = (HashtableOfObject) this.docsToReferences.get(documentName);
+	if (referenceTable == null)
+		this.docsToReferences.put(documentName, referenceTable = new HashtableOfObject(3));
+
+	SimpleWordSet existingWords = (SimpleWordSet) referenceTable.get(category);
+	if (existingWords == null)
+		referenceTable.put(category, existingWords = new SimpleWordSet(3));
+
+	existingWords.add(key);
+}
+void addQueryResults(char[][] categories, char[] key, int matchRule, HashtableOfObject results) {
+	// assumed the disk index already skipped over documents which have been added/changed/deleted
+	// results maps a word -> EntryResult
+	Object[] paths = this.docsToReferences.keyTable;
+	Object[] referenceTables = this.docsToReferences.valueTable;
+	if (matchRule == (SearchPattern.R_EXACT_MATCH + SearchPattern.R_CASE_SENSITIVE) && key != null) {
+		nextPath : for (int i = 0, l = referenceTables.length; i < l; i++) {
+			HashtableOfObject categoryToWords = (HashtableOfObject) referenceTables[i];
+			if (categoryToWords != null) {
+				for (int j = 0, m = categories.length; j < m; j++) {
+					SimpleWordSet wordSet = (SimpleWordSet) categoryToWords.get(categories[j]);
+					if (wordSet != null && wordSet.includes(key)) {
+						EntryResult result = (EntryResult) results.get(key);
+						if (result == null)
+							results.put(key, result = new EntryResult(key, null));
+						result.addDocumentName((String) paths[i]);
+						continue nextPath;
+					}
+				}
+			}
+		}
+	} else {
+		for (int i = 0, l = referenceTables.length; i < l; i++) {
+			HashtableOfObject categoryToWords = (HashtableOfObject) referenceTables[i];
+			if (categoryToWords != null) {
+				for (int j = 0, m = categories.length; j < m; j++) {
+					SimpleWordSet wordSet = (SimpleWordSet) categoryToWords.get(categories[j]);
+					if (wordSet != null) {
+						char[][] words = wordSet.words;
+						for (int k = 0, n = words.length; k < n; k++) {
+							char[] word = words[k];
+							if (word != null && Index.isMatch(key, word, matchRule)) {
+								EntryResult result = (EntryResult) results.get(word);
+								if (result == null)
+									results.put(word, result = new EntryResult(word, null));
+								result.addDocumentName((String) paths[i]);
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+}
+boolean hasChanged() {
+	return this.docsToReferences.elementSize > 0;
+}
+void remove(String documentName) {
+	this.docsToReferences.put(documentName, null);
+}
+boolean shouldMerge() {
+	return this.docsToReferences.elementSize >= NUM_CHANGES;
+}
+}
\ No newline at end of file
diff --git a/search/org/eclipse/jdt/internal/core/index/impl/Block.java b/search/org/eclipse/jdt/internal/core/index/impl/Block.java
deleted file mode 100644
index 4bed4ba..0000000
--- a/search/org/eclipse/jdt/internal/core/index/impl/Block.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.io.IOException;
-import java.io.RandomAccessFile;
-
-/**
- * A block is a container that can hold information (a list of file names, a list of
- * words, ...), be saved on the disk and loaded in memory.
- */
-
-public abstract class Block {
-	/**
-	 * Size of the block
-	 */
-	protected int blockSize;
-
-	/**
-	 * Field in which the information is stored
-	 */
-	protected Field field;
-
-	public Block(int blockSize) {
-		this.blockSize= blockSize;
-		field= new Field(blockSize);
-	}
-	/**
-	 * Empties the block.
-	 */
-	public void clear() {
-		field.clear();
-	}
-	/**
-	 * Flushes the block
-	 */
-	public void flush() {
-		// ignore
-	}
-	/**
-	 * Loads the block with the given number in memory, reading it from a RandomAccessFile.
-	 */
-	public void read(RandomAccessFile raf, int blockNum) throws IOException {
-		raf.seek(blockNum * (long) blockSize);
-		raf.readFully(field.buffer());
-	}
-	/**
-	 * Writes the block in a RandomAccessFile, giving it a block number.
-	 */
-	public void write(RandomAccessFile raf, int blockNum) throws IOException {
-		raf.seek(blockNum * (long) blockSize);
-		raf.write(field.buffer());
-	}
-}
diff --git a/search/org/eclipse/jdt/internal/core/index/impl/BlocksIndexInput.java b/search/org/eclipse/jdt/internal/core/index/impl/BlocksIndexInput.java
deleted file mode 100644
index 3b55fcf..0000000
--- a/search/org/eclipse/jdt/internal/core/index/impl/BlocksIndexInput.java
+++ /dev/null
@@ -1,394 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.util.ArrayList;
-
-import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.core.search.SearchDocument;
-import org.eclipse.jdt.internal.core.index.EntryResult;
-import org.eclipse.jdt.internal.core.util.Util;
-
-/**
- * This input is used for reading indexes saved using a BlocksIndexOutput.
- */
-public class BlocksIndexInput extends IndexInput {
-	public static final int CACHE_SIZE= 16; // Cache 16 blocks of 8K each, for a cache size of 128K
-	protected FileListBlock currentFileListBlock;
-	protected int currentFileListBlockNum;
-	protected int currentIndexBlockNum;
-	protected IndexBlock currentIndexBlock;
-	private RandomAccessFile raf;
-	protected File indexFile;
-	protected LRUCache blockCache;
-	protected boolean opened= false;
-	protected IndexSummary summary;
-
-	public BlocksIndexInput(File inputFile) {
-		this.indexFile= inputFile;
-		blockCache= new LRUCache(CACHE_SIZE);
-	}
-	/**
-	 * @see IndexInput#clearCache()
-	 */
-	public void clearCache() {
-		blockCache= new LRUCache(CACHE_SIZE);
-	}
-	/**
-	 * @see IndexInput#close()
-	 */
-	public void close() throws IOException {
-		if (opened) {
-			summary= null;
-			opened= false;
-			if (raf != null)
-				raf.close();
-		}
-	}
-	/**
-	 * @see IndexInput#getCurrentFile()
-	 */
-	public IndexedFile getCurrentFile() throws IOException {
-		if (!hasMoreFiles())
-			return null;
-		IndexedFile file= null;
-		if ((file= currentFileListBlock.getFile(filePosition)) == null) {
-			currentFileListBlockNum= summary.getBlockNumForFileNum(filePosition);
-			currentFileListBlock= getFileListBlock(currentFileListBlockNum);
-			file= currentFileListBlock.getFile(filePosition);
-		}
-		return file;
-	}
-	/**
-	 * Returns the entry corresponding to the given word.
-	 */
-	protected WordEntry getEntry(char[] word) throws IOException {
-		int blockNum= summary.getBlockNumForWord(word);
-		if (blockNum == -1) return null;
-		IndexBlock block= getIndexBlock(blockNum);
-		return block.findExactEntry(word);
-	}
-	/**
-	 * Returns the FileListBlock with the given number.
-	 */
-	protected FileListBlock getFileListBlock(int blockNum) throws IOException {
-		Integer key= new Integer(blockNum);
-		Block block= (Block) blockCache.get(key);
-		if (block != null && block instanceof FileListBlock)
-			return (FileListBlock) block;
-		FileListBlock fileListBlock= new FileListBlock(IIndexConstants.BLOCK_SIZE);
-		fileListBlock.read(raf, blockNum);
-		blockCache.put(key, fileListBlock);
-		return fileListBlock;
-	}
-	/**
-	 * Returns the IndexBlock (containing words) with the given number.
-	 */
-	protected IndexBlock getIndexBlock(int blockNum) throws IOException {
-		Integer key= new Integer(blockNum);
-		Block block= (Block) blockCache.get(key);
-		if (block != null && block instanceof IndexBlock)
-			return (IndexBlock) block;
-		IndexBlock indexBlock= new GammaCompressedIndexBlock(IIndexConstants.BLOCK_SIZE);
-		indexBlock.read(raf, blockNum);
-		blockCache.put(key, indexBlock);
-		return indexBlock;
-	}
-	/**
-	 * @see IndexInput#getIndexedFile(int)
-	 */
-	public IndexedFile getIndexedFile(int fileNum) throws IOException {
-		int blockNum= summary.getBlockNumForFileNum(fileNum);
-		if (blockNum == -1)
-			return null;
-		FileListBlock block= getFileListBlock(blockNum);
-		return block.getFile(fileNum);
-	}
-	/**
-	 * @see IndexInput#getIndexedFile(IDocument)
-	 */
-	public IndexedFile getIndexedFile(SearchDocument document) throws java.io.IOException {
-		setFirstFile();
-		String name= document.getPath();
-		while (hasMoreFiles()) {
-			IndexedFile file= getCurrentFile();
-			String path= file.getPath();
-			if (path.equals(name))
-				return file;
-			moveToNextFile();
-		}
-		return null;
-	}
-	/**
-	 * Returns the list of numbers of files containing the given word.
-	 */
-
-	protected int[] getMatchingFileNumbers(char[] word) throws IOException {
-		int blockNum= summary.getBlockNumForWord(word);
-		if (blockNum == -1)
-			return new int[0];
-		IndexBlock block= getIndexBlock(blockNum);
-		WordEntry entry= block.findExactEntry(word);
-		return entry == null ? new int[0] : entry.getRefs();
-	}
-	/**
-	 * @see IndexInput#getNumFiles()
-	 */
-	public int getNumFiles() {
-		return summary.getNumFiles();
-	}
-	/**
-	 * @see IndexInput#getNumWords()
-	 */
-	public int getNumWords() {
-		return summary.getNumWords();
-	}
-	/**
-	 * @see IndexInput#getSource()
-	 */
-	public Object getSource() {
-		return indexFile;
-	}
-	/**
-	 * Initialises the blocksIndexInput
-	 */
-	protected void init() throws IOException {
-		clearCache();
-		setFirstFile();
-		setFirstWord();
-	}
-	/**
-	 * @see IndexInput#moveToNextFile()
-	 */
-	public void moveToNextFile() {
-		filePosition++;
-	}
-	/**
-	 * @see IndexInput#moveToNextWordEntry()
-	 */
-	public void moveToNextWordEntry() throws IOException {
-		wordPosition++;
-		if (!hasMoreWords()) {
-			return;
-		}
-		//if end of the current block, we load the next one.
-		boolean endOfBlock= !currentIndexBlock.nextEntry(currentWordEntry);
-		if (endOfBlock) {
-			currentIndexBlock= getIndexBlock(++currentIndexBlockNum);
-			currentIndexBlock.nextEntry(currentWordEntry);
-		}
-	}
-	/**
-	 * @see IndexInput#open()
-	 */
-
-	public void open() throws IOException {
-		if (!opened) {
-			raf= new SafeRandomAccessFile(indexFile, "r"); //$NON-NLS-1$
-			String sig= raf.readUTF();
-			if (!sig.equals(IIndexConstants.SIGNATURE))
-				throw new IOException(Util.bind("exception.wrongFormat")); //$NON-NLS-1$
-			int summaryBlockNum= raf.readInt();
-			raf.seek(summaryBlockNum * (long) IIndexConstants.BLOCK_SIZE);
-			summary= new IndexSummary();
-			summary.read(raf);
-			init();
-			opened= true;
-		}
-	}
-	/**
-	 * @see IndexInput#query(String)
-	 */
-	public String[] query(String word) throws IOException {
-		open();
-		int[] fileNums= getMatchingFileNumbers(word.toCharArray());
-		int size= fileNums.length;
-		String[] paths= new String[size];
-		for (int i= 0; i < size; ++i) {
-			paths[i]= getIndexedFile(fileNums[i]).getPath();
-		}
-		return paths;
-	}
-	/**
-	 * If no prefix is provided in the pattern, then this operation will have to walk
-	 * all the entries of the whole index.
-	 */
-	public EntryResult[] queryEntriesMatching(char[] pattern/*, boolean isCaseSensitive*/) throws IOException {
-		open();
-	
-		if (pattern == null || pattern.length == 0) return null;
-		int[] blockNums = null;
-		int firstStar = CharOperation.indexOf('*', pattern);
-		switch (firstStar){
-			case -1 :
-				WordEntry entry = getEntry(pattern);
-				if (entry == null) return null;
-				return new EntryResult[]{ new EntryResult(entry.getWord(), entry.getRefs()) };
-			case 0 :
-				blockNums = summary.getAllBlockNums();
-				break;
-			default :
-				char[] prefix = CharOperation.subarray(pattern, 0, firstStar);
-				blockNums = summary.getBlockNumsForPrefix(prefix);
-		}
-		if (blockNums == null || blockNums.length == 0)	return null;
-				
-		EntryResult[] entries = new EntryResult[5];
-		int count = 0;
-		for (int i = 0, max = blockNums.length; i < max; i++) {
-			IndexBlock block = getIndexBlock(blockNums[i]);
-			block.reset();
-			boolean found = false;
-			WordEntry entry = new WordEntry();
-			while (block.nextEntry(entry)) {
-				if (CharOperation.match(entry.getWord(), pattern, true)) {
-					if (count == entries.length)
-						System.arraycopy(entries, 0, entries = new EntryResult[count*2], 0, count);
-					entries[count++] = new EntryResult(entry.getWord(), entry.getRefs());
-					found = true;
-				} else {
-					if (found) break;
-				}
-			}
-		}
-		if (count != entries.length)
-			System.arraycopy(entries, 0, entries = new EntryResult[count], 0, count);
-		return entries;
-	}
-	/* (non-Javadoc)
-	 * @see org.eclipse.jdt.internal.core.index.impl.IndexInput#queryEntries(char[], int)
-	 */
-	public EntryResult[] queryEntries(char[] pattern, int matchRule) throws IOException {
-		// TODO should evolve to provide different flavors of matching
-		return queryEntriesPrefixedBy(pattern);
-	}
-	public EntryResult[] queryEntriesPrefixedBy(char[] prefix) throws IOException {
-		open();
-		
-		int blockLoc = summary.getFirstBlockLocationForPrefix(prefix);
-		if (blockLoc < 0) return null;
-			
-		EntryResult[] entries = new EntryResult[5];
-		int count = 0;
-		while(blockLoc >= 0){
-			IndexBlock block = getIndexBlock(summary.getBlockNum(blockLoc));
-			block.reset();
-			boolean found = false;
-			WordEntry entry = new WordEntry();
-			while (block.nextEntry(entry)) {
-				if (CharOperation.prefixEquals(prefix, entry.getWord())) {
-					if (count == entries.length){
-						System.arraycopy(entries, 0, entries = new EntryResult[count*2], 0, count);
-					}
-					entries[count++] = new EntryResult(entry.getWord(), entry.getRefs());
-					found = true;
-				} else {
-					if (found) break;
-				}
-			}
-			/* consider next block ? */
-			blockLoc = summary.getNextBlockLocationForPrefix(prefix, blockLoc);				
-		}
-		if (count == 0) return null;
-		if (count != entries.length){
-			System.arraycopy(entries, 0, entries = new EntryResult[count], 0, count);
-		}
-		return entries;
-	}
-	public String[] queryFilesReferringToPrefix(char[] prefix) throws IOException {
-		open();
-		
-		int blockLoc = summary.getFirstBlockLocationForPrefix(prefix);
-		if (blockLoc < 0) return null;
-			
-		// each filename must be returned already once
-		org.eclipse.jdt.internal.compiler.util.HashtableOfInt fileMatches = new org.eclipse.jdt.internal.compiler.util.HashtableOfInt(20);
-		int count = 0; 
-		while(blockLoc >= 0){
-			IndexBlock block = getIndexBlock(summary.getBlockNum(blockLoc));
-			block.reset();
-			boolean found = false;
-			WordEntry entry = new WordEntry();
-			while (block.nextEntry(entry)) {
-				if (CharOperation.prefixEquals(prefix, entry.getWord()/*, isCaseSensitive*/)) {
-					int [] refs = entry.getRefs();
-					for (int i = 0, max = refs.length; i < max; i++){
-						int ref = refs[i];
-						if (!fileMatches.containsKey(ref)){
-							count++;
-							fileMatches.put(ref, getIndexedFile(ref));
-						}
-					}
-					found = true;
-				} else {
-					if (found) break;
-				}
-			}
-			/* consider next block ? */
-			blockLoc = summary.getNextBlockLocationForPrefix(prefix, blockLoc);				
-		}
-		/* extract indexed files */
-		String[] paths = new String[count];
-		Object[] indexedFiles = fileMatches.valueTable;
-		for (int i = 0, index = 0, max = indexedFiles.length; i < max; i++){
-			IndexedFile indexedFile = (IndexedFile) indexedFiles[i];
-			if (indexedFile != null){
-				paths[index++] = indexedFile.getPath();
-			}
-		}	
-		return paths;
-	}
-	/**
-	 * @see IndexInput#queryInDocumentNames(String)
-	 */
-	public String[] queryInDocumentNames(String word) throws IOException {
-		open();
-		ArrayList matches= new ArrayList();
-		setFirstFile();
-		while (hasMoreFiles()) {
-			IndexedFile file= getCurrentFile();
-			if (word == null || file.getPath().indexOf(word) != -1)
-				matches.add(file.getPath());
-			moveToNextFile();
-		}
-		String[] match= new String[matches.size()];
-		matches.toArray(match);
-		return match;
-	}
-	/**
-	 * @see IndexInput#setFirstFile()
-	 */
-
-	protected void setFirstFile() throws IOException {
-		filePosition= 1;
-		if (getNumFiles() > 0) {
-			currentFileListBlockNum= summary.getBlockNumForFileNum(1);
-			currentFileListBlock= getFileListBlock(currentFileListBlockNum);
-		}
-	}
-	/**
-	 * @see IndexInput#setFirstWord()
-	 */
-
-	protected void setFirstWord() throws IOException {
-		wordPosition= 1;
-		if (getNumWords() > 0) {
-			currentIndexBlockNum= summary.getFirstWordBlockNum();
-			currentIndexBlock= getIndexBlock(currentIndexBlockNum);
-			currentWordEntry= new WordEntry();
-			currentIndexBlock.reset();
-			currentIndexBlock.nextEntry(currentWordEntry);
-		}
-	}
-}
diff --git a/search/org/eclipse/jdt/internal/core/index/impl/BlocksIndexOutput.java b/search/org/eclipse/jdt/internal/core/index/impl/BlocksIndexOutput.java
deleted file mode 100644
index ce18d13..0000000
--- a/search/org/eclipse/jdt/internal/core/index/impl/BlocksIndexOutput.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-
-/**
- * A blocksIndexOutput is used to save an index in a file with the given structure:<br>
- *  - Signature of the file;<br>
- *  - FileListBlocks;<br>
- *  - IndexBlocks;<br>
- *  - Summary of the index.
- */
-
-public class BlocksIndexOutput extends IndexOutput {
-	protected RandomAccessFile indexOut;
-	protected int blockNum;
-	protected boolean opened= false;
-	protected File indexFile;
-	protected FileListBlock fileListBlock;
-	protected IndexBlock indexBlock;
-	protected int numWords= 0;
-	protected IndexSummary summary;
-	protected int numFiles= 0;
-	protected boolean firstInBlock;
-	protected boolean firstIndexBlock;
-	protected boolean firstFileListBlock;
-
-	public BlocksIndexOutput(File indexFile) {
-		this.indexFile= indexFile;
-		summary= new IndexSummary();
-		blockNum= 1;
-		firstInBlock= true;
-		firstIndexBlock= true;
-		firstFileListBlock= true;
-	}
-	/**
-	 * @see IndexOutput#addFile
-	 */
-	public void addFile(IndexedFile indexedFile) throws IOException {
-		if (firstFileListBlock) {
-			firstInBlock= true;
-			fileListBlock= new FileListBlock(IIndexConstants.BLOCK_SIZE);
-			firstFileListBlock= false;
-		}
-		if (fileListBlock.addFile(indexedFile)) {
-			if (firstInBlock) {
-				summary.addFirstFileInBlock(indexedFile, blockNum);
-				firstInBlock= false;
-			}
-			numFiles++;
-		} else {
-			if (fileListBlock.isEmpty()) {
-				return;
-			}
-			flushFiles();
-			addFile(indexedFile);
-		}
-	}
-	/**
-	 * @see IndexOutput#addWord
-	 */
-	public void addWord(WordEntry entry) throws IOException {
-		if (firstIndexBlock) {
-			indexBlock= new GammaCompressedIndexBlock(IIndexConstants.BLOCK_SIZE);
-			firstInBlock= true;
-			firstIndexBlock= false;
-		}
-		if (entry.getNumRefs() == 0)
-			return;
-		if (indexBlock.addEntry(entry)) {
-			if (firstInBlock) {
-				summary.addFirstWordInBlock(entry.getWord(), blockNum);
-				firstInBlock= false;
-			}
-			numWords++;
-		} else {
-			if (indexBlock.isEmpty()) {
-				return;
-			}
-			flushWords();
-			addWord(entry);
-		}
-	}
-	/**
-	 * @see IndexOutput#close
-	 */
-	public void close() throws IOException {
-		if (opened) {
-			indexOut.close();
-			summary= null;
-			numFiles= 0;
-			opened= false;
-		}
-	}
-	/**
-	 * @see IndexOutput#flush
-	 */
-	public void flush() throws IOException {
-		
-		summary.setNumFiles(numFiles);
-		summary.setNumWords(numWords);
-		indexOut.seek(blockNum * (long) IIndexConstants.BLOCK_SIZE);
-		summary.write(indexOut);
-		indexOut.seek(0);
-		indexOut.writeUTF(IIndexConstants.SIGNATURE);
-		indexOut.writeInt(blockNum);
-	}
-	/**
-	 * Writes the current fileListBlock on the disk and initialises it
-	 * (when it's full or it's the end of the index).
-	 */
-	protected void flushFiles() throws IOException {
-		if (!firstFileListBlock
-				&& fileListBlock != null) {
-			fileListBlock.flush();
-			fileListBlock.write(indexOut, blockNum++);
-			fileListBlock.clear();
-			firstInBlock= true;
-		}
-	}
-	/**
-	 * Writes the current indexBlock on the disk and initialises it
-	 * (when it's full or it's the end of the index).
-	 */
-	protected void flushWords() throws IOException {
-		if (!firstInBlock 
-				&& indexBlock != null) { // could have added a document without any indexed word, no block created yet
-			indexBlock.flush();
-			indexBlock.write(indexOut, blockNum++);
-			indexBlock.clear();
-			firstInBlock= true;
-		}
-	}
-	/**
-	 * @see IndexOutput#getDestination
-	 */
-	public Object getDestination() {
-		return indexFile;
-	}
-	/**
-	 * @see IndexOutput#open
-	 */
-	public void open() throws IOException {
-		if (!opened) {
-			summary= new IndexSummary();
-			numFiles= 0;
-			numWords= 0;
-			blockNum= 1;
-			firstInBlock= true;
-			firstIndexBlock= true;
-			firstFileListBlock= true;
-			indexOut= new SafeRandomAccessFile(this.indexFile, "rw"); //$NON-NLS-1$
-			opened= true;
-		}
-	}
-}
diff --git a/search/org/eclipse/jdt/internal/core/index/impl/CodeByteStream.java b/search/org/eclipse/jdt/internal/core/index/impl/CodeByteStream.java
deleted file mode 100644
index 27ddcdf..0000000
--- a/search/org/eclipse/jdt/internal/core/index/impl/CodeByteStream.java
+++ /dev/null
@@ -1,342 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.io.UTFDataFormatException;
-
-public class CodeByteStream {
-	protected byte[] bytes;
-	protected int byteOffset= 0;
-	protected int bitOffset= 0;
-	protected int markByteOffset= -1;
-	protected int markBitOffset= -1;
-
-	public CodeByteStream() {
-		this(16);
-	}
-	public CodeByteStream(byte[] bytes) {
-		this.bytes= bytes;
-	}
-	public CodeByteStream(int initialByteLength) {
-		bytes= new byte[initialByteLength];
-	}
-	public int byteLength() {
-		return (bitOffset + 7) / 8 + byteOffset;
-	}
-	public byte[] getBytes(int startOffset, int endOffset) {
-		int byteLength= byteLength();
-		if (startOffset > byteLength || endOffset > byteLength || startOffset > endOffset)
-			throw new IndexOutOfBoundsException();
-		int length= endOffset - startOffset;
-		byte[] result= new byte[length];
-		System.arraycopy(bytes, startOffset, result, 0, length);
-		if (endOffset == byteLength && bitOffset != 0) {
-			int mask= (1 << bitOffset) - 1;
-			result[length - 1] &= (mask << 8 - bitOffset);
-		}
-		return result;
-	}
-	protected void grow() {
-		byte[] newBytes= new byte[bytes.length * 2 + 1];
-		System.arraycopy(bytes, 0, newBytes, 0, bytes.length);
-		bytes= newBytes;
-	}
-	public void mark() {
-		markByteOffset= byteOffset;
-		markBitOffset= bitOffset;
-	}
-	/**
-	 * Reads a single bit (value == 0 or == 1).
-	 */
-	public int readBit() {
-		int value= (bytes[byteOffset] >> (7 - bitOffset)) & 1;
-		if (++bitOffset >= 8) {
-			bitOffset= 0;
-			++byteOffset;
-		}
-		return value;
-	}
-	/**
-	 * Read up to 32 bits from the stream.
-	 */
-	public int readBits(int numBits) {
-		int value= 0;
-		while (numBits > 0) {
-			int bitsToRead= 8 - bitOffset;
-			if (bitsToRead > numBits)
-				bitsToRead= numBits;
-			int mask= (1 << bitsToRead) - 1;
-			value |= ((bytes[byteOffset] >> (8 - bitOffset - bitsToRead)) & mask) << (numBits - bitsToRead);
-			numBits -= bitsToRead;
-			bitOffset += bitsToRead;
-			if (bitOffset >= 8) {
-				bitOffset -= 8;
-				byteOffset += 1;
-			}
-		}
-		return value;
-	}
-	public final int readByte() {
-
-		// no need to rebuild byte value from bit sequences
-		if (bitOffset == 0) return bytes[byteOffset++] & 255;
-	
-		int value= 0;
-		int numBits = 8;
-		while (numBits > 0) {
-			int bitsToRead= 8 - bitOffset;
-			if (bitsToRead > numBits)
-				bitsToRead= numBits;
-			int mask= (1 << bitsToRead) - 1;
-			value |= ((bytes[byteOffset] >> (8 - bitOffset - bitsToRead)) & mask) << (numBits - bitsToRead);
-			numBits -= bitsToRead;
-			bitOffset += bitsToRead;
-			if (bitOffset >= 8) {
-				bitOffset -= 8;
-				byteOffset += 1;
-			}
-		}
-		return value;
-	}
-	/**
-	 * Reads a value using Gamma coding.
-	 */
-	public int readGamma() {
-		int numBits= readUnary();
-		return readBits(numBits - 1) | (1 << (numBits - 1));
-	}
-	public char[] readUTF() throws UTFDataFormatException {
-		int utflen= readByte();
-		if (utflen == 255) {
-			// long UTF
-			int high = readByte();
-			int low = readByte();
-			utflen = (high << 8) + low;
-		}
-		char str[]= new char[utflen];
-		int count= 0;
-		int strlen= 0;
-		while (count < utflen) {
-			int c= readByte();
-			int char2, char3;
-			switch (c >> 4) {
-				case 0 :
-				case 1 :
-				case 2 :
-				case 3 :
-				case 4 :
-				case 5 :
-				case 6 :
-				case 7 :
-					// 0xxxxxxx
-					count++;
-					str[strlen++]= (char) c;
-					break;
-				case 12 :
-				case 13 :
-					// 110x xxxx   10xx xxxx
-					count += 2;
-					if (count > utflen)
-						throw new UTFDataFormatException();
-					char2= readByte();
-					if ((char2 & 0xC0) != 0x80)
-						throw new UTFDataFormatException();
-					str[strlen++]= (char) (((c & 0x1F) << 6) | (char2 & 0x3F));
-					break;
-				case 14 :
-					// 1110 xxxx  10xx xxxx  10xx xxxx
-					count += 3;
-					if (count > utflen)
-						throw new UTFDataFormatException();
-					char2= readByte();
-					char3= readByte();
-					if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
-						throw new UTFDataFormatException();
-					str[strlen++]= (char) (((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0));
-					break;
-				default :
-					// 10xx xxxx,  1111 xxxx
-					throw new UTFDataFormatException();
-			}
-		}
-		if (strlen < utflen)
-			System.arraycopy(str, 0, str= new char[strlen], 0, strlen);
-		return str;
-	}
-	/**
-	 *  Reads a value in unary.
-	 */
-	public int readUnary() {
-		int value= 1;
-		int mask= 1 << (7 - bitOffset);
-		while ((bytes[byteOffset] & mask) != 0) {
-			++value;
-			if (++bitOffset >= 8) {
-				bitOffset= 0;
-				++byteOffset;
-				mask= 0x80;
-			} else {
-				mask >>>= 1;
-			}
-		}
-		// skip the 0 bit
-		if (++bitOffset >= 8) {
-			bitOffset= 0;
-			++byteOffset;
-		}
-		return value;
-	}
-	public void reset() {
-		byteOffset= bitOffset= 0;
-		markByteOffset= markBitOffset= -1;
-	}
-	public void reset(byte[] bytesValue) {
-		this.bytes= bytesValue;
-		reset();
-	}
-	public void reset(byte[] bytesValue, int byteOffsetValue) {
-		reset(bytesValue);
-		this.byteOffset= byteOffsetValue;
-	}
-	public boolean resetToMark() {
-		if (markByteOffset == -1)
-			return false;
-		byteOffset= markByteOffset;
-		bitOffset= markBitOffset;
-		markByteOffset= markBitOffset= -1;
-		return true;
-	}
-	public void skipBits(int numBits) {
-		int newOffset= byteOffset * 8 + bitOffset + numBits;
-		if (newOffset < 0 || (newOffset + 7) / 8 >= bytes.length)
-			throw new IllegalArgumentException();
-		byteOffset= newOffset / 8;
-		bitOffset= newOffset % 8;
-	}
-	public byte[] toByteArray() {
-		return getBytes(0, byteLength());
-	}
-	/**
-	 * Writes a single bit (value == 0 or == 1).
-	 */
-	public void writeBit(int value) {
-		bytes[byteOffset] |= (value & 1) << (7 - bitOffset);
-		if (++bitOffset >= 8) {
-			bitOffset= 0;
-			if (++byteOffset >= bytes.length)
-				grow();
-		}
-	}
-	/**
-	 * Write up to 32 bits to the stream.
-	 * The least significant numBits bits of value are written.
-	 */
-	public void writeBits(int value, int numBits) {
-		while (numBits > 0) {
-			int bitsToWrite= 8 - bitOffset;
-			if (bitsToWrite > numBits)
-				bitsToWrite= numBits;
-			int shift= 8 - bitOffset - bitsToWrite;
-			int mask= ((1 << bitsToWrite) - 1) << shift;
-			bytes[byteOffset]= (byte) ((bytes[byteOffset] & ~mask) | (((value >>> (numBits - bitsToWrite)) << shift) & mask));
-			numBits -= bitsToWrite;
-			bitOffset += bitsToWrite;
-			if (bitOffset >= 8) {
-				bitOffset -= 8;
-				if (++byteOffset >= bytes.length)
-					grow();
-			}
-		}
-	}
-	public void writeByte(int value) {
-		writeBits(value, 8);
-	}
-	/**
-	 * Writes the given value using Gamma coding, in which positive integer x
-	 * is represented by coding floor(log2(x) in unary followed by the value 
-	 * of x - 2**floor(log2(x)) in binary.
-	 * The value must be >= 1.
-	 */
-	public void writeGamma(int value) {
-		if (value < 1)
-			throw new IllegalArgumentException();
-		int temp= value;
-		int numBits= 0;
-		while (temp != 0) {
-			temp >>>= 1;
-			++numBits;
-		}
-		writeUnary(numBits);
-		writeBits(value, numBits - 1);
-	}
-	public void writeUTF(char[] str, int start, int end) {
-		int utflen= 0;
-		for (int i= start; i < end; i++) {
-			int c= str[i];
-			if ((c >= 0x0001) && (c <= 0x007F)) {
-				utflen++;
-			} else if (c > 0x07FF) {
-				utflen += 3;
-			} else {
-				utflen += 2;
-			}
-		}
-		if (utflen < 255) {
-			writeByte(utflen & 0xFF);
-		} else if (utflen > 65535) {
-			throw new IllegalArgumentException();
-		} else {
-			writeByte(255); // marker for long UTF
-			writeByte((utflen >>> 8) & 0xFF); // high byte
-			writeByte((utflen >>> 0) & 0xFF); // low byte
-		}
-		for (int i= start; i < end; i++) {
-			int c= str[i];
-			if ((c >= 0x0001) && (c <= 0x007F)) {
-				writeByte(c);
-			} else if (c > 0x07FF) {
-				writeByte(0xE0 | ((c >> 12) & 0x0F));
-				writeByte(0x80 | ((c >> 6) & 0x3F));
-				writeByte(0x80 | ((c >> 0) & 0x3F));
-			} else {
-				writeByte(0xC0 | ((c >> 6) & 0x1F));
-				writeByte(0x80 | ((c >> 0) & 0x3F));
-			}
-		}
-	}
-	/**
-	 * Write the given value in unary.  The value must be >= 1.
-	 */
-	public void writeUnary(int value) {
-		if (value < 1)
-			throw new IllegalArgumentException();
-		int mask= 1 << (7 - bitOffset);
-		// write N-1 1-bits
-		while (--value > 0) {
-			bytes[byteOffset] |= mask;
-			if (++bitOffset >= 8) {
-				bitOffset= 0;
-				if (++byteOffset >= bytes.length)
-					grow();
-				mask= 0x80;
-			} else {
-				mask >>>= 1;
-			}
-		}
-		// write a 0-bit
-		bytes[byteOffset] &= ~mask;
-		if (++bitOffset >= 8) {
-			bitOffset= 0;
-			if (++byteOffset >= bytes.length)
-				grow();
-		}
-	}
-}
diff --git a/search/org/eclipse/jdt/internal/core/index/impl/Field.java b/search/org/eclipse/jdt/internal/core/index/impl/Field.java
deleted file mode 100644
index b38e580..0000000
--- a/search/org/eclipse/jdt/internal/core/index/impl/Field.java
+++ /dev/null
@@ -1,380 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.io.UTFDataFormatException;
-
-public class Field {
-	protected byte[] buffer; // contents
-	protected int offset; // offset of the field within the byte array
-	protected int length; // length of the field
-
-	/**
-	 * ByteSegment constructor comment.
-	 */
-	public Field(byte[] bytes) {
-		this.buffer= bytes;
-		this.offset= 0;
-		this.length= bytes.length;
-	}
-	/**
-	 * ByteSegment constructor comment.
-	 */
-	public Field(byte[] bytes, int length) {
-		this.buffer= bytes;
-		this.offset= 0;
-		this.length= length;
-	}
-	/**
-	 * ByteSegment constructor comment.
-	 */
-	public Field(byte[] bytes, int offset, int length) {
-		this.buffer= bytes;
-		this.offset= offset;
-		this.length= length;
-	}
-	/**
-	 * Creates a new field containing an empty buffer of the given length.
-	 */
-	public Field(int length) {
-		this.buffer= new byte[length];
-		this.offset= 0;
-		this.length= length;
-	}
-	public byte[] buffer() {
-		return buffer;
-	}
-	public Field buffer(byte[] someBuffer) {
-		this.buffer= someBuffer;
-		return this;
-	}
-	public Field clear() {
-		clear(buffer, offset, length);
-		return this;
-	}
-	protected static void clear(byte[] buffer, int offset, int length) {
-		int n= offset;
-		for (int i= 0; i < length; i++) {
-			buffer[n]= 0;
-			n++;
-		}
-	}
-	public Field clear(int someLength) {
-		clear(buffer, offset, someLength);
-		return this;
-	}
-	public Field clear(int someOffset, int someLength) {
-		clear(buffer, this.offset + someOffset, someLength);
-		return this;
-	}
-	protected static int compare(byte[] buffer1, int offset1, int length1, byte[] buffer2, int offset2, int length2) {
-		int n= Math.min(length1, length2);
-		for (int i= 0; i < n; i++) {
-			int j1= buffer1[offset1 + i] & 255;
-			int j2= buffer2[offset2 + i] & 255;
-			if (j1 > j2)
-				return 1;
-			if (j1 < j2)
-				return -1;
-		}
-		if (length1 > n) {
-			for (int i= n; i < length1; i++)
-				if (buffer1[offset1 + i] != 0)
-					return 1;
-			return 0;
-		}
-		for (int i= n; i < length2; i++)
-			if (buffer2[offset2 + i] != 0)
-				return -1;
-		return 0;
-	}
-	public static int compare(Field f1, Field f2) {
-		return compare(f1.buffer, f1.offset, f1.length, f2.buffer, f2.offset, f2.length);
-	}
-	// copy bytes from one offset to another within the field
-	public Field copy(int fromOffset, int toOffset, int someLength) {
-		System.arraycopy(buffer, offset + fromOffset, buffer, offset + toOffset, someLength);
-		return this;
-	}
-	public Field dec(int n) {
-		offset -= n;
-		return this;
-	}
-	public byte[] get() {
-		byte[] result= new byte[length];
-		System.arraycopy(buffer, offset, result, 0, length);
-		return result;
-	}
-	public byte[] get(int someOffset, int someLength) {
-		byte[] result= new byte[someLength];
-		System.arraycopy(buffer, this.offset + someOffset, result, 0, someLength);
-		return result;
-	}
-	public Field getField(int someOffset, int someLength) {
-		return new Field(buffer, this.offset + someOffset, someLength);
-	}
-	public int getInt1() {
-		return buffer[this.offset];
-	}
-	public int getInt1(int someOffset) {
-		return buffer[this.offset + someOffset];
-	}
-	public int getInt2() {
-		int i= this.offset;
-		int v= buffer[i++];
-		v= (v << 8) | (buffer[i++] & 255);
-		return v;
-	}
-	public int getInt2(int someOffset) {
-		int i= this.offset + someOffset;
-		int v= buffer[i++];
-		v= (v << 8) | (buffer[i++] & 255);
-		return v;
-	}
-	public int getInt3() {
-		int i= this.offset;
-		int v= buffer[i++];
-		v= (v << 8) | (buffer[i++] & 255);
-		v= (v << 8) | (buffer[i++] & 255);
-		return v;
-	}
-	public int getInt3(int someOffset) {
-		int i= this.offset + someOffset;
-		int v= buffer[i++];
-		v= (v << 8) | (buffer[i++] & 255);
-		v= (v << 8) | (buffer[i++] & 255);
-		return v;
-	}
-	public int getInt4() {
-		int i= this.offset;
-		int v= buffer[i++];
-		v= (v << 8) | (buffer[i++] & 255);
-		v= (v << 8) | (buffer[i++] & 255);
-		v= (v << 8) | (buffer[i++] & 255);
-		return v;
-	}
-	public int getInt4(int someOffset) {
-		int i= this.offset + someOffset;
-		int v= buffer[i++];
-		v= (v << 8) | (buffer[i++] & 255);
-		v= (v << 8) | (buffer[i++] & 255);
-		v= (v << 8) | (buffer[i++] & 255);
-		return v;
-	}
-	public int getUInt1() {
-		return buffer[this.offset] & 255;
-	}
-	public int getUInt1(int someOffset) {
-		return buffer[this.offset + someOffset] & 255;
-	}
-	public int getUInt2() {
-		int i= this.offset;
-		int v= (buffer[i++] & 255);
-		v= (v << 8) | (buffer[i++] & 255);
-		return v;
-	}
-	public int getUInt2(int someOffset) {
-		int i= this.offset + someOffset;
-		int v= (buffer[i++] & 255);
-		v= (v << 8) | (buffer[i++] & 255);
-		return v;
-	}
-	public int getUInt3() {
-		int i= this.offset;
-		int v= (buffer[i++] & 255);
-		v= (v << 8) | (buffer[i++] & 255);
-		v= (v << 8) | (buffer[i++] & 255);
-		return v;
-	}
-	public int getUInt3(int someOffset) {
-		int i= this.offset + someOffset;
-		int v= (buffer[i++] & 255);
-		v= (v << 8) | (buffer[i++] & 255);
-		v= (v << 8) | (buffer[i++] & 255);
-		return v;
-	}
-	public char[] getUTF(int someOffset) throws UTFDataFormatException {
-		int pos= this.offset + someOffset;
-		int utflen= getUInt2(pos);
-		pos += 2;
-		char str[]= new char[utflen];
-		int count= 0;
-		int strlen= 0;
-		while (count < utflen) {
-			int c= buffer[pos++] & 0xFF;
-			int char2, char3;
-			switch (c >> 4) {
-				case 0 :
-				case 1 :
-				case 2 :
-				case 3 :
-				case 4 :
-				case 5 :
-				case 6 :
-				case 7 :
-					// 0xxxxxxx
-					count++;
-					str[strlen++]= (char) c;
-					break;
-				case 12 :
-				case 13 :
-					// 110x xxxx   10xx xxxx
-					count += 2;
-					if (count > utflen)
-						throw new UTFDataFormatException();
-					char2= buffer[pos++] & 0xFF;
-					if ((char2 & 0xC0) != 0x80)
-						throw new UTFDataFormatException();
-					str[strlen++]= (char) (((c & 0x1F) << 6) | (char2 & 0x3F));
-					break;
-				case 14 :
-					// 1110 xxxx  10xx xxxx  10xx xxxx
-					count += 3;
-					if (count > utflen)
-						throw new UTFDataFormatException();
-					char2= buffer[pos++] & 0xFF;
-					char3= buffer[pos++] & 0xFF;
-					if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
-						throw new UTFDataFormatException();
-					str[strlen++]= (char) (((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0));
-					break;
-				default :
-					// 10xx xxxx,  1111 xxxx
-					throw new UTFDataFormatException();
-			}
-		}
-		if (strlen < utflen)
-			System.arraycopy(str, 0, str= new char[strlen], 0, strlen);
-		return str;
-	}
-	public Field inc(int n) {
-		offset += n;
-		return this;
-	}
-	public int length() {
-		return length;
-	}
-	public Field length(int someLength) {
-		this.length= someLength;
-		return this;
-	}
-	/**
-	Returns the offset into the underlying byte array that this field is defined over.
-	*/
-	public int offset() {
-		return offset;
-	}
-	public Field offset(int someOffset) {
-		this.offset= someOffset;
-		return this;
-	}
-	public Field pointTo(int someOffset) {
-		return new Field(buffer, this.offset + someOffset, 0);
-	}
-	public Field put(byte[] b) {
-		return put(0, b);
-	}
-	public Field put(int someOffset, byte[] b) {
-		System.arraycopy(b, 0, buffer, this.offset + someOffset, b.length);
-		return this;
-	}
-	public Field put(int someOffset, Field f) {
-		System.arraycopy(f.buffer, f.offset, buffer, this.offset + someOffset, f.length);
-		return this;
-	}
-	public Field put(Field f) {
-		System.arraycopy(f.buffer, f.offset, buffer, offset, f.length);
-		return this;
-	}
-	public Field putInt1(int n) {
-		buffer[offset]= (byte) (n);
-		return this;
-	}
-	public Field putInt1(int someOffset, int n) {
-		buffer[this.offset + someOffset]= (byte) (n);
-		return this;
-	}
-	public Field putInt2(int n) {
-		int i= offset;
-		buffer[i++]= (byte) (n >> 8);
-		buffer[i++]= (byte) (n >> 0);
-		return this;
-	}
-	public Field putInt2(int someOffset, int n) {
-		int i= this.offset + someOffset;
-		buffer[i++]= (byte) (n >> 8);
-		buffer[i++]= (byte) (n >> 0);
-		return this;
-	}
-	public Field putInt3(int n) {
-		int i= offset;
-		buffer[i++]= (byte) (n >> 16);
-		buffer[i++]= (byte) (n >> 8);
-		buffer[i++]= (byte) (n >> 0);
-		return this;
-	}
-	public Field putInt3(int someOffset, int n) {
-		int i= this.offset + someOffset;
-		buffer[i++]= (byte) (n >> 16);
-		buffer[i++]= (byte) (n >> 8);
-		buffer[i++]= (byte) (n >> 0);
-		return this;
-	}
-	public Field putInt4(int n) {
-		int i= offset;
-		buffer[i++]= (byte) (n >> 24);
-		buffer[i++]= (byte) (n >> 16);
-		buffer[i++]= (byte) (n >> 8);
-		buffer[i++]= (byte) (n >> 0);
-		return this;
-	}
-	public Field putInt4(int someOffset, int n) {
-		int i= this.offset + someOffset;
-		buffer[i++]= (byte) (n >> 24);
-		buffer[i++]= (byte) (n >> 16);
-		buffer[i++]= (byte) (n >> 8);
-		buffer[i++]= (byte) (n >> 0);
-		return this;
-	}
-	public int putUTF(int someOffset, char[] str) {
-		int strlen= str.length;
-		int utflen= 0;
-		for (int i= 0; i < strlen; i++) {
-			int c= str[i];
-			if ((c >= 0x0001) && (c <= 0x007F)) {
-				utflen++;
-			} else if (c > 0x07FF) {
-				utflen += 3;
-			} else {
-				utflen += 2;
-			}
-		}
-		if (utflen > 65535)
-			throw new IllegalArgumentException();
-		int pos= this.offset + someOffset;
-		buffer[pos++]= (byte) ((utflen >>> 8) & 0xFF);
-		buffer[pos++]= (byte) ((utflen >>> 0) & 0xFF);
-		for (int i= 0; i < strlen; i++) {
-			int c= str[i];
-			if ((c >= 0x0001) && (c <= 0x007F)) {
-				buffer[pos++]= ((byte) c);
-			} else if (c > 0x07FF) {
-				buffer[pos++]= ((byte) (0xE0 | ((c >> 12) & 0x0F)));
-				buffer[pos++]= ((byte) (0x80 | ((c >> 6) & 0x3F)));
-				buffer[pos++]= ((byte) (0x80 | ((c >> 0) & 0x3F)));
-			} else {
-				buffer[pos++]= ((byte) (0xC0 | ((c >> 6) & 0x1F)));
-				buffer[pos++]= ((byte) (0x80 | ((c >> 0) & 0x3F)));
-			}
-		}
-		return 2 + utflen;
-	}
-}
diff --git a/search/org/eclipse/jdt/internal/core/index/impl/FileListBlock.java b/search/org/eclipse/jdt/internal/core/index/impl/FileListBlock.java
deleted file mode 100644
index b271e7d..0000000
--- a/search/org/eclipse/jdt/internal/core/index/impl/FileListBlock.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.io.IOException;
-import java.util.ArrayList;
-
-import org.eclipse.jdt.internal.core.util.Util;
-
-public class FileListBlock extends Block {
-
-	protected int offset= 0;
-	protected String prevPath= null;
-	protected String[] paths= null;
-
-	public FileListBlock(int blockSize) {
-		super(blockSize);
-	}
-	/**
-	 * add the name of the indexedfile to the buffr of the field. 
-	 * The name is not the entire name of the indexedfile, but the 
-	 * difference between its name and the name of the previous indexedfile ...	
-	 */
-	public boolean addFile(IndexedFile indexedFile) {
-		int currentOffset= this.offset;
-		if (isEmpty()) {
-			field.putInt4(currentOffset, indexedFile.getFileNumber());
-			currentOffset += 4;
-		}
-		String path= indexedFile.getPath();
-		int prefixLen= prevPath == null ? 0 : Util.prefixLength(prevPath, path);
-		int sizeEstimate= 2 + 2 + (path.length() - prefixLen) * 3;
-		if (currentOffset + sizeEstimate > blockSize - 2)
-			return false;
-		field.putInt2(currentOffset, prefixLen);
-		currentOffset += 2;
-		char[] chars= new char[path.length() - prefixLen];
-		path.getChars(prefixLen, path.length(), chars, 0);
-		currentOffset += field.putUTF(currentOffset, chars);
-		this.offset= currentOffset;
-		prevPath= path;
-		return true;
-	}
-	public void clear() {
-		reset();
-		super.clear();
-	}
-	public void flush() {
-		if (offset > 0) {
-			field.putInt2(offset, 0);
-			field.putInt2(offset + 2, 0);
-			offset= 0;
-		}
-	}
-	public IndexedFile getFile(int fileNum) {
-		IndexedFile resp= null;
-		try {
-			String[] currentPaths = getPaths();
-			int i= fileNum - field.getInt4(0);
-			resp= new IndexedFile(currentPaths[i], fileNum);
-		} catch (Exception e) {
-			//fileNum too big
-		}
-		return resp;
-	}
-	/**
-	 * Creates a vector of paths reading the buffer of the field.
-	 */
-	protected String[] getPaths() throws IOException {
-		if (paths == null) {
-			ArrayList v= new ArrayList();
-			int currentOffset = 4;
-			char[] previousPath = null;
-			for (;;) {
-				int prefixLen= field.getUInt2(currentOffset);
-				currentOffset += 2;
-				int utfLen= field.getUInt2(currentOffset);
-				char[] path= field.getUTF(currentOffset);
-				currentOffset += 2 + utfLen;
-				if (prefixLen != 0) {
-					char[] temp= new char[prefixLen + path.length];
-					System.arraycopy(previousPath, 0, temp, 0, prefixLen);
-					System.arraycopy(path, 0, temp, prefixLen, path.length);
-					path= temp;
-				}
-				if (path.length == 0)
-					break;
-				v.add(new String(path));
-				previousPath= path;
-			}
-			paths= new String[v.size()];
-			v.toArray(paths);
-		}
-		return paths;
-	}
-	public boolean isEmpty() {
-		return offset == 0;
-	}
-	public void reset() {
-		offset= 0;
-		prevPath= null;
-	}
-}
diff --git a/search/org/eclipse/jdt/internal/core/index/impl/GammaCompressedIndexBlock.java b/search/org/eclipse/jdt/internal/core/index/impl/GammaCompressedIndexBlock.java
deleted file mode 100644
index b55ee3b..0000000
--- a/search/org/eclipse/jdt/internal/core/index/impl/GammaCompressedIndexBlock.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.io.UTFDataFormatException;
-
-import org.eclipse.jdt.internal.core.util.Util;
-
-/**
- * Uses prefix coding on words, and gamma coding of document numbers differences.
- */
-public class GammaCompressedIndexBlock extends IndexBlock {
-	CodeByteStream writeCodeStream= new CodeByteStream();
-	CodeByteStream readCodeStream;
-	char[] prevWord= null;
-	int offset= 0;
-
-	public GammaCompressedIndexBlock(int blockSize) {
-		super(blockSize);
-		readCodeStream= new CodeByteStream(field.buffer());
-	}
-	/**
-	 * @see IndexBlock#addEntry
-	 */
-	public boolean addEntry(WordEntry entry) {
-		writeCodeStream.reset();
-		encodeEntry(entry);
-		if (offset + writeCodeStream.byteLength() > this.blockSize - 2) {
-			return false;
-		}
-		byte[] bytes= writeCodeStream.toByteArray();
-		field.put(offset, bytes);
-		offset += bytes.length;
-		prevWord= entry.getWord();
-		return true;
-	}
-	private void encodeEntry(WordEntry entry) {
-		char[] word= entry.getWord();
-		int prefixLen= prevWord == null ? 0 : Util.prefixLength(prevWord, word);
-		writeCodeStream.writeByte(prefixLen);
-		writeCodeStream.writeUTF(word, prefixLen, word.length);
-		int n= entry.getNumRefs();
-		writeCodeStream.writeGamma(n);
-		int prevRef= 0;
-		for (int i= 0; i < n; ++i) {
-			int ref= entry.getRef(i);
-			if (ref <= prevRef)
-				throw new IllegalArgumentException();
-			writeCodeStream.writeGamma(ref - prevRef);
-			prevRef= ref;
-		}
-	}
-	/**
-	 * @see IndexBlock#flush
-	 */
-	public void flush() {
-		if (offset > 0) {
-			field.putInt2(offset, 0);
-			offset= 0;
-			prevWord= null;
-		}
-	}
-	/**
-	 * @see IndexBlock#isEmpty
-	 */
-	public boolean isEmpty() {
-		return offset == 0;
-	}
-	/**
-	 * @see IndexBlock#nextEntry
-	 */
-	public boolean nextEntry(WordEntry entry) {
-		try {
-			readCodeStream.reset(field.buffer(), offset);
-			int prefixLength= readCodeStream.readByte();
-			char[] word= readCodeStream.readUTF();
-			if (prevWord != null && prefixLength > 0) {
-				char[] temp= new char[prefixLength + word.length];
-				System.arraycopy(prevWord, 0, temp, 0, prefixLength);
-				System.arraycopy(word, 0, temp, prefixLength, word.length);
-				word= temp;
-			}
-			if (word.length == 0) {
-				return false;
-			}
-			entry.reset(word);
-			int n= readCodeStream.readGamma();
-			int prevRef= 0;
-			for (int i= 0; i < n; ++i) {
-				int ref= prevRef + readCodeStream.readGamma();
-				if (ref < prevRef)
-					throw new InternalError();
-				entry.addRef(ref);
-				prevRef= ref;
-			}
-			offset= readCodeStream.byteLength();
-			prevWord= word;
-			return true;
-		} catch (UTFDataFormatException e) {
-			return false;
-		}
-	}
-	/**
-	 * @see IndexBlock#reset
-	 */
-	public void reset() {
-		super.reset();
-		offset= 0;
-		prevWord= null;
-	}
-}
diff --git a/search/org/eclipse/jdt/internal/core/index/impl/ICacheEnumeration.java b/search/org/eclipse/jdt/internal/core/index/impl/ICacheEnumeration.java
deleted file mode 100644
index 75a269a..0000000
--- a/search/org/eclipse/jdt/internal/core/index/impl/ICacheEnumeration.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.util.Enumeration;
-
-/**
- * The <code>ICacheEnumeration</code> is used to iterate over both the keys 
- * and values in an LRUCache.  The <code>getValue()</code> method returns the 
- * value of the last key to be retrieved using <code>nextElement()</code>.  
- * The <code>nextElement()</code> method must be called before the 
- * <code>getValue()</code> method.
- *
- * <p>The iteration can be made efficient by making use of the fact that values in 
- * the cache (instances of <code>LRUCacheEntry</code>), know their key.  For this reason,
- * Hashtable lookups don't have to be made at each step of the iteration.
- *
- * <p>Modifications to the cache must not be performed while using the
- * enumeration.  Doing so will lead to an illegal state.
- *
- * @see LRUCache
- */
-public interface ICacheEnumeration extends Enumeration {
-	/**
-	 * Returns the value of the previously accessed key in the enumeration.
-	 * Must be called after a call to nextElement().
-	 *
-	 * @return Value of current cache entry
-	 */
-	public Object getValue();
-}
diff --git a/search/org/eclipse/jdt/internal/core/index/impl/IIndexConstants.java b/search/org/eclipse/jdt/internal/core/index/impl/IIndexConstants.java
deleted file mode 100644
index 67d6545..0000000
--- a/search/org/eclipse/jdt/internal/core/index/impl/IIndexConstants.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-/**
- * This interface provides constants used by the search engine.
- */
-public interface IIndexConstants {
-	/**
-	 * The signature of the index file.
-	 */
-	public static final String SIGNATURE= "INDEX FILE 0.017"; //$NON-NLS-1$
-	/**
-	 * The separator for files in the index file.
-	 */
-	public static final char FILE_SEPARATOR= '/';
-	/**
-	 * The size of a block for a <code>Block</code>.
-	 */
-	public static final int BLOCK_SIZE= 8192;
-}
diff --git a/search/org/eclipse/jdt/internal/core/index/impl/ILRUCacheable.java b/search/org/eclipse/jdt/internal/core/index/impl/ILRUCacheable.java
deleted file mode 100644
index 69a7157..0000000
--- a/search/org/eclipse/jdt/internal/core/index/impl/ILRUCacheable.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-/**
- * Types implementing this interface can occupy a variable amount of space
- * in an LRUCache.  Cached items that do not implement this interface are
- * considered to occupy one unit of space.
- *
- * @see LRUCache
- */
-public interface ILRUCacheable {
-	/**
-	 * Returns the space the receiver consumes in an LRU Cache.  The default space
-	 * value is 1.
-	 *
-	 * @return int Amount of cache space taken by the receiver
-	 */
-	public int getCacheFootprint();
-}
diff --git a/search/org/eclipse/jdt/internal/core/index/impl/InMemoryIndex.java b/search/org/eclipse/jdt/internal/core/index/impl/InMemoryIndex.java
deleted file mode 100644
index 57c9dfb..0000000
--- a/search/org/eclipse/jdt/internal/core/index/impl/InMemoryIndex.java
+++ /dev/null
@@ -1,206 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.io.File;
-import java.io.IOException;
-
-import org.eclipse.jdt.core.search.SearchDocument;
-import org.eclipse.jdt.internal.core.util.Util;
-
-/**
- * This index stores the document names in an <code>ObjectVector</code>, and the words in
- * an <code>HashtableOfObjects</code>.
- */
-
-public class InMemoryIndex {
-
-	/**
-	 * hashtable of WordEntrys = words+numbers of the files they appear in.
-	 */
-	protected WordEntryHashedArray words;
-
-	/**
-	 * List of IndexedFiles = file name + a unique number.
-	 */
-	protected IndexedFileHashedArray files;
-
-	/**
-	 * Size of the index.
-	 */
-	protected long footprint;
-
-	private WordEntry[] sortedWordEntries;
-	private IndexedFile[] sortedFiles;
-	public InMemoryIndex() {
-		init();
-	}
-
-	public IndexedFile addDocument(SearchDocument document) {
-		IndexedFile indexedFile= this.files.add(document);
-		this.footprint += indexedFile.footprint() + 4;
-		this.sortedFiles = null;
-		return indexedFile;
-	}
-	/**
-	 * Adds the references of the word to the index (reference = number of the file the word belongs to).
-	 */
-	protected void addRef(char[] word, int[] references) {
-		int size= references.length;
-		int i= 0;
-		while (i < size) {
-			if (references[i] != 0)
-				addRef(word, references[i]);
-			i++;
-		}
-	}
-	/**
-	 * Looks if the word already exists in the index and add the fileNum to this word.
-	 * If the word does not exist, it adds it in the index.
-	 */
-	protected void addRef(char[] word, int fileNum) {
-		WordEntry entry= this.words.get(word);
-		if (entry == null) {
-			entry= new WordEntry(word);
-			entry.addRef(fileNum);
-			this.words.add(entry);
-			this.sortedWordEntries= null;
-			this.footprint += entry.footprint();
-		} else {
-			this.footprint += entry.addRef(fileNum);
-		}
-	}
-
-	public void addRef(IndexedFile indexedFile, char[] word) {
-		addRef(word, indexedFile.getFileNumber());
-	}
-
-	public void addRef(IndexedFile indexedFile, String word) {
-		addRef(word.toCharArray(), indexedFile.getFileNumber());
-	}
-
-	/**
-	 * Returns the footprint of the index.
-	 */
-	public long getFootprint() {
-		return this.footprint;
-	}
-
-	/**
-	 * Returns the indexed file with the given path, or null if such file does not exist.
-	 */
-	public IndexedFile getIndexedFile(String path) {
-		return files.get(path);
-	}
-
-	/**
-	 * @see IIndex#getNumDocuments()
-	 */
-	public int getNumFiles() {
-		return files.size();
-	}
-
-	/**
-	 * @see IIndex#getNumWords()
-	 */
-	public int getNumWords() {
-		return words.elementSize;
-	}
-	
-	/**
-	 * Returns the words contained in the hashtable of words, sorted by alphabetical order.
-	 */
-	protected IndexedFile[] getSortedFiles() {
-		if (this.sortedFiles == null) {
-			IndexedFile[] indexedFiles= files.asArray();
-			Util.sort(indexedFiles);
-			this.sortedFiles= indexedFiles;
-		}
-		return this.sortedFiles;
-	}
-	/**
-	 * Returns the word entries contained in the hashtable of words, sorted by alphabetical order.
-	 */
-	protected WordEntry[] getSortedWordEntries() {
-		if (this.sortedWordEntries == null) {
-			WordEntry[] wordEntries= this.words.asArray();
-			Util.sort(wordEntries);
-			this.sortedWordEntries= wordEntries;
-		}
-		return this.sortedWordEntries;
-	}
-	/**
-	 * Returns the word entry corresponding to the given word.
-	 */
-	protected WordEntry getWordEntry(char[] word) {
-		return words.get(word);
-	}
-	/**
-	 * Initialises the fields of the index
-	 */
-	public void init() {
-		words= new WordEntryHashedArray(501);
-		files= new IndexedFileHashedArray(101);
-		footprint= 0;
-		sortedWordEntries= null;
-		sortedFiles= null;
-	}
-	/**
-	 * Saves the index in the given file.
-	 * Structure of the saved Index :
-	 *   - IndexedFiles in sorted order.
-	 *		+ example: 
-	 *			"c:/com/Test.java 1"
-	 *			"c:/com/UI.java 2"
-	 *   - References with the words in sorted order
-	 *		+ example: 
-	 *			"classDecl/Test 1"
-	 *			"classDecl/UI 2"
-	 *			"ref/String 1 2"
-	 */
-
-	public void save(File file) throws IOException {
-		BlocksIndexOutput output= new BlocksIndexOutput(file);
-		save(output);
-	}
-	/**
-	 * Saves the index in the given IndexOutput.
-	 * Structure of the saved Index :
-	 *   - IndexedFiles in sorted order.
-	 *		+ example: 
-	 *			"c:/com/Test.java 1"
-	 *			"c:/com/UI.java 2"
-	 *   - References with the words in sorted order
-	 *		+ example: 
-	 *			"classDecl/Test 1"
-	 *			"classDecl/UI 2"
-	 *			"ref/String 1 2"
-	 */
-
-	protected void save(IndexOutput output) throws IOException {
-		boolean ok= false;
-		try {
-			output.open();
-			IndexedFile[] indexedFiles= files.asArray();
-			for (int i= 0, length = indexedFiles.length; i < length; ++i)
-				output.addFile(indexedFiles[i]); // written out in order BUT not alphabetical
-			getSortedWordEntries(); // init the slot
-			for (int i= 0, numWords= sortedWordEntries.length; i < numWords; ++i)
-				output.addWord(sortedWordEntries[i]);
-			output.flush();
-			output.close();
-			ok= true;
-		} finally {
-			if (!ok && output != null)
-				output.close();
-		}
-	}
-}
diff --git a/search/org/eclipse/jdt/internal/core/index/impl/IndexBlock.java b/search/org/eclipse/jdt/internal/core/index/impl/IndexBlock.java
deleted file mode 100644
index 86f13a2..0000000
--- a/search/org/eclipse/jdt/internal/core/index/impl/IndexBlock.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import org.eclipse.jdt.core.compiler.CharOperation;
-
-/**
- * An indexBlock stores wordEntries.
- */
-
-public abstract class IndexBlock extends Block {
-
-	public IndexBlock(int blockSize) {
-		super(blockSize);
-	}
-	/**
-	 * Adds the given wordEntry to the indexBlock.
-	 */
-
-	public abstract boolean addEntry(WordEntry entry);
-	/**
-	 * @see Block#clear()
-	 */
-	public void clear() {
-		reset();
-		super.clear();
-	}
-	public WordEntry findEntryMatching(char[] pattern, boolean isCaseSensitive) {
-		reset();
-		WordEntry entry= new WordEntry();
-		while (nextEntry(entry)) {
-			if (CharOperation.match(pattern, entry.getWord(), isCaseSensitive)) {
-				return entry;
-			}
-		}
-		return null;
-	}
-	public WordEntry findEntryPrefixedBy(char[] word, boolean isCaseSensitive) {
-		reset();
-		WordEntry entry= new WordEntry();
-		while (nextEntry(entry)) {
-			if (CharOperation.prefixEquals(entry.getWord(), word, isCaseSensitive)) {
-				return entry;
-			}
-		}
-		return null;
-	}
-	public WordEntry findExactEntry(char[] word) {
-		reset();
-		WordEntry entry= new WordEntry();
-		while (nextEntry(entry)) {
-			if (CharOperation.equals(entry.getWord(), word)) {
-				return entry;
-			}
-		}
-		return null;
-	}
-	/**
-	 * Returns whether the block is empty or not (if it doesn't contain any wordEntry).
-	 */
-	public abstract boolean isEmpty();
-
-	/**
-	 * Finds the next wordEntry and stores it in the given entry.
-	 */
-	public abstract boolean nextEntry(WordEntry entry);
-
-	public void reset() {
-		// do nothing
-	}
-}
diff --git a/search/org/eclipse/jdt/internal/core/index/impl/IndexImpl.java b/search/org/eclipse/jdt/internal/core/index/impl/IndexImpl.java
deleted file mode 100644
index a0716ba..0000000
--- a/search/org/eclipse/jdt/internal/core/index/impl/IndexImpl.java
+++ /dev/null
@@ -1,330 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.io.*;
-import java.util.*;
-
-import org.eclipse.core.runtime.IPath;
-import org.eclipse.jdt.core.search.*;
-import org.eclipse.jdt.internal.core.index.*;
-
-/**
- * An Index is used to create an index on the disk, and to make queries. It uses a set of 
- * indexers and a mergeFactory. The index fills an inMemoryIndex up 
- * to it reaches a certain size, and then merges it with a main index on the disk.
- * <br> <br>
- * The changes are only taken into account by the queries after a merge.
- */
-
-public class IndexImpl extends Index {
-	/**
-	 * Maximum size of the index in memory.
-	 */
-	public static final int MAX_FOOTPRINT= 10000000;
-
-	/**
-	 * Index in memory, who is merged with mainIndex each times it 
-	 * reaches a certain size.
-	 */
-	protected InMemoryIndex addsIndex;
-	protected IndexInput addsIndexInput;
-
-	/**
-	 * State of the indexGenerator: addsIndex empty <=> MERGED, or
-	 * addsIndex not empty <=> CAN_MERGE
-	 */
-	protected int state;
-
-	/**
-	 * Files removed form the addsIndex.
-	 */
-	protected Map removedInAdds;
-
-	/**
-	 * Files removed form the oldIndex.
-	 */
-	protected Map removedInOld;
-	protected static final int CAN_MERGE= 0;
-	protected static final int MERGED= 1;
-	private File indexFile;
-
-	/**
-	 * String representation of this index.
-	 */
-	public String toString;
-	public IndexImpl(File indexDirectory, boolean reuseExistingFile) throws IOException {
-		this(indexDirectory,".index", reuseExistingFile); //$NON-NLS-1$
-	}
-	public IndexImpl(File indexDirectory, String indexName, boolean reuseExistingFile) throws IOException {
-		state= MERGED;
-		indexFile= new File(indexDirectory, indexName);
-		initialize(reuseExistingFile);
-	}
-	public IndexImpl(String indexName, boolean reuseExistingFile) throws IOException {
-		this(indexName, null, reuseExistingFile);
-	}
-	public IndexImpl(String indexName, String toString, boolean reuseExistingFile) throws IOException {
-		state= MERGED;
-		indexFile= new File(indexName);
-		this.toString = toString;
-		initialize(reuseExistingFile);
-	}
-	public void addIndexEntry(char[] category, char[] key, SearchDocument document) {
-		if (document.indexedFile == null)
-			throw new IllegalStateException();
-		addsIndex.addRef(document.indexedFile, org.eclipse.jdt.core.compiler.CharOperation.concat(category, key));
-	}
-	/**
-	 * Returns true if the index in memory is not empty, so 
-	 * merge() can be called to fill the mainIndex with the files and words
-	 * contained in the addsIndex. 
-	 */
-	protected boolean canMerge() {
-		return state == CAN_MERGE;
-	}
-	/**
-	 * Initialises the indexGenerator.
-	 */
-//	public void empty() throws IOException {
-//
-//		if (indexFile.exists()){
-//			indexFile.delete();
-//			//initialisation of mainIndex
-//			InMemoryIndex mainIndex= new InMemoryIndex();
-//			IndexOutput mainIndexOutput= new BlocksIndexOutput(indexFile);
-//			if (!indexFile.exists())
-//				mainIndex.save(mainIndexOutput);
-//		}
-//
-//		//initialisation of addsIndex
-//		addsIndex= new InMemoryIndex();
-//		addsIndexInput= new SimpleIndexInput(addsIndex);
-//
-//		//vectors who keep track of the removed Files
-//		removedInAdds= new HashMap(11);
-//		removedInOld= new HashMap(11);
-//	}
-	protected String getDocumentName(int number) {
-		// to be supplied by the new Index
-		return null;
-	}
-	public File getIndexFile() {
-		return indexFile;
-	}
-	/**
-	 * Returns the path corresponding to a given document number
-	 */
-//	public String getPath(int documentNumber) throws IOException {
-//		//save();
-//		IndexInput input= new BlocksIndexInput(indexFile);
-//		try {
-//			input.open();
-//			IndexedFile file = input.getIndexedFile(documentNumber);
-//			if (file == null) return null;
-//			return file.getPath();
-//		} finally {
-//			input.close();
-//		}		
-//	}
-	/**
-	 * see IIndex.hasChanged
-	 */
-	public boolean hasChanged() {
-		return canMerge();
-	}
-	/**
-	 * Indexes the given document, using the searchParticipant.
-	 * If the document already exists in the index, it overrides the previous one.
-	 * The changes are taken into account after a merge.
-	 */
-	public void indexDocument(SearchDocument document, SearchParticipant searchParticipant, IPath indexPath) throws IOException {
-		if (timeToMerge())
-			merge();
-
-		IndexedFile indexedFile = addsIndex.getIndexedFile(document.getPath());
-		if (indexedFile != null)
-			remove(indexedFile, MergeFactory.ADDS_INDEX);
-
-		// add the name of the file to the index
-		if (document.indexedFile != null)
-			throw new IllegalStateException();
-		document.indexedFile = addsIndex.addDocument(document);
-
-		searchParticipant.indexDocument(document, indexPath);
-		state = CAN_MERGE;
-	}
-	/**
-	 * Initialises the indexGenerator.
-	 */
-	public void initialize(boolean reuseExistingFile) throws IOException {
-		
-		//initialisation of addsIndex
-		addsIndex= new InMemoryIndex();
-		addsIndexInput= new SimpleIndexInput(addsIndex);
-
-		//vectors who keep track of the removed Files
-		removedInAdds= new HashMap(11);
-		removedInOld= new HashMap(11);
-
-		// check whether existing index file can be read
-		if (reuseExistingFile && indexFile.exists()) {
-			IndexInput mainIndexInput= new BlocksIndexInput(indexFile);
-			try {
-				mainIndexInput.open();
-			} catch(IOException e) {
-				BlocksIndexInput input = (BlocksIndexInput)mainIndexInput;
-				try {
-					input.opened = true;
-					input.close();
-				} finally {
-					input.opened = false;
-				}
-				indexFile.delete();
-				mainIndexInput = null;
-				throw e;
-			}
-			mainIndexInput.close();
-		} else {
-			InMemoryIndex mainIndex= new InMemoryIndex();			
-			IndexOutput mainIndexOutput= new BlocksIndexOutput(indexFile);
-			mainIndex.save(mainIndexOutput);
-		}
-	}
-	/**
-	 * Merges the in memory index and the index on the disk, and saves the results on the disk.
-	 */
-	protected void merge() throws IOException {
-		//System.out.println("merge");
-
-		//initialisation of tempIndex
-		File tempFile= new File(indexFile.getAbsolutePath() + "TempVA"); //$NON-NLS-1$
-
-		IndexInput mainIndexInput= new BlocksIndexInput(indexFile);
-		BlocksIndexOutput tempIndexOutput= new BlocksIndexOutput(tempFile);
-
-		try {
-			//invoke a mergeFactory
-			new MergeFactory(
-				mainIndexInput, 
-				addsIndexInput, 
-				tempIndexOutput, 
-				removedInOld, 
-				removedInAdds).merge();
-			
-			//rename the file created to become the main index
-			File mainIndexFile= (File) mainIndexInput.getSource();
-			File tempIndexFile= (File) tempIndexOutput.getDestination();
-			mainIndexFile.delete();
-			tempIndexFile.renameTo(mainIndexFile);
-		} finally {		
-			//initialise remove vectors and addsindex, and change the state
-			removedInAdds.clear();
-			removedInOld.clear();
-			addsIndex.init();
-			addsIndexInput= new SimpleIndexInput(addsIndex);
-			state= MERGED;
-		}
-	}
-	public EntryResult[] query(char[][] categories, char[] key, int matchRule) {
-		// to be supplied by the new Index
-		return new EntryResult[0];
-	}
-//	public String[] query(String word) throws IOException {
-//		//save();
-//		IndexInput input= new BlocksIndexInput(indexFile);
-//		try {
-//			return input.query(word);
-//		} finally {
-//			input.close();
-//		}
-//	}
-//	public EntryResult[] queryEntries(char[] prefix) throws IOException {
-//		//save();
-//		IndexInput input= new BlocksIndexInput(indexFile);
-//		try {
-//			return input.queryEntriesPrefixedBy(prefix);
-//		} finally {
-//			input.close();
-//		}
-//	}
-	public String[] queryDocumentNames(String word) throws IOException {
-		//save();
-		IndexInput input= new BlocksIndexInput(indexFile);
-		try {
-			return input.queryInDocumentNames(word);
-		} finally {
-			input.close();
-		}
-	}
-//	public String[] queryPrefix(char[] prefix) throws IOException {
-//		//save();
-//		IndexInput input= new BlocksIndexInput(indexFile);
-//		try {
-//			return input.queryFilesReferringToPrefix(prefix);
-//		} finally {
-//			input.close();
-//		}
-//	}
-	public void remove(String documentName) {
-		IndexedFile file= addsIndex.getIndexedFile(documentName);
-		if (file != null) {
-			//the file is in the adds Index, we remove it from this one
-			Int lastRemoved= (Int) removedInAdds.get(documentName);
-			if (lastRemoved != null) {
-				int fileNum= file.getFileNumber();
-				if (lastRemoved.value < fileNum)
-					lastRemoved.value= fileNum;
-			} else
-				removedInAdds.put(documentName, new Int(file.getFileNumber()));
-		} else {
-			//we remove the file from the old index
-			removedInOld.put(documentName, new Int(1));
-		}
-		state= CAN_MERGE;
-	}
-	/**
-	 * Removes the given document from the given index (MergeFactory.ADDS_INDEX for the
-	 * in memory index, MergeFactory.OLD_INDEX for the index on the disk).
-	 */
-	protected void remove(IndexedFile file, int index) {
-		String name= file.getPath();
-		if (index == MergeFactory.ADDS_INDEX) {
-			Int lastRemoved= (Int) removedInAdds.get(name);
-			if (lastRemoved != null) {
-				if (lastRemoved.value < file.getFileNumber())
-					lastRemoved.value= file.getFileNumber();
-			} else
-				removedInAdds.put(name, new Int(file.getFileNumber()));
-		} else if (index == MergeFactory.OLD_INDEX)
-			removedInOld.put(name, new Int(1));
-		else
-			throw new Error();
-		state= CAN_MERGE;
-	}
-	public void save() throws IOException {
-		if (canMerge())
-			merge();
-	}
-	/**
-	 * Returns true if the in memory index reaches a critical size, 
-	 * to merge it with the index on the disk.
-	 */
-	protected boolean timeToMerge() {
-		return (addsIndex.getFootprint() >= MAX_FOOTPRINT);
-	}
-public String toString() {
-	String str = this.toString;
-	if (str == null) str = super.toString();
-	str += "(length: "+ getIndexFile().length() +")"; //$NON-NLS-1$ //$NON-NLS-2$
-	return str;
-}
-}
diff --git a/search/org/eclipse/jdt/internal/core/index/impl/IndexInput.java b/search/org/eclipse/jdt/internal/core/index/impl/IndexInput.java
deleted file mode 100644
index fa9cc84..0000000
--- a/search/org/eclipse/jdt/internal/core/index/impl/IndexInput.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.io.IOException;
-
-import org.eclipse.jdt.core.search.SearchDocument;
-import org.eclipse.jdt.internal.core.index.EntryResult;
-
-
-/**
- * This class provides an input on an index, after it has been generated.
- * You can access all the files of an index via getNextFile(), getCurrentFile() 
- * and moveToNextFile() (idem for the word entries). 
- * The usage is the same for every subclass: creation (constructor), opening
- * (the open() method), usage, and closing (the close() method), to release the
- * data source used by this input.
- */
-public abstract class IndexInput {
-	protected int filePosition;
-	protected WordEntry currentWordEntry;
-	protected int wordPosition;
-
-
-	public IndexInput() {
-		super();
-		wordPosition= 1;
-		filePosition= 1;
-	}
-	/**
-	 * clears the cache of this indexInput, if it keeps track of the information already read.
-	 */
-	public abstract void clearCache();
-	/**
-	 * Closes the IndexInput. For example, if the input is on a RandomAccessFile,
-	 * it calls the close() method of RandomAccessFile. 
-	 */
-	public abstract void close() throws IOException;
-	/**
-	 * Returns the current file the indexInput is pointing to in the index.
-	 */
-	public abstract IndexedFile getCurrentFile() throws IOException;
-	/**
-	 * Returns the current file the indexInput is pointing to in the index.
-	 */
-	public WordEntry getCurrentWordEntry() {
-		if (!hasMoreWords())
-			return null;
-		return currentWordEntry;
-	}
-	/**
-	 * Returns the position of the current file the input is pointing to in the index.
-	 */
-	public int getFilePosition() {
-		return filePosition;
-	}
-	/**
-	 * Returns the indexedFile corresponding to the given document number in the index the input
-	 * reads in, or null if such indexedFile does not exist.
-	 */
-	public abstract IndexedFile getIndexedFile(int fileNum) throws IOException;
-	/**
-	 * Returns the indexedFile corresponding to the given document in the index the input
-	 * reads in (e.g. the indexedFile with the same path in this index), or null if such 
-	 * indexedFile does not exist.
-	 */
-	public abstract IndexedFile getIndexedFile(SearchDocument document) throws IOException;
-	/**
-	 * Returns the number of files in the index.
-	 */
-	public abstract int getNumFiles();
-	/**
-	 * Returns the number of unique words in the index.
-	 */
-	public abstract int getNumWords();
-	/**
-	 * Returns the Object the input is reading from. It can be an IIndex,
-	 * a File, ...
-	 */
-	public abstract Object getSource();
-	/**
-	 * Returns true if the input has not reached the end of the index for the files.
-	 */
-	public boolean hasMoreFiles() {
-		return getFilePosition() <= getNumFiles();
-	}
-	/**
-	 * Returns true if the input has not reached the end of the index for the files.
-	 */
-	public boolean hasMoreWords() {
-		return wordPosition <= getNumWords();
-	}
-	/**
-	 * Moves the pointer on the current file to the next file in the index.
-	 */
-	public abstract void moveToNextFile();
-	/**
-	 * Moves the pointer on the current word to the next file in the index.
-	 */
-	public abstract void moveToNextWordEntry() throws IOException;
-	/**
-	 * Open the Source where the input gets the information from.
-	 */
-	public abstract void open() throws IOException;
-	/**
-	 * Returns the list of the files containing the given word in the index.
-	 */
-	public abstract String[] query(String word) throws IOException;
-	public abstract EntryResult[] queryEntries(char[] pattern, int matchRule) throws IOException;
-	public abstract EntryResult[] queryEntriesPrefixedBy(char[] prefix) throws IOException;
-	public abstract String[] queryFilesReferringToPrefix(char[] prefix) throws IOException;
-	/**
-	 * Returns the list of the files whose name contain the given word in the index.
-	 */
-	public abstract String[] queryInDocumentNames(String word) throws IOException;
-	/**
-	 * Set the pointer on the current file to the first file of the index.
-	 */
-	protected abstract void setFirstFile() throws IOException;
-	/**
-	 * Set the pointer on the current word to the first word of the index.
-	 */
-	protected abstract void setFirstWord() throws IOException;
-}
diff --git a/search/org/eclipse/jdt/internal/core/index/impl/IndexOutput.java b/search/org/eclipse/jdt/internal/core/index/impl/IndexOutput.java
deleted file mode 100644
index 480b514..0000000
--- a/search/org/eclipse/jdt/internal/core/index/impl/IndexOutput.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.io.IOException;
-
-/**
- * An indexOutput is used to write an index into a different object (a File, ...). 
- */
-public abstract class IndexOutput {
-	/**
-	 * Adds a File to the destination.
-	 */
-	public abstract void addFile(IndexedFile file) throws IOException;
-	/**
-	 * Adds a word to the destination.
-	 */
-	public abstract void addWord(WordEntry word) throws IOException;
-	/**
-	 * Closes the output, releasing the resources it was using.
-	 */
-	public abstract void close() throws IOException;
-	/**
-	 * Flushes the output.
-	 */
-	public abstract void flush() throws IOException;
-	/**
-	 * Returns the Object the output is writing to. It can be a file, another type of index, ... 
-	 */
-	public abstract Object getDestination();
-	/**
-	 * Opens the output, before writing any information.
-	 */
-	public abstract void open() throws IOException;
-}
diff --git a/search/org/eclipse/jdt/internal/core/index/impl/IndexSummary.java b/search/org/eclipse/jdt/internal/core/index/impl/IndexSummary.java
deleted file mode 100644
index 7eaa87b..0000000
--- a/search/org/eclipse/jdt/internal/core/index/impl/IndexSummary.java
+++ /dev/null
@@ -1,318 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.util.ArrayList;
-
-import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.internal.core.util.Util;
-
-/**
- * An indexSummary is used when saving an index into a BlocksIndexOuput or 
- * reading it from a BlocksIndexInput. It contains basic informations about 
- * an index: first files/words in each block, number of files/words.
- */
-
-public class IndexSummary {
-	/**
-	 * First file for each block.
-	 */
-	protected ArrayList firstFilesInBlocks= new ArrayList();
-
-	/**
-	 * First word for each block.
-	 */
-	protected ArrayList firstWordsInBlocks= new ArrayList();
-
-	/**
-	 * Number of files in the index.
-	 */
-	protected int numFiles;
-
-	/**
-	 * Number of words in the index.
-	 */
-	protected int numWords;
-
-	static class FirstFileInBlock {
-		IndexedFile indexedFile;
-		int blockNum;
-	}
-
-	static class FirstWordInBlock {
-		char[] word;
-		int blockNum;
-		public String toString(){
-			return "FirstWordInBlock: " + new String(word) + ", blockNum: " + blockNum; //$NON-NLS-1$ //$NON-NLS-2$
-		}
-	}
-
-	protected int firstWordBlockNum;
-	protected boolean firstWordAdded= true;
-	/**
-	 * Adds the given file as the first file for the given Block number. 
-	 */
-	public void addFirstFileInBlock(IndexedFile indexedFile, int blockNum) {
-		FirstFileInBlock entry= new FirstFileInBlock();
-		entry.indexedFile= indexedFile;
-		entry.blockNum= blockNum;
-		firstFilesInBlocks.add(entry);
-	}
-	/**
-	 * Adds the given word as the first word for the given Block number. 
-	 */
-	public void addFirstWordInBlock(char[] word, int blockNum) {
-		if (firstWordAdded) {
-			firstWordBlockNum= blockNum;
-			firstWordAdded= false;
-		}
-		FirstWordInBlock entry= new FirstWordInBlock();
-		entry.word= word;
-		entry.blockNum= blockNum;
-		firstWordsInBlocks.add(entry);
-	}
-	/**
-	 * Returns the numbers of all the blocks
-	 */
-	public int[] getAllBlockNums() {
-
-		int max = firstWordsInBlocks.size();
-		int[] blockNums = new int[max];
-		for (int i = 0; i < max; i++){
-			blockNums[i] = ((FirstWordInBlock)firstWordsInBlocks.get(i)).blockNum;
-		}
-		return blockNums;
-	}
-public int getBlockNum(int blockLocation) {
-	return ((FirstWordInBlock) firstWordsInBlocks.get(blockLocation)).blockNum;
-}
-	/**
-	 * Returns the number of the Block containing the file with the given number. 
-	 */
-	public int getBlockNumForFileNum(int fileNum) {
-		int min= 0;
-		int max= firstFilesInBlocks.size() - 1;
-		while (min <= max) {
-			int mid= (min + max) / 2;
-			FirstFileInBlock entry= (FirstFileInBlock) firstFilesInBlocks.get(mid);
-			int compare= fileNum - entry.indexedFile.getFileNumber();
-			if (compare == 0)
-				return entry.blockNum;
-			if (compare < 0)
-				max= mid - 1;
-			else
-				min= mid + 1;
-		}
-		if (max < 0)
-			return -1;
-		FirstFileInBlock entry= (FirstFileInBlock) firstFilesInBlocks.get(max);
-		return entry.blockNum;
-	}
-	/**
-	 * Returns the number of the Block containing the given word. 
-	 */
-	public int getBlockNumForWord(char[] word) {
-		int min= 0;
-		int max= firstWordsInBlocks.size() - 1;
-		while (min <= max) {
-			int mid= (min + max) / 2;
-			FirstWordInBlock entry= (FirstWordInBlock) firstWordsInBlocks.get(mid);
-			int compare= Util.compare(word, entry.word);
-			if (compare == 0)
-				return entry.blockNum;
-			if (compare < 0)
-				max= mid - 1;
-			else
-				min= mid + 1;
-		}
-		if (max < 0)
-			return -1;
-		FirstWordInBlock entry= (FirstWordInBlock) firstWordsInBlocks.get(max);
-		return entry.blockNum;
-	}
-	public int[] getBlockNumsForPrefix(char[] prefix) {
-		int min= 0;
-		int size= firstWordsInBlocks.size();
-		int max=  size - 1;
-		int match= -1;
-		while (min <= max && match < 0) {
-			int mid= (min + max) / 2;
-			FirstWordInBlock entry= (FirstWordInBlock) firstWordsInBlocks.get(mid);
-			int compare= CharOperation.compareWith(entry.word, prefix);
-			if (compare == 0) {
-				match= mid;
-				break;
-			}	
-			if (compare >= 0)
-				max= mid - 1;
-			else
-				min= mid + 1;
-		}
-		if (max < 0)
-			return new int[0];
-			
-		if (match < 0)
-			match= max;
-		
-		int firstBlock= match - 1;
-		// Look if previous blocks are affected
-		for (; firstBlock >= 0; firstBlock--) {
-			FirstWordInBlock entry= (FirstWordInBlock) firstWordsInBlocks.get(firstBlock);
-			if (!CharOperation.prefixEquals(prefix, entry.word))
-				break;
-		}
-		if (firstBlock < 0)
-			firstBlock= 0;	
-		
-		// Look if next blocks are affected
-		int firstNotIncludedBlock= match + 1;
-		for (; firstNotIncludedBlock < size; firstNotIncludedBlock++) {
-			FirstWordInBlock entry= (FirstWordInBlock) firstWordsInBlocks.get(firstNotIncludedBlock);
-			if (!CharOperation.prefixEquals(prefix, entry.word))
-				break;
-		}
-		
-		int numberOfBlocks= firstNotIncludedBlock - firstBlock;
-		int[] result= new int[numberOfBlocks];
-		int pos= firstBlock;
-		for (int i= 0; i < numberOfBlocks; i++, pos++) {
-			FirstWordInBlock entry= (FirstWordInBlock) firstWordsInBlocks.get(pos);
-			result[i]= entry.blockNum;
-		}
-		return result;
-	}
-public int getFirstBlockLocationForPrefix(char[] prefix) {
-	int min = 0;
-	int size = firstWordsInBlocks.size();
-	int max = size - 1;
-	int match = -1;
-	while (min <= max) {
-		int mid = (min + max) / 2;
-		FirstWordInBlock entry = (FirstWordInBlock) firstWordsInBlocks.get(mid);
-		int compare = CharOperation.compareWith(entry.word, prefix);
-		if (compare == 0) {
-			match = mid;
-			break;
-		}
-		if (compare >= 0) {
-			max = mid - 1;
-		} else {
-			match = mid; // not perfect match, but could be inside
-			min = mid + 1;
-		}
-	}
-	if (max < 0) return -1;
-
-	// no match at all, might be some matching entries inside max block
-	if (match < 0){
-		match = max;
-	} else {
-		// look for possible matches inside previous blocks
-		while (match > 0){
-			FirstWordInBlock entry = (FirstWordInBlock) firstWordsInBlocks.get(match);
-			if (!CharOperation.prefixEquals(prefix, entry.word))
-				break;
-			match--;
-		}
-	}
-	return match;
-}
-	/**
-	 * Returns the number of the first IndexBlock (containing words).
-	 */
-	public int getFirstWordBlockNum() {
-		return firstWordBlockNum;
-	}
-/** 
- * Blocks are contiguous, so the next one is a potential candidate if its first word starts with
- * the given prefix
- */
-public int getNextBlockLocationForPrefix(char[] prefix, int blockLoc) {
-	if (++blockLoc < firstWordsInBlocks.size()){
-		FirstWordInBlock entry= (FirstWordInBlock) firstWordsInBlocks.get(blockLoc);
-		if (CharOperation.prefixEquals(prefix, entry.word)) return blockLoc;
-	}
-	return -1;
-}
-	/**
-	 * Returns the number of files contained in the index.
-	 */
-	public int getNumFiles() {
-		return numFiles;
-	}
-	/**
-	 * Returns the number of words contained in the index.
-	 */
-	public int getNumWords() {
-		return numWords;
-	}
-	/**
-	 * Loads the summary in memory.
-	 */
-	public void read(RandomAccessFile raf) throws IOException {
-		numFiles= raf.readInt();
-		numWords= raf.readInt();
-		firstWordBlockNum= raf.readInt();
-		int numFirstFiles= raf.readInt();
-		for (int i= 0; i < numFirstFiles; ++i) {
-			FirstFileInBlock entry= new FirstFileInBlock();
-			String path= raf.readUTF();
-			int fileNum= raf.readInt();
-			entry.indexedFile= new IndexedFile(path, fileNum);
-			entry.blockNum= raf.readInt();
-			firstFilesInBlocks.add(entry);
-		}
-		int numFirstWords= raf.readInt();
-		for (int i= 0; i < numFirstWords; ++i) {
-			FirstWordInBlock entry= new FirstWordInBlock();
-			entry.word= raf.readUTF().toCharArray();
-			entry.blockNum= raf.readInt();
-			firstWordsInBlocks.add(entry);
-		}
-	}
-	/**
-	 * Sets the number of files of the index.
-	 */
-
-	public void setNumFiles(int numFiles) {
-		this.numFiles= numFiles;
-	}
-	/**
-	 * Sets the number of words of the index.
-	 */
-
-	public void setNumWords(int numWords) {
-		this.numWords= numWords;
-	}
-	/**
-	 * Saves the summary on the disk.
-	 */
-	public void write(RandomAccessFile raf) throws IOException {
-		raf.writeInt(numFiles);
-		raf.writeInt(numWords);
-		raf.writeInt(firstWordBlockNum);
-		raf.writeInt(firstFilesInBlocks.size());
-		for (int i= 0, size= firstFilesInBlocks.size(); i < size; ++i) {
-			FirstFileInBlock entry= (FirstFileInBlock) firstFilesInBlocks.get(i);
-			raf.writeUTF(entry.indexedFile.getPath());
-			raf.writeInt(entry.indexedFile.getFileNumber());
-			raf.writeInt(entry.blockNum);
-		}
-		raf.writeInt(firstWordsInBlocks.size());
-		for (int i= 0, size= firstWordsInBlocks.size(); i < size; ++i) {
-			FirstWordInBlock entry= (FirstWordInBlock) firstWordsInBlocks.get(i);
-			raf.writeUTF(new String(entry.word));
-			raf.writeInt(entry.blockNum);
-		}
-	}
-}
diff --git a/search/org/eclipse/jdt/internal/core/index/impl/IndexedFile.java b/search/org/eclipse/jdt/internal/core/index/impl/IndexedFile.java
deleted file mode 100644
index 4928332..0000000
--- a/search/org/eclipse/jdt/internal/core/index/impl/IndexedFile.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import org.eclipse.core.runtime.Path;
-import org.eclipse.jdt.core.search.IJavaSearchScope;
-import org.eclipse.jdt.core.search.SearchDocument;
-
-/**
- * An indexedFile associates a number to a document path, and document properties. 
- * It is what we add into an index, and the result of a query.
- */
-
-public class IndexedFile {
-	public String path;
-	protected int fileNumber;
-
-	public IndexedFile(String path, int fileNum) {
-		if (fileNum < 1)
-			throw new IllegalArgumentException();
-		this.fileNumber= fileNum;
-		this.path= path;
-	}
-	public IndexedFile(SearchDocument document, int fileNum) {
-		if (fileNum < 1)
-			throw new IllegalArgumentException();
-		this.path= document.getPath();
-		this.fileNumber= fileNum;
-	}
-	/**
-	 * Returns the path represented by pathString converted back to a path relative to the local file system.
-	 *
-	 * @param pathString the path to convert:
-	 * <ul>
-	 *		<li>an absolute IPath (relative to the workspace root) if the path represents a resource in the 
-	 *			workspace
-	 *		<li>a relative IPath (relative to the workspace root) followed by JAR_FILE_ENTRY_SEPARATOR
-	 *			followed by an absolute path (relative to the jar) if the path represents a .class file in
-	 *			an internal jar
-	 *		<li>an absolute path (relative to the file system) followed by JAR_FILE_ENTRY_SEPARATOR
-	 *			followed by an absolute path (relative to the jar) if the path represents a .class file in
-	 *			an external jar
-	 * </ul>
-	 * @return the converted path:
-	 * <ul>
-	 *		<li>the original pathString if the path represents a resource in the workspace
-	 *		<li>an absolute path (relative to the file system) followed by JAR_FILE_ENTRY_SEPARATOR
-	 *			followed by an absolute path (relative to the jar) if the path represents a .class file in
-	 *			an external or internal jar
-	 * </ul>
-	 */
-	public static String convertPath(String pathString) {
-		int index = pathString.indexOf(IJavaSearchScope.JAR_FILE_ENTRY_SEPARATOR);
-		if (index == -1)
-			return pathString;
-			
-		Path jarPath = new Path(pathString.substring(0, index));
-		if (!jarPath.isAbsolute()) {
-			return jarPath.makeAbsolute().toString() + pathString.substring(index, pathString.length());
-		} else {
-			return jarPath.toOSString() + pathString.substring(index, pathString.length());
-		}
-	}
-	/**
-	 * Returns the size of the indexedFile.
-	 */
-	public int footprint() {
-		//object+ 2 slots + size of the string (header + 4 slots + char[])
-		return 8 + (2 * 4) + (8 + (4 * 4) + 8 + path.length() * 2);
-	}
-	/**
-	 * Returns the file number.
-	 */
-	public int getFileNumber() {
-		return fileNumber;
-	}
-	/**
-	 * Returns the path.
-	 */
-	public String getPath() {
-		return path;
-	}
-	/**
-	 * Sets the file number.
-	 */
-	public void setFileNumber(int fileNumber) {
-		this.fileNumber= fileNumber;
-	}
-	public String toString() {
-		return "IndexedFile(" + fileNumber + ": " + path + ")"; //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-3$
-	}
-}
diff --git a/search/org/eclipse/jdt/internal/core/index/impl/IndexedFileHashedArray.java b/search/org/eclipse/jdt/internal/core/index/impl/IndexedFileHashedArray.java
deleted file mode 100644
index 8ebe5cd..0000000
--- a/search/org/eclipse/jdt/internal/core/index/impl/IndexedFileHashedArray.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.util.ArrayList;
-
-import org.eclipse.jdt.core.search.SearchDocument;
-
-public final class IndexedFileHashedArray {
-
-private IndexedFile elements[];
-private int elementSize; // number of elements in the table
-private int threshold;
-private int lastId;
-private ArrayList replacedElements;
-
-public IndexedFileHashedArray(int size) {
-	if (size < 7) size = 7;
-	this.elements = new IndexedFile[2 * size + 1];
-	this.elementSize = 0;
-	this.threshold = size + 1; // size is the expected number of elements
-	this.lastId = 0;
-	this.replacedElements = null;
-}
-
-public IndexedFile add(SearchDocument document) {
-	return add(new IndexedFile(document, ++lastId));
-}
-
-private IndexedFile add(IndexedFile file) {
-	int length = elements.length;
-	String path = file.getPath();
-	int index = (path.hashCode() & 0x7FFFFFFF) % length;
-	IndexedFile current;
-	while ((current = elements[index]) != null) {
-		if (current.getPath().equals(path)) {
-			if (replacedElements == null) replacedElements = new ArrayList(5);
-			replacedElements.add(current);
-			return elements[index] = file;
-		}
-		if (++index == length) index = 0;
-	}
-	elements[index] = file;
-
-	// assumes the threshold is never equal to the size of the table
-	if (++elementSize > threshold) grow();
-	return file;
-}
-
-public IndexedFile[] asArray() {
-	IndexedFile[] array = new IndexedFile[lastId];
-	for (int i = 0, length = elements.length; i < length; i++) {
-		IndexedFile current = elements[i];
-		if (current != null)
-			array[current.fileNumber - 1] = current;
-	}
-	if (replacedElements != null) {
-		for (int i = 0, length = replacedElements.size(); i < length; i++) {
-			IndexedFile current = (IndexedFile) replacedElements.get(i);
-			array[current.fileNumber - 1] = current;
-		}
-	}
-	return array;
-}
-
-public IndexedFile get(String path) {
-	int length = elements.length;
-	int index = (path.hashCode() & 0x7FFFFFFF) % length;
-	IndexedFile current;
-	while ((current = elements[index]) != null) {
-		if (current.getPath().equals(path)) return current;
-		if (++index == length) index = 0;
-	}
-	return null;
-}
-
-private void grow() {
-	IndexedFileHashedArray newArray = new IndexedFileHashedArray(elementSize * 2); // double the number of expected elements
-	for (int i = 0, length = elements.length; i < length; i++)
-		if (elements[i] != null)
-			newArray.add(elements[i]);
-
-	// leave replacedElements as is
-	this.elements = newArray.elements;
-	this.elementSize = newArray.elementSize;
-	this.threshold = newArray.threshold;
-}
-
-public int size() {
-	return elementSize + (replacedElements == null ? 0 : replacedElements.size());
-}
-
-public String toString() {
-	String s = ""; //$NON-NLS-1$
-	IndexedFile[] files = asArray();
-	for (int i = 0, length = files.length; i < length; i++)
-		s += files[i].toString() + "\n"; 	//$NON-NLS-1$
-	return s;
-}
-}
diff --git a/search/org/eclipse/jdt/internal/core/index/impl/LRUCache.java b/search/org/eclipse/jdt/internal/core/index/impl/LRUCache.java
deleted file mode 100644
index e014647..0000000
--- a/search/org/eclipse/jdt/internal/core/index/impl/LRUCache.java
+++ /dev/null
@@ -1,473 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.util.Hashtable;
-import java.util.Enumeration;
-
-/**
- * The <code>LRUCache</code> is a hashtable that stores a finite number of elements.  
- * When an attempt is made to add values to a full cache, the least recently used values
- * in the cache are discarded to make room for the new values as necessary.
- * 
- * <p>The data structure is based on the LRU virtual memory paging scheme.
- * 
- * <p>Objects can take up a variable amount of cache space by implementing
- * the <code>ILRUCacheable</code> interface.
- *
- * <p>This implementation is NOT thread-safe.  Synchronization wrappers would
- * have to be added to ensure atomic insertions and deletions from the cache.
- *
- * @see org.eclipse.jdt.internal.core.index.impl.ILRUCacheable
- */
-public class LRUCache implements Cloneable {
-
-	/**
-	 * This type is used internally by the LRUCache to represent entries 
-	 * stored in the cache.
-	 * It is static because it does not require a pointer to the cache
-	 * which contains it.
-	 *
-	 * @see LRUCache
-	 */
-	protected static class LRUCacheEntry {
-
-		/**
-		 * Hash table key
-		 */
-		/* package */
-		Object _fKey;
-
-		/**
-		 * Hash table value (an LRUCacheEntry object)
-		 */
-		/* package */
-		Object _fValue;
-
-		/**
-		 * Time value for queue sorting
-		 */
-		/* package */
-		int _fTimestamp;
-
-		/**
-		 * Cache footprint of this entry
-		 */
-		int _fSpace;
-
-		/**
-		 * Previous entry in queue
-		 */
-		/* package */
-		LRUCacheEntry _fPrevious;
-
-		/**
-		 * Next entry in queue
-		 */
-		/* package */
-		LRUCacheEntry _fNext;
-
-		/**
-		 * Creates a new instance of the receiver with the provided values
-		 * for key, value, and space.
-		 */
-		public LRUCacheEntry(Object key, Object value, int space) {
-			_fKey= key;
-			_fValue= value;
-			_fSpace= space;
-		}
-
-		/**
-		 * Returns a String that represents the value of this object.
-		 */
-		public String toString() {
-
-			return "LRUCacheEntry [" + _fKey + "-->" + _fValue + "]"; //$NON-NLS-3$ //$NON-NLS-1$ //$NON-NLS-2$
-		}
-	}
-
-	/**
-	 * Amount of cache space used so far
-	 */
-	protected int fCurrentSpace;
-
-	/**
-	 * Maximum space allowed in cache
-	 */
-	protected int fSpaceLimit;
-
-	/**
-	 * Counter for handing out sequential timestamps
-	 */
-	protected int fTimestampCounter;
-
-	/**
-	 * Hash table for fast random access to cache entries
-	 */
-	protected Hashtable fEntryTable;
-
-	/**
-	 * Start of queue (most recently used entry) 
-	 */
-	protected LRUCacheEntry fEntryQueue;
-
-	/**
-	 * End of queue (least recently used entry)
-	 */
-	protected LRUCacheEntry fEntryQueueTail;
-
-	/**
-	 * Default amount of space in the cache
-	 */
-	protected static final int DEFAULT_SPACELIMIT= 100;
-	/**
-	 * Creates a new cache.  Size of cache is defined by 
-	 * <code>DEFAULT_SPACELIMIT</code>.
-	 */
-	public LRUCache() {
-
-		this(DEFAULT_SPACELIMIT);
-	}
-	/**
-	 * Creates a new cache.
-	 * @param size Size of Cache
-	 */
-	public LRUCache(int size) {
-
-		fTimestampCounter= fCurrentSpace= 0;
-		fEntryQueue= fEntryQueueTail= null;
-		fEntryTable= new Hashtable(size);
-		fSpaceLimit= size;
-	}
-	/**
-	 * Returns a new cache containing the same contents.
-	 *
-	 * @return New copy of object.
-	 */
-	public Object clone() {
-
-		LRUCache newCache= newInstance(fSpaceLimit);
-		LRUCacheEntry qEntry;
-
-		/* Preserve order of entries by copying from oldest to newest */
-		qEntry= this.fEntryQueueTail;
-		while (qEntry != null) {
-			newCache.privateAdd(qEntry._fKey, qEntry._fValue, qEntry._fSpace);
-			qEntry= qEntry._fPrevious;
-		}
-		return newCache;
-	}
-	/**
-	 * Flushes all entries from the cache.
-	 */
-	public void flush() {
-
-		fCurrentSpace= 0;
-		LRUCacheEntry entry= fEntryQueueTail; // Remember last entry
-		fEntryTable= new Hashtable(); // Clear it out
-		fEntryQueue= fEntryQueueTail= null;
-		while (entry != null) { // send deletion notifications in LRU order
-			privateNotifyDeletionFromCache(entry);
-			entry= entry._fPrevious;
-		}
-	}
-	/**
-	 * Flushes the given entry from the cache.  Does nothing if entry does not
-	 * exist in cache.
-	 *
-	 * @param key Key of object to flush
-	 */
-	public void flush(Object key) {
-
-		LRUCacheEntry entry;
-
-		entry= (LRUCacheEntry) fEntryTable.get(key);
-
-		/* If entry does not exist, return */
-		if (entry == null)
-			return;
-
-		this.privateRemoveEntry(entry, false);
-	}
-	/**
-	 * Answers the value in the cache at the given key.
-	 * If the value is not in the cache, returns null
-	 *
-	 * @param key Hash table key of object to retrieve
-	 * @return Retreived object, or null if object does not exist
-	 */
-	public Object get(Object key) {
-
-		LRUCacheEntry entry= (LRUCacheEntry) fEntryTable.get(key);
-		if (entry == null) {
-			return null;
-		}
-
-		this.updateTimestamp(entry);
-		return entry._fValue;
-	}
-	/**
-	 * Returns the amount of space that is current used in the cache.
-	 */
-	public int getCurrentSpace() {
-		return fCurrentSpace;
-	}
-	/**
-	 * Returns the maximum amount of space available in the cache.
-	 */
-	public int getSpaceLimit() {
-		return fSpaceLimit;
-	}
-	/**
-	 * Returns an Enumeration of the keys currently in the cache.
-	 */
-	public Enumeration keys() {
-
-		return fEntryTable.keys();
-	}
-	/**
-	 * Returns an enumeration that iterates over all the keys and values 
-	 * currently in the cache.
-	 */
-	public ICacheEnumeration keysAndValues() {
-		return new ICacheEnumeration() {
-
-			Enumeration fValues= fEntryTable.elements();
-			LRUCacheEntry fEntry;
-
-			public boolean hasMoreElements() {
-				return fValues.hasMoreElements();
-			}
-
-			public Object nextElement() {
-				fEntry= (LRUCacheEntry) fValues.nextElement();
-				return fEntry._fKey;
-			}
-
-			public Object getValue() {
-				if (fEntry == null) {
-					throw new java.util.NoSuchElementException();
-				}
-				return fEntry._fValue;
-			}
-		};
-	}
-	/**
-	 * Ensures there is the specified amount of free space in the receiver,
-	 * by removing old entries if necessary.  Returns true if the requested space was
-	 * made available, false otherwise.
-	 *
-	 * @param space Amount of space to free up
-	 */
-	protected boolean makeSpace(int space) {
-
-		int limit;
-
-		limit= this.getSpaceLimit();
-
-		/* if space is already available */
-		if (fCurrentSpace + space <= limit) {
-			return true;
-		}
-
-		/* if entry is too big for cache */
-		if (space > limit) {
-			return false;
-		}
-
-		/* Free up space by removing oldest entries */
-		while (fCurrentSpace + space > limit && fEntryQueueTail != null) {
-			this.privateRemoveEntry(fEntryQueueTail, false);
-		}
-		return true;
-	}
-	/**
-	 * Returns a new LRUCache instance
-	 */
-	protected LRUCache newInstance(int size) {
-		return new LRUCache(size);
-	}
-	/**
-	 * Adds an entry for the given key/value/space.
-	 */
-	protected void privateAdd(Object key, Object value, int space) {
-
-		LRUCacheEntry entry;
-
-		entry= new LRUCacheEntry(key, value, space);
-		this.privateAddEntry(entry, false);
-	}
-	/**
-	 * Adds the given entry from the receiver.
-	 * @param shuffle Indicates whether we are just shuffling the queue 
-	 * (in which case, the entry table is not modified).
-	 */
-	protected void privateAddEntry(LRUCacheEntry entry, boolean shuffle) {
-
-		if (!shuffle) {
-			fEntryTable.put(entry._fKey, entry);
-			fCurrentSpace += entry._fSpace;
-		}
-
-		entry._fTimestamp= fTimestampCounter++;
-		entry._fNext= this.fEntryQueue;
-		entry._fPrevious= null;
-
-		if (fEntryQueue == null) {
-			/* this is the first and last entry */
-			fEntryQueueTail= entry;
-		} else {
-			fEntryQueue._fPrevious= entry;
-		}
-
-		fEntryQueue= entry;
-	}
-	/**
-	 * An entry has been removed from the cache, for example because it has 
-	 * fallen off the bottom of the LRU queue.  
-	 * Subclasses could over-ride this to implement a persistent cache below the LRU cache.
-	 */
-	protected void privateNotifyDeletionFromCache(LRUCacheEntry entry) {
-		// Default is NOP.
-	}
-	/**
-	 * Removes the entry from the entry queue.  
-	 * @param shuffle indicates whether we are just shuffling the queue 
-	 * (in which case, the entry table is not modified).
-	 */
-	protected void privateRemoveEntry(LRUCacheEntry entry, boolean shuffle) {
-
-		LRUCacheEntry previous, next;
-
-		previous= entry._fPrevious;
-		next= entry._fNext;
-
-		if (!shuffle) {
-			fEntryTable.remove(entry._fKey);
-			fCurrentSpace -= entry._fSpace;
-			privateNotifyDeletionFromCache(entry);
-		}
-
-		/* if this was the first entry */
-		if (previous == null) {
-			fEntryQueue= next;
-		} else {
-			previous._fNext= next;
-		}
-
-		/* if this was the last entry */
-		if (next == null) {
-			fEntryQueueTail= previous;
-		} else {
-			next._fPrevious= previous;
-		}
-	}
-	/**
-	 * Sets the value in the cache at the given key. Returns the value.
-	 *
-	 * @param key Key of object to add.
-	 * @param value Value of object to add.
-	 * @return added value.
-	 */
-	public Object put(Object key, Object value) {
-
-		int newSpace, oldSpace, newTotal;
-		LRUCacheEntry entry;
-
-		/* Check whether there's an entry in the cache */
-		newSpace= spaceFor(value);
-		entry= (LRUCacheEntry) fEntryTable.get(key);
-
-		if (entry != null) {
-
-			/**
-			 * Replace the entry in the cache if it would not overflow
-			 * the cache.  Otherwise flush the entry and re-add it so as 
-			 * to keep cache within budget
-			 */
-			oldSpace= entry._fSpace;
-			newTotal= getCurrentSpace() - oldSpace + newSpace;
-			if (newTotal <= getSpaceLimit()) {
-				updateTimestamp(entry);
-				entry._fValue= value;
-				entry._fSpace= newSpace;
-				this.fCurrentSpace= newTotal;
-				return value;
-			} else {
-				privateRemoveEntry(entry, false);
-			}
-		}
-		if (makeSpace(newSpace)) {
-			privateAdd(key, value, newSpace);
-		}
-		return value;
-	}
-	/**
-	 * Removes and returns the value in the cache for the given key.
-	 * If the key is not in the cache, returns null.
-	 *
-	 * @param key Key of object to remove from cache.
-	 * @return Value removed from cache.
-	 */
-	public Object removeKey(Object key) {
-
-		LRUCacheEntry entry= (LRUCacheEntry) fEntryTable.get(key);
-		if (entry == null) {
-			return null;
-		}
-		Object value= entry._fValue;
-		this.privateRemoveEntry(entry, false);
-		return value;
-	}
-	/**
-	 * Sets the maximum amount of space that the cache can store
-	 *
-	 * @param limit Number of units of cache space
-	 */
-	public void setSpaceLimit(int limit) {
-		if (limit < fSpaceLimit) {
-			makeSpace(fSpaceLimit - limit);
-		}
-		fSpaceLimit= limit;
-	}
-	/**
-	 * Returns the space taken by the given value.
-	 */
-	protected int spaceFor(Object value) {
-
-		if (value instanceof ILRUCacheable) {
-			return ((ILRUCacheable) value).getCacheFootprint();
-		} else {
-			return 1;
-		}
-	}
-	/**
-	 * Returns a String that represents the value of this object.  This method
-	 * is for debugging purposes only.
-	 */
-	public String toString() {
-
-		return "LRUCache " + (getCurrentSpace() * 100.0 / getSpaceLimit()) + "% full"; //$NON-NLS-1$ //$NON-NLS-2$
-	}
-	/**
-	 * Updates the timestamp for the given entry, ensuring that the queue is 
-	 * kept in correct order.  The entry must exist
-	 */
-	protected void updateTimestamp(LRUCacheEntry entry) {
-
-		entry._fTimestamp= fTimestampCounter++;
-		if (fEntryQueue != entry) {
-			this.privateRemoveEntry(entry, true);
-			this.privateAddEntry(entry, true);
-		}
-		return;
-	}
-}
diff --git a/search/org/eclipse/jdt/internal/core/index/impl/MergeFactory.java b/search/org/eclipse/jdt/internal/core/index/impl/MergeFactory.java
deleted file mode 100644
index e0d07b6..0000000
--- a/search/org/eclipse/jdt/internal/core/index/impl/MergeFactory.java
+++ /dev/null
@@ -1,230 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.io.IOException;
-import java.util.Map;
-
-import org.eclipse.jdt.internal.core.util.Util;
-
-/**
- * A mergeFactory is used to merge 2 indexes into one. One of the indexes 
- * (oldIndex) is on the disk and the other(addsIndex) is in memory.
- * The merge respects the following rules: <br>
- *   - The files are sorted in alphabetical order;<br>
- *   - if a file is in oldIndex and addsIndex, the one which is added 
- * is the one in the addsIndex.<br>
- */
-public class MergeFactory {
-	/**
-	 * Input on the addsIndex.
-	 */
-	protected IndexInput addsInput;
-
-	/**
-	 * Input on the oldIndex. 
-	 */
-	protected IndexInput oldInput;
-
-	/**
-	 * Output to write the result of the merge in.
-	 */
-	protected BlocksIndexOutput mergeOutput;
-
-	/**
-	 * Files removed from oldIndex. 
-	 */
-	protected Map removedInOld;
-
-	/**
-	 * Files removed from addsIndex. 
-	 */
-	protected Map removedInAdds;
-	protected int[] mappingOld;
-	protected int[] mappingAdds;
-	public static final int ADDS_INDEX= 0;
-	public static final int OLD_INDEX= 1;
-	/**
-	 * MergeFactory constructor comment.
-	 * @param directory java.io.File
-	 */
-	public MergeFactory(IndexInput oldIndexInput, IndexInput addsIndexInput, BlocksIndexOutput mergeIndexOutput, Map removedInOld, Map removedInAdds) {
-		oldInput= oldIndexInput;
-		addsInput= addsIndexInput;
-		mergeOutput= mergeIndexOutput;
-		this.removedInOld= removedInOld;
-		this.removedInAdds= removedInAdds;
-	}
-	/**
-	 * Initialise the merge.
-	 */
-	protected void init() {
-		mappingOld= new int[oldInput.getNumFiles() + 1];
-		mappingAdds= new int[addsInput.getNumFiles() + 1];
-
-	}
-	/**
-	 * Merges the 2 indexes into a new one on the disk.
-	 */
-	public void merge() throws IOException {
-		try {
-			//init
-			addsInput.open();
-			oldInput.open();
-			mergeOutput.open();
-			init();
-			//merge
-			//findChanges();
-			mergeFiles();
-			mergeReferences();
-			mergeOutput.flush();
-		} finally {
-			//closes everything
-			oldInput.close();
-			addsInput.close();
-			mergeOutput.close();
-		}
-	}
-	/**
-	 * Merges the files of the 2 indexes in the new index, removes the files
-	 * to be removed, and records the changes made to propagate them to the 
-	 * word references.
-	 */
-
-	protected void mergeFiles() throws IOException {
-		int positionInMerge= 1;
-		int compare;
-		while (oldInput.hasMoreFiles() || addsInput.hasMoreFiles()) {
-			IndexedFile file1= oldInput.getCurrentFile();
-			IndexedFile file2= addsInput.getCurrentFile();
-
-			//if the file has been removed we don't take it into account
-			while (file1 != null && wasRemoved(file1, OLD_INDEX)) {
-				oldInput.moveToNextFile();
-				file1= oldInput.getCurrentFile();
-			}
-			while (file2 != null && wasRemoved(file2, ADDS_INDEX)) {
-				addsInput.moveToNextFile();
-				file2= addsInput.getCurrentFile();
-			}
-
-			//the addsIndex was empty, we just removed files from the oldIndex
-			if (file1 == null && file2 == null)
-				break;
-
-			//test if we reached the end of one the 2 index
-			if (file1 == null)
-				compare= 1;
-			else if (file2 == null)
-				compare= -1;
-			else
-				compare= file1.getPath().compareTo(file2.getPath());
-
-			//records the changes to Make
-			if (compare == 0) {
-				//the file has been modified: 
-				//we remove it from the oldIndex and add it to the addsIndex
-				removeFile(file1, OLD_INDEX);
-				mappingAdds[file2.getFileNumber()]= positionInMerge;
-				file1.setFileNumber(positionInMerge);
-				mergeOutput.addFile(file1);
-				oldInput.moveToNextFile();
-				addsInput.moveToNextFile();
-			} else if (compare < 0) {
-				mappingOld[file1.getFileNumber()]= positionInMerge;
-				file1.setFileNumber(positionInMerge);
-				mergeOutput.addFile(file1);
-				oldInput.moveToNextFile();
-			} else {
-				mappingAdds[file2.getFileNumber()]= positionInMerge;
-				file2.setFileNumber(positionInMerge);
-				mergeOutput.addFile(file2);
-				addsInput.moveToNextFile();
-			}
-			positionInMerge++;
-		}
-		mergeOutput.flushFiles();		
-	}
-	/**
-	 * Merges the files of the 2 indexes in the new index, according to the changes
-	 * recorded during mergeFiles().
-	 */
-	protected void mergeReferences() throws IOException {
-		int compare;
-		while (oldInput.hasMoreWords() || addsInput.hasMoreWords()) {
-			WordEntry word1= oldInput.getCurrentWordEntry();
-			WordEntry word2= addsInput.getCurrentWordEntry();
-
-			if (word1 == null && word2 == null)
-				break;
-			
-			if (word1 == null)
-				compare= 1;
-			else if (word2 == null)
-				compare= -1;
-			else
-				compare= Util.compare(word1.getWord(), word2.getWord());
-			if (compare < 0) {
-				word1.mapRefs(mappingOld);
-				mergeOutput.addWord(word1);
-				oldInput.moveToNextWordEntry();
-			} else if (compare > 0) {
-				word2.mapRefs(mappingAdds);
-				mergeOutput.addWord(word2);
-				addsInput.moveToNextWordEntry();
-			} else {
-				word1.mapRefs(mappingOld);
-				word2.mapRefs(mappingAdds);
-				word1.addRefs(word2.getRefs());
-				mergeOutput.addWord(word1);
-				addsInput.moveToNextWordEntry();
-				oldInput.moveToNextWordEntry();
-			}
-		}
-		mergeOutput.flushWords();
-	}
-	/**
-	 * Records the deletion of one file.
-	 */
-	protected void removeFile(IndexedFile file, int index) {
-		if (index == OLD_INDEX)
-			mappingOld[file.getFileNumber()]= -1;
-		else
-			mappingAdds[file.getFileNumber()]= -1;
-	}
-	/**
-	 * Returns whether the given file has to be removed from the given index
-	 * (ADDS_INDEX or OLD_INDEX). If it has to be removed, the mergeFactory 
-	 * deletes it and records the changes. 
-	 */
-
-	protected boolean wasRemoved(IndexedFile indexedFile, int index) {
-		String path= indexedFile.getPath();
-		if (index == OLD_INDEX) {
-			if (removedInOld.remove(path) != null) {
-				mappingOld[indexedFile.getFileNumber()]= -1;
-				return true;
-			}
-		} else if (index == ADDS_INDEX) {
-			Int lastRemoved= (Int) removedInAdds.get(path);
-			if (lastRemoved != null) {
-				int fileNum= indexedFile.getFileNumber();
-				if (lastRemoved.value >= fileNum) {
-					mappingAdds[fileNum]= -1;
-					//if (lastRemoved.value == fileNum) // ONLY if files in sorted order for names AND fileNums
-					//removedInAdds.remove(path);
-					return true;
-				}
-			}
-		}
-		return false;
-	}
-}
diff --git a/search/org/eclipse/jdt/internal/core/index/impl/SafeRandomAccessFile.java b/search/org/eclipse/jdt/internal/core/index/impl/SafeRandomAccessFile.java
deleted file mode 100644
index 9cbf908..0000000
--- a/search/org/eclipse/jdt/internal/core/index/impl/SafeRandomAccessFile.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.io.IOException;
-import java.io.RandomAccessFile;
-
-/**
- * A safe subclass of RandomAccessFile, which ensure that it's closed
- * on finalize.
- */
-public class SafeRandomAccessFile extends RandomAccessFile {
-	public SafeRandomAccessFile(java.io.File file, String mode) throws java.io.IOException {
-		super(file, mode);
-	}
-	public SafeRandomAccessFile(String name, String mode) throws java.io.IOException {
-		super(name, mode);
-	}
-	protected void finalize() throws IOException {
-		close();
-	}
-}
diff --git a/search/org/eclipse/jdt/internal/core/index/impl/SimpleIndexBlock.java b/search/org/eclipse/jdt/internal/core/index/impl/SimpleIndexBlock.java
deleted file mode 100644
index bfd89c1..0000000
--- a/search/org/eclipse/jdt/internal/core/index/impl/SimpleIndexBlock.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.io.UTFDataFormatException;
-
-import org.eclipse.jdt.core.compiler.CharOperation;
-
-/**
- * Does no compression of words, and uses 4-byte ints for file numbers and number of files.
- */
-public class SimpleIndexBlock extends IndexBlock {
-	protected int offset= 0;
-
-	public SimpleIndexBlock(int blockSize) {
-		super(blockSize);
-	}
-	/**
-	 * @see IndexBlock#addEntry
-	 */
-	public boolean addEntry(WordEntry entry) {
-		char[] word= entry.getWord();
-		int n= entry.getNumRefs();
-		int sizeEstimate= 2 + word.length * 3 + 4 + n * 4;
-		int off= this.offset;
-		if (off + sizeEstimate > this.blockSize - 2)
-			return false;
-		off += field.putUTF(off, word);
-		field.putInt4(off, n);
-		off += 4;
-		for (int i= 0; i < n; ++i) {
-			field.putInt4(off, entry.getRef(i));
-			off += 4;
-		}
-		this.offset= off;
-		return true;
-	}
-	public WordEntry findEntry(char[] word) {
-		try {
-			int off= 0;
-			int byteLen;
-			while ((byteLen= field.getUInt2(off)) != 0) {
-				char[] tempWord= field.getUTF(off);
-				off += byteLen + 2;
-				if (CharOperation.equals(tempWord, word)) {
-					WordEntry entry= new WordEntry(word);
-					int n= field.getInt4(off);
-					off += 4;
-					for (int i= 0; i < n; ++i) {
-						int ref= field.getInt4(off);
-						off += 4;
-						entry.addRef(ref);
-					}
-					return entry;
-				} else {
-					int n= field.getInt4(off);
-					off += 4 + 4 * n;
-				}
-			}
-			return null;
-		} catch (UTFDataFormatException e) {
-			return null;
-		}
-	}
-	/**
-	 * @see IndexBlock#flush
-	 */
-	public void flush() {
-		if (offset > 0) {
-			field.putInt2(offset, 0);
-			offset= 0;
-		}
-	}
-	/**
-	 * @see IndexBlock#isEmpty
-	 */
-	public boolean isEmpty() {
-		return offset == 0;
-	}
-	/**
-	 * @see IndexBlock#nextEntry
-	 */
-	public boolean nextEntry(WordEntry entry) {
-		try {
-			int off= this.offset;
-			int byteLen= field.getUInt2(off);
-			if (byteLen == 0)
-				return false;
-			char[] word= field.getUTF(off);
-			off += byteLen + 2;
-			entry.reset(word);
-			int n= field.getInt4(off);
-			off += 4;
-			for (int i= 0; i < n; ++i) {
-				int ref= field.getInt4(off);
-				off += 4;
-				entry.addRef(ref);
-			}
-			this.offset= off;
-			return true;
-		} catch (UTFDataFormatException e) {
-			return false;
-		}
-	}
-	/**
-	 * @see IndexBlock#reset
-	 */
-	public void reset() {
-		super.reset();
-		this.offset= 0;
-	}
-}
diff --git a/search/org/eclipse/jdt/internal/core/index/impl/SimpleIndexInput.java b/search/org/eclipse/jdt/internal/core/index/impl/SimpleIndexInput.java
deleted file mode 100644
index 5d132ec..0000000
--- a/search/org/eclipse/jdt/internal/core/index/impl/SimpleIndexInput.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.util.ArrayList;
-
-import org.eclipse.jdt.core.search.SearchDocument;
-import org.eclipse.jdt.internal.core.index.EntryResult;
-
-/**
- * A simpleIndexInput is an input on an in memory Index. 
- */
-
-public class SimpleIndexInput extends IndexInput {
-	protected WordEntry[] sortedWordEntries;
-	protected IndexedFile currentFile;
-	protected IndexedFile[] sortedFiles;
-	protected InMemoryIndex index;
-
-	public SimpleIndexInput(InMemoryIndex index) {
-		super();
-		this.index= index;
-	}
-	/**
-	 * @see IndexInput#clearCache()
-	 */
-	public void clearCache() {
-		// implements abstract method
-	}
-	/**
-	 * @see IndexInput#close()
-	 */
-	public void close() {
-		sortedFiles= null;
-	}
-	/**
-	 * @see IndexInput#getCurrentFile()
-	 */
-	public IndexedFile getCurrentFile() {
-		if (!hasMoreFiles())
-			return null;
-		return currentFile;
-	}
-	/**
-	 * @see IndexInput#getIndexedFile(int)
-	 */
-	public IndexedFile getIndexedFile(int fileNum) {
-		for (int i= 0; i < sortedFiles.length; i++)
-			if (sortedFiles[i].getFileNumber() == fileNum)
-				return sortedFiles[i];
-		return null;
-	}
-	/**
-	 * @see IndexInput#getIndexedFile(IDocument)
-	 */
-	public IndexedFile getIndexedFile(SearchDocument document) {
-		String name= document.getPath();
-		for (int i= index.getNumFiles(); i >= 1; i--) {
-			IndexedFile file= getIndexedFile(i);
-			if (name.equals(file.getPath()))
-				return file;
-		}
-		return null;
-	}
-	/**
-	 * @see IndexInput#getNumFiles()
-	 */
-	public int getNumFiles() {
-		return index.getNumFiles();
-	}
-	/**
-	 * @see IndexInput#getNumWords()
-	 */
-	public int getNumWords() {
-		return sortedWordEntries.length;
-	}
-	/**
-	 * @see IndexInput#getSource()
-	 */
-	public Object getSource() {
-		return index;
-	}
-	public void init() {
-		index.init();
-
-	}
-	/**
-	 * @see IndexInput#moveToNextFile()
-	 */
-	public void moveToNextFile() {
-		filePosition++;
-		if (!hasMoreFiles()) {
-			return;
-		}
-		currentFile= sortedFiles[filePosition - 1];
-	}
-	/**
-	 * @see IndexInput#moveToNextWordEntry()
-	 */
-	public void moveToNextWordEntry() /* throws IOException */ {
-		wordPosition++;
-		if (hasMoreWords())
-			currentWordEntry= sortedWordEntries[wordPosition - 1];
-	}
-	/**
-	 * @see IndexInput#open()
-	 */
-	public void open() {
-		sortedWordEntries= index.getSortedWordEntries();
-		sortedFiles= index.getSortedFiles();
-		filePosition= 1;
-		wordPosition= 1;
-		setFirstFile();
-		setFirstWord();
-	}
-	/**
-	 * @see IndexInput#query(String)
-	 */
-	public String[] query(String word) {
-		char[] wordChar= word.toCharArray();
-		WordEntry wordEntry= index.getWordEntry(wordChar);
-		int[] fileNums= wordEntry.getRefs();
-		String[] paths= new String[fileNums.length];
-		for (int i= 0; i < paths.length; i++)
-			paths[i]= getIndexedFile(fileNums[i]).getPath();
-		return paths;
-	}
-	public EntryResult[] queryEntries(char[] pattern, int matchRule) {
-		return null;
-	}
-	public EntryResult[] queryEntriesPrefixedBy(char[] prefix) {
-		return null;
-	}
-	public String[] queryFilesReferringToPrefix(char[] prefix) {
-			return null;
-	}
-	/**
-	 * @see IndexInput#queryInDocumentNames(String)
-	 */
-	public String[] queryInDocumentNames(String word) {
-		setFirstFile();
-		ArrayList matches= new ArrayList();
-		while (hasMoreFiles()) {
-			IndexedFile file= getCurrentFile();
-			if (word == null || file.getPath().indexOf(word) != -1)
-				matches.add(file.getPath());
-			moveToNextFile();
-		}
-		String[] match= new String[matches.size()];
-		matches.toArray(match);
-		return match;
-	}
-	/**
-	 * @see IndexInput#setFirstFile()
-	 */
-	protected void setFirstFile() {
-		filePosition= 1;
-		if (sortedFiles.length > 0) {
-			currentFile= sortedFiles[0];
-		}
-	}
-	/**
-	 * @see IndexInput#setFirstWord()
-	 */
-	protected void setFirstWord() {
-		wordPosition= 1;
-		if (sortedWordEntries.length > 0)
-			currentWordEntry= sortedWordEntries[0];
-	}
-}
diff --git a/search/org/eclipse/jdt/internal/core/index/impl/WordEntry.java b/search/org/eclipse/jdt/internal/core/index/impl/WordEntry.java
deleted file mode 100644
index 5ef9781..0000000
--- a/search/org/eclipse/jdt/internal/core/index/impl/WordEntry.java
+++ /dev/null
@@ -1,160 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.internal.core.util.Util;
-
-public class WordEntry {
-	public char[] fWord;
-	protected int fNumRefs;
-	protected int[] fRefs;
-	public WordEntry() {
-		this(CharOperation.NO_CHAR);
-	}
-	public WordEntry(char[] word) {
-		fWord= word;
-		fNumRefs= 0;
-		fRefs= new int[1];
-	}
-	/**
-	 * Adds a reference and records the change in footprint.
-	 */
-	public int addRef(int fileNum) {
-		if (fNumRefs > 0 && fRefs[fNumRefs - 1] == fileNum) {
-			return 0;
-		}
-		if (fNumRefs < fRefs.length) {
-			fRefs[fNumRefs++]= fileNum;
-			return 0;
-		} 
-
-		// For rt.jar, 73265 word entries are created. 51997 have 1 ref, then 9438, 3738, 1980, 1214, 779, 547, 429, 371 etc.
-		int newSize= fNumRefs < 4 ? 4 : fNumRefs * 2; // so will start @ 1, grow to 4, 8, 16, 32, 64 etc.
-		System.arraycopy(fRefs, 0, fRefs= new int[newSize], 0, fNumRefs);
-		fRefs[fNumRefs++]= fileNum;
-		return (newSize - fNumRefs + 1) * 4;
-	}
-	/**
-	 * Adds a set of references and records the change in footprint.
-	 */
-	public void addRefs(int[] refs) {
-		int[] newRefs= new int[fNumRefs + refs.length];
-		int pos1= 0;
-		int pos2= 0;
-		int posNew= 0;
-		int compare;
-		int r1= 0;
-		int r2= 0;
-		while (pos1 < fNumRefs || pos2 < refs.length) {
-			if (pos1 >= fNumRefs) {
-				r2= refs[pos2];
-				compare= -1;
-			} else if (pos2 >= refs.length) {
-				compare= 1;
-				r1= fRefs[pos1];
-			} else {
-				r1= fRefs[pos1];
-				r2= refs[pos2];
-				compare= r2 - r1;
-			}
-			if (compare > 0) {
-				newRefs[posNew]= r1;
-				posNew++;
-				pos1++;
-			} else {
-				if (r2 != 0) {
-					newRefs[posNew]= r2;
-					posNew++;
-				}
-				pos2++;
-			}
-		}
-		fRefs= newRefs;
-		fNumRefs= posNew;
-		/*for (int i = 0; i < refs.length; i++)
-		addRef(refs[i]);
-		int[] newRefs = new int[fNumRefs];
-		System.arraycopy(fRefs, 0, newRefs, 0, fNumRefs);
-		fRefs = newRefs;
-		Util.sort(fRefs);*/
-	}
-	/**
-	 * Returns the size of the wordEntry
-	 */
-
-	public int footprint() {
-		return 8 + (3 * 4) + (8 + fWord.length * 2) + (8 + fRefs.length * 4);
-	}
-	/**
-	 * Returns the number of references, e.g. the number of files this word appears in.
-	 */
-	public int getNumRefs() {
-		return fNumRefs;
-	}
-	/**
-	 * returns the file number in the i position in the list of references.
-	 */
-	public int getRef(int i) {
-		if (i < fNumRefs) return fRefs[i];
-		throw new IndexOutOfBoundsException();
-	}
-	/**
-	 * Returns the references of the wordEntry (the number of the files it appears in).
-	 */
-
-	public int[] getRefs() {
-		int[] result= new int[fNumRefs];
-		System.arraycopy(fRefs, 0, result, 0, fNumRefs);
-		return result;
-	}
-	/**
-	 * returns the word of the wordEntry.
-	 */
-
-	public char[] getWord() {
-		return fWord;
-	}
-	/**
-	 * Changes the references of the wordEntry to match the mapping. For example,<br>
-	 * if the current references are [1 3 4]<br>
-	 * and mapping is [1 2 3 4 5]<br>
-	 * in references 1 becomes mapping[1] = 2, 3->4, and 4->5<br>
-	 * => references = [2 4 5].<br>
-	 */
-	public void mapRefs(int[] mappings) {
-		int position= 0;
-		for (int i= 0; i < fNumRefs; i++) {
-			int map= mappings[fRefs[i]];
-			if (map != -1 && map != 0)
-				fRefs[position++]= map;
-		}
-		fNumRefs= position;
-
-		//to be changed!
-		System.arraycopy(fRefs, 0, (fRefs= new int[fNumRefs]), 0, fNumRefs);
-		Util.sort(fRefs);
-	}
-	/**
-	 * Clears the wordEntry.
-	 */
-
-	public void reset(char[] word) {
-		for (int i= fNumRefs; i-- > 0;) {
-			fRefs[i]= 0;
-		}
-		fNumRefs= 0;
-		fWord= word;
-	}
-	public String toString() {
-		return new String(fWord);
-	}
-}
diff --git a/search/org/eclipse/jdt/internal/core/index/impl/WordEntryHashedArray.java b/search/org/eclipse/jdt/internal/core/index/impl/WordEntryHashedArray.java
deleted file mode 100644
index 68581f2..0000000
--- a/search/org/eclipse/jdt/internal/core/index/impl/WordEntryHashedArray.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import org.eclipse.jdt.core.compiler.CharOperation;
-
-public final class WordEntryHashedArray {
-
-// to avoid using Enumerations, walk the objects skipping nulls
-public WordEntry elements[];
-public int elementSize; // number of elements in the table
-public int threshold;
-
-public WordEntryHashedArray(int size) {
-	if (size < 7) size = 7;
-	this.elements = new WordEntry[2 * size + 1];
-	this.elementSize = 0;
-	this.threshold = size + 1; // size is the expected number of elements
-}
-
-public WordEntry add(WordEntry entry) {
-	int length = elements.length;
-	char[] word = entry.getWord();
-	int index = CharOperation.hashCode(word) % length;
-	WordEntry current;
-	while ((current = elements[index]) != null) {
-		if (CharOperation.equals(current.getWord(), word)) return elements[index] = entry;
-		if (++index == length) index = 0;
-	}
-	elements[index] = entry;
-
-	// assumes the threshold is never equal to the size of the table
-	if (++elementSize > threshold) grow();
-	return entry;
-}
-
-public WordEntry[] asArray() {
-	WordEntry[] array = new WordEntry[elementSize];
-	int count = 0;
-	for (int i = 0, length = elements.length; i < length; i++) {
-		WordEntry current = elements[i];
-		if (current != null)
-			array[count++] = current;
-	}
-	if (count < array.length) // add a little protection because of 40950
-		System.arraycopy(array, 0, array = new WordEntry[count], 0, count);
-	return array;
-}
-
-public WordEntry get(char[] word) {
-	int length = elements.length;
-	int index = CharOperation.hashCode(word) % length;
-	WordEntry current;
-	while ((current = elements[index]) != null) {
-		if (CharOperation.equals(current.getWord(), word)) return current;
-		if (++index == length) index = 0;
-	}
-	return null;
-}
-
-private void grow() {
-	WordEntryHashedArray newArray = new WordEntryHashedArray(elementSize * 2); // double the number of expected elements
-	for (int i = 0, length = elements.length; i < length; i++)
-		if (elements[i] != null)
-			newArray.add(elements[i]);
-
-	this.elements = newArray.elements;
-	this.elementSize = newArray.elementSize;
-	this.threshold = newArray.threshold;
-}
-
-public String toString() {
-	String s = ""; //$NON-NLS-1$
-	WordEntry[] entries = asArray();
-	for (int i = 0, length = entries.length; i < length; i++)
-		s += entries[i].toString() + "\n"; 	//$NON-NLS-1$
-	return s;
-}
-}
diff --git a/search/org/eclipse/jdt/internal/core/search/PatternSearchJob.java b/search/org/eclipse/jdt/internal/core/search/PatternSearchJob.java
index e6c01ff..c45d2df 100644
--- a/search/org/eclipse/jdt/internal/core/search/PatternSearchJob.java
+++ b/search/org/eclipse/jdt/internal/core/search/PatternSearchJob.java
@@ -15,9 +15,7 @@
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.OperationCanceledException;
-import org.eclipse.jdt.core.search.IJavaSearchScope;
-import org.eclipse.jdt.core.search.SearchParticipant;
-import org.eclipse.jdt.core.search.SearchPattern;
+import org.eclipse.jdt.core.search.*;
 import org.eclipse.jdt.internal.core.JavaModelManager;
 import org.eclipse.jdt.internal.core.index.Index;
 import org.eclipse.jdt.internal.core.search.indexing.IndexManager;
@@ -27,133 +25,95 @@
 
 public class PatternSearchJob implements IJob {
 
-	protected SearchPattern pattern;
-	protected IJavaSearchScope scope;
-	protected SearchParticipant participant;
-	protected IndexQueryRequestor requestor;
-	protected boolean areIndexesReady;
-	protected long executionTime = 0;
-	
-	public PatternSearchJob(
-		SearchPattern pattern,
-		SearchParticipant participant,
-		IJavaSearchScope scope,
-		IndexQueryRequestor requestor) {
+protected SearchPattern pattern;
+protected IJavaSearchScope scope;
+protected SearchParticipant participant;
+protected IndexQueryRequestor requestor;
+protected boolean areIndexesReady;
+protected long executionTime = 0;
 
-		this.pattern = pattern;
-		this.participant = participant;
-		this.scope = scope;
-		this.requestor = requestor;
-	}
-	public boolean belongsTo(String jobFamily) {
-		return true;
-	}
-	public void cancel() {
-		// search job is cancelled through progress 
-	}
-	public void ensureReadyToRun() {
-		if (!this.areIndexesReady) {
-			getIndexes(null/*progress*/); // may trigger some index recreation
-		}
-	}
-	public boolean execute(IProgressMonitor progressMonitor) {
+public PatternSearchJob(SearchPattern pattern, SearchParticipant participant, IJavaSearchScope scope, IndexQueryRequestor requestor) {
+	this.pattern = pattern;
+	this.participant = participant;
+	this.scope = scope;
+	this.requestor = requestor;
+}
+public boolean belongsTo(String jobFamily) {
+	return true;
+}
+public void cancel() {
+	// search job is cancelled through progress 
+}
+public void ensureReadyToRun() {
+	if (!this.areIndexesReady)
+		getIndexes(null/*progress*/); // may trigger some index recreation
+}
+public boolean execute(IProgressMonitor progressMonitor) {
+	if (progressMonitor != null && progressMonitor.isCanceled()) throw new OperationCanceledException();
 
-		if (progressMonitor != null && progressMonitor.isCanceled())
-			throw new OperationCanceledException();
-		boolean isComplete = COMPLETE;
-		executionTime = 0;
-		Index[] indexes = getIndexes(progressMonitor);
-		try {
-			int max = indexes.length;
+	boolean isComplete = COMPLETE;
+	executionTime = 0;
+	Index[] indexes = getIndexes(progressMonitor);
+	try {
+		int max = indexes.length;
+		if (progressMonitor != null)
+			progressMonitor.beginTask("", max); //$NON-NLS-1$
+		for (int i = 0; i < max; i++) {
+			isComplete &= search(indexes[i], progressMonitor);
 			if (progressMonitor != null) {
-				progressMonitor.beginTask("", max); //$NON-NLS-1$
-			}
-			for (int i = 0; i < max; i++) {
-				isComplete &= search(indexes[i], progressMonitor);
-				if (progressMonitor != null) {
-					if (progressMonitor.isCanceled()) {
-						throw new OperationCanceledException();
-					} else {
-						progressMonitor.worked(1);
-					}
-				}
-			}
-			if (JobManager.VERBOSE) {
-				JobManager.verbose("-> execution time: " + executionTime + "ms - " + this);//$NON-NLS-1$//$NON-NLS-2$
-			}
-			return isComplete;
-		} finally {
-			if (progressMonitor != null) {
-				progressMonitor.done();
+				if (progressMonitor.isCanceled()) throw new OperationCanceledException();
+				progressMonitor.worked(1);
 			}
 		}
+		if (JobManager.VERBOSE)
+			JobManager.verbose("-> execution time: " + executionTime + "ms - " + this);//$NON-NLS-1$//$NON-NLS-2$
+		return isComplete;
+	} finally {
+		if (progressMonitor != null)
+			progressMonitor.done();
 	}
-	public Index[] getIndexes(IProgressMonitor progressMonitor) {
-		
-		// acquire the in-memory indexes on the fly
-		IPath[] indexPaths = this.participant.selectIndexes(this.pattern, this.scope);
-		int length = indexPaths.length;
-		Index[] indexes = new Index[length];
-		int count = 0;
-		IndexManager indexManager = JavaModelManager.getJavaModelManager().getIndexManager();
-		for (int i = 0; i < length; i++) {
-			if (progressMonitor != null && progressMonitor.isCanceled())
-				throw new OperationCanceledException();
-			// may trigger some index recreation work
-			Index index = indexManager.getIndex(indexPaths[i], true /*reuse index file*/, false /*do not create if none*/);
-			if (index != null)
-				indexes[count++] = index; // only consider indexes which are ready
-		}
-		if (count == length) 
-			this.areIndexesReady = true;
-		else
-			System.arraycopy(indexes, 0, indexes=new Index[count], 0, count);
-		return indexes;
-	}	
-
-	public boolean search(Index index, IProgressMonitor progressMonitor) {
-
-		if (progressMonitor != null && progressMonitor.isCanceled())
-			throw new OperationCanceledException();
-
-//			System.out.println("SANITY CHECK: search job using obsolete index: ["+index+ "] instead of: ["+inMemIndex+"]");
-		if (index == null)
-			return COMPLETE;
-		IndexManager indexManager = JavaModelManager.getJavaModelManager().getIndexManager();
-		ReadWriteMonitor monitor = indexManager.getMonitorFor(index);
-		if (monitor == null)
-			return COMPLETE; // index got deleted since acquired
-		try {
-			monitor.enterRead(); // ask permission to read
-
-			/* if index has changed, commit these before querying */
-			if (index.hasChanged()) {
-				try {
-					monitor.exitRead(); // free read lock
-					monitor.enterWrite(); // ask permission to write
-					indexManager.saveIndex(index);
-				} catch (IOException e) {
-					return FAILED;
-				} finally {
-					monitor.exitWriteEnterRead(); // finished writing and reacquire read permission
-				}
-			}
-			long start = System.currentTimeMillis();
-			pattern.findIndexMatches(
-				index,
-				requestor,
-				this.participant,
-				this.scope,
-				progressMonitor);
-			executionTime += System.currentTimeMillis() - start;
-			return COMPLETE;
-		} catch (IOException e) {
-			return FAILED;
-		} finally {
-			monitor.exitRead(); // finished reading
-		}
+}
+public Index[] getIndexes(IProgressMonitor progressMonitor) {
+	// acquire the in-memory indexes on the fly
+	IPath[] indexPaths = this.participant.selectIndexes(this.pattern, this.scope);
+	int length = indexPaths.length;
+	Index[] indexes = new Index[length];
+	int count = 0;
+	IndexManager indexManager = JavaModelManager.getJavaModelManager().getIndexManager();
+	for (int i = 0; i < length; i++) {
+		if (progressMonitor != null && progressMonitor.isCanceled()) throw new OperationCanceledException();
+		// may trigger some index recreation work
+		Index index = indexManager.getIndex(indexPaths[i], true /*reuse index file*/, false /*do not create if none*/);
+		if (index != null)
+			indexes[count++] = index; // only consider indexes which are ready
 	}
-	public String toString() {
-		return "searching " + pattern.toString(); //$NON-NLS-1$
+	if (count == length) 
+		this.areIndexesReady = true;
+	else
+		System.arraycopy(indexes, 0, indexes=new Index[count], 0, count);
+	return indexes;
+}	
+public boolean search(Index index, IProgressMonitor progressMonitor) {
+	if (index == null) return COMPLETE;
+	if (progressMonitor != null && progressMonitor.isCanceled()) throw new OperationCanceledException();
+
+	ReadWriteMonitor monitor = index.monitor;
+	if (monitor == null) return COMPLETE; // index got deleted since acquired
+	try {
+		monitor.enterRead(); // ask permission to read
+		long start = System.currentTimeMillis();
+		pattern.findIndexMatches(index, requestor, this.participant, this.scope, progressMonitor);
+		executionTime += System.currentTimeMillis() - start;
+		return COMPLETE;
+	} catch (IOException e) {
+		if (e instanceof java.io.EOFException)
+			e.printStackTrace();
+		return FAILED;
+	} finally {
+		monitor.exitRead(); // finished reading
 	}
 }
+public String toString() {
+	return "searching " + pattern.toString(); //$NON-NLS-1$
+}
+}
diff --git a/search/org/eclipse/jdt/internal/core/search/SubTypeSearchJob.java b/search/org/eclipse/jdt/internal/core/search/SubTypeSearchJob.java
index 9223ab7..695bef4 100644
--- a/search/org/eclipse/jdt/internal/core/search/SubTypeSearchJob.java
+++ b/search/org/eclipse/jdt/internal/core/search/SubTypeSearchJob.java
@@ -11,92 +11,39 @@
 package org.eclipse.jdt.internal.core.search;
 
 import java.io.IOException;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
 
 import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.OperationCanceledException;
-import org.eclipse.jdt.core.search.IJavaSearchScope;
-import org.eclipse.jdt.core.search.SearchParticipant;
-import org.eclipse.jdt.core.search.SearchPattern;
-import org.eclipse.jdt.internal.core.JavaModelManager;
+import org.eclipse.jdt.core.search.*;
 import org.eclipse.jdt.internal.core.index.Index;
-import org.eclipse.jdt.internal.core.index.impl.BlocksIndexInput;
-import org.eclipse.jdt.internal.core.index.impl.IndexInput;
-import org.eclipse.jdt.internal.core.search.indexing.IndexManager;
-import org.eclipse.jdt.internal.core.search.indexing.ReadWriteMonitor;
+import org.eclipse.jdt.internal.core.util.SimpleSet;
 
 public class SubTypeSearchJob extends PatternSearchJob {
 
-	Map inputs = new HashMap(5);
+SimpleSet indexes = new SimpleSet(5);
 
-public SubTypeSearchJob(
-		SearchPattern pattern,
-		SearchParticipant participant,
-		IJavaSearchScope scope,
-		IndexQueryRequestor requestor) {
-
-		super(
-			pattern,
-			participant,
-			scope,
-			requestor);
+public SubTypeSearchJob(SearchPattern pattern, SearchParticipant participant, IJavaSearchScope scope, IndexQueryRequestor requestor) {
+	super(pattern, participant, scope, requestor);
 }
-public void closeAll(){
-
-	Iterator openedInputs = inputs.values().iterator();
-	while (openedInputs.hasNext()){
-		IndexInput input = (IndexInput) openedInputs.next();
-		try {
-			input.close();
-		} catch(IOException e){
-			// ignore
-		}
+public void finished() {
+	try {
+		Object[] values = this.indexes.values;
+		for (int i = 0, l = values.length; i < l; i++)
+			if (values[i] != null)
+				((Index) values[i]).stopQuery();
+	} catch(IOException e) {
+		// ignore
 	} 
 }
-/**
- * execute method comment.
- */
 public boolean search(Index index, IProgressMonitor progressMonitor) {
-
-	if (progressMonitor != null && progressMonitor.isCanceled()) throw new OperationCanceledException();
-
-	if (index == null) return COMPLETE;		
-	IndexManager indexManager = JavaModelManager.getJavaModelManager().getIndexManager();
-	ReadWriteMonitor monitor = indexManager.getMonitorFor(index);
-	if (monitor == null) return COMPLETE; // index got deleted since acquired
+	if (index == null) return COMPLETE;
 	try {
-		monitor.enterRead(); // ask permission to read
-
-		/* if index has changed, commit these before querying */
-		if (index.hasChanged()){
-			try {
-				monitor.exitRead(); // free read lock
-				monitor.enterWrite(); // ask permission to write
-				indexManager.saveIndex(index);
-			} catch(IOException e){
-				return FAILED;
-			} finally {
-				monitor.exitWriteEnterRead(); // finished writing and reacquire read permission
-			}
+		if (!indexes.includes(index)) {
+			indexes.add(index);
+			index.startQuery();
 		}
-		long start = System.currentTimeMillis();
-
-		IndexInput input;
-		if ((input = (IndexInput) inputs.get(index)) == null){
-			input = new BlocksIndexInput(index.getIndexFile());
-			input.open();
-			inputs.put(index, input);
-			//System.out.println("Acquiring INPUT for "+index);
-		}
-		pattern.findIndexMatches(input, requestor, this.participant, this.scope, progressMonitor);
-		executionTime += System.currentTimeMillis() - start;
-		return COMPLETE;
-	} catch(IOException e){
+	} catch (IOException e) {
 		return FAILED;
-	} finally {
-		monitor.exitRead(); // finished reading
 	}
+	return super.search(index, progressMonitor);
 }
 }
diff --git a/search/org/eclipse/jdt/internal/core/search/indexing/AbstractIndexer.java b/search/org/eclipse/jdt/internal/core/search/indexing/AbstractIndexer.java
index 2061488..f4d0aa8 100644
--- a/search/org/eclipse/jdt/internal/core/search/indexing/AbstractIndexer.java
+++ b/search/org/eclipse/jdt/internal/core/search/indexing/AbstractIndexer.java
@@ -23,8 +23,8 @@
 		this.document = document;
 	}
 	public void addClassDeclaration(int modifiers, char[] packageName,char[] name,  char[][] enclosingTypeNames, char[] superclass, char[][] superinterfaces) {
-		addIndexEntry(TYPE_DECL, TypeDeclarationPattern.createIndexKey(packageName, enclosingTypeNames, name, true));
-	
+		addIndexEntry(TYPE_DECL, TypeDeclarationPattern.createIndexKey(name, packageName, enclosingTypeNames, CLASS_SUFFIX));
+
 		addIndexEntry(
 			SUPER_REF, 
 			SuperTypeReferencePattern.createIndexKey(
@@ -60,8 +60,8 @@
 		SearchParticipant.addIndexEntry(category, key, this.document);
 	}
 	public void addInterfaceDeclaration(int modifiers, char[] packageName, char[] name, char[][] enclosingTypeNames, char[][] superinterfaces) {
-		addIndexEntry(TYPE_DECL, TypeDeclarationPattern.createIndexKey(packageName, enclosingTypeNames, name, false));
-	
+		addIndexEntry(TYPE_DECL, TypeDeclarationPattern.createIndexKey(name, packageName, enclosingTypeNames, INTERFACE_SUFFIX));
+
 		if (superinterfaces != null)
 			for (int i = 0, max = superinterfaces.length; i < max; i++)
 				addIndexEntry(
diff --git a/search/org/eclipse/jdt/internal/core/search/indexing/AddFolderToIndex.java b/search/org/eclipse/jdt/internal/core/search/indexing/AddFolderToIndex.java
index 261a616..3f2457c 100644
--- a/search/org/eclipse/jdt/internal/core/search/indexing/AddFolderToIndex.java
+++ b/search/org/eclipse/jdt/internal/core/search/indexing/AddFolderToIndex.java
@@ -43,7 +43,7 @@
 		/* ensure no concurrent write access to index */
 		Index index = manager.getIndex(this.containerPath, true, /*reuse index file*/ true /*create if none*/);
 		if (index == null) return true;
-		ReadWriteMonitor monitor = manager.getMonitorFor(index);
+		ReadWriteMonitor monitor = index.monitor;
 		if (monitor == null) return true; // index got deleted since acquired
 
 		try {
diff --git a/search/org/eclipse/jdt/internal/core/search/indexing/AddJarFileToIndex.java b/search/org/eclipse/jdt/internal/core/search/indexing/AddJarFileToIndex.java
index ad49658..3e10ad0 100644
--- a/search/org/eclipse/jdt/internal/core/search/indexing/AddJarFileToIndex.java
+++ b/search/org/eclipse/jdt/internal/core/search/indexing/AddJarFileToIndex.java
@@ -75,7 +75,7 @@
 					JobManager.verbose("-> index could not be created for " + this.containerPath); //$NON-NLS-1$
 				return true;
 			}
-			ReadWriteMonitor monitor = manager.getMonitorFor(index);
+			ReadWriteMonitor monitor = index.monitor;
 			if (monitor == null) {
 				if (JobManager.VERBOSE)
 					JobManager.verbose("-> index for " + this.containerPath + " just got deleted"); //$NON-NLS-1$//$NON-NLS-2$
diff --git a/search/org/eclipse/jdt/internal/core/search/indexing/IIndexConstants.java b/search/org/eclipse/jdt/internal/core/search/indexing/IIndexConstants.java
index 7afbfe5..18d2e9f 100644
--- a/search/org/eclipse/jdt/internal/core/search/indexing/IIndexConstants.java
+++ b/search/org/eclipse/jdt/internal/core/search/indexing/IIndexConstants.java
@@ -13,19 +13,16 @@
 public interface IIndexConstants {
 
 	/* index encoding */
-	char[] REF= "ref/".toCharArray(); //$NON-NLS-1$
-	char[] FIELD_REF= "fieldRef/".toCharArray(); //$NON-NLS-1$
-	char[] METHOD_REF= "methodRef/".toCharArray(); //$NON-NLS-1$
-	char[] CONSTRUCTOR_REF= "constructorRef/".toCharArray(); //$NON-NLS-1$
-	char[] TYPE_REF= "typeRef/".toCharArray(); //$NON-NLS-1$
-	char[] SUPER_REF = "superRef/".toCharArray(); //$NON-NLS-1$
-	char[] TYPE_DECL = "typeDecl/".toCharArray(); //$NON-NLS-1$
-	int 	TYPE_DECL_LENGTH = 9;
-	char[] CLASS_DECL= "typeDecl/C/".toCharArray(); //$NON-NLS-1$
-	char[] INTERFACE_DECL= "typeDecl/I/".toCharArray(); //$NON-NLS-1$
-	char[] METHOD_DECL= "methodDecl/".toCharArray(); //$NON-NLS-1$
-	char[] CONSTRUCTOR_DECL= "constructorDecl/".toCharArray(); //$NON-NLS-1$
-	char[] FIELD_DECL= "fieldDecl/".toCharArray(); //$NON-NLS-1$
+	char[] REF= "ref".toCharArray(); //$NON-NLS-1$
+	char[] FIELD_REF= "fieldRef".toCharArray(); //$NON-NLS-1$
+	char[] METHOD_REF= "methodRef".toCharArray(); //$NON-NLS-1$
+	char[] CONSTRUCTOR_REF= "constructorRef".toCharArray(); //$NON-NLS-1$
+	char[] TYPE_REF= "typeRef".toCharArray(); //$NON-NLS-1$
+	char[] SUPER_REF = "superRef".toCharArray(); //$NON-NLS-1$
+	char[] TYPE_DECL = "typeDecl".toCharArray(); //$NON-NLS-1$
+	char[] METHOD_DECL= "methodDecl".toCharArray(); //$NON-NLS-1$
+	char[] CONSTRUCTOR_DECL= "constructorDecl".toCharArray(); //$NON-NLS-1$
+	char[] FIELD_DECL= "fieldDecl".toCharArray(); //$NON-NLS-1$
 	char[] OBJECT = "Object".toCharArray(); //$NON-NLS-1$
 	char[][] COUNTS= 
 		new char[][] { new char[] {'/', '0'}, new char[] {'/', '1'}, new char[] {'/', '2'}, new char[] {'/', '3'}, new char[] {'/', '4'},
diff --git a/search/org/eclipse/jdt/internal/core/search/indexing/IndexAllProject.java b/search/org/eclipse/jdt/internal/core/search/indexing/IndexAllProject.java
index b64d0e3..6b0e671 100644
--- a/search/org/eclipse/jdt/internal/core/search/indexing/IndexAllProject.java
+++ b/search/org/eclipse/jdt/internal/core/search/indexing/IndexAllProject.java
@@ -56,12 +56,11 @@
 
 		Index index = this.manager.getIndexForUpdate(this.containerPath, true, /*reuse index file*/ true /*create if none*/);
 		if (index == null) return true;
-		ReadWriteMonitor monitor = this.manager.getMonitorFor(index);
+		ReadWriteMonitor monitor = index.monitor;
 		if (monitor == null) return true; // index got deleted since acquired
 
 		try {
 			monitor.enterRead(); // ask permission to read
-			saveIfNecessary(index, monitor);
 
 			String[] paths = index.queryDocumentNames(""); // all file names //$NON-NLS-1$
 			int max = paths == null ? 0 : paths.length;
diff --git a/search/org/eclipse/jdt/internal/core/search/indexing/IndexBinaryFolder.java b/search/org/eclipse/jdt/internal/core/search/indexing/IndexBinaryFolder.java
index 6580f52..de2e65f 100644
--- a/search/org/eclipse/jdt/internal/core/search/indexing/IndexBinaryFolder.java
+++ b/search/org/eclipse/jdt/internal/core/search/indexing/IndexBinaryFolder.java
@@ -49,12 +49,11 @@
 
 		Index index = this.manager.getIndexForUpdate(this.containerPath, true, /*reuse index file*/ true /*create if none*/);
 		if (index == null) return true;
-		ReadWriteMonitor monitor = this.manager.getMonitorFor(index);
+		ReadWriteMonitor monitor = index.monitor;
 		if (monitor == null) return true; // index got deleted since acquired
 
 		try {
 			monitor.enterRead(); // ask permission to read
-			saveIfNecessary(index, monitor);
 
 			String[] paths = index.queryDocumentNames(""); // all file names //$NON-NLS-1$
 			int max = paths == null ? 0 : paths.length;
diff --git a/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java b/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java
index 02d82ca..12f6a13 100644
--- a/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java
+++ b/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java
@@ -24,7 +24,6 @@
 import org.eclipse.jdt.internal.core.index.Index;
 import org.eclipse.jdt.internal.core.search.JavaWorkspaceScope;
 import org.eclipse.jdt.internal.core.search.PatternSearchJob;
-import org.eclipse.jdt.internal.core.search.matching.TypeDeclarationPattern;
 import org.eclipse.jdt.internal.core.search.processing.IJob;
 import org.eclipse.jdt.internal.core.search.processing.JobManager;
 import org.eclipse.jdt.internal.core.util.SimpleLookupTable;
@@ -36,9 +35,6 @@
 	public SimpleLookupTable indexNames = new SimpleLookupTable();
 	private Map indexes = new HashMap(5);
 
-	/* read write monitors */
-	private Map monitors = new HashMap(5);
-
 	/* need to save ? */
 	private boolean needToSave = false;
 	private static final CRC32 checksumCalculator = new CRC32();
@@ -131,9 +127,8 @@
 			File indexFile = new File(indexName);
 			if (indexFile.exists()) { // check before creating index so as to avoid creating a new empty index if file is missing
 				try {
-					index = new org.eclipse.jdt.internal.core.index.impl.IndexImpl(indexName, "Index for " + path.toOSString(), true /*reuse index file*/); //$NON-NLS-1$
+					index = new Index(indexName, "Index for " + path.toOSString(), true /*reuse index file*/); //$NON-NLS-1$
 					indexes.put(path, index);
-					monitors.put(index, new ReadWriteMonitor());
 					return index;
 				} catch (IOException e) {
 					// failed to read the existing file or its no longer compatible
@@ -157,9 +152,8 @@
 			try {
 				if (VERBOSE)
 					JobManager.verbose("-> create empty index: "+indexName+" path: "+path.toOSString()); //$NON-NLS-1$ //$NON-NLS-2$
-				index = new org.eclipse.jdt.internal.core.index.impl.IndexImpl(indexName, "Index for " + path.toOSString(), false /*do not reuse index file*/); //$NON-NLS-1$
+				index = new Index(indexName, "Index for " + path.toOSString(), false /*do not reuse index file*/); //$NON-NLS-1$
 				indexes.put(path, index);
-				monitors.put(index, new ReadWriteMonitor());
 				return index;
 			} catch (IOException e) {
 				if (VERBOSE)
@@ -199,20 +193,10 @@
 
 	return this.javaPluginLocation = JavaCore.getPlugin().getStateLocation();
 }
-/**
- * Index access is controlled through a read-write monitor so as
- * to ensure there is no concurrent read and write operations
- * (only concurrent reading is allowed).
- */
-public ReadWriteMonitor getMonitorFor(Index index){
-	return (ReadWriteMonitor) monitors.get(index);
-}
 public void indexDocument(SearchDocument searchDocument, SearchParticipant searchParticipant, Index index, IPath indexPath) throws IOException {
 	try {
 		searchDocument.index = index;
-		((org.eclipse.jdt.internal.core.index.impl.IndexImpl) index).indexDocument(searchDocument, searchParticipant, indexPath);
-// to be replaced by
-//		searchParticipant.indexDocument(searchDocument, indexPath);
+		searchParticipant.indexDocument(searchDocument, indexPath);
 	} finally {
 		searchDocument.index = null;
 	}
@@ -289,7 +273,7 @@
 public void jobWasCancelled(IPath path) {
 	Object o = this.indexes.get(path);
 	if (o instanceof Index) {
-		this.monitors.remove(o);
+		((Index) o).monitor = null;
 		this.indexes.remove(path);
 	}
 	updateIndexState(computeIndexName(path), UNKNOWN_STATE);
@@ -353,15 +337,15 @@
 	// only called to over write an existing cached index...
 	try {
 		Index index = (Index) this.indexes.get(path);
-		ReadWriteMonitor monitor = (ReadWriteMonitor) this.monitors.remove(index);
+		ReadWriteMonitor monitor = index.monitor;
 
 		// Path is already canonical
 		String indexPath = computeIndexName(path);
 		if (VERBOSE)
 			JobManager.verbose("-> recreating index: "+indexPath+" for path: "+path.toOSString()); //$NON-NLS-1$ //$NON-NLS-2$
-		index = new org.eclipse.jdt.internal.core.index.impl.IndexImpl(indexPath, "Index for " + path.toOSString(), false /*reuse index file*/); //$NON-NLS-1$
+		index = new Index(indexPath, "Index for " + path.toOSString(), false /*reuse index file*/); //$NON-NLS-1$
 		indexes.put(path, index);
-		monitors.put(index, monitor);
+		index.monitor = monitor;
 		return index;
 	} catch (IOException e) {
 		// The file could not be created. Possible reason: the project has been deleted.
@@ -392,7 +376,7 @@
 		indexFile.delete();
 	Object o = this.indexes.get(path);
 	if (o instanceof Index)
-		this.monitors.remove(o);
+		((Index) o).monitor = null;
 	this.indexes.remove(path);
 	updateIndexState(indexName, null);
 }
@@ -436,7 +420,6 @@
 	super.reset();
 	if (this.indexes != null) {
 		this.indexes = new HashMap(5);
-		this.monitors = new HashMap(5);
 		this.indexStates = null;
 	}
 	this.indexNames = new SimpleLookupTable();
@@ -476,34 +459,37 @@
 		}
 	}
 
+	boolean allSaved = true;
 	for (int i = 0, length = toSave.size(); i < length; i++) {
 		Index index = (Index) toSave.get(i);
-		ReadWriteMonitor monitor = getMonitorFor(index);
+		ReadWriteMonitor monitor = index.monitor;
 		if (monitor == null) continue; // index got deleted since acquired
 		try {
 			// take read lock before checking if index has changed
 			// don't take write lock yet since it can cause a deadlock (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=50571)
 			monitor.enterRead(); 
 			if (index.hasChanged()) {
-				monitor.exitRead();
-				monitor.enterWrite();
-				try {
-					saveIndex(index);
-				} catch(IOException e){
-					if (VERBOSE) {
-						JobManager.verbose("-> got the following exception while saving:"); //$NON-NLS-1$
-						e.printStackTrace();
+				if (monitor.exitReadEnterWrite()) {
+					try {
+						saveIndex(index);
+					} catch(IOException e) {
+						if (VERBOSE) {
+							JobManager.verbose("-> got the following exception while saving:"); //$NON-NLS-1$
+							e.printStackTrace();
+						}
+						allSaved = false;
+					} finally {
+						monitor.exitWriteEnterRead();
 					}
-					//Util.log(e);
-				} finally {
-					monitor.exitWriteEnterRead();
+				} else {
+					allSaved = false;
 				}
 			}
 		} finally {
 			monitor.exitRead();
 		}
 	}
-	needToSave = false;
+	this.needToSave = !allSaved;
 }
 public void scheduleDocumentIndexing(final SearchDocument searchDocument, final IPath indexPath, final SearchParticipant searchParticipant) {
 	request(new IndexRequest(indexPath, this) {
@@ -513,7 +499,7 @@
 			/* ensure no concurrent write access to index */
 			Index index = getIndex(indexPath, true, /*reuse index file*/ true /*create if none*/);
 			if (index == null) return true;
-			ReadWriteMonitor monitor = getMonitorFor(index);
+			ReadWriteMonitor monitor = index.monitor;
 			if (monitor == null) return true; // index got deleted since acquired
 			
 			try {
@@ -543,9 +529,7 @@
 	SearchParticipant[] participants = SearchEngine.getSearchParticipants();
 	IJavaSearchScope scope = new JavaWorkspaceScope();
 	for (int i = 0, length = participants.length; i < length; i++) {
-		SearchParticipant participant = participants[i];
-		SearchPattern pattern = new TypeDeclarationPattern(null, null, null, ' ', SearchPattern.R_PATTERN_MATCH);
-		PatternSearchJob job = new PatternSearchJob(pattern, participant, scope, null);
+		PatternSearchJob job = new PatternSearchJob(null, participants[i], scope, null);
 		Index[] selectedIndexes = job.getIndexes(null);
 		for (int j = 0, max = selectedIndexes.length; j < max; j++) {
 			String path = selectedIndexes[j].getIndexFile().getAbsolutePath();
diff --git a/search/org/eclipse/jdt/internal/core/search/indexing/IndexRequest.java b/search/org/eclipse/jdt/internal/core/search/indexing/IndexRequest.java
index 7616ba5..ae74453 100644
--- a/search/org/eclipse/jdt/internal/core/search/indexing/IndexRequest.java
+++ b/search/org/eclipse/jdt/internal/core/search/indexing/IndexRequest.java
@@ -10,10 +10,7 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.search.indexing;
 
-import java.io.IOException;
-
 import org.eclipse.core.runtime.IPath;
-import org.eclipse.jdt.internal.core.index.Index;
 import org.eclipse.jdt.internal.core.search.processing.IJob;
 
 public abstract class IndexRequest implements IJob {
@@ -39,21 +36,6 @@
 		// tag the index as inconsistent
 		this.manager.aboutToUpdateIndex(this.containerPath, updatedIndexState());
 	}
-	/*
-	 * This code is assumed to be invoked while monitor has read lock
-	 */
-	protected void saveIfNecessary(Index index, ReadWriteMonitor monitor) throws IOException {
-		/* if index has changed, commit these before querying */
-		if (index.hasChanged()) {
-			try {
-				monitor.exitRead(); // free read lock
-				monitor.enterWrite(); // ask permission to write
-				this.manager.saveIndex(index);
-			} finally {
-				monitor.exitWriteEnterRead(); // finished writing and reacquire read permission
-			}
-		}
-	}
 	protected Integer updatedIndexState() {
 		return IndexManager.UPDATING_STATE;
 	}
diff --git a/search/org/eclipse/jdt/internal/core/search/indexing/ReadWriteMonitor.java b/search/org/eclipse/jdt/internal/core/search/indexing/ReadWriteMonitor.java
index 43b5133..bf44009 100644
--- a/search/org/eclipse/jdt/internal/core/search/indexing/ReadWriteMonitor.java
+++ b/search/org/eclipse/jdt/internal/core/search/indexing/ReadWriteMonitor.java
@@ -16,22 +16,21 @@
  */
 public class ReadWriteMonitor {
 
-	/**
-	 * <0 : writing (cannot go beyond -1, i.e one concurrent writer)
-	 * =0 : idle
-	 * >0 : reading (number of concurrent readers)
-	 */
-	private int status = 0;
+/**
+ * <0 : writing (cannot go beyond -1, i.e one concurrent writer)
+ * =0 : idle
+ * >0 : reading (number of concurrent readers)
+ */
+private int status = 0;
 /**
  * Concurrent reading is allowed
  * Blocking only when already writing.
  */
 public synchronized void enterRead() {
-
-	while (status < 0){
+	while (status < 0) {
 		try {
 			wait();
-		} catch(InterruptedException e){
+		} catch(InterruptedException e) {
 			// ignore
 		}
 	}
@@ -42,11 +41,10 @@
  * Blocking only when already writing or reading.
  */
 public synchronized void enterWrite() {
-
-	while (status != 0){
+	while (status != 0) {
 		try {
 			wait();
-		} catch(InterruptedException e){
+		} catch(InterruptedException e) {
 			// ignore
 		}
 	}
@@ -68,6 +66,18 @@
 	if (++status == 0) notifyAll();
 }
 /**
+ * Atomic exitRead/enterWrite: Allows to keep monitor in between
+ * exit read and next enter write.
+ * Use when writing changes is optional, otherwise call the individual methods.
+ * Returns false if multiple readers are accessing the index.
+ */
+public synchronized boolean exitReadEnterWrite() {
+	if (status != 1) return false; // only continue if this is the only reader
+
+	status = -1;
+	return true;
+}
+/**
  * Atomic exitWrite/enterRead: Allows to keep monitor in between
  * exit write and next enter read.
  * When writing is over, all readers are granted permissing to restart
@@ -83,5 +93,19 @@
 public synchronized void exitWriteEnterRead() {
 	this.exitWrite();
 	this.enterRead();
-} 
+}
+public String toString() {
+	StringBuffer buffer = new StringBuffer();
+	if (status == 0) {
+		buffer.append("Monitor idle "); //$NON-NLS-1$
+	} else if (status < 0) {
+		buffer.append("Monitor writing "); //$NON-NLS-1$
+	} else if (status > 0) {
+		buffer.append("Monitor reading "); //$NON-NLS-1$
+	}
+	buffer.append("(status = "); //$NON-NLS-1$
+	buffer.append(this.status);
+	buffer.append(")"); //$NON-NLS-1$
+	return buffer.toString();
+}
 }
diff --git a/search/org/eclipse/jdt/internal/core/search/indexing/RemoveFolderFromIndex.java b/search/org/eclipse/jdt/internal/core/search/indexing/RemoveFolderFromIndex.java
index a69aefa..a0272aa 100644
--- a/search/org/eclipse/jdt/internal/core/search/indexing/RemoveFolderFromIndex.java
+++ b/search/org/eclipse/jdt/internal/core/search/indexing/RemoveFolderFromIndex.java
@@ -38,7 +38,7 @@
 		/* ensure no concurrent write access to index */
 		Index index = manager.getIndex(this.containerPath, true, /*reuse index file*/ false /*create if none*/);
 		if (index == null) return true;
-		ReadWriteMonitor monitor = manager.getMonitorFor(index);
+		ReadWriteMonitor monitor = index.monitor;
 		if (monitor == null) return true; // index got deleted since acquired
 
 		try {
diff --git a/search/org/eclipse/jdt/internal/core/search/indexing/RemoveFromIndex.java b/search/org/eclipse/jdt/internal/core/search/indexing/RemoveFromIndex.java
index 31191e5..da94b1c 100644
--- a/search/org/eclipse/jdt/internal/core/search/indexing/RemoveFromIndex.java
+++ b/search/org/eclipse/jdt/internal/core/search/indexing/RemoveFromIndex.java
@@ -28,7 +28,7 @@
 		/* ensure no concurrent write access to index */
 		Index index = manager.getIndex(this.containerPath, true, /*reuse index file*/ false /*create if none*/);
 		if (index == null) return true;
-		ReadWriteMonitor monitor = manager.getMonitorFor(index);
+		ReadWriteMonitor monitor = index.monitor;
 		if (monitor == null) return true; // index got deleted since acquired
 
 		try {
diff --git a/search/org/eclipse/jdt/internal/core/search/indexing/SaveIndex.java b/search/org/eclipse/jdt/internal/core/search/indexing/SaveIndex.java
index cf03c2a..e2ca4b4 100644
--- a/search/org/eclipse/jdt/internal/core/search/indexing/SaveIndex.java
+++ b/search/org/eclipse/jdt/internal/core/search/indexing/SaveIndex.java
@@ -31,7 +31,7 @@
 		/* ensure no concurrent write access to index */
 		Index index = this.manager.getIndex(this.containerPath, true /*reuse index file*/, false /*don't create if none*/);
 		if (index == null) return true;
-		ReadWriteMonitor monitor = this.manager.getMonitorFor(index);
+		ReadWriteMonitor monitor = index.monitor;
 		if (monitor == null) return true; // index got deleted since acquired
 
 		try {
diff --git a/search/org/eclipse/jdt/internal/core/search/matching/AndPattern.java b/search/org/eclipse/jdt/internal/core/search/matching/AndPattern.java
index 01f8418..0ecded0 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/AndPattern.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/AndPattern.java
@@ -14,12 +14,10 @@
 
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.OperationCanceledException;
-import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.search.*;
-import org.eclipse.jdt.internal.core.index.EntryResult;
-import org.eclipse.jdt.internal.core.index.impl.IndexInput;
-import org.eclipse.jdt.internal.core.index.impl.IndexedFile;
+import org.eclipse.jdt.internal.core.index.*;
 import org.eclipse.jdt.internal.core.search.IndexQueryRequestor;
+import org.eclipse.jdt.internal.core.util.SimpleSet;
 
 /**
  * Query the index multiple times and do an 'and' on the results.
@@ -29,97 +27,50 @@
 public AndPattern(int patternKind, int matchRule) {
 	super(patternKind, matchRule);
 }
-
-/**
- * Query a given index for matching entries. 
- */
-protected void findIndexMatches(IndexInput input, IndexQueryRequestor requestor, SearchParticipant participant, IJavaSearchScope scope, IProgressMonitor progressMonitor, char[] queryKey, char[] category) throws IOException {
-
+public void findIndexMatches(Index index, IndexQueryRequestor requestor, SearchParticipant participant, IJavaSearchScope scope, IProgressMonitor progressMonitor) throws IOException {
 	if (progressMonitor != null && progressMonitor.isCanceled()) throw new OperationCanceledException();
-	
-	/* narrow down a set of entries using prefix criteria */
-	long[] possibleRefs = null;
-	int maxRefs = -1;
+
 	this.resetQuery();
-	do {
-		queryKey = encodeIndexKey();
-		char[] pattern = CharOperation.concat(category, queryKey);
-		EntryResult[] entries = input.queryEntries(pattern, SearchPattern.R_PREFIX_MATCH);
-		if (entries == null) break;
+	SimpleSet intersectedNames = null;
+	try {
+		index.startQuery();
+		do {
+			SearchPattern pattern = currentPattern();
+			EntryResult[] entries = pattern.queryIn(index);
+			if (entries == null) return;
 
-		int numFiles = input.getNumFiles();
-		long[] references = null;
-		int referencesLength = -1;
-		for (int i = 0, max = entries.length; i < max; i++) {
-			if (progressMonitor != null && progressMonitor.isCanceled()) throw new OperationCanceledException();
+			SearchPattern decodedResult = pattern.getBlankPattern();
+			SimpleSet newIntersectedNames = new SimpleSet();
+			for (int i = 0, l = entries.length; i < l; i++) {
+				if (progressMonitor != null && progressMonitor.isCanceled()) throw new OperationCanceledException();
 
-			/* retrieve and decode entry */	
-			EntryResult entry = entries[i];
-			char[] word = entry.getWord();
-			char[] indexKey = CharOperation.subarray(word, category.length, word.length);
-			SearchPattern decodedPattern = getBlankPattern();
-			decodedPattern.decodeIndexKey(indexKey);
-			if (matchesDecodedPattern(decodedPattern)) {
-				/* accumulate references in an array of bits : 1 if the reference is present, 0 otherwise */
-				int[] fileReferences = entry.getFileReferences();
-				for (int j = 0, refLength = fileReferences.length; j < refLength; j++) {
-					int fileReference = fileReferences[j];
-					int vectorIndex = fileReference / 64; // a long has 64 bits
-					if (references == null) {
-						referencesLength = (numFiles / 64) + 1;
-						references = new long[referencesLength];
-					}
-					long mask = 1L << (fileReference % 64);
-					references[vectorIndex] |= mask;
-				}
-			}
-		}
-		
-		/* only select entries which actually match the entire search pattern */
-		if (references == null) return;
-		if (possibleRefs == null) {
-			/* first query : these are the possible references */
-			possibleRefs = references;
-			maxRefs = numFiles;
-		} else {
-			/* eliminate possible references that don't match the current references */
-			int possibleLength = possibleRefs.length;
-			for (int i = 0, length = references.length; i < length; i++) {
-				if (i < possibleLength)
-					possibleRefs[i] &= references[i];
-				else
-					possibleRefs[i] = 0;
-			}
-			// check to see that there are still possible references after the merge
-			while (--possibleLength >= 0 && possibleRefs[possibleLength] == 0);
-			if (possibleLength == -1) return;
-		}
-	} while (this.hasNextQuery());
-
-	/* report possible references that remain */
-	if (possibleRefs != null) {
-		int[] refs = new int[maxRefs];
-		int refsLength = 0;
-		for (int reference = 1; reference <= maxRefs; reference++) {
-			int vectorIndex = reference / 64; // a long has 64 bits
-			if ((possibleRefs[vectorIndex] & (1L << (reference % 64))) != 0)
-				refs[refsLength++] = reference;
-		}
-		System.arraycopy(refs, 0, refs = new int[refsLength], 0, refsLength);
-		for (int i = 0; i < refsLength; i++) { // TODO (jerome) merge with previous loop
-			int reference = refs[i];
-			if (reference != -1) { // if the reference has not been eliminated
-				IndexedFile file = input.getIndexedFile(reference);
-				if (file != null) {
-					String documentPath = IndexedFile.convertPath(file.getPath());
-					if (scope.encloses(documentPath)) {
-						if (!requestor.acceptIndexMatch(documentPath, null, participant)) // AndPatterns cannot provide the decoded pattern 
-							throw new OperationCanceledException();
+				EntryResult entry = entries[i];
+				decodedResult.decodeIndexKey(entry.getWord());
+				if (pattern.matchesDecodedKey(decodedResult)) {
+					String[] names = entry.getDocumentNames(index);
+					if (intersectedNames != null) {
+						for (int j = 0, n = names.length; j < n; j++)
+							if (intersectedNames.includes(names[j]))
+								newIntersectedNames.add(names[j]);
+					} else {
+						for (int j = 0, n = names.length; j < n; j++)
+							newIntersectedNames.add(names[j]);
 					}
 				}
 			}
-		}
+
+			if (newIntersectedNames.elementSize == 0) return;
+			intersectedNames = newIntersectedNames;
+		} while (this.hasNextQuery());
+	} finally {
+		index.stopQuery();
 	}
+	if (intersectedNames == null) return;
+
+	Object[] names = intersectedNames.values;
+	for (int i = 0, l = names.length; i < l; i++)
+		if (names[i] != null)
+			acceptMatch((String) names[i], null, requestor, participant, scope); // AndPatterns cannot provide the decoded result
 }
 /**
  * Returns whether another query must be done.
diff --git a/search/org/eclipse/jdt/internal/core/search/matching/ClassFileMatchLocator.java b/search/org/eclipse/jdt/internal/core/search/matching/ClassFileMatchLocator.java
index 054f8ff..58650e0 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/ClassFileMatchLocator.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/ClassFileMatchLocator.java
@@ -64,7 +64,7 @@
 	SearchPattern pattern = locator.pattern;
 	BinaryType binaryType = (BinaryType) classFile.getType();
 	if (matchBinary(pattern, info, null))
-		locator.reportBinaryMatch(null, binaryType, info, IJavaSearchResultCollector.EXACT_MATCH);
+		locator.reportBinaryMemberDeclaration(null, binaryType, info, IJavaSearchResultCollector.EXACT_MATCH);
 
 	int accuracy = IJavaSearchResultCollector.EXACT_MATCH;
 	if (pattern.mustResolve) {
@@ -81,7 +81,7 @@
 						IMethod methodHandle = binaryType.getMethod(
 							new String(method.isConstructor() ? binding.compoundName[binding.compoundName.length-1] : method.selector),
 							CharOperation.toStrings(Signature.getParameterTypes(convertClassFileFormat(method.signature()))));
-						locator.reportBinaryMatch(null, methodHandle, info, IJavaSearchResultCollector.EXACT_MATCH);
+						locator.reportBinaryMemberDeclaration(null, methodHandle, info, IJavaSearchResultCollector.EXACT_MATCH);
 					}
 				}
 
@@ -90,7 +90,7 @@
 					FieldBinding field = fields[i];
 					if (locator.patternLocator.resolveLevel(field) == PatternLocator.ACCURATE_MATCH) {
 						IField fieldHandle = binaryType.getField(new String(field.name));
-						locator.reportBinaryMatch(null, fieldHandle, info, IJavaSearchResultCollector.EXACT_MATCH);
+						locator.reportBinaryMemberDeclaration(null, fieldHandle, info, IJavaSearchResultCollector.EXACT_MATCH);
 					}
 				}
 
@@ -111,7 +111,7 @@
 				IMethod methodHandle = binaryType.getMethod(
 					new String(method.isConstructor() ? info.getName() : method.getSelector()),
 					CharOperation.toStrings(Signature.getParameterTypes(convertClassFileFormat(method.getMethodDescriptor()))));
-				locator.reportBinaryMatch(null, methodHandle, info, accuracy);
+				locator.reportBinaryMemberDeclaration(null, methodHandle, info, accuracy);
 			}
 		}
 	}
@@ -122,7 +122,7 @@
 			IBinaryField field = fields[i];
 			if (matchBinary(pattern, field, info)) {
 				IField fieldHandle = binaryType.getField(new String(field.getName()));
-				locator.reportBinaryMatch(null, fieldHandle, info, accuracy);
+				locator.reportBinaryMemberDeclaration(null, fieldHandle, info, accuracy);
 			}
 		}
 	}
diff --git a/search/org/eclipse/jdt/internal/core/search/matching/ConstructorLocator.java b/search/org/eclipse/jdt/internal/core/search/matching/ConstructorLocator.java
index ecf8cae..e239cbb 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/ConstructorLocator.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/ConstructorLocator.java
@@ -10,6 +10,7 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.search.matching;
 
+import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.internal.compiler.ast.*;
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
 import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
@@ -127,6 +128,9 @@
 		return resolveLevel((ConstructorDeclaration) node, true);
 	return IMPOSSIBLE_MATCH;
 }
+protected int referenceType() {
+	return IJavaElement.METHOD;
+}
 protected int resolveLevel(AllocationExpression allocation) {
 	// constructor name is simple type name
 	char[][] typeName = allocation.type.getTypeName();
diff --git a/search/org/eclipse/jdt/internal/core/search/matching/ConstructorPattern.java b/search/org/eclipse/jdt/internal/core/search/matching/ConstructorPattern.java
index f0013a4..fe234a4 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/ConstructorPattern.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/ConstructorPattern.java
@@ -10,8 +10,11 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.search.matching;
 
+import java.io.IOException;
+
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.search.SearchPattern;
+import org.eclipse.jdt.internal.core.index.*;
 
 public class ConstructorPattern extends SearchPattern {
 
@@ -25,11 +28,19 @@
 public char[][] parameterSimpleNames;
 public int parameterCount;
 
+protected static char[][] REF_CATEGORIES = { CONSTRUCTOR_REF };
+protected static char[][] REF_AND_DECL_CATEGORIES = { CONSTRUCTOR_REF, CONSTRUCTOR_DECL };
+protected static char[][] DECL_CATEGORIES = { CONSTRUCTOR_DECL };
+
+/**
+ * Constructor entries are encoded as TypeName '/' Arity:
+ * e.g. 'X/0'
+ */
 public static char[] createIndexKey(char[] typeName, int argCount) {
-	ConstructorPattern pattern = new ConstructorPattern(R_EXACT_MATCH | R_CASE_SENSITIVE);
-	pattern.declaringSimpleName = typeName;
-	pattern.parameterCount = argCount;
-	return pattern.encodeIndexKey();
+	char[] countChars = argCount < 10
+		? COUNTS[argCount]
+		: ("/" + String.valueOf(argCount)).toCharArray(); //$NON-NLS-1$
+	return CharOperation.concat(typeName, countChars);
 }
 
 public ConstructorPattern(
@@ -72,58 +83,21 @@
 	this.parameterCount = Integer.parseInt(new String(key, lastSeparatorIndex + 1, size - lastSeparatorIndex - 1));
 	this.declaringSimpleName = CharOperation.subarray(key, 0, lastSeparatorIndex);
 }
-/**
- * Constructor declaration entries are encoded as 'constructorDecl/' TypeName '/' Arity:
- * e.g. 'constructorDecl/X/0'
- *
- * Constructor reference entries are encoded as 'constructorRef/' TypeName '/' Arity:
- * e.g. 'constructorRef/X/0'
- */
-public char[] encodeIndexKey() {
-	// will have a common pattern in the new story
-	if (this.isCaseSensitive && this.declaringSimpleName != null) {
-		switch(this.matchMode) {
-			case EXACT_MATCH :
-				int arity = this.parameterCount;
-				if (arity >= 0) {
-					char[] countChars = arity < 10 ? COUNTS[arity] : ("/" + String.valueOf(arity)).toCharArray(); //$NON-NLS-1$
-					return CharOperation.concat(this.declaringSimpleName, countChars);
-				}
-			case PREFIX_MATCH :
-				return this.declaringSimpleName;
-			case PATTERN_MATCH :
-				int starPos = CharOperation.indexOf('*', this.declaringSimpleName);
-				switch(starPos) {
-					case -1 :
-						return this.declaringSimpleName;
-					default : 
-						char[] result = new char[starPos];
-						System.arraycopy(this.declaringSimpleName, 0, result, 0, starPos);
-						return result;
-					case 0 : // fall through
-				}
-		}
-	}
-	return CharOperation.NO_CHAR; // find them all
-}
 public SearchPattern getBlankPattern() {
 	return new ConstructorPattern(R_EXACT_MATCH | R_CASE_SENSITIVE);
 }
 public char[][] getMatchCategories() {
 	if (this.findReferences)
-		if (this.findDeclarations) 
-			return new char[][] {CONSTRUCTOR_REF, CONSTRUCTOR_DECL};
-		else
-			return new char[][] {CONSTRUCTOR_REF};
-	else if (this.findDeclarations)
-		return new char[][] {CONSTRUCTOR_DECL};
+		return this.findDeclarations ? REF_AND_DECL_CATEGORIES : REF_CATEGORIES;
+	if (this.findDeclarations)
+		return DECL_CATEGORIES;
 	return CharOperation.NO_CHAR_CHAR;
 }
-public boolean matchesDecodedPattern(SearchPattern decodedPattern) {
+public boolean matchesDecodedKey(SearchPattern decodedPattern) {
 	ConstructorPattern pattern = (ConstructorPattern) decodedPattern;
-	if (this.parameterCount != -1 && this.parameterCount != pattern.parameterCount) return false;
 
-	return matchesName(this.declaringSimpleName, pattern.declaringSimpleName);
+	return (this.parameterCount == pattern.parameterCount || this.parameterCount == -1)
+		&& matchesName(this.declaringSimpleName, pattern.declaringSimpleName);
 }
 protected boolean mustResolve() {
 	if (this.declaringQualification != null) return true;
@@ -134,6 +108,31 @@
 			if (this.parameterQualifications[i] != null) return true;
 	return this.findReferences; // need to check resolved default constructors and explicit constructor calls
 }
+public EntryResult[] queryIn(Index index) throws IOException {
+	char[] key = this.declaringSimpleName; // can be null
+	int matchRule = getMatchRule();
+
+	switch(this.matchMode) {
+		case R_EXACT_MATCH :
+			if (this.declaringSimpleName != null && this.parameterCount >= 0)
+				key = createIndexKey(this.declaringSimpleName, this.parameterCount);
+			else // do a prefix query with the declaringSimpleName
+				matchRule = matchRule - R_EXACT_MATCH + R_PREFIX_MATCH;
+			break;
+		case R_PREFIX_MATCH :
+			// do a prefix query with the declaringSimpleName
+			break;
+		case R_PATTERN_MATCH :
+			if (this.parameterCount >= 0)
+				key = createIndexKey(this.declaringSimpleName == null ? ONE_STAR : this.declaringSimpleName, this.parameterCount);
+			else if (this.declaringSimpleName != null && this.declaringSimpleName[this.declaringSimpleName.length - 1] != '*')
+				key = CharOperation.concat(this.declaringSimpleName, ONE_STAR, SEPARATOR);
+			// else do a pattern query with just the declaringSimpleName
+			break;
+	}
+
+	return index.query(getMatchCategories(), key, matchRule); // match rule is irrelevant when the key is null
+}
 public String toString() {
 	StringBuffer buffer = new StringBuffer(20);
 	if (this.findDeclarations) {
@@ -163,13 +162,13 @@
 	buffer.append(')');
 	buffer.append(", "); //$NON-NLS-1$
 	switch(this.matchMode) {
-		case EXACT_MATCH : 
+		case R_EXACT_MATCH : 
 			buffer.append("exact match, "); //$NON-NLS-1$
 			break;
-		case PREFIX_MATCH :
+		case R_PREFIX_MATCH :
 			buffer.append("prefix match, "); //$NON-NLS-1$
 			break;
-		case PATTERN_MATCH :
+		case R_PATTERN_MATCH :
 			buffer.append("pattern match, "); //$NON-NLS-1$
 			break;
 	}
diff --git a/search/org/eclipse/jdt/internal/core/search/matching/FieldLocator.java b/search/org/eclipse/jdt/internal/core/search/matching/FieldLocator.java
index e294049..f877030 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/FieldLocator.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/FieldLocator.java
@@ -14,7 +14,9 @@
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.core.search.*;
 import org.eclipse.jdt.core.search.IJavaSearchResultCollector;
+import org.eclipse.jdt.core.search.SearchMatch;
 import org.eclipse.jdt.internal.compiler.ast.*;
 import org.eclipse.jdt.internal.compiler.env.IBinaryType;
 import org.eclipse.jdt.internal.compiler.lookup.*;
@@ -120,9 +122,11 @@
 		}
 	} else if (reference instanceof FieldReference) {
 		long position = ((FieldReference) reference).nameSourcePosition;
-		locator.report(position, position, element, accuracy);
+		SearchMatch match = JavaSearchMatch.newReferenceMatch(IJavaElement.FIELD, element, accuracy, ((int) (position >>> 32)), ((int) position)+1, locator);
+		locator.report(match);
 	} else if (reference instanceof SingleNameReference) {
-		locator.report(reference.sourceStart, reference.sourceEnd, element, accuracy);
+		SearchMatch match = JavaSearchMatch.newReferenceMatch(IJavaElement.FIELD, element, accuracy, reference.sourceStart, reference.sourceEnd+1, locator);
+		locator.report(match);
 	} else if (reference instanceof QualifiedNameReference) {
 		QualifiedNameReference qNameRef = (QualifiedNameReference) reference;
 		int length = qNameRef.tokens.length;
@@ -174,7 +178,7 @@
 				accuracies[i] = -1;
 			}
 		}
-		locator.reportAccurateReference(reference.sourceStart, reference.sourceEnd, qNameRef.tokens, element, accuracies);
+		locator.reportAccurateReference(IJavaElement.FIELD, reference.sourceStart, reference.sourceEnd, qNameRef.tokens, element, accuracies);
 	}
 }
 protected void reportDeclaration(FieldBinding fieldBinding, MatchLocator locator, SimpleSet knownFields) throws CoreException {
@@ -197,7 +201,7 @@
 		if (resource == null)
 			resource = type.getJavaProject().getProject();
 		info = locator.getBinaryInfo((org.eclipse.jdt.internal.core.ClassFile) type.getClassFile(), resource);
-		locator.reportBinaryMatch(resource, field, info, IJavaSearchResultCollector.EXACT_MATCH);
+		locator.reportBinaryMemberDeclaration(resource, field, info, IJavaSearchResultCollector.EXACT_MATCH);
 	} else {
 		ClassScope scope = ((SourceTypeBinding) declaringClass).scope;
 		if (scope != null) {
@@ -211,18 +215,16 @@
 				}
 			} 
 			if (fieldDecl != null) {
-				locator.report(
-					resource, 
-					fieldDecl.sourceStart, 
-					fieldDecl.sourceEnd, 
-					field,
-					IJavaSearchResultCollector.EXACT_MATCH, 
-					locator.getParticipant());
+				SearchMatch match = new FieldDeclarationMatch(field, IJavaSearchResultCollector.EXACT_MATCH, fieldDecl.sourceStart, fieldDecl.sourceEnd+1, locator.getParticipant(), resource);
+				locator.report(match);
 
 			}
 		}
 	}
 }
+protected int referenceType() {
+	return IJavaElement.FIELD;
+}
 public int resolveLevel(ASTNode possiblelMatchingNode) {
 	if (this.pattern.findReferences) {
 		if (possiblelMatchingNode instanceof FieldReference)
diff --git a/search/org/eclipse/jdt/internal/core/search/matching/FieldPattern.java b/search/org/eclipse/jdt/internal/core/search/matching/FieldPattern.java
index 74248ba..3962291 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/FieldPattern.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/FieldPattern.java
@@ -28,7 +28,7 @@
 protected static char[][] DECL_CATEGORIES = { FIELD_DECL };
 
 public static char[] createIndexKey(char[] fieldName) {
-	return fieldName != null ? fieldName : CharOperation.NO_CHAR;
+	return encodeIndexKey(fieldName, R_EXACT_MATCH);
 }
 
 public FieldPattern(
@@ -54,24 +54,22 @@
 public void decodeIndexKey(char[] key) {
 	this.name = key;
 }
-public char[] encodeIndexKey() {
-	return encodeIndexKey(this.name);
-}
 public SearchPattern getBlankPattern() {
 	return new FieldPattern(false, false, false, null, null, null, null, null, R_EXACT_MATCH | R_CASE_SENSITIVE);
 }
+public char[] getIndexKey() {
+	return encodeIndexKey(this.name, this.matchMode);
+}
 public char[][] getMatchCategories() {
-	return this.findReferences
-			? (this.findDeclarations || this.writeAccess ? REF_AND_DECL_CATEGORIES : REF_CATEGORIES)
-			: DECL_CATEGORIES;
+	if (this.findReferences)
+		return this.findDeclarations || this.writeAccess ? REF_AND_DECL_CATEGORIES : REF_CATEGORIES;
+	if (this.findDeclarations)
+		return DECL_CATEGORIES;
+	return CharOperation.NO_CHAR_CHAR;
 }
-public boolean matchesDecodedPattern(SearchPattern decodedPattern) {
-	return matchesName(this.name, ((FieldPattern) decodedPattern).name);
+public boolean matchesDecodedKey(SearchPattern decodedPattern) {
+	return true; // index key is not encoded so query results all match
 }
-/**
- * Returns whether a method declaration or message send will need to be resolved to 
- * find out if this method pattern matches it.
- */
 protected boolean mustResolve() {
 	if (this.declaringSimpleName != null || this.declaringQualification != null) return true;
 	if (this.typeSimpleName != null || this.typeQualification != null) return true;
@@ -104,13 +102,13 @@
 	else if (typeQualification != null) buffer.append("*"); //$NON-NLS-1$
 	buffer.append(", "); //$NON-NLS-1$
 	switch(this.matchMode) {
-		case EXACT_MATCH : 
+		case R_EXACT_MATCH : 
 			buffer.append("exact match, "); //$NON-NLS-1$
 			break;
-		case PREFIX_MATCH :
+		case R_PREFIX_MATCH :
 			buffer.append("prefix match, "); //$NON-NLS-1$
 			break;
-		case PATTERN_MATCH :
+		case R_PATTERN_MATCH :
 			buffer.append("pattern match, "); //$NON-NLS-1$
 			break;
 	}
diff --git a/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchMatch.java b/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchMatch.java
index 88db200..3f80ccd 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchMatch.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchMatch.java
@@ -12,8 +12,11 @@
 
 import org.eclipse.core.resources.IResource;
 import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.core.search.PackageReferenceMatch;
 import org.eclipse.jdt.core.search.SearchMatch;
 import org.eclipse.jdt.core.search.SearchParticipant;
+import org.eclipse.jdt.internal.core.JavaElement;
 
 public class JavaSearchMatch extends SearchMatch {
 	
@@ -21,24 +24,78 @@
 	public IJavaElement element;
 	
 	public JavaSearchMatch(
-			IResource resource,
 			IJavaElement element,
-			String documentPath,
-			int accuracy,  
-			SearchParticipant participant,
-			int sourceStart, 
-			int sourceEnd, 
-			int sourceLineNumber) {
+			int accuracy,
+			int sourceStart,  
+			int sourceEnd,
+			SearchParticipant participant, 
+			IResource resource) {
 		super(
 			element.getElementName(), 
-			documentPath, 
+			element.getPath().toString(),  // document path
 			accuracy, 
 			participant, 
 			sourceStart, 
 			sourceEnd, 
-			sourceLineNumber, 
-			element.toString());
+			-1, // line number
+			((JavaElement)element).toStringWithAncestors());
 		this.resource = resource;
 		this.element = element;
 	}
+	public static JavaSearchMatch newDeclarationMatch(
+			IJavaElement element,
+			int accuracy,
+			int sourceStart,  
+			int sourceEnd,
+			MatchLocator locator) {
+		SearchParticipant participant = locator.getParticipant(); 
+		IResource resource = locator.currentPossibleMatch.resource;
+		return newDeclarationMatch(element, accuracy, sourceStart, sourceEnd, participant, resource);
+	}
+	public static JavaSearchMatch newDeclarationMatch(
+			IJavaElement element,
+			int accuracy,
+			int sourceStart,  
+			int sourceEnd,
+			SearchParticipant participant, 
+			IResource resource) {
+		switch (element.getElementType()) {
+			case IJavaElement.PACKAGE_FRAGMENT:
+				return new PackageDeclarationMatch(element, accuracy, sourceStart, sourceEnd, participant, resource);
+			case IJavaElement.TYPE:
+				return new TypeDeclarationMatch(element, accuracy, sourceStart, sourceEnd, participant, resource);
+			case IJavaElement.FIELD:
+				return new FieldDeclarationMatch(element, accuracy, sourceStart, sourceEnd, participant, resource);
+			case IJavaElement.METHOD:
+				return new MethodDeclarationMatch(element, accuracy, sourceStart, sourceEnd, participant, resource);
+			case IJavaElement.LOCAL_VARIABLE:
+				return new LocalVariableDeclarationMatch(element, accuracy, sourceStart, sourceEnd, participant, resource);
+			default:
+				return new JavaSearchMatch(element, accuracy, sourceStart, sourceEnd, participant, resource);
+		}
+	}
+	public static JavaSearchMatch newReferenceMatch(
+			int referenceType,
+			IJavaElement enclosingElement,
+			int accuracy,
+			int sourceStart,  
+			int sourceEnd,
+			MatchLocator locator) {
+		SearchParticipant participant = locator.getParticipant(); 
+		IResource resource = locator.currentPossibleMatch.resource;
+		switch (referenceType) {
+			case IJavaElement.PACKAGE_FRAGMENT:
+				return new PackageReferenceMatch(enclosingElement, accuracy, sourceStart, sourceEnd, participant, resource);
+			case IJavaElement.TYPE:
+				return new TypeReferenceMatch(enclosingElement, accuracy, sourceStart, sourceEnd, participant, resource);
+			case IJavaElement.FIELD:
+				return new FieldReferenceMatch(enclosingElement, accuracy, sourceStart, sourceEnd, participant, resource);
+			case IJavaElement.METHOD:
+				return new MethodReferenceMatch(enclosingElement, accuracy, sourceStart, sourceEnd, participant, resource);
+			case IJavaElement.LOCAL_VARIABLE:
+				return new LocalVariableReferenceMatch(enclosingElement, accuracy, sourceStart, sourceEnd, participant, resource);
+			default:
+				return new JavaSearchMatch(enclosingElement, accuracy, sourceStart, sourceEnd, participant, resource);
+		}
+	}
 }
diff --git a/search/org/eclipse/jdt/internal/core/search/matching/LocalVariableLocator.java b/search/org/eclipse/jdt/internal/core/search/matching/LocalVariableLocator.java
index c76212c..c1f5210 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/LocalVariableLocator.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/LocalVariableLocator.java
@@ -12,6 +12,7 @@
 
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.search.SearchMatch;
 import org.eclipse.jdt.internal.compiler.ast.*;
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
 import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
@@ -43,14 +44,17 @@
 }
 protected void matchReportReference(ASTNode reference, IJavaElement element, int accuracy, MatchLocator locator) throws CoreException {
 	if (reference instanceof SingleNameReference) {
-		locator.report(reference.sourceStart, reference.sourceEnd, element, accuracy);
+		SearchMatch match = JavaSearchMatch.newReferenceMatch(IJavaElement.LOCAL_VARIABLE, element, accuracy, reference.sourceStart, reference.sourceEnd+1, locator);
+		locator.report(match);
 	} else if (reference instanceof QualifiedNameReference) {
 		QualifiedNameReference qNameRef = (QualifiedNameReference) reference;
 		long sourcePosition = qNameRef.sourcePositions[0];
-		locator.report(sourcePosition, sourcePosition, element, accuracy);
+		SearchMatch match = JavaSearchMatch.newReferenceMatch(IJavaElement.LOCAL_VARIABLE, element, accuracy, ((int) (sourcePosition >>> 32)), ((int) sourcePosition)+1, locator);
+		locator.report(match);
 	} else if (reference instanceof LocalDeclaration) {
 		LocalVariable localVariable = getLocalVariable();
-		locator.report(localVariable.nameStart, localVariable.nameEnd, localVariable, accuracy);
+		SearchMatch match = JavaSearchMatch.newReferenceMatch(IJavaElement.LOCAL_VARIABLE, localVariable, accuracy, localVariable.nameStart, localVariable.nameEnd+1, locator);
+		locator.report(match);
 	}
 }
 protected int matchContainer() {
@@ -65,6 +69,9 @@
 		? ACCURATE_MATCH
 		: IMPOSSIBLE_MATCH;
 }
+protected int referenceType() {
+	return IJavaElement.LOCAL_VARIABLE;
+}
 public int resolveLevel(ASTNode possiblelMatchingNode) {
 	if (this.pattern.findReferences)
 		if (possiblelMatchingNode instanceof NameReference)
diff --git a/search/org/eclipse/jdt/internal/core/search/matching/LocalVariablePattern.java b/search/org/eclipse/jdt/internal/core/search/matching/LocalVariablePattern.java
index 889982d..8a2fa5e 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/LocalVariablePattern.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/LocalVariablePattern.java
@@ -10,8 +10,6 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.search.matching;
 
-import java.io.IOException;
-
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.OperationCanceledException;
 import org.eclipse.jdt.core.*;
@@ -29,7 +27,7 @@
 	super(LOCAL_VAR_PATTERN, findDeclarations, readAccess, writeAccess, localVariable.getElementName().toCharArray(), matchRule);
 	this.localVariable = localVariable;
 }
-public void findIndexMatches(Index index, IndexQueryRequestor requestor, SearchParticipant participant, IJavaSearchScope scope, IProgressMonitor progressMonitor) throws IOException {
+public void findIndexMatches(Index index, IndexQueryRequestor requestor, SearchParticipant participant, IJavaSearchScope scope, IProgressMonitor progressMonitor) {
     IPackageFragmentRoot root = (IPackageFragmentRoot)this.localVariable.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
 	String path;
     if (root.isArchive()) {
@@ -55,13 +53,13 @@
 	buffer.append(this.localVariable.toStringWithAncestors());
 	buffer.append(", "); //$NON-NLS-1$
 	switch(this.matchMode) {
-		case EXACT_MATCH : 
+		case R_EXACT_MATCH : 
 			buffer.append("exact match, "); //$NON-NLS-1$
 			break;
-		case PREFIX_MATCH :
+		case R_PREFIX_MATCH :
 			buffer.append("prefix match, "); //$NON-NLS-1$
 			break;
-		case PATTERN_MATCH :
+		case R_PATTERN_MATCH :
 			buffer.append("pattern match, "); //$NON-NLS-1$
 			break;
 	}
diff --git a/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java b/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java
index cfc2d35..d622838 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java
@@ -473,6 +473,9 @@
 	}
 	return null;
 }
+protected boolean encloses(IJavaElement element) {
+	return element != null && this.scope.encloses(element);
+}
 protected IBinaryType getBinaryInfo(ClassFile classFile, IResource resource) throws CoreException {
 	BinaryType binaryType = (BinaryType) classFile.getType();
 	if (classFile.isOpen())
@@ -776,7 +779,11 @@
 			SearchDocument document = participant.getDocument(resource.getFullPath().toString());
 			this.currentPossibleMatch = new PossibleMatch(this, resource, null, document);
 			try {
-				this.report(-1, -2, searchPattern.focus, IJavaSearchResultCollector.EXACT_MATCH);
+				IJavaElement element = searchPattern.focus;
+				if (encloses(element)) {
+					SearchMatch match = JavaSearchMatch.newDeclarationMatch(element, IJavaSearchResultCollector.EXACT_MATCH, -1, -1, this);
+					report(match);
+				}
 			} catch (CoreException e) {
 				if (e instanceof JavaModelException) {
 					throw (JavaModelException) e;
@@ -803,7 +810,10 @@
 						SearchDocument document = participant.getDocument(resource.getFullPath().toString());
 						this.currentPossibleMatch = new PossibleMatch(this, resource, null, document);
 						try {
-							report(-1, -2, pkg, IJavaSearchResultCollector.EXACT_MATCH);
+							if (encloses(pkg)) {
+								SearchMatch match = JavaSearchMatch.newDeclarationMatch(pkg, IJavaSearchResultCollector.EXACT_MATCH, -1, -1, this);
+								report(match);
+							}
 						} catch (JavaModelException e) {
 							throw e;
 						} catch (CoreException e) {
@@ -933,51 +943,34 @@
 	for (int i = 0, l = types.length; i < l; i++)
 		purgeMethodStatements(types[i], true); 
 }
-protected void report(int sourceStart, int sourceEnd, IJavaElement element, int accuracy) throws CoreException {
-	if (element != null && this.scope.encloses(element)) {
-		if (SearchEngine.VERBOSE) {
-			IResource res = this.currentPossibleMatch.resource;
-			System.out.println("Reporting match"); //$NON-NLS-1$
-			System.out.println("\tResource: " + (res == null ? " <unknown> " : res.getFullPath().toString())); //$NON-NLS-2$//$NON-NLS-1$
-			System.out.println("\tPositions: [" + sourceStart + ", " + sourceEnd + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
-			System.out.println("\tJava element: " + ((JavaElement)element).toStringWithAncestors()); //$NON-NLS-1$
-			System.out.println(accuracy == IJavaSearchResultCollector.EXACT_MATCH
-				? "\tAccuracy: EXACT_MATCH" //$NON-NLS-1$
-				: "\tAccuracy: POTENTIAL_MATCH"); //$NON-NLS-1$
-		}
-		report(
-			this.currentPossibleMatch.resource, 
-			sourceStart, 
-			sourceEnd, 
-			element, 
-			accuracy, 
-			getParticipant());
-	}
-}
 public SearchParticipant getParticipant() {
 	return this.currentPossibleMatch.document.getParticipant();
 }
 
-protected void report(IResource resource, int sourceStart, int sourceEnd, IJavaElement element, int accuracy, SearchParticipant participant) throws CoreException {
+protected void report(SearchMatch match) throws CoreException {
 	long start = -1;
-	if (SearchEngine.VERBOSE)
+	if (SearchEngine.VERBOSE) {
 		start = System.currentTimeMillis();
-	String documentPath = element.getPath().toString();
-	SearchMatch match = new JavaSearchMatch(resource, element, documentPath, accuracy, participant, sourceStart, sourceEnd+1, -1);
+		System.out.println("Reporting match"); //$NON-NLS-1$
+		System.out.println("\tDocument path: " + match.getDocumentPath()); //$NON-NLS-2$//$NON-NLS-1$
+		System.out.println("\tPositions: [" + match.getSourceStart() + ", " + match.getSourceEnd() + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		System.out.println("\tJava element: " + match.getDescriptiveLocation()); //$NON-NLS-1$
+		System.out.println(match.getAccuracy() == IJavaSearchResultCollector.EXACT_MATCH
+			? "\tAccuracy: EXACT_MATCH" //$NON-NLS-1$
+			: "\tAccuracy: POTENTIAL_MATCH"); //$NON-NLS-1$
+	}
 	this.requestor.acceptSearchMatch(match);
 	if (SearchEngine.VERBOSE)
 		this.resultCollectorTime += System.currentTimeMillis()-start;
 }
-protected void report(long start, long end, IJavaElement element, int accuracy) throws CoreException {
-	report((int) (start >>> 32), (int) end, element, accuracy); // extract the start and end from the encoded long positions
-}
 /**
  * Finds the accurate positions of the sequence of tokens given by qualifiedName
  * in the source and reports a reference to this this qualified name
  * to the search requestor.
  */
-protected void reportAccurateReference(int sourceStart, int sourceEnd, char[] name, IJavaElement element, int accuracy) throws CoreException {
+protected void reportAccurateReference(int referenceType, int sourceStart, int sourceEnd, char[] name, IJavaElement element, int accuracy) throws CoreException {
 	if (accuracy == -1) return;
+	if (!encloses(element)) return;
 
 	// compute source positions of the qualified reference 
 	Scanner scanner = this.parser.scanner;
@@ -994,18 +987,22 @@
 			// ignore
 		}
 		if (token == TerminalTokens.TokenNameIdentifier && this.pattern.matchesName(name, scanner.getCurrentTokenSource())) {
-			report(currentPosition, scanner.currentPosition - 1, element, accuracy);
+			SearchMatch match = JavaSearchMatch.newReferenceMatch(referenceType, element, accuracy, currentPosition, scanner.currentPosition, this);
+			report(match);
 			return;
 		}
 	} while (token != TerminalTokens.TokenNameEOF);
-	report(sourceStart, sourceEnd, element, accuracy);
+	SearchMatch match = JavaSearchMatch.newReferenceMatch(referenceType, element, accuracy, sourceStart, sourceEnd+1, this);
+	report(match);
 }
 /**
  * Finds the accurate positions of each valid token in the source and
  * reports a reference to this token to the search requestor.
  * A token is valid if it has an accuracy which is not -1.
  */
-protected void reportAccurateReference(int sourceStart, int sourceEnd, char[][] tokens, IJavaElement element, int[] accuracies) throws CoreException {
+protected void reportAccurateReference(int referenceType, int sourceStart, int sourceEnd, char[][] tokens, IJavaElement element, int[] accuracies) throws CoreException {
+	if (!encloses(element)) return;
+	
 	// compute source positions of the qualified reference 
 	Scanner scanner = this.parser.scanner;
 	scanner.setSource(this.currentPossibleMatch.getContents());
@@ -1049,9 +1046,11 @@
 		if (accuracies[accuracyIndex] != -1) {
 			// accept reference
 			if (refSourceStart != -1) {
-				report(refSourceStart, refSourceEnd, element, accuracies[accuracyIndex]);
+				SearchMatch match = JavaSearchMatch.newReferenceMatch(referenceType, element, accuracies[accuracyIndex], refSourceStart, refSourceEnd+1, this);
+				report(match);
 			} else {
-				report(sourceStart, sourceEnd, element, accuracies[accuracyIndex]);
+				SearchMatch match = JavaSearchMatch.newReferenceMatch(referenceType, element, accuracies[accuracyIndex], sourceStart, sourceEnd+1, this);
+				report(match);
 			}
 			i = 0;
 		}
@@ -1062,7 +1061,7 @@
 	} while (token != TerminalTokens.TokenNameEOF);
 
 }
-protected void reportBinaryMatch(IResource resource, IMember binaryMember, IBinaryType info, int accuracy) throws CoreException {
+protected void reportBinaryMemberDeclaration(IResource resource, IMember binaryMember, IBinaryType info, int accuracy) throws CoreException {
 	ISourceRange range = binaryMember.getNameRange();
 	if (range.getOffset() == -1) {
 		ClassFile classFile = (ClassFile) binaryMember.getClassFile();
@@ -1078,11 +1077,10 @@
 		}
 	}
 	int startIndex = range.getOffset();
-	int endIndex = startIndex + range.getLength() - 1;
-	if (resource == null)
-		report(startIndex, endIndex, binaryMember, accuracy);
-	else
-		report(resource, startIndex, endIndex, binaryMember, accuracy, getParticipant());
+	int endIndex = startIndex + range.getLength();
+	if (resource == null) resource =  this.currentPossibleMatch.resource;
+	SearchMatch match = JavaSearchMatch.newDeclarationMatch(binaryMember, accuracy, startIndex, endIndex, getParticipant(), resource);
+	report(match);
 }
 /**
  * Visit the given method declaration and report the nodes that match exactly the
@@ -1105,8 +1103,10 @@
 				// ignore
 			}
 			int nameSourceEnd = scanner.currentPosition - 1;
-
-			report(nameSourceStart, nameSourceEnd, enclosingElement, accuracy);
+			if (encloses(enclosingElement)) {
+				SearchMatch match = JavaSearchMatch.newDeclarationMatch(enclosingElement, accuracy, nameSourceStart, nameSourceEnd+1, this);
+				report(match);
+			}
 		}
 	}
 
@@ -1129,7 +1129,7 @@
 			if ((this.matchContainer & PatternLocator.METHOD_CONTAINER) != 0) {
 				if (enclosingElement == null)
 					enclosingElement = createHandle(method, parent);
-				if (enclosingElement != null) { // skip if unable to find method
+				if (encloses(enclosingElement)) {
 					for (int i = 0, l = nodes.length; i < l; i++) {
 						ASTNode node = nodes[i];
 						Integer level = (Integer) nodeSet.matchingNodes.removeKey(node);
@@ -1210,7 +1210,10 @@
 	IJavaElement enclosingElement = null;
 	if (accuracy > -1) {
 		enclosingElement = createHandle(field, type, parent);
-		report(field.sourceStart, field.sourceEnd, enclosingElement, accuracy);
+		if (encloses(enclosingElement)) {
+			SearchMatch match = JavaSearchMatch.newDeclarationMatch(enclosingElement, accuracy, field.sourceStart, field.sourceEnd+1, this);
+			report(match);
+		}
 	}
 
 	// handle the nodes for the local type first
@@ -1234,11 +1237,12 @@
 			} else {
 				if (enclosingElement == null)
 					enclosingElement = createHandle(field, type, parent);
-				for (int i = 0, l = nodes.length; i < l; i++) {
-					ASTNode node = nodes[i];
-					Integer level = (Integer) nodeSet.matchingNodes.removeKey(node);
-					this.patternLocator.matchReportReference(node, enclosingElement, level.intValue(), this);
-				}
+				if (encloses(enclosingElement))
+					for (int i = 0, l = nodes.length; i < l; i++) {
+						ASTNode node = nodes[i];
+						Integer level = (Integer) nodeSet.matchingNodes.removeKey(node);
+						this.patternLocator.matchReportReference(node, enclosingElement, level.intValue(), this);
+					}
 			}
 		}
 	}
@@ -1264,8 +1268,10 @@
 	if (enclosingElement == null) return;
 
 	// report the type declaration
-	if (accuracy > -1)
-		report(type.sourceStart, type.sourceEnd, enclosingElement, accuracy);
+	if (accuracy > -1 && encloses(enclosingElement)) {
+		SearchMatch match = JavaSearchMatch.newDeclarationMatch(enclosingElement, accuracy, type.sourceStart, type.sourceEnd+1, this);
+		report(match);
+	}
 
 	boolean matchedClassContainer = (this.matchContainer & PatternLocator.CLASS_CONTAINER) != 0;
 
@@ -1280,7 +1286,8 @@
 				for (int i = 0, l = nodes.length; i < l; i++) {
 					ASTNode node = nodes[i];
 					Integer level = (Integer) nodeSet.matchingNodes.removeKey(node);
-					this.patternLocator.matchReportReference(node, enclosingElement, level.intValue(), this);
+					if (encloses(enclosingElement))
+						this.patternLocator.matchReportReference(node, enclosingElement, level.intValue(), this);
 				}
 			}
 		}
diff --git a/search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java b/search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java
index b2d13fe..0794786 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java
@@ -14,7 +14,9 @@
 import org.eclipse.core.runtime.*;
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.core.search.*;
 import org.eclipse.jdt.core.search.IJavaSearchResultCollector;
+import org.eclipse.jdt.core.search.SearchMatch;
 import org.eclipse.jdt.internal.compiler.ast.*;
 import org.eclipse.jdt.internal.compiler.env.IBinaryType;
 import org.eclipse.jdt.internal.compiler.lookup.*;
@@ -143,16 +145,17 @@
 		if (element != null)
 			reportDeclaration(((MessageSend) reference).binding, locator, declPattern.knownMethods);
 	} else if (this.pattern.findReferences && reference instanceof MessageSend) {
-		// message ref are starting at the selector start
-		locator.report(
-			(int) (((MessageSend) reference).nameSourcePosition >>> 32),
-			reference.sourceEnd,
-			element,
-			accuracy);
+		int sourceStart = (int) (((MessageSend) reference).nameSourcePosition >>> 32);
+		SearchMatch match = JavaSearchMatch.newReferenceMatch(IJavaElement.METHOD, element, accuracy, sourceStart, reference.sourceEnd+1, locator);
+		locator.report(match);
 	} else {
-		super.matchReportReference(reference, element, accuracy, locator);
+		SearchMatch match = JavaSearchMatch.newReferenceMatch(IJavaElement.METHOD, element, accuracy, reference.sourceStart, reference.sourceEnd+1, locator);
+		locator.report(match);
 	}
 }
+protected int referenceType() {
+	return IJavaElement.METHOD;
+}
 protected void reportDeclaration(MethodBinding methodBinding, MatchLocator locator, SimpleSet knownMethods) throws CoreException {
 	ReferenceBinding declaringClass = methodBinding.declaringClass;
 	IType type = locator.lookupType(declaringClass);
@@ -175,7 +178,7 @@
 		if (resource == null)
 			resource = type.getJavaProject().getProject();
 		info = locator.getBinaryInfo((org.eclipse.jdt.internal.core.ClassFile)type.getClassFile(), resource);
-		locator.reportBinaryMatch(resource, method, info, IJavaSearchResultCollector.EXACT_MATCH);
+		locator.reportBinaryMemberDeclaration(resource, method, info, IJavaSearchResultCollector.EXACT_MATCH);
 	} else {
 		ClassScope scope = ((SourceTypeBinding) declaringClass).scope;
 		if (scope != null) {
@@ -188,14 +191,10 @@
 					break;
 				}
 			} 
-			if (methodDecl != null)
-				locator.report(
-					resource, 
-					methodDecl.sourceStart, 
-					methodDecl.sourceEnd, 
-					method, 
-					IJavaSearchResultCollector.EXACT_MATCH, 
-					locator.getParticipant());
+			if (methodDecl != null) {
+				SearchMatch match = new MethodDeclarationMatch(method, IJavaSearchResultCollector.EXACT_MATCH, methodDecl.sourceStart, methodDecl.sourceEnd+1, locator.getParticipant(), resource);
+				locator.report(match);
+			}
 		}
 	}
 }
diff --git a/search/org/eclipse/jdt/internal/core/search/matching/MethodPattern.java b/search/org/eclipse/jdt/internal/core/search/matching/MethodPattern.java
index 5aece92..f307c63 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/MethodPattern.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/MethodPattern.java
@@ -10,9 +10,12 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.search.matching;
 
+import java.io.IOException;
+
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.search.SearchPattern;
+import org.eclipse.jdt.internal.core.index.*;
 
 public class MethodPattern extends SearchPattern {
 
@@ -34,11 +37,19 @@
 // extra reference info
 protected IType declaringType;
 
+protected static char[][] REF_CATEGORIES = { METHOD_REF };
+protected static char[][] REF_AND_DECL_CATEGORIES = { METHOD_REF, METHOD_DECL };
+protected static char[][] DECL_CATEGORIES = { METHOD_DECL };
+
+/**
+ * Method entries are encoded as selector '/' Arity:
+ * e.g. 'foo/0'
+ */
 public static char[] createIndexKey(char[] selector, int argCount) {
-	MethodPattern pattern = new MethodPattern(R_EXACT_MATCH | R_CASE_SENSITIVE);
-	pattern.selector = selector;
-	pattern.parameterCount = argCount;
-	return pattern.encodeIndexKey();
+	char[] countChars = argCount < 10
+		? COUNTS[argCount]
+		: ("/" + String.valueOf(argCount)).toCharArray(); //$NON-NLS-1$
+	return CharOperation.concat(selector, countChars);
 }
 
 public MethodPattern(
@@ -89,75 +100,36 @@
 	this.parameterCount = Integer.parseInt(new String(key, lastSeparatorIndex + 1, size - lastSeparatorIndex - 1));
 	this.selector = CharOperation.subarray(key, 0, lastSeparatorIndex);
 }
-/**
- * Method declaration entries are encoded as 'methodDecl/' selector '/' Arity
- * e.g. 'methodDecl/X/0'
- *
- * Method reference entries are encoded as 'methodRef/' selector '/' Arity
- * e.g. 'methodRef/X/0'
- */
-public char[] encodeIndexKey() {
-	// will have a common pattern in the new story
-	if (this.isCaseSensitive && this.selector != null) {
-		switch(this.matchMode) {
-			case EXACT_MATCH :
-				int arity = this.parameterCount;
-				if (arity >= 0) {
-					char[] countChars = arity < 10 ? COUNTS[arity] : ("/" + String.valueOf(arity)).toCharArray(); //$NON-NLS-1$
-					return CharOperation.concat(this.selector, countChars);
-				}
-			case PREFIX_MATCH :
-				return this.selector;
-			case PATTERN_MATCH :
-				int starPos = CharOperation.indexOf('*', this.selector);
-				switch(starPos) {
-					case -1 :
-						return this.selector;
-					default : 
-						char[] result = new char[starPos];
-						System.arraycopy(this.selector, 0, result, 0, starPos);
-						return result;
-					case 0 : // fall through
-				}
-		}
-	}
-	return CharOperation.NO_CHAR; // find them all
-}
 public SearchPattern getBlankPattern() {
 	return new MethodPattern(R_EXACT_MATCH | R_CASE_SENSITIVE);
 }
 public char[][] getMatchCategories() {
 	if (this.findReferences)
-		if (this.findDeclarations) 
-			return new char[][] {METHOD_REF, METHOD_DECL};
-		else
-			return new char[][] {METHOD_REF};
-	else if (this.findDeclarations)
-		return new char[][] {METHOD_DECL};
+		return this.findDeclarations ? REF_AND_DECL_CATEGORIES : REF_CATEGORIES;
+	if (this.findDeclarations)
+		return DECL_CATEGORIES;
 	return CharOperation.NO_CHAR_CHAR;
 }
 public boolean isPolymorphicSearch() {
 	return this.findReferences;
 }
-public boolean matchesDecodedPattern(SearchPattern decodedPattern) {
+public boolean matchesDecodedKey(SearchPattern decodedPattern) {
 	MethodPattern pattern = (MethodPattern) decodedPattern;
-	if (this.parameterCount != -1 && this.parameterCount != pattern.parameterCount) return false;
 
-	return matchesName(this.selector, pattern.selector);
+	return (this.parameterCount == pattern.parameterCount || this.parameterCount == -1)
+		&& matchesName(this.selector, pattern.selector);
 }
 /**
  * Returns whether a method declaration or message send must be resolved to 
  * find out if this method pattern matches it.
  */
 protected boolean mustResolve() {
-	// declaring type 
-	// If declaring type is specified - even with simple name - always resolves 
-	// (see MethodPattern.matchLevel)
+	// declaring type
+	// If declaring type is specified - even with simple name - always resolves
 	if (declaringSimpleName != null || declaringQualification != null) return true;
 
 	// return type
-	// If return type is specified - even with simple name - always resolves 
-	// (see MethodPattern.matchLevel)
+	// If return type is specified - even with simple name - always resolves
 	if (returnSimpleName != null || returnQualification != null) return true;
 
 	// parameter types
@@ -166,6 +138,31 @@
 			if (parameterQualifications[i] != null) return true;
 	return false;
 }
+public EntryResult[] queryIn(Index index) throws IOException {
+	char[] key = this.selector; // can be null
+	int matchRule = getMatchRule();
+
+	switch(this.matchMode) {
+		case R_EXACT_MATCH :
+			if (this.selector != null && this.parameterCount >= 0)
+				key = createIndexKey(this.selector, this.parameterCount);
+			else // do a prefix query with the selector
+				matchRule = matchRule - R_EXACT_MATCH + R_PREFIX_MATCH;
+			break;
+		case R_PREFIX_MATCH :
+			// do a prefix query with the selector
+			break;
+		case R_PATTERN_MATCH :
+			if (this.parameterCount >= 0)
+				key = createIndexKey(this.selector == null ? ONE_STAR : this.selector, this.parameterCount);
+			else if (this.selector != null && this.selector[this.selector.length - 1] != '*')
+				key = CharOperation.concat(this.selector, ONE_STAR, SEPARATOR);
+			// else do a pattern query with just the selector
+			break;
+	}
+
+	return index.query(getMatchCategories(), key, matchRule); // match rule is irrelevant when the key is null
+}
 public String toString() {
 	StringBuffer buffer = new StringBuffer(20);
 	if (this.findDeclarations) {
@@ -207,13 +204,13 @@
 		buffer.append("*"); //$NON-NLS-1$
 	buffer.append(", "); //$NON-NLS-1$
 	switch(this.matchMode) {
-		case EXACT_MATCH : 
+		case R_EXACT_MATCH : 
 			buffer.append("exact match, "); //$NON-NLS-1$
 			break;
-		case PREFIX_MATCH :
+		case R_PREFIX_MATCH :
 			buffer.append("prefix match, "); //$NON-NLS-1$
 			break;
-		case PATTERN_MATCH :
+		case R_PATTERN_MATCH :
 			buffer.append("pattern match, "); //$NON-NLS-1$
 			break;
 	}
diff --git a/search/org/eclipse/jdt/internal/core/search/matching/OrPattern.java b/search/org/eclipse/jdt/internal/core/search/matching/OrPattern.java
index ea1d5e5..db5b279 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/OrPattern.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/OrPattern.java
@@ -14,7 +14,7 @@
 
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.jdt.core.search.*;
-import org.eclipse.jdt.internal.core.index.impl.IndexInput;
+import org.eclipse.jdt.internal.core.index.Index;
 import org.eclipse.jdt.internal.core.search.IndexQueryRequestor;
 
 public class OrPattern extends SearchPattern {
@@ -40,18 +40,16 @@
 	else
 		System.arraycopy(rightPatterns, 0, this.patterns, leftSize, rightSize);
 }
-/**
- * Query a given index for matching entries. 
- *
- */
-public void findIndexMatches(IndexInput input, IndexQueryRequestor requestor, SearchParticipant participant, IJavaSearchScope scope, IProgressMonitor progressMonitor) throws IOException {
+public void findIndexMatches(Index index, IndexQueryRequestor requestor, SearchParticipant participant, IJavaSearchScope scope, IProgressMonitor progressMonitor) throws IOException {
 	// per construction, OR pattern can only be used with a PathCollector (which already gather results using a set)
-	for (int i = 0, length = this.patterns.length; i < length; i++)
-		this.patterns[i].findIndexMatches(input, requestor, participant, scope, progressMonitor);
+	try {
+		index.startQuery();
+		for (int i = 0, length = this.patterns.length; i < length; i++)
+			this.patterns[i].findIndexMatches(index, requestor, participant, scope, progressMonitor);
+	} finally {
+		index.stopQuery();
+	}
 }
-/**
- * see SearchPattern.isPolymorphicSearch
- */
 public boolean isPolymorphicSearch() {
 	for (int i = 0, length = this.patterns.length; i < length; i++)
 		if (this.patterns[i].isPolymorphicSearch()) return true;
diff --git a/search/org/eclipse/jdt/internal/core/search/matching/PackageDeclarationPattern.java b/search/org/eclipse/jdt/internal/core/search/matching/PackageDeclarationPattern.java
index 93f682d..ddb1fd9 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/PackageDeclarationPattern.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/PackageDeclarationPattern.java
@@ -10,10 +10,8 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.search.matching;
 
-import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.jdt.core.search.*;
-import org.eclipse.jdt.internal.core.index.impl.IndexInput;
-import org.eclipse.jdt.internal.core.search.IndexQueryRequestor;
+import org.eclipse.jdt.internal.core.index.*;
 
 public class PackageDeclarationPattern extends SearchPattern {
 
@@ -23,8 +21,9 @@
 	super(PKG_DECL_PATTERN, matchRule);
 	this.pkgName = pkgName;
 }
-public void findIndexMatches(IndexInput input, IndexQueryRequestor requestor, SearchParticipant participant, IJavaSearchScope scope, IProgressMonitor progressMonitor) /* throws IOException */ {
+public EntryResult[] queryIn(Index index) {
 	// package declarations are not indexed
+	return null;
 }
 public String toString() {
 	StringBuffer buffer = new StringBuffer(20);
@@ -35,13 +34,13 @@
 		buffer.append("*"); //$NON-NLS-1$
 	buffer.append(">, "); //$NON-NLS-1$
 	switch(this.matchMode) {
-		case EXACT_MATCH : 
+		case R_EXACT_MATCH : 
 			buffer.append("exact match, "); //$NON-NLS-1$
 			break;
-		case PREFIX_MATCH :
+		case R_PREFIX_MATCH :
 			buffer.append("prefix match, "); //$NON-NLS-1$
 			break;
-		case PATTERN_MATCH :
+		case R_PATTERN_MATCH :
 			buffer.append("pattern match, "); //$NON-NLS-1$
 			break;
 	}
diff --git a/search/org/eclipse/jdt/internal/core/search/matching/PackageReferenceLocator.java b/search/org/eclipse/jdt/internal/core/search/matching/PackageReferenceLocator.java
index 9b93c05..e36b7fa 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/PackageReferenceLocator.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/PackageReferenceLocator.java
@@ -16,7 +16,8 @@
 import org.eclipse.jdt.core.IPackageFragment;
 import org.eclipse.jdt.core.IPackageFragmentRoot;
 import org.eclipse.jdt.core.JavaModelException;
-import org.eclipse.jdt.core.search.IJavaSearchConstants;
+import org.eclipse.jdt.core.search.SearchMatch;
+import org.eclipse.jdt.core.search.SearchPattern;
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.ast.*;
 import org.eclipse.jdt.internal.compiler.lookup.*;
@@ -97,12 +98,12 @@
 	if (this.pattern.pkgName == null) return ACCURATE_MATCH;
 
 	switch (this.matchMode) {
-		case IJavaSearchConstants.EXACT_MATCH:
-		case IJavaSearchConstants.PREFIX_MATCH:
+		case SearchPattern.R_EXACT_MATCH:
+		case SearchPattern.R_PREFIX_MATCH:
 			if (CharOperation.prefixEquals(this.pattern.pkgName, CharOperation.concatWith(tokens, '.'), this.isCaseSensitive))
 				return POSSIBLE_MATCH;
 			break;
-		case IJavaSearchConstants.PATTERN_MATCH:
+		case SearchPattern.R_PATTERN_MATCH:
 			char[] patternName = this.pattern.pkgName[this.pattern.pkgName.length - 1] == '*'
 				? this.pattern.pkgName
 				: CharOperation.concat(this.pattern.pkgName, ".*".toCharArray()); //$NON-NLS-1$
@@ -116,16 +117,19 @@
 	if (binding == null) {
 		this.matchReportReference(importRef, element, accuracy, locator);
 	} else {
-		long[] positions = importRef.sourcePositions;
-		int last = positions.length - 1;
-		if (binding instanceof ProblemReferenceBinding)
-			binding = ((ProblemReferenceBinding) binding).original;
-		if (binding instanceof ReferenceBinding) {
-			PackageBinding pkgBinding = ((ReferenceBinding) binding).fPackage;
-			if (pkgBinding != null)
-				last = pkgBinding.compoundName.length;
+		if (locator.encloses(element)) {
+			long[] positions = importRef.sourcePositions;
+			int last = positions.length - 1;
+			if (binding instanceof ProblemReferenceBinding)
+				binding = ((ProblemReferenceBinding) binding).original;
+			if (binding instanceof ReferenceBinding) {
+				PackageBinding pkgBinding = ((ReferenceBinding) binding).fPackage;
+				if (pkgBinding != null)
+					last = pkgBinding.compoundName.length;
+			}
+			SearchMatch match = JavaSearchMatch.newReferenceMatch(IJavaElement.PACKAGE_FRAGMENT, element, accuracy, ((int) (positions[0] >>> 32)), ((int) positions[last - 1])+1, locator);
+			locator.report(match);
 		}
-		locator.report(positions[0], positions[last - 1], element, accuracy);
 	}
 }
 protected void matchReportReference(ASTNode reference, IJavaElement element, int accuracy, MatchLocator locator) throws CoreException {
@@ -182,7 +186,13 @@
 		last = this.pattern.segments.length;
 		if (last > positions.length) last = positions.length;
 	}
-	locator.report(positions[0], positions[last - 1], element, accuracy);
+	int sourceStart = (int) (positions[0] >>> 32);
+	int sourceEnd = ((int) positions[last - 1])+1;
+	SearchMatch match = JavaSearchMatch.newReferenceMatch(IJavaElement.PACKAGE_FRAGMENT, element, accuracy, sourceStart, sourceEnd, locator);
+	locator.report(match);
+}
+protected int referenceType() {
+	return IJavaElement.PACKAGE_FRAGMENT;
 }
 public int resolveLevel(ASTNode node) {
 	if (node instanceof QualifiedTypeReference)
diff --git a/search/org/eclipse/jdt/internal/core/search/matching/PackageReferencePattern.java b/search/org/eclipse/jdt/internal/core/search/matching/PackageReferencePattern.java
index dca3db3..4e73276 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/PackageReferencePattern.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/PackageReferencePattern.java
@@ -20,6 +20,8 @@
 protected char[][] segments;
 protected int currentSegment;
 
+protected static char[][] CATEGORIES = { REF };
+
 public PackageReferencePattern(char[] pkgName, int matchRule) {
 	this(matchRule);
 
@@ -40,24 +42,25 @@
 	// Package reference keys are encoded as 'name' (where 'name' is the last segment of the package name)
 	this.pkgName = key; // decode into the pkg name, see matchesDecodedPattern()
 }
-public char[] encodeIndexKey() {
-	if (this.currentSegment < 0) return null;
-	// Package reference keys are encoded as 'name' (where 'name' is the last segment of the package name)
-	return encodeIndexKey(this.segments[this.currentSegment]);
-}
 public SearchPattern getBlankPattern() {
 	return new PackageReferencePattern(R_EXACT_MATCH | R_CASE_SENSITIVE);
 }
+public char[] getIndexKey() {
+	// Package reference keys are encoded as 'name' (where 'name' is the last segment of the package name)
+	if (this.currentSegment >= 0) 
+		return encodeIndexKey(this.segments[this.currentSegment], this.matchMode);
+	return null;
+}
 public char[][] getMatchCategories() {
-	return new char[][] {REF};
+	return CATEGORIES;
 }
 protected boolean hasNextQuery() {
 	// if package has at least 4 segments, don't look at the first 2 since they are mostly
 	// redundant (eg. in 'org.eclipse.jdt.core.*' 'org.eclipse' is used all the time)
 	return --this.currentSegment >= (this.segments.length >= 4 ? 2 : 0);
 }
-public boolean matchesDecodedPattern(SearchPattern decodedPattern) {
-	return matchesName(this.segments[this.currentSegment], ((PackageReferencePattern) decodedPattern).pkgName);
+public boolean matchesDecodedKey(SearchPattern decodedPattern) {
+	return true; // index key is not encoded so query results all match
 }
 protected void resetQuery() {
 	/* walk the segments from end to start as it will find less potential references using 'lang' than 'java' */
diff --git a/search/org/eclipse/jdt/internal/core/search/matching/PatternLocator.java b/search/org/eclipse/jdt/internal/core/search/matching/PatternLocator.java
index 3716c78..2d42982 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/PatternLocator.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/PatternLocator.java
@@ -155,11 +155,11 @@
 	if (pattern == null) return true; // null is as if it was "*"
 	if (name != null) {
 		switch (this.matchMode) {
-			case IJavaSearchConstants.EXACT_MATCH :
+			case SearchPattern.R_EXACT_MATCH :
 				return CharOperation.equals(pattern, name, this.isCaseSensitive);
-			case IJavaSearchConstants.PREFIX_MATCH :
+			case SearchPattern.R_PREFIX_MATCH :
 				return CharOperation.prefixEquals(pattern, name, this.isCaseSensitive);
-			case IJavaSearchConstants.PATTERN_MATCH :
+			case SearchPattern.R_PATTERN_MATCH :
 				if (!this.isCaseSensitive)
 					pattern = CharOperation.toLowerCase(pattern);
 				return CharOperation.match(pattern, name, this.isCaseSensitive);
@@ -217,15 +217,20 @@
  * Reports the match of the given import reference.
  */
 protected void matchReportImportRef(ImportReference importRef, Binding binding, IJavaElement element, int accuracy, MatchLocator locator) throws CoreException {
-	// default is to report a match as a regular ref.
-	this.matchReportReference(importRef, element, accuracy, locator);
+	if (locator.encloses(element)) {
+		// default is to report a match as a regular ref.
+		this.matchReportReference(importRef, element, accuracy, locator);
+	}
 }
 /**
  * Reports the match of the given reference.
  */
 protected void matchReportReference(ASTNode reference, IJavaElement element, int accuracy, MatchLocator locator) throws CoreException {
-	// default is to report a match on the whole node.
-	locator.report(reference.sourceStart, reference.sourceEnd, element, accuracy);
+	SearchMatch match = JavaSearchMatch.newReferenceMatch(referenceType(), element, accuracy, reference.sourceStart, reference.sourceEnd+1, locator);
+	locator.report(match);
+}
+protected int referenceType() {
+	return 0; // defaults to unknown (a generic JavaSearchMatch will be created)
 }
 /**
  * Finds out whether the given ast node matches this search pattern.
diff --git a/search/org/eclipse/jdt/internal/core/search/matching/QualifiedTypeDeclarationPattern.java b/search/org/eclipse/jdt/internal/core/search/matching/QualifiedTypeDeclarationPattern.java
index e24c4c9..d40bfd8 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/QualifiedTypeDeclarationPattern.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/QualifiedTypeDeclarationPattern.java
@@ -24,45 +24,41 @@
 	this.simpleName = this.isCaseSensitive ? simpleName : CharOperation.toLowerCase(simpleName);
 	this.classOrInterface = classOrInterface;
 
-	this.mustResolve = qualification != null;
+	this.mustResolve = this.qualification != null;
 }
 QualifiedTypeDeclarationPattern(int matchRule) {
 	super(matchRule);
 }
 public void decodeIndexKey(char[] key) {
-	int size = key.length;
+	int slash = CharOperation.indexOf(SEPARATOR, key, 0);
+	this.simpleName = CharOperation.subarray(key, 0, slash);
 
-	this.classOrInterface = key[0];
-	int oldSlash = 1;
-	int slash = CharOperation.indexOf(SEPARATOR, key, oldSlash + 1);
-	char[] pkgName = slash == oldSlash + 1
-		? CharOperation.NO_CHAR
-		: CharOperation.subarray(key, oldSlash+1, slash);
-	this.simpleName = CharOperation.subarray(key, slash + 1, slash = CharOperation.indexOf(SEPARATOR, key, slash + 1));
-
-	char[][] decodedEnclosingTypeNames;
-	if (slash + 1 < size) {
-		decodedEnclosingTypeNames = (slash + 3 == size && key[slash + 1] == ONE_ZERO[0])
-			? ONE_ZERO_CHAR
-			: CharOperation.splitOn('/', CharOperation.subarray(key, slash + 1, size - 1));
+	int start = slash + 1;
+	slash = CharOperation.indexOf(SEPARATOR, key, start);
+	int secondSlash = CharOperation.indexOf(SEPARATOR, key, slash + 1);
+	if (start + 1 == secondSlash) {
+		this.qualification = CharOperation.NO_CHAR; // no package name or enclosingTypeNames
+	} else if (slash + 1 == secondSlash) {
+		this.qualification = CharOperation.subarray(key, start, slash); // only a package name
 	} else {
-		decodedEnclosingTypeNames = CharOperation.NO_CHAR_CHAR;
+		this.qualification = CharOperation.subarray(key, start, secondSlash);
+		this.qualification[slash - start] = '.';
 	}
-	this.qualification = CharOperation.concatWith(pkgName, decodedEnclosingTypeNames, '.');
+
+	this.classOrInterface = key[key.length - 1];
 }
 public SearchPattern getBlankPattern() {
 	return new QualifiedTypeDeclarationPattern(R_EXACT_MATCH | R_CASE_SENSITIVE);
 }
-public boolean matchesDecodedPattern(SearchPattern decodedPattern) {
+public boolean matchesDecodedKey(SearchPattern decodedPattern) {
 	QualifiedTypeDeclarationPattern pattern = (QualifiedTypeDeclarationPattern) decodedPattern;
 	switch(this.classOrInterface) {
 		case CLASS_SUFFIX :
 		case INTERFACE_SUFFIX :
 			if (this.classOrInterface != pattern.classOrInterface) return false;
-		case TYPE_SUFFIX : // nothing
 	}
 
-	return matchesName(this.simpleName, pattern.simpleName) && matchesName(this.pkg, pattern.qualification);
+	return matchesName(this.simpleName, pattern.simpleName) && matchesName(this.qualification, pattern.qualification);
 }
 public String toString() {
 	StringBuffer buffer = new StringBuffer(20);
@@ -88,13 +84,13 @@
 		buffer.append("*"); //$NON-NLS-1$
 	buffer.append(">, "); //$NON-NLS-1$
 	switch(this.matchMode) {
-		case EXACT_MATCH : 
+		case R_EXACT_MATCH : 
 			buffer.append("exact match, "); //$NON-NLS-1$
 			break;
-		case PREFIX_MATCH :
+		case R_PREFIX_MATCH :
 			buffer.append("prefix match, "); //$NON-NLS-1$
 			break;
-		case PATTERN_MATCH :
+		case R_PATTERN_MATCH :
 			buffer.append("pattern match, "); //$NON-NLS-1$
 			break;
 	}
diff --git a/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeReferenceLocator.java b/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeReferenceLocator.java
index 040f823..82a247e 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeReferenceLocator.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeReferenceLocator.java
@@ -10,6 +10,7 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.search.matching;
 
+import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.internal.compiler.ast.*;
 import org.eclipse.jdt.internal.compiler.lookup.*;
 
@@ -50,6 +51,9 @@
 protected int matchContainer() {
 	return CLASS_CONTAINER;
 }
+protected int referenceType() {
+	return IJavaElement.TYPE;
+}
 public int resolveLevel(ASTNode node) {
 	if (!(node instanceof TypeReference)) return IMPOSSIBLE_MATCH;
 
diff --git a/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeReferencePattern.java b/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeReferencePattern.java
index e7fe409..fb72b23 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeReferencePattern.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeReferencePattern.java
@@ -10,17 +10,12 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.search.matching;
 
-import java.io.*;
-import java.util.HashMap;
+import java.io.IOException;
 
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.OperationCanceledException;
 import org.eclipse.jdt.core.compiler.*;
 import org.eclipse.jdt.core.search.*;
 import org.eclipse.jdt.internal.core.search.indexing.IIndexConstants;
-import org.eclipse.jdt.internal.core.index.EntryResult;
-import org.eclipse.jdt.internal.core.index.impl.*;
-import org.eclipse.jdt.internal.core.search.*;
+import org.eclipse.jdt.internal.core.index.*;
 
 public class SuperTypeReferencePattern extends SearchPattern {
 
@@ -36,12 +31,7 @@
 
 protected boolean checkOnlySuperinterfaces; // used for IMPLEMENTORS
 
-/**
- * A map from IndexInputs to IEntryResult[]
- */
-public HashMap entryResults;
-
-private static final EntryResult[] NO_ENTRY_RESULT = new EntryResult[0];
+protected static char[][] CATEGORIES = { SUPER_REF };
 
 public static char[] createIndexKey(
 	int modifiers,
@@ -52,40 +42,70 @@
 	char[] superTypeName,
 	char superClassOrInterface) {
 
-	SuperTypeReferencePattern pattern = new SuperTypeReferencePattern(R_EXACT_MATCH | R_CASE_SENSITIVE);
-	pattern.modifiers = modifiers;
-	pattern.pkgName = packageName;
-	pattern.classOrInterface = classOrInterface;
-	pattern.superClassOrInterface = superClassOrInterface;
 	if (superTypeName == null)
 		superTypeName = OBJECT;
-	pattern.enclosingTypeName = CharOperation.concatWith(enclosingTypeNames, '$');
-	pattern.simpleName = CharOperation.lastSegment(typeName, '.');
-	pattern.superSimpleName = CharOperation.lastSegment(superTypeName, '.');
-	pattern.superQualification = null;
-	if (pattern.superSimpleName != superTypeName) {
-		int length = superTypeName.length - pattern.superSimpleName.length - 1;
-		pattern.superQualification = new char[length];
-		System.arraycopy(superTypeName, 0, pattern.superQualification, 0, length);
+	char[] simpleName = CharOperation.lastSegment(typeName, '.');
+	char[] enclosingTypeName = CharOperation.concatWith(enclosingTypeNames, '$');
+	char[] superSimpleName = CharOperation.lastSegment(superTypeName, '.');
+	char[] superQualification = null;
+	if (superSimpleName != superTypeName) {
+		int length = superTypeName.length - superSimpleName.length - 1;
+		superQualification = new char[length];
+		System.arraycopy(superTypeName, 0, superQualification, 0, length);
 	}
 
 	// if the supertype name contains a $, then split it into: source name and append the $ prefix to the qualification
 	//	e.g. p.A$B ---> p.A$ + B
-	char[] superTypeSourceName = CharOperation.lastSegment(pattern.superSimpleName, '$');
-	if (superTypeSourceName != pattern.superSimpleName) {
-		int start = pattern.superQualification == null ? 0 : pattern.superQualification.length + 1;
-		int prefixLength = pattern.superSimpleName.length - superTypeSourceName.length;
+	char[] superTypeSourceName = CharOperation.lastSegment(superSimpleName, '$');
+	if (superTypeSourceName != superSimpleName) {
+		int start = superQualification == null ? 0 : superQualification.length + 1;
+		int prefixLength = superSimpleName.length - superTypeSourceName.length;
 		char[] mangledQualification = new char[start + prefixLength];
-		if (pattern.superQualification != null) {
-			System.arraycopy(pattern.superQualification, 0, mangledQualification, 0, start-1);
+		if (superQualification != null) {
+			System.arraycopy(superQualification, 0, mangledQualification, 0, start-1);
 			mangledQualification[start-1] = '.';
 		}
-		System.arraycopy(pattern.superSimpleName, 0, mangledQualification, start, prefixLength);
-		pattern.superQualification = mangledQualification;
-		pattern.superSimpleName = superTypeSourceName;
+		System.arraycopy(superSimpleName, 0, mangledQualification, start, prefixLength);
+		superQualification = mangledQualification;
+		superSimpleName = superTypeSourceName;
 	} 
-	
-	return pattern.encodeIndexKey();
+
+	int superLength = superSimpleName == null ? 0 : superSimpleName.length;
+	int superQLength = superQualification == null ? 0 : superQualification.length;
+	int simpleLength = simpleName == null ? 0 : simpleName.length;
+	int enclosingLength = enclosingTypeName == null ? 0 : enclosingTypeName.length;
+	int packageLength = packageName == null ? 0 : packageName.length;
+	char[] result = new char[superLength + superQLength + simpleLength + enclosingLength + packageLength + 8];
+	int pos = 0;
+	if (superLength > 0) {
+		System.arraycopy(superSimpleName, 0, result, pos, superLength);
+		pos += superLength;
+	}
+	result[pos++] = SEPARATOR;
+	if (superQLength > 0) {
+		System.arraycopy(superQualification, 0, result, pos, superQLength);
+		pos += superQLength;
+	}
+	result[pos++] = SEPARATOR;
+	if (simpleLength > 0) {
+		System.arraycopy(simpleName, 0, result, pos, simpleLength);
+		pos += simpleLength;
+	}
+	result[pos++] = SEPARATOR;
+	if (enclosingLength > 0) {
+		System.arraycopy(enclosingTypeName, 0, result, pos, enclosingLength);
+		pos += enclosingLength;
+	}
+	result[pos++] = SEPARATOR;
+	if (packageLength > 0) {
+		System.arraycopy(packageName, 0, result, pos, packageLength);
+		pos += packageLength;
+	}
+	result[pos++] = SEPARATOR;
+	result[pos++] = superClassOrInterface;
+	result[pos++] = classOrInterface;
+	result[pos] = (char) modifiers;
+	return result;
 }
 
 public SuperTypeReferencePattern(
@@ -105,156 +125,73 @@
 	super(SUPER_REF_PATTERN, matchRule);
 }
 /*
- * superSimpleName / superQualification / superClassOrInterface /  simpleName / enclosingTypeName / pkgName / classOrInterface modifiers
+ * superSimpleName / superQualification / simpleName / enclosingTypeName / pkgName / superClassOrInterface classOrInterface modifiers
  */
 public void decodeIndexKey(char[] key) {
-	int slash = -1;
-	this.superSimpleName = CharOperation.subarray(key, slash + 1, slash = CharOperation.indexOf(SEPARATOR, key, slash + 1));
-	int oldSlash = slash;
-	slash = CharOperation.indexOf(SEPARATOR, key, slash + 1);
-	this.superQualification = (slash == oldSlash + 1)
-		? null // could not have been known at index time
-		: CharOperation.subarray(key, oldSlash + 1, slash);
-	this.superClassOrInterface = key[slash + 1];
-	slash += 2;
-	this.simpleName = CharOperation.subarray(key, slash + 1, slash = CharOperation.indexOf(SEPARATOR, key, slash + 1));
-	oldSlash = slash;
-	slash = CharOperation.indexOf(SEPARATOR, key, slash + 1);
-	if (slash == oldSlash + 1) { // could not have been known at index time
+	int slash = CharOperation.indexOf(SEPARATOR, key, 0);
+	this.superSimpleName = CharOperation.subarray(key, 0, slash);
+
+	// some values may not have been know when indexed so decode as null
+	int start = slash + 1;
+	slash = CharOperation.indexOf(SEPARATOR, key, start);
+	this.superQualification = slash == start ? null : CharOperation.subarray(key, start, slash);
+
+	slash = CharOperation.indexOf(SEPARATOR, key, start = slash + 1);
+	this.simpleName = CharOperation.subarray(key, start, slash);
+
+	slash = CharOperation.indexOf(SEPARATOR, key, start = slash + 1);
+	if (slash == start) {
 		this.enclosingTypeName = null;
 	} else {
-		this.enclosingTypeName = (slash == oldSlash + 2 && key[oldSlash + 1] == ONE_ZERO[0])
-			? ONE_ZERO
-			: CharOperation.subarray(key, oldSlash + 1, slash);
+		char[] names = CharOperation.subarray(key, start, slash);
+		this.enclosingTypeName = CharOperation.equals(ONE_ZERO, names) ? ONE_ZERO : names;
 	}
-	oldSlash = slash;
-	slash = CharOperation.indexOf(SEPARATOR, key, slash + 1);
-	this.pkgName = (slash == oldSlash + 1)
-		? null // could not have been known at index time
-		: CharOperation.subarray(key, oldSlash + 1, slash);
+
+	slash = CharOperation.indexOf(SEPARATOR, key, start = slash + 1);
+	this.pkgName = slash == start ? null : CharOperation.subarray(key, start, slash);
+
+	this.superClassOrInterface = key[slash + 1];
 	this.classOrInterface = key[slash + 1];
 	this.modifiers = key[slash + 2]; // implicit cast to int type
 }
-/*
- * superSimpleName / superQualification / superClassOrInterface /  simpleName / enclosingTypeName / pkgName / classOrInterface modifiers
- */
-public char[] encodeIndexKey() {
-	int superSimpleNameLength = this.superSimpleName == null ? 0 : this.superSimpleName.length;
-	int superQualificationLength = this.superQualification == null ? 0 : this.superQualification.length;
-	int simpleNameLength = this.simpleName == null ? 0 : this.simpleName.length;
-	int enclosingTypeNameLength = this.enclosingTypeName == null ? 0 : this.enclosingTypeName.length;
-	int pkgNameLength = this.pkgName == null ? 0 : this.pkgName.length;
-
-	int length = superSimpleNameLength + superQualificationLength + simpleNameLength
-		+ enclosingTypeNameLength + pkgNameLength + 9;
-	char[] result = new char[length];
-	int pos = 0;
-	if (superSimpleNameLength > 0) {
-		System.arraycopy(this.superSimpleName, 0, result, pos, superSimpleNameLength);
-		pos += superSimpleNameLength;
-	}
-	result[pos++] = SEPARATOR;
-	if (this.superClassOrInterface != 0) { // 0 when querying index
-		if (superQualificationLength > 0) {
-			System.arraycopy(this.superQualification, 0, result, pos, superQualificationLength);
-			pos += superQualificationLength;
-		}
-		result[pos++] = SEPARATOR;
-		result[pos++] = this.superClassOrInterface;
-		result[pos++] = SEPARATOR;
-		if (simpleNameLength > 0) {
-			System.arraycopy(this.simpleName, 0, result, pos, simpleNameLength);
-			pos += simpleNameLength;
-		}
-		result[pos++] = SEPARATOR;
-		if (enclosingTypeNameLength > 0) {
-			System.arraycopy(this.enclosingTypeName, 0, result, pos, enclosingTypeNameLength);
-			pos += enclosingTypeNameLength;
-		}
-		result[pos++] = SEPARATOR;
-		if (pkgNameLength > 0) {
-			System.arraycopy(this.pkgName, 0, result, pos, pkgNameLength);
-			pos += pkgNameLength;
-		}
-		result[pos++] = SEPARATOR;
-		result[pos++] = this.classOrInterface;
-		result[pos++] = (char) this.modifiers;
-	}
-	if (pos != length) {
-		System.arraycopy(result, 0, result = new char[pos], 0, pos);
-	}
-	return result;
-}
-/**
- * Query a given index for matching entries. 
- */
-public void findIndexMatches(IndexInput input, IndexQueryRequestor requestor, SearchParticipant participant, IJavaSearchScope scope, IProgressMonitor progressMonitor) throws IOException {
-	if (this.entryResults == null) {
-		// non-optimized case
-		super.findIndexMatches(input, requestor, participant, scope, progressMonitor);	
-		return;
-	}
-
-	if (progressMonitor != null && progressMonitor.isCanceled()) throw new OperationCanceledException();
-
-	/* narrow down a set of entries using prefix criteria */
-	EntryResult[] entries = (EntryResult[]) this.entryResults.get(input);
-	if (entries == null) {
-		entries = input.queryEntriesPrefixedBy(SUPER_REF);
-		if (entries == null)
-			entries = NO_ENTRY_RESULT;
-		this.entryResults.put(input, entries);
-	}
-	if (entries == NO_ENTRY_RESULT) return;
-
-	/* only select entries which actually match the entire search pattern */
-	int slash = SUPER_REF.length;
-	char[] name = this.superSimpleName;
-	int length = name == null ? 0 : name.length;
-	nextEntry: for (int i = 0, max = entries.length; i < max; i++) {
-		/* check that the entry is a super ref to the super simple name */
-		EntryResult entry = entries[i];
-		if (name != null) {
-			char[] word = entry.getWord();
-			if (slash + length >= word.length) continue;
-			
-			// ensure it is the end of the ref (a simple name is not a prefix of ref)
-			if (word[length + slash] != '/') continue; 
-			
-			// compare ref to simple name
-			for (int j = 0; j < length; j++)
-				if (word[j + slash] != name[j]) continue nextEntry;
-		}
-
-		/* retrieve and decode entry */	
-		char[] word = entry.getWord();
-		char[] indexKey = CharOperation.subarray(word, SUPER_REF.length, word.length);
-		SearchPattern decodedPattern = getBlankPattern();
-		decodedPattern.decodeIndexKey(indexKey);
-
-		int[] references = entry.getFileReferences();
-		for (int iReference = 0, refererencesLength = references.length; iReference < refererencesLength; iReference++) {
-			String documentPath = IndexedFile.convertPath( input.getIndexedFile(references[iReference]).getPath());
-			if (scope.encloses(documentPath)) {
-				if (!requestor.acceptIndexMatch(documentPath, decodedPattern, participant)) 
-					throw new OperationCanceledException();
-			}
-		}
-	}
-}
 public SearchPattern getBlankPattern() {
 	return new SuperTypeReferencePattern(R_EXACT_MATCH | R_CASE_SENSITIVE);
 }
 public char[][] getMatchCategories() {
-	return new char[][] {SUPER_REF};
+	return CATEGORIES;
 }
-public boolean matchesDecodedPattern(SearchPattern decodedPattern) {
+public boolean matchesDecodedKey(SearchPattern decodedPattern) {
 	SuperTypeReferencePattern pattern = (SuperTypeReferencePattern) decodedPattern;
 	if (this.checkOnlySuperinterfaces)
 		if (pattern.superClassOrInterface != IIndexConstants.INTERFACE_SUFFIX) return false;
 
+	if (pattern.superQualification != null)
+		if (!matchesName(this.superQualification, pattern.superQualification)) return false;
+
 	return matchesName(this.superSimpleName, pattern.superSimpleName);
 }
+public EntryResult[] queryIn(Index index) throws IOException {
+	char[] key = this.superSimpleName; // can be null
+	int matchRule = getMatchRule();
+
+	// cannot include the superQualification since it may not exist in the index
+	switch(this.matchMode) {
+		case R_EXACT_MATCH :
+			// do a prefix query with the superSimpleName
+			matchRule = matchRule - R_EXACT_MATCH + R_PREFIX_MATCH;
+			if (this.superSimpleName != null)
+				key = CharOperation.append(this.superSimpleName, SEPARATOR);
+			break;
+		case R_PREFIX_MATCH :
+			// do a prefix query with the superSimpleName
+			break;
+		case R_PATTERN_MATCH :
+			// do a pattern query with the superSimpleName
+			break;
+	}
+
+	return index.query(getMatchCategories(), key, matchRule); // match rule is irrelevant when the key is null
+}
 public String toString(){
 	StringBuffer buffer = new StringBuffer(20);
 	buffer.append(
@@ -267,13 +204,13 @@
 		buffer.append("*"); //$NON-NLS-1$
 	buffer.append(">, "); //$NON-NLS-1$
 	switch(this.matchMode) {
-		case EXACT_MATCH : 
+		case R_EXACT_MATCH : 
 			buffer.append("exact match, "); //$NON-NLS-1$
 			break;
-		case PREFIX_MATCH :
+		case R_PREFIX_MATCH :
 			buffer.append("prefix match, "); //$NON-NLS-1$
 			break;
-		case PATTERN_MATCH :
+		case R_PATTERN_MATCH :
 			buffer.append("pattern match, "); //$NON-NLS-1$
 			break;
 	}
diff --git a/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationPattern.java b/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationPattern.java
index 43a912f..343ce72 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationPattern.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationPattern.java
@@ -10,8 +10,11 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.search.matching;
 
+import java.io.IOException;
+
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.search.SearchPattern;
+import org.eclipse.jdt.internal.core.index.*;
 
 public class TypeDeclarationPattern extends SearchPattern {
 
@@ -24,13 +27,45 @@
 // set to TYPE_SUFFIX for matching both classes and interfaces
 public char classOrInterface; 
 
-public static char[] createIndexKey(char[] packageName, char[][] enclosingTypeNames, char[] typeName, boolean isClass) {
-	TypeDeclarationPattern pattern = new TypeDeclarationPattern(R_EXACT_MATCH | R_CASE_SENSITIVE);
-	pattern.pkg = packageName;
-	pattern.enclosingTypeNames = enclosingTypeNames;
-	pattern.simpleName = typeName;
-	pattern.classOrInterface = isClass ? CLASS_SUFFIX : INTERFACE_SUFFIX;
-	return pattern.encodeIndexKey();
+protected static char[][] CATEGORIES = { TYPE_DECL };
+
+public static char[] createIndexKey(char[] typeName, char[] packageName, char[][] enclosingTypeNames, char classOrInterface) {
+	int typeNameLength = typeName == null ? 0 : typeName.length;
+	int packageLength = packageName == null ? 0 : packageName.length;
+	int enclosingNamesLength = 0;
+	if (enclosingTypeNames != null) {
+		for (int i = 0, length = enclosingTypeNames.length; i < length;) {
+			enclosingNamesLength += enclosingTypeNames[i].length;
+			if (++i < length)
+				enclosingNamesLength++; // for the '.' separator
+		}
+	}
+
+	char[] result = new char[typeNameLength + packageLength + enclosingNamesLength + 4];
+	int pos = 0;
+	if (typeNameLength > 0) {
+		System.arraycopy(typeName, 0, result, pos, typeNameLength);
+		pos += typeNameLength;
+	}
+	result[pos++] = SEPARATOR;
+	if (packageLength > 0) {
+		System.arraycopy(packageName, 0, result, pos, packageLength);
+		pos += packageLength;
+	}
+	result[pos++] = SEPARATOR;
+	if (enclosingNamesLength > 0) {
+		for (int i = 0, length = enclosingTypeNames.length; i < length;) {
+			char[] enclosingName = enclosingTypeNames[i];
+			int itsLength = enclosingName.length;
+			System.arraycopy(enclosingName, 0, result, pos, itsLength);
+			pos += itsLength;
+			if (++i < length)
+				result[pos++] = '.';
+		}
+	}
+	result[pos++] = SEPARATOR;
+	result[pos] = classOrInterface;
+	return result;
 }
 
 public TypeDeclarationPattern(
@@ -43,7 +78,7 @@
 	this(matchRule);
 
 	this.pkg = this.isCaseSensitive ? pkg : CharOperation.toLowerCase(pkg);
-	if (isCaseSensitive || enclosingTypeNames == null) {
+	if (this.isCaseSensitive || enclosingTypeNames == null) {
 		this.enclosingTypeNames = enclosingTypeNames;
 	} else {
 		int length = enclosingTypeNames.length;
@@ -53,137 +88,104 @@
 	}
 	this.simpleName = this.isCaseSensitive ? simpleName : CharOperation.toLowerCase(simpleName);
 	this.classOrInterface = classOrInterface;
-	
-	this.mustResolve = pkg != null && enclosingTypeNames != null;
+
+	this.mustResolve = this.pkg != null && this.enclosingTypeNames != null;
 }
 TypeDeclarationPattern(int matchRule) {
 	super(TYPE_DECL_PATTERN, matchRule);
 }
 /*
- * Type entries are encoded as 'typeDecl/' ('C' | 'I') '/' PackageName '/' TypeName '/' EnclosingTypeName
- * e.g. typeDecl/C/java.lang/Object/
- * e.g. typeDecl/I/java.lang/Cloneable/
- * e.g. typeDecl/C/javax.swing/LazyValue/UIDefaults
- * 
- * Current encoding is optimized for queries: all classes/interfaces
+ * Type entries are encoded as simpleTypeName / packageName / enclosingTypeName / 'C' or 'I'
+ * e.g. Object/java.lang//C
+ * e.g. Cloneable/java.lang//I
+ * e.g. LazyValue/javax.swing/UIDefaults/C
  */
 public void decodeIndexKey(char[] key) {
-	int size = key.length;
+	int slash = CharOperation.indexOf(SEPARATOR, key, 0);
+	this.simpleName = CharOperation.subarray(key, 0, slash);
 
-	this.classOrInterface = key[0];
-	int oldSlash = 1;
-	int slash = CharOperation.indexOf(SEPARATOR, key, oldSlash + 1);
-	this.pkg = (slash == oldSlash + 1)
-		? CharOperation.NO_CHAR
-		: CharOperation.subarray(key, oldSlash + 1, slash);
-	this.simpleName = CharOperation.subarray(key, slash + 1, slash = CharOperation.indexOf(SEPARATOR, key, slash + 1));
+	int start = slash + 1;
+	slash = CharOperation.indexOf(SEPARATOR, key, start);
+	this.pkg = slash == start ? CharOperation.NO_CHAR : CharOperation.subarray(key, start, slash);
 
-	if (slash+1 < size) {
-		this.enclosingTypeNames = (slash + 3 == size && key[slash + 1] == ONE_ZERO[0])
-			? ONE_ZERO_CHAR
-			: CharOperation.splitOn('/', CharOperation.subarray(key, slash+1, size-1));
-	} else {
+	slash = CharOperation.indexOf(SEPARATOR, key, start = slash + 1);
+	if (slash == start) {
 		this.enclosingTypeNames = CharOperation.NO_CHAR_CHAR;
-	}
-}
-/*
- * classOrInterface / package / simpleName / enclosingTypeNames
- */
-public char[] encodeIndexKey() {
-	char[] packageName = this.isCaseSensitive ? pkg : null;
-	switch(this.classOrInterface) {
-		case CLASS_SUFFIX :
-			if (packageName == null) 
-				return new char[] {CLASS_SUFFIX, SEPARATOR};
-			break;
-		case INTERFACE_SUFFIX :
-			if (packageName == null) 
-				return new char[] {INTERFACE_SUFFIX, SEPARATOR};
-			break;
-		default :
-			return CharOperation.NO_CHAR; // cannot do better given encoding
+	} else {
+		char[] names = CharOperation.subarray(key, start, slash);
+		this.enclosingTypeNames = CharOperation.equals(ONE_ZERO, names) ? ONE_ZERO_CHAR : CharOperation.splitOn('.', names);
 	}
 
-	char[] typeName = this.isCaseSensitive ? this.simpleName : null;
-	if (typeName != null && this.matchMode == PATTERN_MATCH) {
-		int starPos = CharOperation.indexOf('*', typeName);
-		switch(starPos) {
-			case -1 :
-				break;
-			case 0 :
-				typeName = null;
-				break;
-			default : 
-				typeName = CharOperation.subarray(typeName, 0, starPos);
-		}
-	}
-
-	int packageLength = packageName.length;
-	int enclosingTypeNamesLength = 0;
-	if (this.enclosingTypeNames != null)
-		for (int i = 0, length = this.enclosingTypeNames.length; i < length; i++)
-			enclosingTypeNamesLength += this.enclosingTypeNames[i].length + 1;
-	int pos = 0;
-	int typeNameLength = typeName == null ? 0 : typeName.length;
-	int resultLength = pos + packageLength + typeNameLength + enclosingTypeNamesLength + 4;
-	char[] result = new char[resultLength];
-	result[pos++] = this.classOrInterface;
-	result[pos++] = SEPARATOR;
-	if (packageLength > 0) {
-		System.arraycopy(packageName, 0, result, pos, packageLength);
-		pos += packageLength;
-	}
-	result[pos++] = SEPARATOR;
-	if (typeName != null) {
-		System.arraycopy(typeName, 0, result, pos, typeNameLength);
-		pos += typeNameLength;
-
-		result[pos++] = SEPARATOR;
-		if (enclosingTypeNames != null) {
-			for (int i = 0, length = this.enclosingTypeNames.length; i < length; i++) {
-				int enclosingTypeNameLength = this.enclosingTypeNames[i].length;
-				System.arraycopy(this.enclosingTypeNames[i], 0, result, pos, enclosingTypeNameLength);
-				pos += enclosingTypeNameLength;
-				result[pos++] = SEPARATOR;
-			}
-		}
-	}
-	if (pos != resultLength) {
-		System.arraycopy(result, 0, result = new char[pos], 0, pos);
-	}
-	return result;
+	this.classOrInterface = key[key.length - 1];
 }
 public SearchPattern getBlankPattern() {
 	return new TypeDeclarationPattern(R_EXACT_MATCH | R_CASE_SENSITIVE);
 }
 public char[][] getMatchCategories() {
-	return new char[][] {TYPE_DECL};
+	return CATEGORIES;
 }
-public boolean matchesDecodedPattern(SearchPattern decodedPattern) {
+public boolean matchesDecodedKey(SearchPattern decodedPattern) {
 	TypeDeclarationPattern pattern = (TypeDeclarationPattern) decodedPattern;
 	switch(this.classOrInterface) {
 		case CLASS_SUFFIX :
 		case INTERFACE_SUFFIX :
 			if (this.classOrInterface != pattern.classOrInterface) return false;
-		case TYPE_SUFFIX : // nothing
 	}
 
-	/* check qualification - exact match only */
+	if (!matchesName(this.simpleName, pattern.simpleName))
+		return false;
+
+	// check package - exact match only
 	if (this.pkg != null && !CharOperation.equals(this.pkg, pattern.pkg, this.isCaseSensitive))
 		return false;
-	/* check enclosingTypeName - exact match only */
+
+	// check enclosingTypeNames - exact match only
 	if (this.enclosingTypeNames != null) {
-		// empty char[][] means no enclosing type (in which case, the decoded one is the empty char array)
-		if (this.enclosingTypeNames.length == 0) {
-			if (pattern.enclosingTypeNames != CharOperation.NO_CHAR_CHAR) return false;
-		} else {
-			if (!CharOperation.equals(this.enclosingTypeNames, pattern.enclosingTypeNames, this.isCaseSensitive))
-				if (!CharOperation.equals(pattern.enclosingTypeNames, ONE_ZERO_CHAR)) // if not a local or anonymous type
-					return false;
-		}
+		if (this.enclosingTypeNames.length == 0)
+			return pattern.enclosingTypeNames.length == 0;
+		if (this.enclosingTypeNames.length == 1 && pattern.enclosingTypeNames.length == 1)
+			return CharOperation.equals(this.enclosingTypeNames[0], pattern.enclosingTypeNames[0], this.isCaseSensitive);
+		if (pattern.enclosingTypeNames == ONE_ZERO_CHAR)
+			return true; // is a local or anonymous type
+		return CharOperation.equals(this.enclosingTypeNames, pattern.enclosingTypeNames, this.isCaseSensitive);
+	}
+	return true;
+}
+public EntryResult[] queryIn(Index index) throws IOException {
+	char[] key = this.simpleName; // can be null
+	int matchRule = getMatchRule();
+
+	switch(this.matchMode) {
+		case R_PREFIX_MATCH :
+			// do a prefix query with the simpleName
+			break;
+		case R_EXACT_MATCH :
+			if (this.simpleName != null) {
+				matchRule = matchRule - R_EXACT_MATCH + R_PREFIX_MATCH;
+				key = this.pkg == null
+					? CharOperation.append(this.simpleName, SEPARATOR)
+					: CharOperation.concat(this.simpleName, SEPARATOR, this.pkg, SEPARATOR, CharOperation.NO_CHAR);
+				break; // do a prefix query with the simpleName and possibly the pkg
+			}
+			matchRule = matchRule - R_EXACT_MATCH + R_PATTERN_MATCH;
+			// fall thru to encode the key and do a pattern query
+		case R_PATTERN_MATCH :
+			if (this.pkg == null) {
+				if (this.simpleName == null) {
+					if (this.classOrInterface == CLASS_SUFFIX || this.classOrInterface == INTERFACE_SUFFIX)
+						key = new char[] {ONE_STAR[0], SEPARATOR, this.classOrInterface}; // find all classes or all interfaces
+				} else if (this.simpleName[this.simpleName.length - 1] != '*') {
+					key = CharOperation.concat(this.simpleName, ONE_STAR, SEPARATOR);
+				}
+				break; // do a pattern query with the current encoded key
+			}
+			// must decode to check enclosingTypeNames due to the encoding of local types
+			key = CharOperation.concat(
+				this.simpleName == null ? ONE_STAR : this.simpleName, SEPARATOR, this.pkg, SEPARATOR, ONE_STAR);
+			break;
 	}
 
-	return matchesName(this.simpleName, pattern.simpleName);
+	return index.query(getMatchCategories(), key, matchRule); // match rule is irrelevant when the key is null
 }
 public String toString() {
 	StringBuffer buffer = new StringBuffer(20);
@@ -219,13 +221,13 @@
 		buffer.append("*"); //$NON-NLS-1$
 	buffer.append(">, "); //$NON-NLS-1$
 	switch(this.matchMode){
-		case EXACT_MATCH : 
+		case R_EXACT_MATCH : 
 			buffer.append("exact match, "); //$NON-NLS-1$
 			break;
-		case PREFIX_MATCH :
+		case R_PREFIX_MATCH :
 			buffer.append("prefix match, "); //$NON-NLS-1$
 			break;
-		case PATTERN_MATCH :
+		case R_PATTERN_MATCH :
 			buffer.append("pattern match, "); //$NON-NLS-1$
 			break;
 	}
diff --git a/search/org/eclipse/jdt/internal/core/search/matching/TypeReferenceLocator.java b/search/org/eclipse/jdt/internal/core/search/matching/TypeReferenceLocator.java
index b476e1c..080477b 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/TypeReferenceLocator.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/TypeReferenceLocator.java
@@ -100,11 +100,11 @@
 			: CharOperation.concat(this.pattern.qualification, this.pattern.simpleName, '.');
 		char[] qualifiedTypeName = CharOperation.concatWith(tokens, '.');
 		switch (this.matchMode) {
-			case IJavaSearchConstants.EXACT_MATCH :
-			case IJavaSearchConstants.PREFIX_MATCH :
+			case SearchPattern.R_EXACT_MATCH :
+			case SearchPattern.R_PREFIX_MATCH :
 				if (CharOperation.prefixEquals(qualifiedPattern, qualifiedTypeName, this.isCaseSensitive)) return POSSIBLE_MATCH;
 				break;
-			case IJavaSearchConstants.PATTERN_MATCH:
+			case SearchPattern.R_PATTERN_MATCH:
 				if (CharOperation.match(qualifiedPattern, qualifiedTypeName, this.isCaseSensitive)) return POSSIBLE_MATCH;
 				break;
 		}
@@ -135,21 +135,27 @@
 		// try to match all enclosing types for which the token matches as well.
 		while (typeBinding != null && lastIndex >= 0) {
 			if (resolveLevelForType(this.pattern.simpleName, this.pattern.qualification, typeBinding) == ACCURATE_MATCH) {
-				long[] positions = importRef.sourcePositions;
-				locator.report(positions[this.pattern.qualification == null ? lastIndex : 0], positions[lastIndex], element, accuracy);
+				if (locator.encloses(element)) {
+					long[] positions = importRef.sourcePositions;
+					SearchMatch match = JavaSearchMatch.newReferenceMatch(IJavaElement.TYPE, element, accuracy, ((int) ((positions[this.pattern.qualification == null ? lastIndex : 0]) >>> 32)), ((int) positions[lastIndex])+1, locator);
+					locator.report(match);
+				}
 				return;
 			}
 			lastIndex--;
 			typeBinding = typeBinding.enclosingType();
 		}
 	}
-	locator.reportAccurateReference(importRef.sourceStart, importRef.sourceEnd, this.pattern.simpleName, element, accuracy);
+	locator.reportAccurateReference(IJavaElement.TYPE, importRef.sourceStart, importRef.sourceEnd, this.pattern.simpleName, element, accuracy);
 }
 protected void matchReportReference(ArrayTypeReference arrayRef, IJavaElement element, int accuracy, MatchLocator locator) throws CoreException {
-	if (this.pattern.simpleName == null)
-		locator.report(arrayRef.sourceStart, arrayRef.sourceEnd, element, accuracy);
-	else
-		locator.reportAccurateReference(arrayRef.sourceStart, arrayRef.sourceEnd, this.pattern.simpleName, element, accuracy);
+	if (this.pattern.simpleName == null) {
+		if (locator.encloses(element)) {
+			SearchMatch match = JavaSearchMatch.newReferenceMatch(IJavaElement.TYPE, element, accuracy, arrayRef.sourceStart, arrayRef.sourceEnd+1, locator);
+			locator.report(match);
+		}
+	} else
+		locator.reportAccurateReference(IJavaElement.TYPE, arrayRef.sourceStart, arrayRef.sourceEnd, this.pattern.simpleName, element, accuracy);
 }
 protected void matchReportReference(ASTNode reference, IJavaElement element, int accuracy, MatchLocator locator) throws CoreException {
 	if (this.isDeclarationOfReferencedTypesPattern) {
@@ -164,8 +170,10 @@
 		matchReportReference((QualifiedTypeReference) reference, element, accuracy, locator);
 	else if (reference instanceof ArrayTypeReference)
 		matchReportReference((ArrayTypeReference) reference, element, accuracy, locator);
-	else
-		super.matchReportReference(reference, element, accuracy, locator);
+	else {
+		SearchMatch match = JavaSearchMatch.newReferenceMatch(IJavaElement.TYPE, element, accuracy, reference.sourceStart, reference.sourceEnd+1, locator);
+		locator.report(match);
+	}
 }
 protected void matchReportReference(QualifiedNameReference qNameRef, IJavaElement element, int accuracy, MatchLocator locator) throws CoreException {
 	Binding binding = qNameRef.binding;
@@ -202,15 +210,18 @@
 		ReferenceBinding refBinding = (ReferenceBinding) typeBinding; 
 		while (refBinding != null && lastIndex >= 0) {
 			if (resolveLevelForType(this.pattern.simpleName, this.pattern.qualification, refBinding) == ACCURATE_MATCH) {
-				long[] positions = qNameRef.sourcePositions;
-				locator.report(positions[this.pattern.qualification == null ? lastIndex : 0], positions[lastIndex], element, accuracy);
+				if (locator.encloses(element)) {
+					long[] positions = qNameRef.sourcePositions;
+					SearchMatch match = JavaSearchMatch.newReferenceMatch(IJavaElement.TYPE, element, accuracy, ((int) ((positions[this.pattern.qualification == null ? lastIndex : 0]) >>> 32)), ((int) positions[lastIndex])+1, locator);
+					locator.report(match);
+				}
 				return;
 			}
 			lastIndex--;
 			refBinding = refBinding.enclosingType();
 		}
 	}
-	locator.reportAccurateReference(qNameRef.sourceStart, qNameRef.sourceEnd, this.pattern.simpleName, element, accuracy);
+	locator.reportAccurateReference(IJavaElement.TYPE, qNameRef.sourceStart, qNameRef.sourceEnd, this.pattern.simpleName, element, accuracy);
 }
 protected void matchReportReference(QualifiedTypeReference qTypeRef, IJavaElement element, int accuracy, MatchLocator locator) throws CoreException {
 	TypeBinding typeBinding = qTypeRef.resolvedType;
@@ -227,15 +238,21 @@
 		ReferenceBinding refBinding = (ReferenceBinding) typeBinding; 
 		while (refBinding != null && lastIndex >= 0) {
 			if (resolveLevelForType(this.pattern.simpleName, this.pattern.qualification, refBinding) == ACCURATE_MATCH) {
-				long[] positions = qTypeRef.sourcePositions;
-				locator.report(positions[this.pattern.qualification == null ? lastIndex : 0], positions[lastIndex], element, accuracy);
+				if (locator.encloses(element)) {
+					long[] positions = qTypeRef.sourcePositions;
+					SearchMatch match = JavaSearchMatch.newReferenceMatch(IJavaElement.TYPE, element, accuracy, ((int) ((positions[this.pattern.qualification == null ? lastIndex : 0]) >>> 32)), ((int) positions[lastIndex])+1, locator);
+					locator.report(match);
+				}
 				return;
 			}
 			lastIndex--;
 			refBinding = refBinding.enclosingType();
 		}
 	}
-	locator.reportAccurateReference(qTypeRef.sourceStart, qTypeRef.sourceEnd, this.pattern.simpleName, element, accuracy);
+	locator.reportAccurateReference(IJavaElement.TYPE, qTypeRef.sourceStart, qTypeRef.sourceEnd, this.pattern.simpleName, element, accuracy);
+}
+protected int referenceType() {
+	return IJavaElement.TYPE;
 }
 protected void reportDeclaration(ASTNode reference, IJavaElement element, MatchLocator locator, SimpleSet knownTypes) throws CoreException {
 	int maxType = -1;
@@ -297,18 +314,13 @@
 	while (maxType >= 0 && type != null) {
 		if (!knownTypes.includes(type)) {
 			if (isBinary) {
-				locator.reportBinaryMatch(resource, type, info, IJavaSearchResultCollector.EXACT_MATCH);
+				locator.reportBinaryMemberDeclaration(resource, type, info, IJavaSearchResultCollector.EXACT_MATCH);
 			} else {
 				ClassScope scope = ((SourceTypeBinding) typeBinding).scope;
 				if (scope != null) {
 					TypeDeclaration typeDecl = scope.referenceContext;
-					locator.report(
-						resource, 
-						typeDecl.sourceStart, 
-						typeDecl.sourceEnd, 
-						type, 
-						IJavaSearchResultCollector.EXACT_MATCH, 
-						locator.getParticipant());
+					SearchMatch match = new TypeDeclarationMatch(type, IJavaSearchResultCollector.EXACT_MATCH, typeDecl.sourceStart, typeDecl.sourceEnd+1, locator.getParticipant(), resource);
+					locator.report(match);
 				}
 			}
 			knownTypes.add(type);
diff --git a/search/org/eclipse/jdt/internal/core/search/matching/TypeReferencePattern.java b/search/org/eclipse/jdt/internal/core/search/matching/TypeReferencePattern.java
index 330d586..247e705 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/TypeReferencePattern.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/TypeReferencePattern.java
@@ -10,8 +10,11 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.search.matching;
 
+import java.io.IOException;
+
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.search.SearchPattern;
+import org.eclipse.jdt.internal.core.index.*;
 
 public class TypeReferencePattern extends AndPattern {
 
@@ -28,7 +31,7 @@
 protected static char[][] REF_CATEGORIES = { REF };
 
 public static char[] createIndexKey(char[] typeName) {
-	return typeName != null ? typeName : CharOperation.NO_CHAR;
+	return encodeIndexKey(typeName, R_EXACT_MATCH);
 }
 
 public TypeReferencePattern(char[] qualification, char[] simpleName, int matchRule) {
@@ -51,21 +54,21 @@
 	int nameLength = CharOperation.indexOf(SEPARATOR, key);
 	if (nameLength != -1)
 		key = CharOperation.subarray(key, 0, nameLength);
-	
-	this.simpleName = key; // decode into the simple name, see matchesDecodedPattern()
-}
-public char[] encodeIndexKey() {
-	if (this.simpleName != null)
-		return encodeIndexKey(this.simpleName);
 
-	// Optimization, eg. type reference is 'org.eclipse.jdt.core.*'
-	if (this.currentSegment >= 0) 
-		return encodeIndexKey(this.segments[this.currentSegment]);
-	return null;
+	this.simpleName = key; // decode into the simple name, see matchesDecodedPattern()
 }
 public SearchPattern getBlankPattern() {
 	return new TypeReferencePattern(R_EXACT_MATCH | R_CASE_SENSITIVE);
 }
+public char[] getIndexKey() {
+	if (this.simpleName != null)
+		return encodeIndexKey(this.simpleName, this.matchMode);
+
+	// Optimization, eg. type reference is 'org.eclipse.jdt.core.*'
+	if (this.currentSegment >= 0) 
+		return encodeIndexKey(this.segments[this.currentSegment], this.matchMode);
+	return null;
+}
 public char[][] getMatchCategories() {
 	return this.simpleName == null ? REF_CATEGORIES : CATEGORIES;
 }
@@ -77,12 +80,17 @@
 	// redundant (eg. in 'org.eclipse.jdt.core.*' 'org.eclipse' is used all the time)
 	return --this.currentSegment >= (this.segments.length >= 4 ? 2 : 0);
 }
-public boolean matchesDecodedPattern(SearchPattern decodedPattern) {
-	if (this.simpleName != null)
-		return matchesName(this.simpleName, ((TypeReferencePattern) decodedPattern).simpleName);
+public boolean matchesDecodedKey(SearchPattern decodedPattern) {
+	return matchesName(
+		this.simpleName != null ? this.simpleName : this.segments[this.currentSegment],
+		((TypeReferencePattern) decodedPattern).simpleName);
+}
+public EntryResult[] queryIn(Index index) throws IOException {
+	int matchRule = getMatchRule();
+	if (this.simpleName != null && this.matchMode == R_EXACT_MATCH)
+		matchRule = matchRule - R_EXACT_MATCH + R_PREFIX_MATCH; // must do a prefix match in SUPER_REF & CONSTRUCTOR_REF
 
-	// Optimization, eg. type reference is 'org.eclipse.jdt.core.*'
-	return matchesName(this.segments[this.currentSegment], ((TypeReferencePattern) decodedPattern).simpleName);
+	return index.query(getMatchCategories(), getIndexKey(), matchRule);
 }
 protected void resetQuery() {
 	/* walk the segments from end to start as it will find less potential references using 'lang' than 'java' */
@@ -103,13 +111,13 @@
 		buffer.append("*"); //$NON-NLS-1$
 	buffer.append(">, "); //$NON-NLS-1$
 	switch(this.matchMode) {
-		case EXACT_MATCH : 
+		case R_EXACT_MATCH : 
 			buffer.append("exact match, "); //$NON-NLS-1$
 			break;
-		case PREFIX_MATCH :
+		case R_PREFIX_MATCH :
 			buffer.append("prefix match, "); //$NON-NLS-1$
 			break;
-		case PATTERN_MATCH :
+		case R_PATTERN_MATCH :
 			buffer.append("pattern match, "); //$NON-NLS-1$
 			break;
 	}
diff --git a/search/org/eclipse/jdt/internal/core/search/pattern/InternalSearchPattern.java b/search/org/eclipse/jdt/internal/core/search/pattern/InternalSearchPattern.java
index 2875da2..42c8d88 100644
--- a/search/org/eclipse/jdt/internal/core/search/pattern/InternalSearchPattern.java
+++ b/search/org/eclipse/jdt/internal/core/search/pattern/InternalSearchPattern.java
@@ -12,15 +12,10 @@
 
 import java.io.IOException;
 
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.OperationCanceledException;
-import org.eclipse.jdt.core.IJavaElement;
-import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.core.runtime.*;
 import org.eclipse.jdt.core.search.*;
 import org.eclipse.jdt.internal.core.JavaModelManager;
 import org.eclipse.jdt.internal.core.index.*;
-import org.eclipse.jdt.internal.core.index.impl.*;
 import org.eclipse.jdt.internal.core.search.*;
 import org.eclipse.jdt.internal.core.search.indexing.IndexManager;
 import org.eclipse.jdt.internal.core.util.Util;
@@ -30,187 +25,102 @@
  */
 public abstract class InternalSearchPattern {
 
-	public final int kind;
-	public final boolean isCaseSensitive;
-	public final int matchMode;
+public boolean mustResolve = true;
 
-	/* focus element (used for reference patterns*/
-	public IJavaElement focus;
-
-	public InternalSearchPattern(int patternKind, int matchRule) {
-		this.kind = patternKind;
-		this.isCaseSensitive = (matchRule & SearchPattern.R_CASE_SENSITIVE) != 0;
-		this.matchMode = matchRule - (this.isCaseSensitive ? SearchPattern.R_CASE_SENSITIVE : 0);
-	}
-
-	public abstract char[] encodeIndexKey();
-
-	protected char[] encodeIndexKey(char[] key) {
-		// TODO (kent) with new index, need to encode key for case insensitive queries too
-		// also want to pass along the entire pattern
-		if (this.isCaseSensitive && key != null) {
-			switch(this.matchMode) {
-				case SearchPattern.R_EXACT_MATCH :
-				case  SearchPattern.R_PREFIX_MATCH :
-					return key;
-				case  SearchPattern.R_PATTERN_MATCH :
-					int starPos = CharOperation.indexOf('*', key);
-					switch(starPos) {
-						case -1 :
-							return key;
-						default : 
-							char[] result = new char[starPos];
-							System.arraycopy(key, 0, result, 0, starPos);
-							return result;
-						case 0 : // fall through
-					}
-					break;
-				case  SearchPattern.R_REGEXP_MATCH:
-					// TODO (jerome) implement
-					return key;
-			}
-		}
-		return CharOperation.NO_CHAR; // find them all
-	}
-
-	/**
-	 * Query a given index for matching entries. 
-	 */
-	public void findIndexMatches(Index index, IndexQueryRequestor requestor, SearchParticipant participant, IJavaSearchScope scope, IProgressMonitor progressMonitor) throws IOException {
-		if (progressMonitor != null && progressMonitor.isCanceled()) throw new OperationCanceledException();
-		IndexInput input = new BlocksIndexInput(index.getIndexFile());
-		try {
-			input.open();
-			findIndexMatches(input, requestor, participant, scope, progressMonitor);
-		} finally {
-			input.close();
-		}
-	}
-
-	/**
-	 * Query a given index for matching entries. 
-	 *
-	 */
-	public void findIndexMatches(IndexInput input, IndexQueryRequestor requestor, SearchParticipant participant, IJavaSearchScope scope, IProgressMonitor progressMonitor) throws IOException {
-		char[][] categories = getMatchCategories();
-		char[] queryKey = encodeIndexKey();
-		for (int i = 0, l = categories.length; i < l; i++) {
-			if (progressMonitor != null && progressMonitor.isCanceled()) throw new OperationCanceledException();
-
-			findIndexMatches(input, requestor, participant, scope, progressMonitor, queryKey, categories[i]);
-		}
-	}
-
-	protected void findIndexMatches(IndexInput input, IndexQueryRequestor requestor, SearchParticipant participant, IJavaSearchScope scope, IProgressMonitor progressMonitor, char[] queryKey, char[] category) throws IOException {
-		/* narrow down a set of entries using prefix criteria */
-		// TODO per construction the queryKey will always be the most specific prefix. This should evolve to be the search pattern directly, using proper match rule
-		// ideally the index query API should be defined to avoid the need for concatenating the category to the key
-		char[] pattern = CharOperation.concat(category, queryKey);
-		EntryResult[] entries = input.queryEntries(pattern, SearchPattern.R_PREFIX_MATCH);
+protected void acceptMatch(String documentName, SearchPattern pattern, IndexQueryRequestor requestor, SearchParticipant participant, IJavaSearchScope scope) {
+	String documentPath = Index.convertPath(documentName);
+	if (scope.encloses(documentPath))
+		if (!requestor.acceptIndexMatch(documentPath, pattern, participant)) 
+			throw new OperationCanceledException();
+}
+protected SearchPattern currentPattern() {
+	return (SearchPattern) this;
+}
+/**
+ * Query a given index for matching entries. Assumes the sender has opened the index and will close when finished.
+ */
+public void findIndexMatches(Index index, IndexQueryRequestor requestor, SearchParticipant participant, IJavaSearchScope scope, IProgressMonitor monitor) throws IOException {
+	if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
+	try {
+		index.startQuery();
+		SearchPattern pattern = currentPattern();
+		EntryResult[] entries = pattern.queryIn(index);
 		if (entries == null) return;
-
-		/* only select entries which actually match the entire search pattern */
-		for (int iMatch = 0, matchesLength = entries.length; iMatch < matchesLength; iMatch++) {
-			if (progressMonitor != null && progressMonitor.isCanceled()) throw new OperationCanceledException();
-
-			/* retrieve and decode entry */	
-			EntryResult entry = entries[iMatch];
-			char[] word = entry.getWord();
-			char[] indexKey = CharOperation.subarray(word, category.length, word.length);
-			SearchPattern decodedPattern = getBlankPattern();
-			decodedPattern.decodeIndexKey(indexKey);
-			if (matchesDecodedPattern(decodedPattern)) {
-				int[] references = entry.getFileReferences();
-				for (int iReference = 0, refererencesLength = references.length; iReference < refererencesLength; iReference++) {
-					String documentPath = IndexedFile.convertPath( input.getIndexedFile(references[iReference]).getPath());
-					if (scope.encloses(documentPath)) {
-						if (!requestor.acceptIndexMatch(documentPath, decodedPattern, participant)) 
-							throw new OperationCanceledException();
-					}
-				}
+	
+		SearchPattern decodedResult = pattern.getBlankPattern();
+		for (int i = 0, l = entries.length; i < l; i++) {
+			if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
+	
+			EntryResult entry = entries[i];
+			decodedResult.decodeIndexKey(entry.getWord());
+			if (pattern.matchesDecodedKey(decodedResult)) {
+				String[] names = entry.getDocumentNames(index);
+				for (int j = 0, n = names.length; j < n; j++)
+					acceptMatch(names[j], decodedResult, requestor, participant, scope);
 			}
 		}
+	} finally {
+		index.stopQuery();
 	}
+}
+/**
+ * Searches for matches to a given query. Search queries can be created using helper
+ * methods (from a String pattern or a Java element) and encapsulate the description of what is
+ * being searched (for example, search method declarations in a case sensitive way).
+ *
+ * @param scope the search result has to be limited to the given scope
+ * @param resultCollector a callback object to which each match is reported
+ */
+public void findMatches(SearchParticipant[] participants, IJavaSearchScope scope, SearchRequestor requestor, IProgressMonitor monitor) throws CoreException {
+	if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
 
-	/**
-	 * Searches for matches to a given query. Search queries can be created using helper
-	 * methods (from a String pattern or a Java element) and encapsulate the description of what is
-	 * being searched (for example, search method declarations in a case sensitive way).
-	 *
-	 * @param scope the search result has to be limited to the given scope
-	 * @param resultCollector a callback object to which each match is reported
-	 */
-	public void findMatches(SearchParticipant[] participants, IJavaSearchScope scope, SearchRequestor requestor, IProgressMonitor monitor) throws CoreException {
-		
-		if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
-		
-		/* initialize progress monitor */
-		if (monitor != null) {
-			monitor.beginTask(Util.bind("engine.searching"), 100); //$NON-NLS-1$
-		}
+	/* initialize progress monitor */
+	if (monitor != null)
+		monitor.beginTask(Util.bind("engine.searching"), 100); //$NON-NLS-1$
+	if (SearchEngine.VERBOSE)
+		System.out.println("Searching for " + this + " in " + scope); //$NON-NLS-1$//$NON-NLS-2$
 
-		if (SearchEngine.VERBOSE) {
-			System.out.println("Searching for " + this + " in " + scope); //$NON-NLS-1$//$NON-NLS-2$
-		}
-	
-		IndexManager indexManager = JavaModelManager.getJavaModelManager().getIndexManager();
-		try {
-			requestor.beginReporting();
-			
-			for (int iParticipant = 0, length = participants == null ? 0 : participants.length; iParticipant < length; iParticipant++) {
-				
+	IndexManager indexManager = JavaModelManager.getJavaModelManager().getIndexManager();
+	try {
+		requestor.beginReporting();
+		for (int i = 0, l = participants == null ? 0 : participants.length; i < l; i++) {
+			if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
+
+			SearchParticipant participant = participants[i];
+			try {
+				participant.beginSearching();
+				requestor.enterParticipant(participant);
+				PathCollector pathCollector = new PathCollector();
+				indexManager.performConcurrentJob(
+					new PatternSearchJob((SearchPattern) this, participant, scope, pathCollector),
+					IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH,
+					monitor);
 				if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
-	
-				SearchParticipant participant = participants[iParticipant];
-				try {
-					participant.beginSearching();
-					requestor.enterParticipant(participant);
-		
-					// find index matches			
-					PathCollector pathCollector = new PathCollector();
-					indexManager.performConcurrentJob(
-						new PatternSearchJob(
-							(SearchPattern)this, 
-							participant,
-							scope, 
-							pathCollector),
-						IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH,
-						monitor);
-					if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
-		
-					// locate index matches if any (note that all search matches could have been issued during index querying)
-					String[] indexMatchPaths = pathCollector.getPaths();
-					pathCollector = null; // release
-					int indexMatchLength = indexMatchPaths == null ? 0 : indexMatchPaths.length;
-					SearchDocument[] indexMatches = new SearchDocument[indexMatchLength];
-					for (int iMatch = 0;iMatch < indexMatchLength; iMatch++) {
-						String documentPath = indexMatchPaths[iMatch];
-						indexMatches[iMatch] = participant.getDocument(documentPath);
-					}
-					participant.locateMatches(indexMatches, (SearchPattern)this, scope, requestor, monitor);
-				} finally {		
-					requestor.exitParticipant(participant);
-					participant.doneSearching();
-				}
 
-				if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
+				// locate index matches if any (note that all search matches could have been issued during index querying)
+				String[] indexMatchPaths = pathCollector.getPaths();
+				pathCollector = null; // release
+				int indexMatchLength = indexMatchPaths == null ? 0 : indexMatchPaths.length;
+				SearchDocument[] indexMatches = new SearchDocument[indexMatchLength];
+				for (int j = 0; j < indexMatchLength; j++)
+					indexMatches[j] = participant.getDocument(indexMatchPaths[j]);
+				participant.locateMatches(indexMatches, (SearchPattern) this, scope, requestor, monitor);
+			} finally {		
+				requestor.exitParticipant(participant);
+				participant.doneSearching();
 			}
-		} finally {
-			requestor.endReporting();
-			if (monitor != null) monitor.done();
 		}
-	}			
-
-	public abstract SearchPattern getBlankPattern();
-
-	public abstract char[][] getMatchCategories();
-
-	public abstract boolean matchesDecodedPattern(SearchPattern decodedPattern);
-
-	/*
-	 * Returns whether this pattern is a polymorphic search pattern.
-	 */
-	public boolean isPolymorphicSearch() {
-		return false;
+	} finally {
+		requestor.endReporting();
+		if (monitor != null)
+			monitor.done();
 	}
 }
+public boolean isPolymorphicSearch() {
+	return false;
+}
+public EntryResult[] queryIn(Index index) throws IOException {
+	SearchPattern pattern = (SearchPattern) this;
+	return index.query(pattern.getMatchCategories(), pattern.getIndexKey(), pattern.getMatchRule());
+}
+}