JDK_1_5-Merge with HEAD: v_422a
diff --git a/buildnotes_jdt-core.html b/buildnotes_jdt-core.html
index 0da2f12..4360b50 100644
--- a/buildnotes_jdt-core.html
+++ b/buildnotes_jdt-core.html
@@ -120,16 +120,65 @@
 <p><hr><h1>
 Eclipse Platform Build Notes&nbsp;<br>
 Java Development Tooling Core</h1>
-Eclipse SDK 3.0M9 Build - ?th April 2004
+Eclipse SDK 3.0M9 Build - 20th April 2004
 <br>Project org.eclipse.jdt.core v_422
 (<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_422">cvs</a>).
 <h2>
 What's new in this drop</h2>
 <ul>
+<li>Added API for User Library Container support in JavaCore:
+<pre>
+
+	/**
+	 * Name of the User Library Container id.
+	 */
+	public static final String USER_LIBRARY_CONTAINER_ID= "org.eclipse.jdt.USER_LIBRARY"; //$NON-NLS-1$
+	
+	/**
+	 * Returns the names of all defined user libraries. The corresponding classpath container path
+	 * is the name appended to the USER_LIBRARY_CONTAINER_ID.  
+	 * @return Return an array containing the names of all known user defined.
+	 */
+	public static String[] getUserLibraryNames();
+</pre>
+</li>
+<li>Added API to get classpath container comparison ID in ClasspathContainerInitializer:
+<pre>
+	/**
+	 * Returns an object which identifies a container for comparison purpose. This allows
+	 * to eliminate redundant containers when accumulating classpath entries (e.g. 
+	 * runtime classpath computation). When requesting a container comparison ID, one
+	 * should ensure using its corresponding container initializer. Indeed, a random container
+	 * initializer cannot be held responsible for determining comparison IDs for arbitrary 
+	 * containers.
+	 * <p>
+	 * @param containerPath the path of the container which is being checked
+	 * @param project the project for which the container is to being checked
+	 * @return returns an Object identifying the container for comparison
+	 * @since 3.0
+	 */
+	public Object getComparisonID(IPath containerPath, IJavaProject project);
+</pre>
+By default, containers are identical if they have same container path first segment
+but this may be refined by other container initializer implementations.
+<br>
+For example, the User Library classpath container initializer added for User Library Container API
+implementation (UserLibraryClasspathContainerInitializer) refines the comparison ID to the entire container path.
+</li>
 </ul>
 
 <h3>Problem Reports Fixed</h3>
-<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=37657">37657</a>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=52747">52747</a>
+formatter - please special case empty array init
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=59000">59000</a>
+Code formatter struggles with end-of-line comments
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=52679">52679</a>
+Code formatter formats braces in case and default statements, but no settings exist
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=52940">52940</a>
+Formatter: Separate control of new lines in control statements by statement type
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=47815">47815</a>
+Refactoring doesn't work with some project names [refactoring] 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=37657">37657</a>
 [plan item] Improve code formatter
 <br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50989">50989</a>
 Non-externalized strings wrap lines incorrectly
diff --git a/dom/org/eclipse/jdt/core/dom/AST.java b/dom/org/eclipse/jdt/core/dom/AST.java
index 657d706..abd5dac 100644
--- a/dom/org/eclipse/jdt/core/dom/AST.java
+++ b/dom/org/eclipse/jdt/core/dom/AST.java
@@ -234,9 +234,8 @@
 		Map options,
 		IProgressMonitor monitor) {
 		
-		// TODO (olivier) - honor <code>level</code> indicating AST api level
 		ASTConverter converter = new ASTConverter(options, true, monitor);
-		AST ast = new AST();
+		AST ast = AST.newAST(level);
 		BindingResolver resolver = new DefaultBindingResolver(compilationUnitDeclaration.scope);
 		ast.setBindingResolver(resolver);
 		converter.setAST(ast);
diff --git a/dom/org/eclipse/jdt/core/dom/ASTConverter.java b/dom/org/eclipse/jdt/core/dom/ASTConverter.java
index c56b829..7aaf3a1 100644
--- a/dom/org/eclipse/jdt/core/dom/ASTConverter.java
+++ b/dom/org/eclipse/jdt/core/dom/ASTConverter.java
@@ -16,7 +16,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.OperationCanceledException;
 import org.eclipse.jdt.core.JavaCore;
@@ -30,6 +29,7 @@
 import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
 import org.eclipse.jdt.internal.compiler.env.IConstants;
+import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
 import org.eclipse.jdt.internal.compiler.lookup.CompilerModifiers;
 import org.eclipse.jdt.internal.compiler.parser.Scanner;
 import org.eclipse.jdt.internal.compiler.parser.TerminalTokens;
@@ -2498,22 +2498,60 @@
 		return false;
 	}
 	
-	protected void lookupForScopes() {
+	private void lookupForScopes() {
 		if (this.pendingNameScopeResolution != null) {
 			for (Iterator iterator = this.pendingNameScopeResolution.iterator(); iterator.hasNext(); ) {
 				Name name = (Name) iterator.next();
-				this.ast.getBindingResolver().recordScope(name, name.lookupScope());
+				this.ast.getBindingResolver().recordScope(name, lookupScope(name));
 			}
 		}
 		if (this.pendingThisExpressionScopeResolution != null) {
 			for (Iterator iterator = this.pendingThisExpressionScopeResolution.iterator(); iterator.hasNext(); ) {
 				ThisExpression thisExpression = (ThisExpression) iterator.next();
-				this.ast.getBindingResolver().recordScope(thisExpression, thisExpression.lookupScope());
+				this.ast.getBindingResolver().recordScope(thisExpression, lookupScope(thisExpression));
 			}
 		}
 		
 	}
 	
+	private BlockScope lookupScope(ASTNode node) {
+		ASTNode currentNode = node;
+		while(currentNode != null
+			&&!(currentNode instanceof MethodDeclaration)
+			&& !(currentNode instanceof Initializer)
+			&& !(currentNode instanceof FieldDeclaration)) {
+			currentNode = currentNode.getParent();
+		}
+		if (currentNode == null) {
+			return null;
+		}
+		if (currentNode instanceof Initializer) {
+			Initializer initializer = (Initializer) currentNode;
+			while(!(currentNode instanceof TypeDeclaration)) {
+				currentNode = currentNode.getParent();
+			}
+			org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDecl = (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) this.ast.getBindingResolver().getCorrespondingNode(currentNode);
+			if ((initializer.getModifiers() & Modifier.STATIC) != 0) {
+				return typeDecl.staticInitializerScope;
+			} else {
+				return typeDecl.initializerScope;
+			}
+		} else if (currentNode instanceof FieldDeclaration) {
+			FieldDeclaration fieldDeclaration = (FieldDeclaration) currentNode;
+			while(!(currentNode instanceof TypeDeclaration)) {
+				currentNode = currentNode.getParent();
+			}
+			org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDecl = (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) this.ast.getBindingResolver().getCorrespondingNode(currentNode);
+			if ((fieldDeclaration.getModifiers() & Modifier.STATIC) != 0) {
+				return typeDecl.staticInitializerScope;
+			} else {
+				return typeDecl.initializerScope;
+			}
+		}
+		AbstractMethodDeclaration abstractMethodDeclaration = (AbstractMethodDeclaration) this.ast.getBindingResolver().getCorrespondingNode(currentNode);
+		return abstractMethodDeclaration.scope;
+	}
+
 	protected void recordName(Name name, org.eclipse.jdt.internal.compiler.ast.ASTNode compilerNode) {
 		if (compilerNode != null) {
 			recordNodes(name, compilerNode);
diff --git a/dom/org/eclipse/jdt/core/dom/ASTParser.java b/dom/org/eclipse/jdt/core/dom/ASTParser.java
index 4909861..a21b266 100644
--- a/dom/org/eclipse/jdt/core/dom/ASTParser.java
+++ b/dom/org/eclipse/jdt/core/dom/ASTParser.java
@@ -272,8 +272,13 @@
 	 * </p>
 	 * <p>
      * Binding information is obtained from the Java model.
-     * This means that the compilation unit must be located
-     * relative to the Java model via [TODO].
+     * This means that the compilation unit must be located relative to the
+     * Java model. This happens automatically when the source code comes from
+     * either {@link #setSource(ICompilationUnit) setSource(ICompilationUnit)}
+     * or {@link #setSource(IClassFile) setSource(IClassFile)}.
+     * When source is supplied by {@link #setSource(char[]) setSource(char[])},
+     * the location must be extablished explicitly by calling 
+     * {@link #setProject(IJavaProject)} and  {@link #setUnitName(String)}.
 	 * Note that the compiler options that affect doc comment checking may also
 	 * affect whether any bindings are resolved for nodes within doc comments.
 	 * </p>
diff --git a/dom/org/eclipse/jdt/core/dom/Name.java b/dom/org/eclipse/jdt/core/dom/Name.java
index 94abee6..bea5692 100644
--- a/dom/org/eclipse/jdt/core/dom/Name.java
+++ b/dom/org/eclipse/jdt/core/dom/Name.java
@@ -11,9 +11,6 @@
 
 package org.eclipse.jdt.core.dom;
 
-import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
-import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
-
 /**
  * Abstract base class for all AST nodes that represent names.
  * There are exactly two kinds of name: simple ones 
@@ -117,44 +114,5 @@
 	 * @param buffer the buffer
 	 * @since 3.0
 	 */
-	abstract void appendName(StringBuffer buffer);
-
-	BlockScope lookupScope() {
-		ASTNode currentNode = this;
-		while(currentNode != null
-			&&!(currentNode instanceof MethodDeclaration)
-			&& !(currentNode instanceof Initializer)
-			&& !(currentNode instanceof FieldDeclaration)) {
-			currentNode = currentNode.getParent();
-		}
-		if (currentNode == null) {
-			return null;
-		}
-		if (currentNode instanceof Initializer) {
-			Initializer initializer = (Initializer) currentNode;
-			while(!(currentNode instanceof TypeDeclaration)) {
-				currentNode = currentNode.getParent();
-			}
-			org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDecl = (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) this.ast.getBindingResolver().getCorrespondingNode(currentNode);
-			if ((initializer.getModifiers() & Modifier.STATIC) != 0) {
-				return typeDecl.staticInitializerScope;
-			} else {
-				return typeDecl.initializerScope;
-			}
-		} else if (currentNode instanceof FieldDeclaration) {
-			FieldDeclaration fieldDeclaration = (FieldDeclaration) currentNode;
-			while(!(currentNode instanceof TypeDeclaration)) {
-				currentNode = currentNode.getParent();
-			}
-			org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDecl = (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) this.ast.getBindingResolver().getCorrespondingNode(currentNode);
-			if ((fieldDeclaration.getModifiers() & Modifier.STATIC) != 0) {
-				return typeDecl.staticInitializerScope;
-			} else {
-				return typeDecl.initializerScope;
-			}
-		}
-		AbstractMethodDeclaration abstractMethodDeclaration = (AbstractMethodDeclaration) this.ast.getBindingResolver().getCorrespondingNode(currentNode);
-		return abstractMethodDeclaration.scope;
-	}	
-	
+	abstract void appendName(StringBuffer buffer);	
 }
diff --git a/dom/org/eclipse/jdt/core/dom/ThisExpression.java b/dom/org/eclipse/jdt/core/dom/ThisExpression.java
index be50ee0..2990822 100644
--- a/dom/org/eclipse/jdt/core/dom/ThisExpression.java
+++ b/dom/org/eclipse/jdt/core/dom/ThisExpression.java
@@ -13,9 +13,6 @@
 
 import java.util.List;
 
-import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
-import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
-
 /**
  * Simple or qualified "this" AST node type.
  *
@@ -185,48 +182,4 @@
 			memSize()
 			+ (this.optionalQualifier == null ? 0 : getQualifier().treeSize());
 	}
-
-	/**
-	 * Internal method used by ASTConverter.
-	 * 
-	 * @return the block scope
-	 */
-	BlockScope lookupScope() {
-		// TODO (olivier) - this method should be moved to ASTConverter
-		ASTNode currentNode = this;
-		while(currentNode != null
-			&&!(currentNode instanceof MethodDeclaration)
-			&& !(currentNode instanceof Initializer)
-			&& !(currentNode instanceof FieldDeclaration)) {
-			currentNode = currentNode.getParent();
-		}
-		if (currentNode == null) {
-			return null;
-		}
-		if (currentNode instanceof Initializer) {
-			Initializer initializer = (Initializer) currentNode;
-			while(!(currentNode instanceof TypeDeclaration)) {
-				currentNode = currentNode.getParent();
-			}
-			org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDecl = (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) this.ast.getBindingResolver().getCorrespondingNode(currentNode);
-			if ((initializer.getModifiers() & Modifier.STATIC) != 0) {
-				return typeDecl.staticInitializerScope;
-			} else {
-				return typeDecl.initializerScope;
-			}
-		} else if (currentNode instanceof FieldDeclaration) {
-			FieldDeclaration fieldDeclaration = (FieldDeclaration) currentNode;
-			while(!(currentNode instanceof TypeDeclaration)) {
-				currentNode = currentNode.getParent();
-			}
-			org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDecl = (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) this.ast.getBindingResolver().getCorrespondingNode(currentNode);
-			if ((fieldDeclaration.getModifiers() & Modifier.STATIC) != 0) {
-				return typeDecl.staticInitializerScope;
-			} else {
-				return typeDecl.initializerScope;
-			}
-		}
-		AbstractMethodDeclaration abstractMethodDeclaration = (AbstractMethodDeclaration) this.ast.getBindingResolver().getCorrespondingNode(currentNode);
-		return abstractMethodDeclaration.scope;
-	}	
 }
diff --git a/dom/org/eclipse/jdt/core/dom/rewrite/ASTRewrite.java b/dom/org/eclipse/jdt/core/dom/rewrite/ASTRewrite.java
index d2dad23..0c4efd7 100644
--- a/dom/org/eclipse/jdt/core/dom/rewrite/ASTRewrite.java
+++ b/dom/org/eclipse/jdt/core/dom/rewrite/ASTRewrite.java
@@ -12,10 +12,7 @@
 
 import java.util.Iterator;
 import java.util.Map;
-import org.eclipse.text.edits.MultiTextEdit;
-import org.eclipse.text.edits.TextEdit;
-import org.eclipse.text.edits.TextEditGroup;
-import org.eclipse.jface.text.IDocument;
+
 import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.core.dom.AST;
 import org.eclipse.jdt.core.dom.ASTNode;
@@ -29,19 +26,36 @@
 import org.eclipse.jdt.internal.core.dom.rewrite.TrackedNodePosition;
 import org.eclipse.jdt.internal.core.dom.rewrite.RewriteEventStore.CopySourceInfo;
 
+import org.eclipse.jface.text.IDocument;
+
+import org.eclipse.text.edits.MultiTextEdit;
+import org.eclipse.text.edits.TextEdit;
+import org.eclipse.text.edits.TextEditGroup;
+
 /**
- * This API is work in progress, and will be changed for the final 3.0 release.
- * TODO - Work in progress. missing spec
+ * Infrastucture for modifying code by describing changes to AST nodes.
+ * The AST rewriter collects descriptions of modifications to nodes and
+ * translates these descriptions into text edits that can then be applied to
+ * the original source. The key thing is that this is all done without actually
+ * modifying the original AST, which has the virtue of allowing one to entertain
+ * several alternate sets of changes on the same AST (e.g., for calculating
+ * quick fix proposals). The rewrite infrastructure tries to generate minimal
+ * text changes, preserve existing comments and indentation, and follow code
+ * formatter settings. If the freedom to explore multiple alternate changes is
+ * not required, consider using the AST's built-in rewriter 
+ * (see {@link org.eclipse.jdt.core.dom.CompilationUnit#rewrite(IDocument, Map)}).
  * <p>
+ * The following code snippet illustrated usage of this class:
+ * </p>
  * <pre>
  * Document doc = new Document("import java.util.List;\nclass X {}\n");
- * ASTParser parser = ASTParser.newParser(AST.LEVEL_3_0);
+ * ASTParser parser = ASTParser.newParser(AST.LEVEL_2_0);
  * parser.setSource(doc.get().toCharArray());
  * CompilationUnit cu = (CompilationUnit) parser.createAST(null);
  * AST ast = cu.getAST();
  * ImportDeclaration id = ast.newImportDeclaration();
  * id.setName(ast.newName(new String[] {"java", "util", "Set"});
- * ASTRewrite rewriter = new ASTRewrite(ast);
+ * ASTRewrite rewriter = ASTRewrite.create(ast);
  * TypeDeclaration td = (TypeDeclaration) cu.types().get(0);
  * ITrackedNodePosition tdLocation = rewriter.track(td);
  * ListRewriter lrw = rewriter.getListRewrite(cu,
@@ -54,7 +68,6 @@
  * // tdLocation.getStartPosition() and tdLocation.getLength()
  * // are new source range for "class X {}" in doc.get()
  * </pre>
- * </p>
  * <p>
  * This class is not intended to be subclassed.
  * </p>
@@ -68,16 +81,23 @@
 	private final RewriteEventStore eventStore;
 	private final NodeInfoStore nodeStore;
 	
-	/* TODO (martin/david) - You get more flexibility to evolve an API class
-	 * by declaring a public static factory method as API and keeping
-	 * the constructor private or package-private.
-	 */
 	/**
-	 * Creates a new AST rewrite for the given AST.
+	 * Creates a new instance for describing manipulations of
+	 * the given AST.
+	 * 
+	 * @param ast the AST whose nodes will be rewritten
+	 */
+	public static ASTRewrite create(AST ast) {
+		return new ASTRewrite(ast);
+	}
+
+	/**
+	 * Creates a new instance for the given AST.
 	 * 
 	 * @param ast the AST being rewritten
+	 * @see #create(AST)
 	 */
-	public ASTRewrite(AST ast) {
+	private ASTRewrite(AST ast) {
 		this.ast= ast;
 		this.eventStore= new RewriteEventStore();
 		this.nodeStore= new NodeInfoStore(ast);
diff --git a/formatter/org/eclipse/jdt/core/formatter/DefaultCodeFormatterConstants.java b/formatter/org/eclipse/jdt/core/formatter/DefaultCodeFormatterConstants.java
index f7725d0..5764d1e 100644
--- a/formatter/org/eclipse/jdt/core/formatter/DefaultCodeFormatterConstants.java
+++ b/formatter/org/eclipse/jdt/core/formatter/DefaultCodeFormatterConstants.java
@@ -403,6 +403,21 @@
 	public static final String FORMATTER_BRACE_POSITION_FOR_BLOCK = JavaCore.PLUGIN_ID + ".formatter.brace_position_for_block";	//$NON-NLS-1$
 	/**
 	 * <pre>
+	 * FORMATTER / Option to position the braces of a block in a case statement when the block is the first statement following
+	 *             the case
+	 *     - option id:         "org.eclipse.jdt.core.formatter.brace_position_for_block_in_case"
+	 *     - possible values:   { END_OF_LINE, NEXT_LINE, NEXT_LINE_SHIFTED, NEXT_LINE_ON_WRAP }
+	 *     - default:           END_OF_LINE
+	 * </pre>
+	 * @see #END_OF_LINE
+	 * @see #NEXT_LINE
+	 * @see #NEXT_LINE_SHIFTED
+	 * @see #NEXT_LINE_ON_WRAP
+	 * @since 3.0
+	 */
+	public static final String FORMATTER_BRACE_POSITION_FOR_BLOCK_IN_CASE = JavaCore.PLUGIN_ID + ".formatter.brace_position_for_block_in_case";	//$NON-NLS-1$
+	/**
+	 * <pre>
 	 * FORMATTER / Option to position the braces of a constructor declaration
 	 *     - option id:         "org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration"
 	 *     - possible values:   { END_OF_LINE, NEXT_LINE, NEXT_LINE_SHIFTED, NEXT_LINE_ON_WRAP }
@@ -677,6 +692,18 @@
 	public static final String FORMATTER_INSERT_NEW_LINE_AFTER_OPENING_BRACE_IN_ARRAY_INITIALIZER = JavaCore.PLUGIN_ID + ".formatter.insert_new_line_after_opening_brace_in_array_initializer";//$NON-NLS-1$
 	/**
 	 * <pre>
+	 * FORMATTER / Option to insert a new line before the catch keyword in try statement
+	 *     - option id:         "org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement"
+	 *     - possible values:   { INSERT, DO_NOT_INSERT }
+	 *     - default:           DO_NOT_INSERT
+	 * </pre>
+	 * @see JavaCore#INSERT
+	 * @see JavaCore#DO_NOT_INSERT
+	 * @since 3.0
+	 */
+	public static final String FORMATTER_INSERT_NEW_LINE_BEFORE_CATCH_IN_TRY_STATEMENT = JavaCore.PLUGIN_ID + ".formatter.insert_new_line_before_catch_in_try_statement";	//$NON-NLS-1$
+	/**
+	 * <pre>
 	 * FORMATTER / Option to insert a new line before the closing brace in an array initializer
 	 *     - option id:         "org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer"
 	 *     - possible values:   { INSERT, DO_NOT_INSERT }
@@ -689,6 +716,42 @@
 	public static final String FORMATTER_INSERT_NEW_LINE_BEFORE_CLOSING_BRACE_IN_ARRAY_INITIALIZER = JavaCore.PLUGIN_ID + ".formatter.insert_new_line_before_closing_brace_in_array_initializer";//$NON-NLS-1$
 	/**
 	 * <pre>
+	 * FORMATTER / Option to insert a new line before the else keyword in if statement
+	 *     - option id:         "org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement"
+	 *     - possible values:   { INSERT, DO_NOT_INSERT }
+	 *     - default:           DO_NOT_INSERT
+	 * </pre>
+	 * @see JavaCore#INSERT
+	 * @see JavaCore#DO_NOT_INSERT
+	 * @since 3.0
+	 */
+	public static final String FORMATTER_INSERT_NEW_LINE_BEFORE_ELSE_IN_IF_STATEMENT = JavaCore.PLUGIN_ID + ".formatter.insert_new_line_before_else_in_if_statement";	//$NON-NLS-1$
+	/**
+	 * <pre>
+	 * FORMATTER / Option to insert a new line before the finally keyword in try statement
+	 *     - option id:         "org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement"
+	 *     - possible values:   { INSERT, DO_NOT_INSERT }
+	 *     - default:           DO_NOT_INSERT
+	 * </pre>
+	 * @see JavaCore#INSERT
+	 * @see JavaCore#DO_NOT_INSERT
+	 * @since 3.0
+	 */
+	public static final String FORMATTER_INSERT_NEW_LINE_BEFORE_FINALLY_IN_TRY_STATEMENT = JavaCore.PLUGIN_ID + ".formatter.insert_new_line_before_finally_in_try_statement";	//$NON-NLS-1$
+	/**
+	 * <pre>
+	 * FORMATTER / Option to insert a new line before while in do statement
+	 *     - option id:         "org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement"
+	 *     - possible values:   { INSERT, DO_NOT_INSERT }
+	 *     - default:           DO_NOT_INSERT
+	 * </pre>
+	 * @see JavaCore#INSERT
+	 * @see JavaCore#DO_NOT_INSERT
+	 * @since 3.0
+	 */
+	public static final String FORMATTER_INSERT_NEW_LINE_BEFORE_WHILE_IN_DO_STATEMENT = JavaCore.PLUGIN_ID + ".formatter.insert_new_line_before_while_in_do_statement";	//$NON-NLS-1$
+	/**
+	 * <pre>
 	 * FORMATTER / Option to insert a new line in control statements
 	 *     - option id:         "org.eclipse.jdt.core.formatter.insert_new_line_in_control_statements"
 	 *     - possible values:   { INSERT, DO_NOT_INSERT }
@@ -697,6 +760,7 @@
 	 * @see JavaCore#INSERT
 	 * @see JavaCore#DO_NOT_INSERT
 	 * @since 3.0
+	 * @deprecated Will be removed before M9 please use the specific FORMATTER_INSERT_NEW_LINE_IN_XX_STATEMENT where XX represents the specific statement
 	 */
 	public static final String FORMATTER_INSERT_NEW_LINE_IN_CONTROL_STATEMENTS = JavaCore.PLUGIN_ID + ".formatter.insert_new_line_in_control_statements";	//$NON-NLS-1$
 	/**
@@ -747,7 +811,6 @@
 	 * @since 3.0
 	 */
 	public static final String FORMATTER_INSERT_NEW_LINE_IN_EMPTY_TYPE_DECLARATION = JavaCore.PLUGIN_ID + ".formatter.insert_new_line_in_empty_type_declaration";	//$NON-NLS-1$
-
 	/**
 	 * <pre>
 	 * FORMATTER / Option to insert a space after an assignment operator
@@ -810,6 +873,18 @@
 	public static final String FORMATTER_INSERT_SPACE_AFTER_COLON_IN_ASSERT = JavaCore.PLUGIN_ID + ".formatter.insert_space_after_colon_in_assert"; //$NON-NLS-1$
 	/**
 	 * <pre>
+	 * FORMATTER / Option to insert a space after colon in a case statement when a opening brace follows the colon
+	 *     - option id:         "org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case"
+	 *     - possible values:   { INSERT, DO_NOT_INSERT }
+	 *     - default:           INSERT
+	 * </pre>
+	 * @see JavaCore#INSERT
+	 * @see JavaCore#DO_NOT_INSERT
+	 * @since 3.0
+	 */
+	public static final String FORMATTER_INSERT_SPACE_AFTER_COLON_IN_CASE = JavaCore.PLUGIN_ID + ".formatter.insert_space_after_colon_in_case";	//$NON-NLS-1$
+	/**
+	 * <pre>
 	 * FORMATTER / Option to insert a space after the colon in a conditional expression
 	 *     - option id:         "org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional"
 	 *     - possible values:   { INSERT, DO_NOT_INSERT }
@@ -2049,6 +2124,18 @@
 	public static final String FORMATTER_KEEP_ELSE_STATEMENT_ON_SAME_LINE = JavaCore.PLUGIN_ID + ".formatter.keep_else_statement_on_same_line"; //$NON-NLS-1$
 	/**
 	 * <pre>
+	 * FORMATTER / Option to keep empty array initializer one one line
+	 *     - option id:         "org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line"
+	 *     - possible values:   { TRUE, FALSE }
+	 *     - default:           FALSE
+	 * </pre>
+	 * @see #TRUE
+	 * @see #FALSE
+	 * @since 3.0
+	 */
+	public static final String FORMATTER_KEEP_EMPTY_ARRAY_INITIALIZER_ON_ONE_LINE = JavaCore.PLUGIN_ID + ".formatter.keep_empty_array_initializer_on_one_line"; //$NON-NLS-1$
+	/**
+	 * <pre>
 	 * FORMATTER / Option to keep simple if statement on the one line
 	 *     - option id:         "org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line"
 	 *     - possible values:   { TRUE, FALSE }
diff --git a/formatter/org/eclipse/jdt/internal/formatter/CodeFormatterVisitor.java b/formatter/org/eclipse/jdt/internal/formatter/CodeFormatterVisitor.java
index 7b0ccba..b6d115c 100644
--- a/formatter/org/eclipse/jdt/internal/formatter/CodeFormatterVisitor.java
+++ b/formatter/org/eclipse/jdt/internal/formatter/CodeFormatterVisitor.java
@@ -483,6 +483,53 @@
 		methodDeclaration.traverse(this, scope);
 	}
 	
+	/**
+	 * @param block
+	 * @param scope
+	 * @param block_brace_position
+	 * @return
+	 */
+	private void formatBlock(Block block, BlockScope scope, String block_brace_position, boolean insertSpaceBeforeOpeningBrace) {
+		formatOpeningBrace(block_brace_position, insertSpaceBeforeOpeningBrace);
+		final Statement[] statements = block.statements;
+		if (statements != null) {
+			this.scribe.printNewLine();
+			if (this.preferences.indent_statements_compare_to_block) {
+				this.scribe.indent();
+			}
+			formatStatements(scope, statements, true);
+			this.scribe.printComment();
+	
+			if (this.preferences.indent_statements_compare_to_block) {
+				this.scribe.unIndent();
+			}
+		} else if (this.preferences.insert_new_line_in_empty_block) {
+			this.scribe.printNewLine();
+			if (this.preferences.indent_statements_compare_to_block) {
+				this.scribe.indent();
+			}
+			this.scribe.printComment();
+	
+			if (this.preferences.indent_statements_compare_to_block) {
+				this.scribe.unIndent();
+			}
+		} else {
+			if (this.preferences.indent_statements_compare_to_block) {
+				this.scribe.indent();
+			}
+			this.scribe.printComment();
+	
+			if (this.preferences.indent_statements_compare_to_block) {
+				this.scribe.unIndent();
+			}
+		}
+		this.scribe.printNextToken(TerminalTokens.TokenNameRBRACE);
+		this.scribe.printTrailingComment();
+		if (DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED.equals(block_brace_position)) {
+			this.scribe.unIndent();
+		}
+	}
+
 	private void format(FieldDeclaration fieldDeclaration, ASTVisitor visitor, MethodScope scope, boolean isChunkStart, boolean isFirstClassBodyDeclaration) {
 		
 		if (isFirstClassBodyDeclaration) {
@@ -653,7 +700,7 @@
 					
 					if (i != length - 1) {
 						this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_multiple_field_declarations);
-
+						this.scribe.printTrailingComment();
 						this.scribe.alignFragment(multiFieldDeclarationsAlignment, i);
 
 						if (this.preferences.insert_space_after_comma_in_multiple_field_declarations) {
@@ -875,6 +922,7 @@
 					for (int i = 0; i < superInterfaceLength; i++) {
 						if (i > 0) {
 							this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_superinterfaces);
+							this.scribe.printTrailingComment();
 							this.scribe.alignFragment(interfaceAlignment, i+1);
 							if (this.preferences.insert_space_after_comma_in_superinterfaces) {
 								this.scribe.space();
@@ -948,7 +996,6 @@
 		if (anonymous_type_declaration_brace_position.equals(DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED)) {
 			this.scribe.unIndent();
 		}
-		return;
 	}
 
 	private void formatCascadingMessageSends(CascadingMethodInvocationFragmentBuilder builder, BlockScope scope) {
@@ -985,6 +1032,7 @@
 						for (int j = 0; j < argumentLength; j++) {
 							if (j > 0) {
 								this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_method_invocation_arguments);
+								this.scribe.printTrailingComment();
 							}
 							this.scribe.alignFragment(argumentsAlignment, j);
 							if (j > 0 && this.preferences.insert_space_after_comma_in_method_invocation_arguments) {
@@ -1047,6 +1095,7 @@
 								for (int j = 0; j < argumentLength; j++) {
 									if (j > 0) {
 										this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_method_invocation_arguments);
+										this.scribe.printTrailingComment();
 									}
 									this.scribe.alignFragment(argumentsAlignment, j);
 									if (j > 0 && this.preferences.insert_space_after_comma_in_method_invocation_arguments) {
@@ -1172,7 +1221,7 @@
 		final Statement[] statements = block.statements;
 		statements[0].traverse(this, scope);
 		this.scribe.space();
-		this.scribe.printNextToken(TerminalTokens.TokenNameRBRACE, false, true);
+		this.scribe.printNextToken(TerminalTokens.TokenNameRBRACE, false);
 		this.scribe.printTrailingComment();
 	}	
 
@@ -1241,6 +1290,7 @@
 			if (insertSpaceAfterComma) {
 				this.scribe.space();
 			}
+			this.scribe.printTrailingComment();
 		}
 	}
 
@@ -1337,6 +1387,7 @@
 					for (int i = 0; i < argumentLength; i++) {
 						if (i > 0) {
 							this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, spaceBeforeComma);
+							this.scribe.printTrailingComment();
 						}
 						this.scribe.alignFragment(argumentsAlignment, i);
 						if (i > 0 && spaceAfterComma) {
@@ -1461,6 +1512,7 @@
 					for (int i = 0; i < thrownExceptionsLength; i++) {
 						if (i > 0) {
 							this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, spaceBeforeComma);
+							this.scribe.printTrailingComment();
 							this.scribe.alignFragment(throwsAlignment, i);
 							if (spaceAfterComma) {
 								this.scribe.space();
@@ -1780,6 +1832,7 @@
 					for (int i = 0; i < argumentLength; i++) {
 						if (i > 0) {
 							this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_allocation_expression);
+							this.scribe.printTrailingComment();
 						}
 						this.scribe.alignFragment(argumentsAlignment, i);
 						if (i > 0 && this.preferences.insert_space_after_comma_in_allocation_expression) {
@@ -1903,11 +1956,11 @@
 			manageOpeningParenthesizedExpression(arrayInitializer, numberOfParens);
 		}
 		
-		String array_initializer_brace_position = this.preferences.brace_position_for_array_initializer;
-		formatOpeningBrace(array_initializer_brace_position, this.preferences.insert_space_before_opening_brace_in_array_initializer);
-		
 		final Expression[] expressions = arrayInitializer.expressions;
 		if (expressions != null) {
+			String array_initializer_brace_position = this.preferences.brace_position_for_array_initializer;
+			formatOpeningBrace(array_initializer_brace_position, this.preferences.insert_space_before_opening_brace_in_array_initializer);
+		
 			int expressionsLength = expressions.length;
 			final boolean insert_new_line_after_opening_brace = this.preferences.insert_new_line_after_opening_brace_in_array_initializer;
 			if (expressionsLength > 1) {
@@ -1938,6 +1991,7 @@
 						expressions[0].traverse(this, scope);
 						for (int i = 1; i < expressionsLength; i++) {
 							this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_array_initializer);
+							this.scribe.printTrailingComment();
 							this.scribe.alignFragment(arrayInitializerAlignment, i);
 							if (this.preferences.insert_space_after_comma_in_array_initializer) {
 								this.scribe.space();
@@ -1946,6 +2000,7 @@
 							if (i == expressionsLength - 1) {
 								if (isComma()) {
 									this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_array_initializer);
+									this.scribe.printTrailingComment();
 								}
 							}
 						}
@@ -1967,6 +2022,7 @@
 				expressions[0].traverse(this, scope);
 				if (isComma()) {
 					this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_array_initializer);
+					this.scribe.printTrailingComment();
 				}
 				if (insert_new_line_after_opening_brace) {
 					this.scribe.unIndent();
@@ -1977,13 +2033,26 @@
 			} else if (this.preferences.insert_space_before_closing_brace_in_array_initializer) {
 				this.scribe.space();
 			}
-		} else if (this.preferences.insert_space_between_empty_braces_in_array_initializer) {
-			this.scribe.space();
+			this.scribe.printNextToken(TerminalTokens.TokenNameRBRACE, false); 
+			if (array_initializer_brace_position.equals(DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED)) {
+				this.scribe.unIndent();
+			}	
+		} else {
+			boolean keepEmptyArrayInitializerOnTheSameLine = this.preferences.keep_empty_array_initializer_on_one_line;
+			String array_initializer_brace_position = this.preferences.brace_position_for_array_initializer;
+			if (keepEmptyArrayInitializerOnTheSameLine) {
+				this.scribe.printNextToken(TerminalTokens.TokenNameLBRACE, this.preferences.insert_space_before_opening_brace_in_array_initializer);
+			} else {
+				formatOpeningBrace(array_initializer_brace_position, this.preferences.insert_space_before_opening_brace_in_array_initializer);
+			}
+			if (this.preferences.insert_space_between_empty_braces_in_array_initializer) {
+				this.scribe.space();
+			}
+			this.scribe.printNextToken(TerminalTokens.TokenNameRBRACE, false); 
+			if (keepEmptyArrayInitializerOnTheSameLine && array_initializer_brace_position.equals(DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED)) {
+				this.scribe.unIndent();
+			}
 		}
-		this.scribe.printNextToken(TerminalTokens.TokenNameRBRACE, false, true); 
-		if (array_initializer_brace_position.equals(DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED)) {
-			this.scribe.unIndent();
-		}	
 	
 		if (numberOfParens > 0) {
 			manageClosingParenthesizedExpression(arrayInitializer, numberOfParens);
@@ -2076,7 +2145,7 @@
 		if (numberOfParens > 0) {
 			manageOpeningParenthesizedExpression(arrayTypeReference, numberOfParens);
 		}
-		this.scribe.printNextToken(SINGLETYPEREFERENCE_EXPECTEDTOKENS, false, true);
+		this.scribe.printNextToken(SINGLETYPEREFERENCE_EXPECTEDTOKENS);
 		
 		int dimensions = getExtraDimension();
 		if (dimensions != 0) {
@@ -2108,7 +2177,7 @@
 		if (numberOfParens > 0) { 
 			manageOpeningParenthesizedExpression(arrayTypeReference, numberOfParens);
 		}
-		this.scribe.printNextToken(SINGLETYPEREFERENCE_EXPECTEDTOKENS, false, true);
+		this.scribe.printNextToken(SINGLETYPEREFERENCE_EXPECTEDTOKENS);
 		int dimensions = getExtraDimension();
 		if (dimensions != 0) {
 			if (this.preferences.insert_space_before_opening_bracket_in_array_type_reference) {
@@ -2216,50 +2285,10 @@
 	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.Block, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
 	 */
 	public boolean visit(Block block, BlockScope scope) {
-	
-		String block_brace_position = this.preferences.brace_position_for_block;
-		formatOpeningBrace(block_brace_position, this.preferences.insert_space_before_opening_brace_in_block);
-		final Statement[] statements = block.statements;
-		if (statements != null) {
-			this.scribe.printNewLine();
-			if (this.preferences.indent_statements_compare_to_block) {
-				this.scribe.indent();
-			}
-			formatStatements(scope, statements, true);
-			this.scribe.printComment();
-	
-			if (this.preferences.indent_statements_compare_to_block) {
-				this.scribe.unIndent();
-			}
-		} else if (this.preferences.insert_new_line_in_empty_block) {
-			this.scribe.printNewLine();
-			if (this.preferences.indent_statements_compare_to_block) {
-				this.scribe.indent();
-			}
-			this.scribe.printComment();
-	
-			if (this.preferences.indent_statements_compare_to_block) {
-				this.scribe.unIndent();
-			}
-		} else {
-			if (this.preferences.indent_statements_compare_to_block) {
-				this.scribe.indent();
-			}
-			this.scribe.printComment();
-	
-			if (this.preferences.indent_statements_compare_to_block) {
-				this.scribe.unIndent();
-			}
-		}
-		this.scribe.printNextToken(TerminalTokens.TokenNameRBRACE);
-		this.scribe.printTrailingComment();
-		if (DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED.equals(block_brace_position)) {
-			this.scribe.unIndent();
-		}		
-		return false;	
+		formatBlock(block, scope, this.preferences.brace_position_for_block, this.preferences.insert_space_before_opening_brace_in_block);	
+		return false;
 	}
 
-
 	/**
 	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.Break, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
 	 */
@@ -2714,7 +2743,7 @@
 			formatNecessaryEmptyStatement(); 
 		}
 		
-		if (this.preferences.insert_new_line_in_control_statements) {
+		if (this.preferences.insert_new_line_before_while_in_do_statement || this.preferences.insert_new_line_in_control_statements) {
 			this.scribe.printNewLine();
 		}
 		this.scribe.printNextToken(TerminalTokens.TokenNamewhile, this.preferences.insert_space_after_closing_brace_in_block);
@@ -2815,6 +2844,7 @@
 					for (int i = 0; i < argumentLength; i++) {
 						if (i > 0) {
 							this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_explicit_constructor_call_arguments);
+							this.scribe.printTrailingComment();
 						}
 						this.scribe.alignFragment(argumentsAlignment, i);
 						if (i > 0 && this.preferences.insert_space_after_comma_in_explicit_constructor_call_arguments) {
@@ -2919,6 +2949,7 @@
 						if (this.preferences.insert_space_after_comma_in_for_inits) {
 							this.scribe.space();
 						}
+						this.scribe.printTrailingComment();
 					}				
 				}
 			}
@@ -2944,6 +2975,7 @@
 					if (this.preferences.insert_space_after_comma_in_for_increments) {
 						this.scribe.space();
 					}
+					this.scribe.printTrailingComment();
 				}
 			}
 		}
@@ -3010,7 +3042,7 @@
 				} else {
                     formatLeftCurlyBrace(line, this.preferences.brace_position_for_block);
 					thenStatement.traverse(this, scope);
-					if (elseStatement != null && this.preferences.insert_new_line_in_control_statements) {
+					if (elseStatement != null && (this.preferences.insert_new_line_before_else_in_if_statement || this.preferences.insert_new_line_in_control_statements)) {
 						this.scribe.printNewLine();
 					}
 				}
@@ -3501,6 +3533,7 @@
 					for (int i = 0; i < argumentLength; i++) {
 						if (i > 0) {
 							this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_allocation_expression);
+							this.scribe.printTrailingComment();
 						}
 						this.scribe.alignFragment(argumentsAlignment, i);
 						if (i > 0 && this.preferences.insert_space_after_comma_in_allocation_expression) {
@@ -3656,7 +3689,7 @@
 		if (numberOfParens > 0) {
 			manageOpeningParenthesizedExpression(singleNameReference, numberOfParens);
 		}
-		this.scribe.printNextToken(SINGLETYPEREFERENCE_EXPECTEDTOKENS, false, true);
+		this.scribe.printNextToken(SINGLETYPEREFERENCE_EXPECTEDTOKENS);
 		
 		if (numberOfParens > 0) {
 			manageClosingParenthesizedExpression(singleNameReference, numberOfParens);
@@ -3675,7 +3708,7 @@
 		if (numberOfParens > 0) {
 			manageOpeningParenthesizedExpression(singleTypeReference, numberOfParens);
 		}
-		this.scribe.printNextToken(SINGLETYPEREFERENCE_EXPECTEDTOKENS, false, true);
+		this.scribe.printNextToken(SINGLETYPEREFERENCE_EXPECTEDTOKENS);
 
 		if (numberOfParens > 0) {
 			manageClosingParenthesizedExpression(singleTypeReference, numberOfParens);
@@ -3694,7 +3727,7 @@
 		if (numberOfParens > 0) {
 			manageOpeningParenthesizedExpression(singleTypeReference, numberOfParens);
 		}
-		this.scribe.printNextToken(SINGLETYPEREFERENCE_EXPECTEDTOKENS, false, true);
+		this.scribe.printNextToken(SINGLETYPEREFERENCE_EXPECTEDTOKENS);
 
 		if (numberOfParens > 0) {
 			manageClosingParenthesizedExpression(singleTypeReference, numberOfParens);
@@ -3767,11 +3800,15 @@
 			for (int i = 0; i < statementsLength; i++) {
 				final Statement statement = statements[i];
 				if (statement instanceof CaseStatement) {
+					if (wasACase) {
+						this.scribe.printNewLine();
+					}
 					if ((wasACase && this.preferences.indent_switchstatements_compare_to_cases) 
 						|| (wasAStatement && this.preferences.indent_switchstatements_compare_to_cases)) {
 						this.scribe.unIndent();
 					}
 					statement.traverse(this, scope);
+					this.scribe.printTrailingComment();
 					wasACase = true;
 					wasAStatement = false;
 					if (this.preferences.indent_switchstatements_compare_to_cases) {
@@ -3792,13 +3829,34 @@
 							this.scribe.unIndent();
 						}
 					}
+					if (wasACase) {
+						this.scribe.printNewLine();
+					}
 					statement.traverse(this, scope);
 					if (this.preferences.indent_breaks_compare_to_cases) {
 						this.scribe.unIndent();
 					}
 					wasACase = false;
 					wasAStatement = false;
+				} else if (statement instanceof Block) {
+					String bracePosition;
+					if (wasACase) {
+						if (this.preferences.indent_switchstatements_compare_to_cases) {
+							this.scribe.unIndent();
+						}
+						bracePosition =	this.preferences.brace_position_for_block_in_case;
+						formatBlock((Block) statement, scope, bracePosition, this.preferences.insert_space_after_colon_in_case);
+						if (this.preferences.indent_switchstatements_compare_to_cases) {
+							this.scribe.indent();
+						}
+					} else {
+						bracePosition =	this.preferences.brace_position_for_block;
+						formatBlock((Block) statement, scope, bracePosition, this.preferences.insert_space_before_opening_brace_in_block);
+					}
+					wasAStatement = true;
+					wasACase = false;
 				} else {
+					this.scribe.printNewLine();
 					statement.traverse(this, scope);
 					wasAStatement = true;
 					wasACase = false;
@@ -3809,6 +3867,7 @@
 					 */	
 					this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
 					this.scribe.printTrailingComment();
+					this.scribe.printNewLine();
 				} else if (statement instanceof LocalDeclaration) {
 					LocalDeclaration currentLocal = (LocalDeclaration) statement;
 					if (i < (statementsLength - 1)) {
@@ -3823,6 +3882,7 @@
 								 */	
 								this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
 								this.scribe.printTrailingComment();
+								this.scribe.printNewLine();
 							}
 						} else {
 							/*
@@ -3830,6 +3890,7 @@
 							 */	
 							this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
 							this.scribe.printTrailingComment();
+							this.scribe.printNewLine();
 						}
 					} else {
 						/*
@@ -3837,9 +3898,11 @@
 						 */	
 						this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
 						this.scribe.printTrailingComment();
+						this.scribe.printNewLine();
 					}
+				} else if (!wasACase) {
+					this.scribe.printNewLine();
 				}
-				this.scribe.printNewLine();
 			}
 		}		
 		
@@ -3941,11 +4004,11 @@
 
 		this.scribe.printNextToken(TerminalTokens.TokenNametry);
 		tryStatement.tryBlock.traverse(this, scope);
-		if (this.preferences.insert_new_line_in_control_statements) {
-			this.scribe.printNewLine();
-		}	
 		if (tryStatement.catchArguments != null) {
 			for (int i = 0, max = tryStatement.catchBlocks.length; i < max; i++) {
+				if (this.preferences.insert_new_line_before_catch_in_try_statement || this.preferences.insert_new_line_in_control_statements) {
+					this.scribe.printNewLine();
+				}	
 				this.scribe.printNextToken(TerminalTokens.TokenNamecatch, this.preferences.insert_space_after_closing_brace_in_block);
 				final int line = this.scribe.line;
 				this.scribe.printNextToken(TerminalTokens.TokenNameLPAREN, this.preferences.insert_space_before_opening_paren_in_catch);
@@ -3960,12 +4023,12 @@
 				
 				formatLeftCurlyBrace(line, this.preferences.brace_position_for_block);
 				tryStatement.catchBlocks[i].traverse(this, scope);
-				if (this.preferences.insert_new_line_in_control_statements) {
-					this.scribe.printNewLine();
-				}	
 			}
 		}
 		if (tryStatement.finallyBlock != null) {
+			if (this.preferences.insert_new_line_before_finally_in_try_statement || this.preferences.insert_new_line_in_control_statements) {
+				this.scribe.printNewLine();
+			}	
 			this.scribe.printNextToken(TerminalTokens.TokenNamefinally, this.preferences.insert_space_after_closing_brace_in_block);
 			tryStatement.finallyBlock.traverse(this, scope);
 		}
diff --git a/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatterOptions.java b/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatterOptions.java
index d7c21d4..eec2ce1 100644
--- a/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatterOptions.java
+++ b/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatterOptions.java
@@ -57,6 +57,7 @@
 	public String brace_position_for_anonymous_type_declaration;
 	public String brace_position_for_array_initializer;
 	public String brace_position_for_block;
+	public String brace_position_for_block_in_case;
 	public String brace_position_for_constructor_declaration;
 	public String brace_position_for_method_declaration;
 	public String brace_position_for_type_declaration;
@@ -85,7 +86,11 @@
 	public boolean indent_switchstatements_compare_to_switch;
 	
 	public boolean insert_new_line_after_opening_brace_in_array_initializer;
+	public boolean insert_new_line_before_catch_in_try_statement;
 	public boolean insert_new_line_before_closing_brace_in_array_initializer;
+	public boolean insert_new_line_before_else_in_if_statement;
+	public boolean insert_new_line_before_finally_in_try_statement;
+	public boolean insert_new_line_before_while_in_do_statement;
 	public boolean insert_new_line_in_control_statements;
 	public boolean insert_new_line_in_empty_anonymous_type_declaration;
 	public boolean insert_new_line_in_empty_block;
@@ -96,6 +101,7 @@
 	public boolean insert_space_after_closing_paren_in_cast;
 	public boolean insert_space_after_closing_brace_in_block;
 	public boolean insert_space_after_colon_in_assert;
+	public boolean insert_space_after_colon_in_case;
 	public boolean insert_space_after_colon_in_conditional;
 	public boolean insert_space_after_colon_in_labeled_statement;
 	public boolean insert_space_after_comma_in_allocation_expression;
@@ -199,6 +205,7 @@
 	public boolean compact_else_if;
 	public boolean keep_guardian_clause_on_one_line;
 	public boolean keep_else_statement_on_same_line;
+	public boolean keep_empty_array_initializer_on_one_line;
 	public boolean keep_simple_if_on_one_line;
 	public boolean keep_then_statement_on_same_line;
 	public int number_of_empty_lines_to_preserve;
@@ -247,6 +254,7 @@
 		options.put(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_ANONYMOUS_TYPE_DECLARATION, this.brace_position_for_anonymous_type_declaration);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_ARRAY_INITIALIZER, this.brace_position_for_array_initializer);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_BLOCK, this.brace_position_for_block);
+		options.put(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_BLOCK_IN_CASE, this.brace_position_for_block_in_case);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_CONSTRUCTOR_DECLARATION, this.brace_position_for_constructor_declaration);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_METHOD_DECLARATION, this.brace_position_for_method_declaration);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_TYPE_DECLARATION, this.brace_position_for_type_declaration);
@@ -271,7 +279,11 @@
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INDENT_SWITCHSTATEMENTS_COMPARE_TO_CASES, this.indent_switchstatements_compare_to_cases ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INDENT_SWITCHSTATEMENTS_COMPARE_TO_SWITCH, this.indent_switchstatements_compare_to_switch ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_NEW_LINE_AFTER_OPENING_BRACE_IN_ARRAY_INITIALIZER, this.insert_new_line_after_opening_brace_in_array_initializer? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
+		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_NEW_LINE_BEFORE_CATCH_IN_TRY_STATEMENT, this.insert_new_line_before_catch_in_try_statement? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_NEW_LINE_BEFORE_CLOSING_BRACE_IN_ARRAY_INITIALIZER, this.insert_new_line_before_closing_brace_in_array_initializer? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
+		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_NEW_LINE_BEFORE_ELSE_IN_IF_STATEMENT, this.insert_new_line_before_else_in_if_statement? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
+		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_NEW_LINE_BEFORE_FINALLY_IN_TRY_STATEMENT, this.insert_new_line_before_finally_in_try_statement? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
+		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_NEW_LINE_BEFORE_WHILE_IN_DO_STATEMENT, this.insert_new_line_before_while_in_do_statement? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_NEW_LINE_IN_CONTROL_STATEMENTS, this.insert_new_line_in_control_statements? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_NEW_LINE_IN_EMPTY_ANONYMOUS_TYPE_DECLARATION, this.insert_new_line_in_empty_anonymous_type_declaration? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_NEW_LINE_IN_EMPTY_BLOCK, this.insert_new_line_in_empty_block? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
@@ -282,6 +294,7 @@
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_CLOSING_PAREN_IN_CAST, this.insert_space_after_closing_paren_in_cast? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_CLOSING_BRACE_IN_BLOCK, this.insert_space_after_closing_brace_in_block? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_COLON_IN_ASSERT, this.insert_space_after_colon_in_assert? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
+		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_COLON_IN_CASE, this.insert_space_after_colon_in_case? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_COLON_IN_CONDITIONAL, this.insert_space_after_colon_in_conditional? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_COLON_IN_LABELED_STATEMENT, this.insert_space_after_colon_in_labeled_statement? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_COMMA_IN_ALLOCATION_EXPRESSION, this.insert_space_after_comma_in_allocation_expression? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
@@ -385,6 +398,7 @@
 		options.put(DefaultCodeFormatterConstants.FORMATTER_COMPACT_ELSE_IF, this.compact_else_if ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_KEEP_GUARDIAN_CLAUSE_ON_ONE_LINE, this.keep_guardian_clause_on_one_line ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_KEEP_ELSE_STATEMENT_ON_SAME_LINE, this.keep_else_statement_on_same_line ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
+		options.put(DefaultCodeFormatterConstants.FORMATTER_KEEP_EMPTY_ARRAY_INITIALIZER_ON_ONE_LINE, this.keep_empty_array_initializer_on_one_line ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_KEEP_SIMPLE_IF_ON_ONE_LINE, this.keep_simple_if_on_one_line ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_KEEP_THEN_STATEMENT_ON_SAME_LINE, this.keep_then_statement_on_same_line ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_NUMBER_OF_EMPTY_LINES_TO_PRESERVE, Integer.toString(this.number_of_empty_lines_to_preserve));
@@ -584,6 +598,14 @@
 				this.brace_position_for_block = DefaultCodeFormatterConstants.END_OF_LINE;
 			}
 		}
+		final Object bracePositionForBlockInCaseOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_BLOCK_IN_CASE);
+		if (bracePositionForBlockInCaseOption != null) {
+			try {
+				this.brace_position_for_block_in_case = (String) bracePositionForBlockInCaseOption;
+			} catch(ClassCastException e) {
+				this.brace_position_for_block_in_case = DefaultCodeFormatterConstants.END_OF_LINE;
+			}
+		}
 		final Object bracePositionForConstructorDeclarationOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_CONSTRUCTOR_DECLARATION);
 		if (bracePositionForConstructorDeclarationOption != null) {
 			try {
@@ -774,10 +796,26 @@
 		if (insertNewLineAfterOpeningBraceInArrayInitializerOption != null) {
 			this.insert_new_line_after_opening_brace_in_array_initializer = JavaCore.INSERT.equals(insertNewLineAfterOpeningBraceInArrayInitializerOption);
 		}
+		final Object insertNewLineBeforeCatchInTryStatementOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_INSERT_NEW_LINE_BEFORE_CATCH_IN_TRY_STATEMENT);
+		if (insertNewLineBeforeCatchInTryStatementOption != null) {
+			this.insert_new_line_before_catch_in_try_statement = JavaCore.INSERT.equals(insertNewLineBeforeCatchInTryStatementOption);
+		}
 		final Object insertNewLineBeforeClosingBraceInArrayInitializerOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_INSERT_NEW_LINE_BEFORE_CLOSING_BRACE_IN_ARRAY_INITIALIZER);
 		if (insertNewLineBeforeClosingBraceInArrayInitializerOption != null) {
 			this.insert_new_line_before_closing_brace_in_array_initializer = JavaCore.INSERT.equals(insertNewLineBeforeClosingBraceInArrayInitializerOption);
 		}
+		final Object insertNewLineBeforeElseInIfStatementOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_INSERT_NEW_LINE_BEFORE_ELSE_IN_IF_STATEMENT);
+		if (insertNewLineBeforeElseInIfStatementOption != null) {
+			this.insert_new_line_before_else_in_if_statement = JavaCore.INSERT.equals(insertNewLineBeforeElseInIfStatementOption);
+		}
+		final Object insertNewLineBeforeFinallyInTryStatementOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_INSERT_NEW_LINE_BEFORE_FINALLY_IN_TRY_STATEMENT);
+		if (insertNewLineBeforeFinallyInTryStatementOption != null) {
+			this.insert_new_line_before_finally_in_try_statement = JavaCore.INSERT.equals(insertNewLineBeforeFinallyInTryStatementOption);
+		}
+		final Object insertNewLineBeforeWhileInDoStatementOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_INSERT_NEW_LINE_BEFORE_WHILE_IN_DO_STATEMENT);
+		if (insertNewLineBeforeWhileInDoStatementOption != null) {
+			this.insert_new_line_before_while_in_do_statement = JavaCore.INSERT.equals(insertNewLineBeforeWhileInDoStatementOption);
+		}
 		final Object insertNewLineInControlStatementsOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_INSERT_NEW_LINE_IN_CONTROL_STATEMENTS);
 		if (insertNewLineInControlStatementsOption != null) {
 			this.insert_new_line_in_control_statements = JavaCore.INSERT.equals(insertNewLineInControlStatementsOption);
@@ -818,6 +856,10 @@
 		if (insertSpaceAfterColonInAssertOption != null) {
 			this.insert_space_after_colon_in_assert = JavaCore.INSERT.equals(insertSpaceAfterColonInAssertOption);
 		}
+		final Object insertSpaceAfterColonInCaseOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_COLON_IN_CASE);
+		if (insertSpaceAfterColonInCaseOption != null) {
+			this.insert_space_after_colon_in_case = JavaCore.INSERT.equals(insertSpaceAfterColonInCaseOption);
+		}
 		final Object insertSpaceAfterColonInConditionalOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_COLON_IN_CONDITIONAL);
 		if (insertSpaceAfterColonInConditionalOption != null) {
 			this.insert_space_after_colon_in_conditional = JavaCore.INSERT.equals(insertSpaceAfterColonInConditionalOption);
@@ -1230,6 +1272,10 @@
 		if (keepElseStatementOnSameLineOption != null) {
 			this.keep_else_statement_on_same_line = DefaultCodeFormatterConstants.TRUE.equals(keepElseStatementOnSameLineOption);
 		}
+		final Object keepEmptyArrayInitializerOnOneLineOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_KEEP_EMPTY_ARRAY_INITIALIZER_ON_ONE_LINE);
+		if (keepEmptyArrayInitializerOnOneLineOption != null) {
+			this.keep_empty_array_initializer_on_one_line = DefaultCodeFormatterConstants.TRUE.equals(keepEmptyArrayInitializerOnOneLineOption);
+		}
 		final Object keepSimpleIfOnOneLineOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_KEEP_SIMPLE_IF_ON_ONE_LINE);
 		if (keepSimpleIfOnOneLineOption != null) {
 			this.keep_simple_if_on_one_line = DefaultCodeFormatterConstants.TRUE.equals(keepSimpleIfOnOneLineOption);
@@ -1299,6 +1345,7 @@
 		this.brace_position_for_anonymous_type_declaration = DefaultCodeFormatterConstants.END_OF_LINE;
 		this.brace_position_for_array_initializer = DefaultCodeFormatterConstants.END_OF_LINE;
 		this.brace_position_for_block = DefaultCodeFormatterConstants.END_OF_LINE;
+		this.brace_position_for_block_in_case = DefaultCodeFormatterConstants.END_OF_LINE;
 		this.brace_position_for_constructor_declaration = DefaultCodeFormatterConstants.END_OF_LINE;
 		this.brace_position_for_method_declaration = DefaultCodeFormatterConstants.END_OF_LINE;
 		this.brace_position_for_type_declaration = DefaultCodeFormatterConstants.END_OF_LINE;
@@ -1323,7 +1370,11 @@
 		this.indent_switchstatements_compare_to_cases = true;
 		this.indent_switchstatements_compare_to_switch = true;
 		this.insert_new_line_after_opening_brace_in_array_initializer = false;
+		this.insert_new_line_before_catch_in_try_statement = false;
 		this.insert_new_line_before_closing_brace_in_array_initializer = false;
+		this.insert_new_line_before_else_in_if_statement = false;
+		this.insert_new_line_before_finally_in_try_statement = false;
+		this.insert_new_line_before_while_in_do_statement = false;
 		this.insert_new_line_in_control_statements = false;
 		this.insert_new_line_in_empty_anonymous_type_declaration = true;
 		this.insert_new_line_in_empty_block = true;
@@ -1334,6 +1385,7 @@
 		this.insert_space_after_closing_paren_in_cast = true;
 		this.insert_space_after_closing_brace_in_block = true;
 		this.insert_space_after_colon_in_assert = true;
+		this.insert_space_after_colon_in_case = true;
 		this.insert_space_after_colon_in_conditional = true;
 		this.insert_space_after_colon_in_labeled_statement = true;
 		this.insert_space_after_comma_in_allocation_expression = true;
@@ -1437,6 +1489,7 @@
 		this.compact_else_if = true;
 		this.keep_guardian_clause_on_one_line = false;
 		this.keep_else_statement_on_same_line = false;
+		this.keep_empty_array_initializer_on_one_line = false;
 		this.keep_simple_if_on_one_line = false;
 		this.keep_then_statement_on_same_line = false;
 		this.number_of_empty_lines_to_preserve = 0;
@@ -1467,6 +1520,7 @@
 		this.brace_position_for_anonymous_type_declaration = DefaultCodeFormatterConstants.END_OF_LINE;
 		this.brace_position_for_array_initializer = DefaultCodeFormatterConstants.END_OF_LINE;
 		this.brace_position_for_block = DefaultCodeFormatterConstants.END_OF_LINE;
+		this.brace_position_for_block_in_case = DefaultCodeFormatterConstants.END_OF_LINE;
 		this.brace_position_for_constructor_declaration = DefaultCodeFormatterConstants.END_OF_LINE;
 		this.brace_position_for_method_declaration = DefaultCodeFormatterConstants.END_OF_LINE;
 		this.brace_position_for_type_declaration = DefaultCodeFormatterConstants.END_OF_LINE;
@@ -1491,7 +1545,11 @@
 		this.indent_switchstatements_compare_to_cases = true;
 		this.indent_switchstatements_compare_to_switch = false;
 		this.insert_new_line_after_opening_brace_in_array_initializer = false;
+		this.insert_new_line_before_catch_in_try_statement = false;
 		this.insert_new_line_before_closing_brace_in_array_initializer = false;
+		this.insert_new_line_before_else_in_if_statement = false;
+		this.insert_new_line_before_finally_in_try_statement = false;
+		this.insert_new_line_before_while_in_do_statement = false;
 		this.insert_new_line_in_control_statements = false;
 		this.insert_new_line_in_empty_anonymous_type_declaration = true;
 		this.insert_new_line_in_empty_block = true;
@@ -1502,6 +1560,7 @@
 		this.insert_space_after_closing_paren_in_cast = true;
 		this.insert_space_after_closing_brace_in_block = true;
 		this.insert_space_after_colon_in_assert = true;
+		this.insert_space_after_colon_in_case = true;
 		this.insert_space_after_colon_in_conditional = true;
 		this.insert_space_after_colon_in_labeled_statement = true;
 		this.insert_space_after_comma_in_allocation_expression = true;
@@ -1605,6 +1664,7 @@
 		this.compact_else_if = true;
 		this.keep_guardian_clause_on_one_line = true;
 		this.keep_else_statement_on_same_line = false;
+		this.keep_empty_array_initializer_on_one_line = false;
 		this.keep_simple_if_on_one_line = true;
 		this.keep_then_statement_on_same_line = false;
 		this.number_of_empty_lines_to_preserve = 1;
diff --git a/formatter/org/eclipse/jdt/internal/formatter/Scribe.java b/formatter/org/eclipse/jdt/internal/formatter/Scribe.java
index 84deebf..2c404de 100644
--- a/formatter/org/eclipse/jdt/internal/formatter/Scribe.java
+++ b/formatter/org/eclipse/jdt/internal/formatter/Scribe.java
@@ -1100,20 +1100,6 @@
 			throw new AbortFormatting(e);
 		}
 	}
-		
-	public void printNextToken(int expectedTokenType, boolean considerSpaceIfAny, boolean considerNewLineAfterComment){
-		printComment();
-		try {
-			this.currentToken = this.scanner.getNextToken();
-			char[] currentTokenSource = this.scanner.getRawTokenSource();
-			if (expectedTokenType != this.currentToken) {
-				throw new AbortFormatting("unexpected token type, expecting:"+expectedTokenType+", actual:"+this.currentToken);//$NON-NLS-1$//$NON-NLS-2$
-			}
-			this.print(currentTokenSource, considerSpaceIfAny);
-		} catch (InvalidInputException e) {
-			throw new AbortFormatting(e);
-		}
-	}
 
 	public void printNextToken(int[] expectedTokenTypes){
 		printComment();
@@ -1135,27 +1121,6 @@
 			throw new AbortFormatting(e);
 		}
 	}
-	
-	public void printNextToken(int[] expectedTokenTypes, boolean considerSpaceIfAny, boolean considerNewLineAfterComment){
-		printComment();
-		try {
-			this.currentToken = this.scanner.getNextToken();
-			char[] currentTokenSource = this.scanner.getRawTokenSource();
-			if (Arrays.binarySearch(expectedTokenTypes, this.currentToken) < 0) {
-				StringBuffer expectations = new StringBuffer(5);
-				for (int i = 0; i < expectedTokenTypes.length; i++){
-					if (i > 0) {
-						expectations.append(',');
-					}
-					expectations.append(expectedTokenTypes[i]);
-				}				
-				throw new AbortFormatting("unexpected token type, expecting:["+expectations.toString()+"], actual:"+this.currentToken);//$NON-NLS-1$//$NON-NLS-2$
-			}
-			this.print(currentTokenSource, considerSpaceIfAny);
-		} catch (InvalidInputException e) {
-			throw new AbortFormatting(e);
-		}
-	}
 
 	public void printQualifiedReference(int sourceEnd) {
 		int currentTokenStartPosition = this.scanner.currentPosition;
diff --git a/model/org/eclipse/jdt/core/ClasspathContainerInitializer.java b/model/org/eclipse/jdt/core/ClasspathContainerInitializer.java
index 83a3b1f..57fa28c 100644
--- a/model/org/eclipse/jdt/core/ClasspathContainerInitializer.java
+++ b/model/org/eclipse/jdt/core/ClasspathContainerInitializer.java
@@ -147,5 +147,29 @@
     	// By default, a container path is the only available description
     	return containerPath.makeRelative().toString();
     }
+
+	/**
+	 * Returns an object which identifies a container for comparison purpose. This allows
+	 * to eliminate redundant containers when accumulating classpath entries (e.g. 
+	 * runtime classpath computation). When requesting a container comparison ID, one
+	 * should ensure using its corresponding container initializer. Indeed, a random container
+	 * initializer cannot be held responsible for determining comparison IDs for arbitrary 
+	 * containers.
+	 * <p>
+	 * @param containerPath the path of the container which is being checked
+	 * @param project the project for which the container is to being checked
+	 * @return returns an Object identifying the container for comparison
+	 * @since 3.0
+	 */
+	public Object getComparisonID(IPath containerPath, IJavaProject project) {
+
+		// By default, containers are identical if they have the same containerPath first segment,
+		// but this may be refined by other container initializer implementations.
+		if (containerPath == null) {
+			return null;
+		} else {
+			return containerPath.segment(0);
+		}
+	}
 }
 
diff --git a/model/org/eclipse/jdt/core/ICompilationUnit.java b/model/org/eclipse/jdt/core/ICompilationUnit.java
index 22a5f07..2988336 100644
--- a/model/org/eclipse/jdt/core/ICompilationUnit.java
+++ b/model/org/eclipse/jdt/core/ICompilationUnit.java
@@ -31,6 +31,12 @@
  */
 public interface ICompilationUnit extends IJavaElement, ISourceReference, IParent, IOpenable, IWorkingCopy, ISourceManipulation, ICodeAssist {
 /**
+ * Constant indicating that a reconcile operation should not return an AST.
+ * @since 3.0
+ */
+public static final int NO_AST = 0;
+
+/**
  * Changes this compilation unit handle into a working copy. A new <code>IBuffer</code> is
  * created using this compilation unit handle's owner. Uses the primary owner is none was
  * specified when this compilation unit handle was created.
@@ -483,58 +489,6 @@
  * <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 createAST boolean indicating whether a compilation unit AST should be created.
- * @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>
- * @deprecated Replaced by {@link #reconcile(int, boolean, WorkingCopyOwner, IProgressMonitor).
- * TODO (jeem) this method to be deleted for April 20, 2004 I-build
- * @since 3.0
- */
-CompilationUnit reconcile(boolean createAST, 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
@@ -559,10 +513,8 @@
  * API is not supported, or if the working copy was already consistent.
  * </p>
  *
- * @param astLevel if positive, a compilation unit AST that should be created
- * and returned, and the value specifies the
- * {@linkplain AST#AST(int)
- * AST API level} for that AST; if zero, no AST is wanted
+ * @param astLevel either {@link #NO_AST} if no AST is wanted,
+ * or the {@linkplain AST#AST(int) AST API level} of the AST if one is wanted
  * @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 
diff --git a/model/org/eclipse/jdt/core/JavaCore.java b/model/org/eclipse/jdt/core/JavaCore.java
index 945fb99..b4b2def 100644
--- a/model/org/eclipse/jdt/core/JavaCore.java
+++ b/model/org/eclipse/jdt/core/JavaCore.java
@@ -67,6 +67,7 @@
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
 import org.eclipse.jdt.internal.core.*;
+import org.eclipse.jdt.internal.core.util.MementoTokenizer;
 import org.eclipse.jdt.internal.core.util.Util;
 
 /**
@@ -122,6 +123,11 @@
 	protected static final String ATT_HANDLE_ID =
 		"org.eclipse.jdt.internal.core.JavaModelManager.handleId" ; //$NON-NLS-1$
 
+	/**
+	 * Name of the User Library Container id.
+	 */
+	public static final String USER_LIBRARY_CONTAINER_ID= "org.eclipse.jdt.USER_LIBRARY"; //$NON-NLS-1$
+	
 	// *************** Possible IDs for configurable options. ********************
 
 	/**
@@ -987,21 +993,7 @@
 		if (handleIdentifier == null) {
 			return null;
 		}
-		String delimiters = new String(new char[] {
-			JavaElement.JEM_COUNT,
-			JavaElement.JEM_JAVAPROJECT,
-			JavaElement.JEM_PACKAGEFRAGMENTROOT,
-			JavaElement.JEM_PACKAGEFRAGMENT,
-			JavaElement.JEM_FIELD,
-			JavaElement.JEM_METHOD,
-			JavaElement.JEM_INITIALIZER,
-			JavaElement.JEM_COMPILATIONUNIT,
-			JavaElement.JEM_CLASSFILE,
-			JavaElement.JEM_TYPE,
-			JavaElement.JEM_PACKAGEDECLARATION,
-			JavaElement.JEM_IMPORTDECLARATION,
-			JavaElement.JEM_LOCALVARIABLE});
-		StringTokenizer memento = new StringTokenizer(handleIdentifier, delimiters, true);
+		MementoTokenizer memento = new MementoTokenizer(handleIdentifier);
 		JavaModel model = JavaModelManager.getJavaModelManager().getJavaModel();
 		return model.getHandleFromMemento(memento, owner);
 	}
@@ -2381,6 +2373,17 @@
 	}
 	
 	/**
+	 * Returns the names of all defined user libraries. The corresponding classpath container path
+	 * is the name appended to the USER_LIBRARY_CONTAINER_ID.  
+	 * @return Return an array containing the names of all known user defined.
+	 */
+	public static String[] getUserLibraryNames() {
+		return new String[0];
+	 	// TODO (frederic) to be finalized in coordination with jdt-ui
+		// return UserLibraryManager.getUserLibraryNames();
+	}
+
+	/**
 	 * Returns the working copies that have the given owner. 
 	 * Only compilation units in working copy mode are returned.
 	 * If the owner is <code>null</code>, primary working copies are returned.
@@ -3626,7 +3629,7 @@
 		// persist options
 		getPlugin().savePluginPreferences();
 	}
-	
+
 	/**
 	 * Shutdown the JavaCore plug-in.
 	 * <p>
diff --git a/model/org/eclipse/jdt/internal/core/BinaryMethod.java b/model/org/eclipse/jdt/internal/core/BinaryMethod.java
index 4c798f3..dbc446f 100644
--- a/model/org/eclipse/jdt/internal/core/BinaryMethod.java
+++ b/model/org/eclipse/jdt/internal/core/BinaryMethod.java
@@ -143,10 +143,11 @@
  */
 public String getHandleMemento() {
 	StringBuffer buff = new StringBuffer(((JavaElement) getParent()).getHandleMemento());
-	buff.append(getHandleMementoDelimiter());
-	buff.append(getElementName());
+	char delimiter = getHandleMementoDelimiter();
+	buff.append(delimiter);
+	escapeMementoName(buff, getElementName());
 	for (int i = 0; i < this.parameterTypes.length; i++) {
-		buff.append(getHandleMementoDelimiter());
+		buff.append(delimiter);
 		buff.append(this.parameterTypes[i]);
 	}
 	if (this.occurrenceCount > 1) {
diff --git a/model/org/eclipse/jdt/internal/core/BinaryType.java b/model/org/eclipse/jdt/internal/core/BinaryType.java
index 77365df..51e0c9b 100644
--- a/model/org/eclipse/jdt/internal/core/BinaryType.java
+++ b/model/org/eclipse/jdt/internal/core/BinaryType.java
@@ -13,7 +13,6 @@
 import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.StringTokenizer;
 
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.jdt.core.*;
@@ -23,6 +22,7 @@
 import org.eclipse.jdt.internal.compiler.env.IBinaryType;
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
 import org.eclipse.jdt.internal.core.hierarchy.TypeHierarchy;
+import org.eclipse.jdt.internal.core.util.MementoTokenizer;
 import org.eclipse.jdt.internal.core.util.Util;
 
 /**
@@ -267,7 +267,7 @@
 /*
  * @see JavaElement
  */
-public IJavaElement getHandleFromMemento(String token, StringTokenizer memento, WorkingCopyOwner workingCopyOwner) {
+public IJavaElement getHandleFromMemento(String token, MementoTokenizer memento, WorkingCopyOwner workingCopyOwner) {
 	switch (token.charAt(0)) {
 		case JEM_COUNT:
 			return getHandleUpdatingCountFromMemento(memento, workingCopyOwner);
diff --git a/model/org/eclipse/jdt/internal/core/BufferFactoryWrapper.java b/model/org/eclipse/jdt/internal/core/BufferFactoryWrapper.java
index a401191..44538e2 100644
--- a/model/org/eclipse/jdt/internal/core/BufferFactoryWrapper.java
+++ b/model/org/eclipse/jdt/internal/core/BufferFactoryWrapper.java
@@ -28,11 +28,7 @@
 	}
 	
 	public static WorkingCopyOwner create(org.eclipse.jdt.core.IBufferFactory factory) {
-		if (factory != null && factory == DefaultWorkingCopyOwner.PRIMARY.factory) {
-			return DefaultWorkingCopyOwner.PRIMARY;
-		} else {
-			return new BufferFactoryWrapper(factory);
-		}
+		return new BufferFactoryWrapper(factory);
 	}
 
 	/* (non-Javadoc)
diff --git a/model/org/eclipse/jdt/internal/core/ClassFile.java b/model/org/eclipse/jdt/internal/core/ClassFile.java
index 8d6ba89..c44f9ed 100644
--- a/model/org/eclipse/jdt/internal/core/ClassFile.java
+++ b/model/org/eclipse/jdt/internal/core/ClassFile.java
@@ -12,7 +12,6 @@
 
 import java.io.IOException;
 import java.util.Map;
-import java.util.StringTokenizer;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
@@ -46,6 +45,7 @@
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
 import org.eclipse.jdt.internal.compiler.env.IBinaryType;
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
+import org.eclipse.jdt.internal.core.util.MementoTokenizer;
 import org.eclipse.jdt.internal.core.util.Util;
 
 /**
@@ -308,7 +308,7 @@
 /*
  * @see JavaElement
  */
-public IJavaElement getHandleFromMemento(String token, StringTokenizer memento, WorkingCopyOwner owner) {
+public IJavaElement getHandleFromMemento(String token, MementoTokenizer memento, WorkingCopyOwner owner) {
 	switch (token.charAt(0)) {
 		case JEM_COUNT:
 			return getHandleUpdatingCountFromMemento(memento, owner);
diff --git a/model/org/eclipse/jdt/internal/core/ClassFileWorkingCopy.java b/model/org/eclipse/jdt/internal/core/ClassFileWorkingCopy.java
index f798a60..06b9b06 100644
--- a/model/org/eclipse/jdt/internal/core/ClassFileWorkingCopy.java
+++ b/model/org/eclipse/jdt/internal/core/ClassFileWorkingCopy.java
@@ -518,20 +518,6 @@
 	}
 
 	/**
-	 * @see ICompilationUnit#reconcile(boolean, boolean, WorkingCopyOwner, IProgressMonitor)
-	 * @since 3.0
-	 * @deprecated TODO (jeem) remove after the ICompilationUnit API method is removed
-	 */
-	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(int, boolean, WorkingCopyOwner, IProgressMonitor)
 	 * @since 3.0
 	 */
diff --git a/model/org/eclipse/jdt/internal/core/CompilationUnit.java b/model/org/eclipse/jdt/internal/core/CompilationUnit.java
index 9b5b473..76728e6 100644
--- a/model/org/eclipse/jdt/internal/core/CompilationUnit.java
+++ b/model/org/eclipse/jdt/internal/core/CompilationUnit.java
@@ -26,12 +26,12 @@
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
+import org.eclipse.jdt.internal.core.util.MementoTokenizer;
 import org.eclipse.jdt.internal.core.util.Util;
 
 /**
  * @see ICompilationUnit
  */
-
 public class CompilationUnit extends Openable implements ICompilationUnit, org.eclipse.jdt.internal.compiler.env.ICompilationUnit, SuffixConstants {
 	
 	public WorkingCopyOwner owner;
@@ -630,10 +630,11 @@
 public char[] getFileName(){
 	return getElementName().toCharArray();
 }
+
 /*
  * @see JavaElement
  */
-public IJavaElement getHandleFromMemento(String token, StringTokenizer memento, WorkingCopyOwner workingCopyOwner) {
+public IJavaElement getHandleFromMemento(String token, MementoTokenizer memento, WorkingCopyOwner workingCopyOwner) {
 	switch (token.charAt(0)) {
 		case JEM_COUNT:
 			return getHandleUpdatingCountFromMemento(memento, workingCopyOwner);
@@ -651,6 +652,7 @@
 	}
 	return null;
 }
+
 /**
  * @see JavaElement#getHandleMementoDelimiter()
  */
@@ -1056,28 +1058,14 @@
  * @deprecated
  */
 public IMarker[] reconcile() throws JavaModelException {
-	reconcile(0/*don't create AST*/, false/*don't force problem detection*/, null/*use primary owner*/, null/*no progress monitor*/);
+	reconcile(NO_AST, false/*don't force problem detection*/, null/*use primary owner*/, null/*no progress monitor*/);
 	return null;
 }
 /**
  * @see IWorkingCopy#reconcile(boolean, IProgressMonitor)
  */
 public void reconcile(boolean forceProblemDetection, IProgressMonitor monitor) throws JavaModelException {
-	reconcile(0/*don't create AST*/, forceProblemDetection, null/*use primary owner*/, monitor);
-}
-/**
- * @see ICompilationUnit#reconcile(boolean, boolean, WorkingCopyOwner, IProgressMonitor)
- * @since 3.0
- * @deprecated TODO (jeem) remove after the ICompilationUnit API method is removed
- */
-public org.eclipse.jdt.core.dom.CompilationUnit reconcile(
-	boolean createAST,
-	boolean forceProblemDetection,
-	WorkingCopyOwner workingCopyOwner,
-	IProgressMonitor monitor)
-	throws JavaModelException {
-
-	return reconcile(AST.LEVEL_2_0, forceProblemDetection, workingCopyOwner, monitor);
+	reconcile(NO_AST, forceProblemDetection, null/*use primary owner*/, monitor);
 }
 
 /**
diff --git a/model/org/eclipse/jdt/internal/core/DefaultWorkingCopyOwner.java b/model/org/eclipse/jdt/internal/core/DefaultWorkingCopyOwner.java
index 9e4c351..9897465 100644
--- a/model/org/eclipse/jdt/internal/core/DefaultWorkingCopyOwner.java
+++ b/model/org/eclipse/jdt/internal/core/DefaultWorkingCopyOwner.java
@@ -20,12 +20,6 @@
  */
 public class DefaultWorkingCopyOwner extends WorkingCopyOwner {
 	
-	/**
-	 * Note this field is temporary public so that JDT/UI can reach in and change the factory. It will disapear before 3.0.
-	 * @deprecated
-	 */
-	public org.eclipse.jdt.core.IBufferFactory factory; // TODO remove before 3.0
-	
 	public WorkingCopyOwner primaryBufferProvider;
 		
 	public static final DefaultWorkingCopyOwner PRIMARY =  new DefaultWorkingCopyOwner();
@@ -39,8 +33,7 @@
 	 */
 	public IBuffer createBuffer(ICompilationUnit workingCopy) {
 		if (this.primaryBufferProvider != null) return this.primaryBufferProvider.createBuffer(workingCopy);
-		if (this.factory == null) return super.createBuffer(workingCopy);
-		return this.factory.createBuffer(workingCopy);
+		return super.createBuffer(workingCopy);
 	}
 	public String toString() {
 		return "Primary owner"; //$NON-NLS-1$
diff --git a/model/org/eclipse/jdt/internal/core/ImportContainer.java b/model/org/eclipse/jdt/internal/core/ImportContainer.java
index e6cc381..4f3c774 100644
--- a/model/org/eclipse/jdt/internal/core/ImportContainer.java
+++ b/model/org/eclipse/jdt/internal/core/ImportContainer.java
@@ -10,8 +10,6 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
-import java.util.StringTokenizer;
-
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.IImportContainer;
 import org.eclipse.jdt.core.IImportDeclaration;
@@ -19,6 +17,7 @@
 import org.eclipse.jdt.core.ISourceRange;
 import org.eclipse.jdt.core.ISourceReference;
 import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.internal.core.util.MementoTokenizer;
 
 /**
  * @see IImportContainer
@@ -40,7 +39,7 @@
 /*
  * @see JavaElement
  */
-public IJavaElement getHandleFromMemento(String token, StringTokenizer memento, WorkingCopyOwner workingCopyOwner) {
+public IJavaElement getHandleFromMemento(String token, MementoTokenizer memento, WorkingCopyOwner workingCopyOwner) {
 	switch (token.charAt(0)) {
 		case JEM_COUNT:
 			return getHandleUpdatingCountFromMemento(memento, workingCopyOwner);
diff --git a/model/org/eclipse/jdt/internal/core/ImportDeclaration.java b/model/org/eclipse/jdt/internal/core/ImportDeclaration.java
index bdd6141..f3b53c6 100644
--- a/model/org/eclipse/jdt/internal/core/ImportDeclaration.java
+++ b/model/org/eclipse/jdt/internal/core/ImportDeclaration.java
@@ -59,7 +59,7 @@
  */
 public String getHandleMemento(){
 	StringBuffer buff= new StringBuffer(((JavaElement)getParent()).getHandleMemento());
-	buff.append(getElementName());
+	escapeMementoName(buff, getElementName());
 	if (this.occurrenceCount > 1) {
 		buff.append(JEM_COUNT);
 		buff.append(this.occurrenceCount);
diff --git a/model/org/eclipse/jdt/internal/core/JavaElement.java b/model/org/eclipse/jdt/internal/core/JavaElement.java
index 7909dc8..9525876 100644
--- a/model/org/eclipse/jdt/internal/core/JavaElement.java
+++ b/model/org/eclipse/jdt/internal/core/JavaElement.java
@@ -10,7 +10,6 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
-import java.util.*;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -21,6 +20,7 @@
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.jdom.IDOMCompilationUnit;
 import org.eclipse.jdt.core.jdom.IDOMNode;
+import org.eclipse.jdt.internal.core.util.MementoTokenizer;
 import org.eclipse.jdt.internal.core.util.Util;
 
 /**
@@ -30,8 +30,9 @@
  */
 public abstract class JavaElement extends PlatformObject implements IJavaElement {
 
+	public static final char JEM_ESCAPE = '\\';
 	public static final char JEM_JAVAPROJECT = '=';
-	public static final char JEM_PACKAGEFRAGMENTROOT = IPath.SEPARATOR;
+	public static final char JEM_PACKAGEFRAGMENTROOT = '/';
 	public static final char JEM_PACKAGEFRAGMENT = '<';
 	public static final char JEM_FIELD = '^';
 	public static final char JEM_METHOD = '~';
@@ -128,6 +129,29 @@
 	protected boolean equalsDOMNode(IDOMNode node) {
 		return false;
 	}
+	protected void escapeMementoName(StringBuffer buffer, String mementoName) {
+		for (int i = 0, length = mementoName.length(); i < length; i++) {
+			char character = mementoName.charAt(i);
+			switch (character) {
+				case JEM_ESCAPE:
+				case JEM_COUNT:
+				case JEM_JAVAPROJECT:
+				case JEM_PACKAGEFRAGMENTROOT:
+				case JEM_PACKAGEFRAGMENT:
+				case JEM_FIELD:
+				case JEM_METHOD:
+				case JEM_INITIALIZER:
+				case JEM_COMPILATIONUNIT:
+				case JEM_CLASSFILE:
+				case JEM_TYPE:
+				case JEM_PACKAGEDECLARATION:
+				case JEM_IMPORTDECLARATION:
+				case JEM_LOCALVARIABLE:
+					buffer.append(JEM_ESCAPE);
+			}
+			buffer.append(character);
+		}
+	}
 	/**
 	 * @see IJavaElement
 	 */
@@ -290,12 +314,12 @@
 	 * The given token is the current delimiter indicating the type of the next token(s).
 	 * The given working copy owner is used only for compilation unit handles.
 	 */
-	public abstract IJavaElement getHandleFromMemento(String token, StringTokenizer memento, WorkingCopyOwner owner);
+	public abstract IJavaElement getHandleFromMemento(String token, MementoTokenizer memento, WorkingCopyOwner owner);
 	/*
 	 * Creates a Java element handle from the given memento.
 	 * The given working copy owner is used only for compilation unit handles.
 	 */
-	public IJavaElement getHandleFromMemento(StringTokenizer memento, WorkingCopyOwner owner) {
+	public IJavaElement getHandleFromMemento(MementoTokenizer memento, WorkingCopyOwner owner) {
 		if (!memento.hasMoreTokens()) return this;
 		String token = memento.nextToken();
 		return getHandleFromMemento(token, memento, owner);
@@ -304,7 +328,7 @@
 	 * Update the occurence count of the receiver and creates a Java element handle from the given memento.
 	 * The given working copy owner is used only for compilation unit handles.
 	 */
-	public IJavaElement getHandleUpdatingCountFromMemento(StringTokenizer memento, WorkingCopyOwner owner) {
+	public IJavaElement getHandleUpdatingCountFromMemento(MementoTokenizer memento, WorkingCopyOwner owner) {
 		this.occurrenceCount = Integer.parseInt(memento.nextToken());
 		if (!memento.hasMoreTokens()) return this;
 		String token = memento.nextToken();
@@ -322,7 +346,7 @@
 	public String getHandleMemento(){
 		StringBuffer buff= new StringBuffer(((JavaElement)getParent()).getHandleMemento());
 		buff.append(getHandleMementoDelimiter());
-		buff.append(getElementName());
+		escapeMementoName(buff, getElementName());
 		if (this.occurrenceCount > 1) {
 			buff.append(JEM_COUNT);
 			buff.append(this.occurrenceCount);
diff --git a/model/org/eclipse/jdt/internal/core/JavaModel.java b/model/org/eclipse/jdt/internal/core/JavaModel.java
index f5a7e61..193a5b4 100644
--- a/model/org/eclipse/jdt/internal/core/JavaModel.java
+++ b/model/org/eclipse/jdt/internal/core/JavaModel.java
@@ -14,7 +14,6 @@
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.Map;
-import java.util.StringTokenizer;
 
 import org.eclipse.core.resources.IContainer;
 import org.eclipse.core.resources.IFile;
@@ -31,6 +30,7 @@
 import org.eclipse.jdt.core.IJavaModel;
 import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.internal.core.util.MementoTokenizer;
 import org.eclipse.jdt.internal.core.util.Util;
 
 /**
@@ -165,7 +165,7 @@
 /*
  * @see JavaElement
  */
-public IJavaElement getHandleFromMemento(String token, StringTokenizer memento, WorkingCopyOwner owner) {
+public IJavaElement getHandleFromMemento(String token, MementoTokenizer memento, WorkingCopyOwner owner) {
 	switch (token.charAt(0)) {
 		case JEM_COUNT:
 			return getHandleUpdatingCountFromMemento(memento, owner);
diff --git a/model/org/eclipse/jdt/internal/core/JavaProject.java b/model/org/eclipse/jdt/internal/core/JavaProject.java
index 763fc74..0891042 100644
--- a/model/org/eclipse/jdt/internal/core/JavaProject.java
+++ b/model/org/eclipse/jdt/internal/core/JavaProject.java
@@ -28,7 +28,6 @@
 import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.Map;
-import java.util.StringTokenizer;
 
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
@@ -72,6 +71,7 @@
 import org.eclipse.jdt.internal.compiler.util.ObjectVector;
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
 import org.eclipse.jdt.internal.core.eval.EvaluationContextWrapper;
+import org.eclipse.jdt.internal.core.util.MementoTokenizer;
 import org.eclipse.jdt.internal.core.util.Util;
 import org.eclipse.jdt.internal.eval.EvaluationContext;
 import org.w3c.dom.Element;
@@ -1322,7 +1322,7 @@
 	/*
 	 * @see JavaElement
 	 */
-	public IJavaElement getHandleFromMemento(String token, StringTokenizer memento, WorkingCopyOwner owner) {
+	public IJavaElement getHandleFromMemento(String token, MementoTokenizer memento, WorkingCopyOwner owner) {
 		switch (token.charAt(0)) {
 			case JEM_COUNT:
 				return getHandleUpdatingCountFromMemento(memento, owner);
diff --git a/model/org/eclipse/jdt/internal/core/LocalVariable.java b/model/org/eclipse/jdt/internal/core/LocalVariable.java
index 0b4e9c6..3d48d1f 100644
--- a/model/org/eclipse/jdt/internal/core/LocalVariable.java
+++ b/model/org/eclipse/jdt/internal/core/LocalVariable.java
@@ -11,7 +11,6 @@
 package org.eclipse.jdt.internal.core;
 
 import java.util.HashMap;
-import java.util.StringTokenizer;
 
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.IPath;
@@ -20,6 +19,7 @@
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.WorkingCopyOwner;
+import org.eclipse.jdt.internal.core.util.MementoTokenizer;
 import org.eclipse.jdt.internal.core.util.Util;
 
 
@@ -74,7 +74,7 @@
 		// a local variable has no info
 	}
 
-	public IJavaElement getHandleFromMemento(String token, StringTokenizer memento, WorkingCopyOwner owner) {
+	public IJavaElement getHandleFromMemento(String token, MementoTokenizer memento, WorkingCopyOwner owner) {
 		switch (token.charAt(0)) {
 			case JEM_COUNT:
 				return getHandleUpdatingCountFromMemento(memento, owner);
diff --git a/model/org/eclipse/jdt/internal/core/Member.java b/model/org/eclipse/jdt/internal/core/Member.java
index 85dbda5..332c7eb 100644
--- a/model/org/eclipse/jdt/internal/core/Member.java
+++ b/model/org/eclipse/jdt/internal/core/Member.java
@@ -11,7 +11,6 @@
 package org.eclipse.jdt.internal.core;
 
 import java.util.ArrayList;
-import java.util.StringTokenizer;
 
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.Flags;
@@ -26,6 +25,7 @@
 import org.eclipse.jdt.core.jdom.IDOMNode;
 import org.eclipse.jdt.internal.compiler.impl.Constant;
 import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
+import org.eclipse.jdt.internal.core.util.MementoTokenizer;
 
 /**
  * @see IMember
@@ -155,7 +155,7 @@
 /*
  * @see JavaElement
  */
-public IJavaElement getHandleFromMemento(String token, StringTokenizer memento, WorkingCopyOwner workingCopyOwner) {
+public IJavaElement getHandleFromMemento(String token, MementoTokenizer memento, WorkingCopyOwner workingCopyOwner) {
 	switch (token.charAt(0)) {
 		case JEM_COUNT:
 			return getHandleUpdatingCountFromMemento(memento, workingCopyOwner);
diff --git a/model/org/eclipse/jdt/internal/core/NameLookup.java b/model/org/eclipse/jdt/internal/core/NameLookup.java
index 1b88bba..4147acd 100644
--- a/model/org/eclipse/jdt/internal/core/NameLookup.java
+++ b/model/org/eclipse/jdt/internal/core/NameLookup.java
@@ -33,6 +33,7 @@
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.search.*;
 import org.eclipse.jdt.core.search.IJavaSearchConstants;
 import org.eclipse.jdt.core.search.ITypeNameRequestor;
 import org.eclipse.jdt.core.search.SearchEngine;
@@ -407,8 +408,8 @@
 				workspace,
 				pkg.getElementName().toCharArray(),
 				typeName.toCharArray(),
-				partialMatch ? IJavaSearchConstants.PREFIX_MATCH : IJavaSearchConstants.EXACT_MATCH,
-				partialMatch ? IJavaSearchConstants.CASE_INSENSITIVE : IJavaSearchConstants.CASE_SENSITIVE,
+				partialMatch ? SearchPattern.R_PREFIX_MATCH : SearchPattern.R_EXACT_MATCH,
+				!partialMatch, // case sensitive
 				IJavaSearchConstants.TYPE,
 				SearchEngine.createJavaSearchScope(new IJavaElement[] {pkg}, false),
 				nameRequestor,
diff --git a/model/org/eclipse/jdt/internal/core/PackageFragment.java b/model/org/eclipse/jdt/internal/core/PackageFragment.java
index 3b2e89f..b37fcda 100644
--- a/model/org/eclipse/jdt/internal/core/PackageFragment.java
+++ b/model/org/eclipse/jdt/internal/core/PackageFragment.java
@@ -13,7 +13,6 @@
 import java.util.*;
 import java.util.ArrayList;
 import java.util.Map;
-import java.util.StringTokenizer;
 
 import org.eclipse.core.resources.IContainer;
 import org.eclipse.core.resources.IFolder;
@@ -31,6 +30,7 @@
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.Signature;
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
+import org.eclipse.jdt.internal.core.util.MementoTokenizer;
 import org.eclipse.jdt.internal.core.util.Util;
 
 /**
@@ -243,7 +243,7 @@
 /*
  * @see JavaElement
  */
-public IJavaElement getHandleFromMemento(String token, StringTokenizer memento, WorkingCopyOwner owner) {
+public IJavaElement getHandleFromMemento(String token, MementoTokenizer memento, WorkingCopyOwner owner) {
 	switch (token.charAt(0)) {
 		case JEM_COUNT:
 			return getHandleUpdatingCountFromMemento(memento, owner);
diff --git a/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java b/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java
index fd1e5e0..56df0d7 100644
--- a/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java
+++ b/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java
@@ -10,7 +10,6 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
-import java.util.*;
 import java.util.ArrayList;
 import java.util.Enumeration;
 import java.util.Map;
@@ -25,6 +24,7 @@
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.core.util.MementoTokenizer;
 import org.eclipse.jdt.internal.core.util.Util;
 
 /**
@@ -481,7 +481,7 @@
 /*
  * @see JavaElement
  */
-public IJavaElement getHandleFromMemento(String token, StringTokenizer memento, WorkingCopyOwner owner) {
+public IJavaElement getHandleFromMemento(String token, MementoTokenizer memento, WorkingCopyOwner owner) {
 	switch (token.charAt(0)) {
 		case JEM_COUNT:
 			return getHandleUpdatingCountFromMemento(memento, owner);
@@ -528,7 +528,7 @@
 	}
 	StringBuffer buff= new StringBuffer(((JavaElement)getParent()).getHandleMemento());
 	buff.append(getHandleMementoDelimiter());
-	buff.append(path.toString()); 
+	escapeMementoName(buff, path.toString()); 
 	if (this.occurrenceCount > 1) {
 		buff.append(JEM_COUNT);
 		buff.append(this.occurrenceCount);
diff --git a/model/org/eclipse/jdt/internal/core/SearchableEnvironment.java b/model/org/eclipse/jdt/internal/core/SearchableEnvironment.java
index 9f3375b..6455af5 100644
--- a/model/org/eclipse/jdt/internal/core/SearchableEnvironment.java
+++ b/model/org/eclipse/jdt/internal/core/SearchableEnvironment.java
@@ -19,6 +19,7 @@
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.core.search.*;
 import org.eclipse.jdt.core.search.IJavaSearchConstants;
 import org.eclipse.jdt.core.search.IJavaSearchScope;
 import org.eclipse.jdt.core.search.ITypeNameRequestor;
@@ -252,8 +253,8 @@
 					this.project.getProject().getWorkspace(),
 					qualification,
 					simpleName,
-					PREFIX_MATCH,
-					CASE_INSENSITIVE,
+					SearchPattern.R_PREFIX_MATCH,
+					false, // not case sensitive
 					IJavaSearchConstants.TYPE,
 					this.searchScope,
 					nameRequestor,
diff --git a/model/org/eclipse/jdt/internal/core/SortElementBuilder.java b/model/org/eclipse/jdt/internal/core/SortElementBuilder.java
index 33d9157..c7fd1e8 100644
--- a/model/org/eclipse/jdt/internal/core/SortElementBuilder.java
+++ b/model/org/eclipse/jdt/internal/core/SortElementBuilder.java
@@ -932,7 +932,7 @@
 		this.comparator = comparator;
 		this.positionsToMap = positionsToMap;
 		this.scanner = new Scanner(false, false, false, ClassFileConstants.JDK1_3/*sourceLevel*/, null, null, true/*taskCaseSensitive*/);
-		this.ast = new AST();
+		this.ast = AST.newAST(AST.LEVEL_2_0);
 	}
 	
 	/*
diff --git a/model/org/eclipse/jdt/internal/core/SourceMethod.java b/model/org/eclipse/jdt/internal/core/SourceMethod.java
index 2aed5bd..046433a 100644
--- a/model/org/eclipse/jdt/internal/core/SourceMethod.java
+++ b/model/org/eclipse/jdt/internal/core/SourceMethod.java
@@ -91,10 +91,11 @@
  */
 public String getHandleMemento() {
 	StringBuffer buff = new StringBuffer(((JavaElement) getParent()).getHandleMemento());
-	buff.append(getHandleMementoDelimiter());
-	buff.append(getElementName());
+	char delimiter = getHandleMementoDelimiter();
+	buff.append(delimiter);
+	escapeMementoName(buff, getElementName());
 	for (int i = 0; i < fParameterTypes.length; i++) {
-		buff.append(getHandleMementoDelimiter());
+		buff.append(delimiter);
 		buff.append(fParameterTypes[i]);
 	}
 	if (this.occurrenceCount > 1) {
diff --git a/model/org/eclipse/jdt/internal/core/SourceRefElement.java b/model/org/eclipse/jdt/internal/core/SourceRefElement.java
index 98916f6..64e6a7b 100644
--- a/model/org/eclipse/jdt/internal/core/SourceRefElement.java
+++ b/model/org/eclipse/jdt/internal/core/SourceRefElement.java
@@ -11,7 +11,6 @@
 package org.eclipse.jdt.internal.core;
 
 import java.util.HashMap;
-import java.util.StringTokenizer;
 
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.IPath;
@@ -24,6 +23,7 @@
 import org.eclipse.jdt.core.ISourceRange;
 import org.eclipse.jdt.core.ISourceReference;
 import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.internal.core.util.MementoTokenizer;
 import org.eclipse.jdt.internal.core.util.Util;
 
 /**
@@ -102,7 +102,7 @@
 /*
  * @see JavaElement
  */
-public IJavaElement getHandleFromMemento(String token, StringTokenizer memento, WorkingCopyOwner workingCopyOwner) {
+public IJavaElement getHandleFromMemento(String token, MementoTokenizer memento, WorkingCopyOwner workingCopyOwner) {
 	switch (token.charAt(0)) {
 		case JEM_COUNT:
 			return getHandleUpdatingCountFromMemento(memento, workingCopyOwner);
diff --git a/model/org/eclipse/jdt/internal/core/SourceType.java b/model/org/eclipse/jdt/internal/core/SourceType.java
index cfde30f..584b205 100644
--- a/model/org/eclipse/jdt/internal/core/SourceType.java
+++ b/model/org/eclipse/jdt/internal/core/SourceType.java
@@ -12,7 +12,6 @@
 
 import java.io.InputStream;
 import java.util.ArrayList;
-import java.util.StringTokenizer;
 
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.jdt.core.*;
@@ -26,6 +25,7 @@
 import org.eclipse.jdt.internal.codeassist.SelectionEngine;
 import org.eclipse.jdt.internal.compiler.env.ISourceType;
 import org.eclipse.jdt.internal.core.hierarchy.TypeHierarchy;
+import org.eclipse.jdt.internal.core.util.MementoTokenizer;
 import org.eclipse.jdt.internal.core.util.Util;
 
 /**
@@ -206,7 +206,7 @@
 /*
  * @see JavaElement
  */
-public IJavaElement getHandleFromMemento(String token, StringTokenizer memento, WorkingCopyOwner workingCopyOwner) {
+public IJavaElement getHandleFromMemento(String token, MementoTokenizer memento, WorkingCopyOwner workingCopyOwner) {
 	switch (token.charAt(0)) {
 		case JEM_COUNT:
 			return getHandleUpdatingCountFromMemento(memento, workingCopyOwner);
diff --git a/model/org/eclipse/jdt/internal/core/UserLibrary.java b/model/org/eclipse/jdt/internal/core/UserLibrary.java
new file mode 100644
index 0000000..2a4b10f
--- /dev/null
+++ b/model/org/eclipse/jdt/internal/core/UserLibrary.java
@@ -0,0 +1,169 @@
+/*******************************************************************************
+ * 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;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.internal.core.util.Util;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ * Internal model element to represent a user library and code to serialize / deserialize.
+ */
+public class UserLibrary {
+
+	private static final String CURRENT_VERSION= "1"; //$NON-NLS-1$
+
+	private static final String TAG_VERSION= "version"; //$NON-NLS-1$
+	private static final String TAG_USERLIBRARY= "userlibrary"; //$NON-NLS-1$
+	private static final String TAG_SOURCEATTACHMENT= "sourceattachment"; //$NON-NLS-1$
+	private static final String TAG_SOURCEATTACHMENTROOT= "sourceattachmentroot"; //$NON-NLS-1$
+	private static final String TAG_PATH= "path"; //$NON-NLS-1$
+	private static final String TAG_ARCHIVE= "archive"; //$NON-NLS-1$
+	private static final String TAG_SYSTEMLIBRARY= "systemlibrary"; //$NON-NLS-1$
+	
+	private boolean isSystemLibrary;
+	private IClasspathEntry[] entries;
+
+	public UserLibrary(IClasspathEntry[] entries, boolean isSystemLibrary) {
+		Assert.isNotNull(entries);
+		this.entries= entries;
+		this.isSystemLibrary= isSystemLibrary;
+	}
+	
+	public IClasspathEntry[] getEntries() {
+		return this.entries;
+	}
+	
+	public boolean isSystemLibrary() {
+		return this.isSystemLibrary;
+	}
+	
+	/* (non-Javadoc)
+	 * @see java.lang.Object#equals(java.lang.Object)
+	 */
+	public boolean equals(Object obj) {
+		if (obj != null && obj.getClass() == getClass()) {
+			UserLibrary other= (UserLibrary) obj;
+			if (this.entries.length == other.entries.length && this.isSystemLibrary == other.isSystemLibrary) {
+				for (int i= 0; i < this.entries.length; i++) {
+					if (!this.entries[i].equals(other.entries[i])) {
+						return false;
+					}
+				}
+				return true;
+			}
+		}
+		return false;
+	}
+	
+	/* (non-Javadoc)
+	 * @see java.lang.Object#hashCode()
+	 */
+	public int hashCode() {
+		int hashCode= 0;
+		if (this.isSystemLibrary) {
+			hashCode++;
+		}
+		for (int i= 0; i < this.entries.length; i++) {
+			hashCode= hashCode * 17 + this.entries.hashCode();
+		}
+		return hashCode;
+	}
+	
+	/* package */  String serialize() throws IOException {
+		ByteArrayOutputStream s = new ByteArrayOutputStream();
+		OutputStreamWriter writer = new OutputStreamWriter(s, "UTF8"); //$NON-NLS-1$
+		XMLWriter xmlWriter = new XMLWriter(writer);
+		
+		HashMap library = new HashMap();
+		library.put(TAG_VERSION, String.valueOf(CURRENT_VERSION));
+		library.put(TAG_SYSTEMLIBRARY, String.valueOf(this.isSystemLibrary));
+		xmlWriter.printTag(TAG_USERLIBRARY, library, true, true, false);
+		
+		for (int i = 0; i < this.entries.length; ++i) {
+			IClasspathEntry curr= this.entries[i];
+			
+			HashMap archive = new HashMap();
+			archive.put(TAG_PATH, curr.getPath().toString());
+			IPath sourceAttach= curr.getSourceAttachmentPath();
+			if (sourceAttach != null)
+				archive.put(TAG_SOURCEATTACHMENT, sourceAttach);
+			IPath sourceAttachRoot= curr.getSourceAttachmentRootPath();
+			if (sourceAttachRoot != null)
+				archive.put(TAG_SOURCEATTACHMENTROOT, sourceAttachRoot);				
+			xmlWriter.printTag(TAG_ARCHIVE, archive, true, true, true);
+		}	
+		xmlWriter.endTag(TAG_USERLIBRARY, true);
+		writer.flush();
+		writer.close();
+		return s.toString("UTF8");//$NON-NLS-1$
+	}
+	
+	/* package */ static UserLibrary createFromString(Reader reader) throws IOException {
+		Element cpElement;
+		try {
+			DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+			cpElement = parser.parse(new InputSource(reader)).getDocumentElement();
+		} catch (SAXException e) {
+			throw new IOException(Util.bind("file.badFormat")); //$NON-NLS-1$
+		} catch (ParserConfigurationException e) {
+			throw new IOException(Util.bind("file.badFormat")); //$NON-NLS-1$
+		} finally {
+			reader.close();
+		}
+		
+		if (!cpElement.getNodeName().equalsIgnoreCase(TAG_USERLIBRARY)) { //$NON-NLS-1$
+			throw new IOException(Util.bind("file.badFormat")); //$NON-NLS-1$
+		}
+		// String version= cpElement.getAttribute(TAG_VERSION);
+		// in case we update the format: add code to read older versions
+		
+		boolean isSystem= Boolean.valueOf(cpElement.getAttribute(TAG_SYSTEMLIBRARY)).booleanValue();
+		
+		NodeList list= cpElement.getChildNodes();
+		int length = list.getLength();
+		
+		ArrayList res= new ArrayList(length);
+		for (int i = 0; i < length; ++i) {
+			Node node = list.item(i);
+			
+			if (node.getNodeType() == Node.ELEMENT_NODE) {
+				Element element= (Element) node;
+				if (element.getNodeName().equals(TAG_ARCHIVE)) {
+					String path = element.getAttribute(TAG_PATH);
+					IPath sourceAttach= element.hasAttribute(TAG_SOURCEATTACHMENT) ? new Path(element.getAttribute(TAG_SOURCEATTACHMENT)) : null;
+					IPath sourceAttachRoot= element.hasAttribute(TAG_SOURCEATTACHMENTROOT) ? new Path(element.getAttribute(TAG_SOURCEATTACHMENTROOT)) : null;
+					res.add(JavaCore.newLibraryEntry(new Path(path), sourceAttach, sourceAttachRoot));
+				}
+			}
+		}
+		
+		IClasspathEntry[] entries= (IClasspathEntry[]) res.toArray(new IClasspathEntry[res.size()]);
+		
+		return new UserLibrary(entries, isSystem);
+	}
+}
diff --git a/model/org/eclipse/jdt/internal/core/UserLibraryClasspathContainer.java b/model/org/eclipse/jdt/internal/core/UserLibraryClasspathContainer.java
new file mode 100644
index 0000000..338f095
--- /dev/null
+++ b/model/org/eclipse/jdt/internal/core/UserLibraryClasspathContainer.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * 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;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jdt.core.IClasspathContainer;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.JavaCore;
+
+/**
+ *
+ */
+public class UserLibraryClasspathContainer implements IClasspathContainer {
+	
+	private String name;
+	
+	public UserLibraryClasspathContainer(String libName) {
+		this.name= libName;
+	}
+	
+	/* (non-Javadoc)
+	 * @see org.eclipse.jdt.core.IClasspathContainer#getClasspathEntries()
+	 */
+	public IClasspathEntry[] getClasspathEntries() {
+		IClasspathContainer library= UserLibraryManager.getUserLibrary(this.name);
+		if (library != null) {
+			return library.getClasspathEntries();
+		}
+		return new IClasspathEntry[0];
+		
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.jdt.core.IClasspathContainer#getDescription()
+	 */
+	public String getDescription() {
+		return this.name;
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.jdt.core.IClasspathContainer#getKind()
+	 */
+	public int getKind() {
+		IClasspathContainer library= UserLibraryManager.getUserLibrary(this.name);
+		if (library != null) {
+			return library.getKind();
+		}
+		return K_APPLICATION;
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.jdt.core.IClasspathContainer#getPath()
+	 */
+	public IPath getPath() {
+		return new Path(JavaCore.USER_LIBRARY_CONTAINER_ID).append(this.name);
+	}
+}
diff --git a/model/org/eclipse/jdt/internal/core/UserLibraryClasspathContainerInitializer.java b/model/org/eclipse/jdt/internal/core/UserLibraryClasspathContainerInitializer.java
new file mode 100644
index 0000000..f4f7daa
--- /dev/null
+++ b/model/org/eclipse/jdt/internal/core/UserLibraryClasspathContainerInitializer.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * 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;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.jdt.core.ClasspathContainerInitializer;
+import org.eclipse.jdt.core.IClasspathContainer;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.JavaCore;
+
+/**
+ *
+ */
+public class UserLibraryClasspathContainerInitializer extends ClasspathContainerInitializer {
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.jdt.core.ClasspathContainerInitializer#initialize(org.eclipse.core.runtime.IPath, org.eclipse.jdt.core.IJavaProject)
+	 */
+	public void initialize(IPath containerPath, IJavaProject project) throws CoreException {
+		if (isUserLibraryContainer(containerPath)) {
+			String userLibName= containerPath.segment(1);
+						
+			IClasspathContainer library = UserLibraryManager.getUserLibrary(userLibName);
+			if (library != null) {
+				JavaCore.setClasspathContainer(containerPath, new IJavaProject[] { project }, 	new IClasspathContainer[] { library }, null);
+			}
+		}
+	}
+	
+	private boolean isUserLibraryContainer(IPath path) {
+		return path != null && path.segmentCount() == 2 && JavaCore.USER_LIBRARY_CONTAINER_ID.equals(path.segment(0));
+	}
+	
+	/* (non-Javadoc)
+	 * @see org.eclipse.jdt.core.ClasspathContainerInitializer#canUpdateClasspathContainer(org.eclipse.core.runtime.IPath, org.eclipse.jdt.core.IJavaProject)
+	 */
+	public boolean canUpdateClasspathContainer(IPath containerPath, IJavaProject project) {
+		return isUserLibraryContainer(containerPath);
+	}
+
+	/**
+	 * @see org.eclipse.jdt.core.ClasspathContainerInitializer#requestClasspathContainerUpdate(org.eclipse.core.runtime.IPath, org.eclipse.jdt.core.IJavaProject, org.eclipse.jdt.core.IClasspathContainer)
+	 */
+	public void requestClasspathContainerUpdate(IPath containerPath, IJavaProject project, IClasspathContainer containerSuggestion) throws CoreException {
+		if (isUserLibraryContainer(containerPath)) {
+			String name= containerPath.segment(1);
+			if (containerSuggestion != null) {
+				UserLibrary library= new UserLibrary(containerSuggestion.getClasspathEntries(), containerSuggestion.getKind() == IClasspathContainer.K_SYSTEM);
+				UserLibraryManager.setUserLibrary(name, library, null); // should use a real progress monitor
+			} else {
+				UserLibraryManager.setUserLibrary(name, null, null); // should use a real progress monitor
+			}
+		}
+	}
+
+	/**
+	 * @see org.eclipse.jdt.core.ClasspathContainerInitializer#getDescription(org.eclipse.core.runtime.IPath, org.eclipse.jdt.core.IJavaProject)
+	 */
+	public String getDescription(IPath containerPath, IJavaProject project) {
+		if (isUserLibraryContainer(containerPath)) {
+			return containerPath.segment(1);
+		}
+		return super.getDescription(containerPath, project);
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.jdt.core.ClasspathContainerInitializer#getComparisonID(org.eclipse.core.runtime.IPath, org.eclipse.jdt.core.IJavaProject)
+	 */
+	public Object getComparisonID(IPath containerPath, IJavaProject project) {
+		return containerPath;
+	}
+}
diff --git a/model/org/eclipse/jdt/internal/core/UserLibraryManager.java b/model/org/eclipse/jdt/internal/core/UserLibraryManager.java
new file mode 100644
index 0000000..31f9b97
--- /dev/null
+++ b/model/org/eclipse/jdt/internal/core/UserLibraryManager.java
@@ -0,0 +1,241 @@
+/*******************************************************************************
+ * 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;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Preferences;
+import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.core.runtime.Preferences.IPropertyChangeListener;
+import org.eclipse.core.runtime.Preferences.PropertyChangeEvent;
+import org.eclipse.jdt.core.IClasspathContainer;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.internal.core.util.Util;
+
+/**
+ *
+ */
+public class UserLibraryManager {
+	
+	public final static String CP_USERLIBRARY_PREFERENCES_PREFIX = JavaCore.PLUGIN_ID+".userLibrary."; //$NON-NLS-1$
+	public final static String CP_ENTRY_IGNORE = "##<cp entry ignore>##"; //$NON-NLS-1$
+
+	private static Map userLibraries;
+	private static final boolean logProblems= false;
+	private static IPropertyChangeListener listener= new IPropertyChangeListener() {
+
+		public void propertyChange(PropertyChangeEvent event) {
+			String key= event.getProperty();
+			if (key.startsWith(CP_USERLIBRARY_PREFERENCES_PREFIX)) {
+				try {
+					recreatePersistedUserLibraryEntry(key, (String) event.getNewValue(), false, true);
+				} catch (JavaModelException e) {
+					if (logProblems) {
+						Util.log(e, "Exception while rebinding user library '"+ key.substring(CP_USERLIBRARY_PREFERENCES_PREFIX.length()) +"'."); //$NON-NLS-1$ //$NON-NLS-2$
+					}
+					
+				}
+			}
+		}
+		
+	};
+	
+	private UserLibraryManager() {
+		// do not instantiate
+	}
+		
+	/**
+	 * Returns the names of all defined user libraries. The corresponding classpath container path
+	 * is the name appended to the CONTAINER_ID.  
+	 * @return Return an array containing the names of all known user defined.
+	 */
+	public static String[] getUserLibraryNames() {
+		Set set= getLibraryMap().keySet();
+		return (String[]) set.toArray(new String[set.size()]);
+	}
+	
+	/**
+	 * Gets the library for a given name or <code>null</code> if no such library exists.
+	 * @param name The name of the library
+	 * @return The library registered for the given name or <code>null</code>.
+	 */
+	public static IClasspathContainer getUserLibrary(String name) {
+		return (IClasspathContainer) getLibraryMap().get(name);
+	}
+
+	/**
+	 * Registers user libraries for given names. If a library for the given name already exists, its value will be updated.
+	 * This call will also rebind all related classpath container. 
+	 * @param newNames The names to register the libraries for
+	 * @param newLibs The libraries to register
+	 * @param monitor A progress monitor used when rebinding the classpath containers
+	 * @throws JavaModelException
+	 */
+	public static void setUserLibraries(String[] newNames, UserLibrary[] newLibs, IProgressMonitor monitor) throws JavaModelException {
+		Assert.isTrue(newNames.length == newLibs.length, "names and libraries should have the same length"); //$NON-NLS-1$
+		
+		if (monitor == null) {
+			monitor= new NullProgressMonitor();
+		}
+		
+		monitor.beginTask("Configure user libraries...", newNames.length);	//$NON-NLS-1$
+		try {
+			int last= newNames.length - 1;
+			for (int i= 0; i < newLibs.length; i++) {
+				internalSetUserLibrary(newNames[i], newLibs[i], i == last, true, new SubProgressMonitor(monitor, 1));
+			}
+		} finally {
+			monitor.done();
+		}
+	}
+	
+	/**
+	 * Registers a user library for a given name. If a library for the given name already exists, its value will be updated.
+	 * This call will also rebind all related classpath container. 
+	 * @param name The name to register the library for
+	 * @param library The library to register
+	 * @param monitor A progress monitor used when rebinding the classpath containers
+	 * @throws JavaModelException
+	 */
+	public static void setUserLibrary(String name, UserLibrary library, IProgressMonitor monitor) throws JavaModelException {
+		internalSetUserLibrary(name, library, true, true, monitor);
+	}
+	
+	static Map getLibraryMap() {
+		if (userLibraries == null) {
+			userLibraries= new HashMap();
+			// load variables and containers from preferences into cache
+			Preferences preferences = JavaCore.getPlugin().getPluginPreferences();
+			preferences.addPropertyChangeListener(listener);
+
+			// only get variable from preferences not set to their default
+			String[] propertyNames = preferences.propertyNames();
+			for (int i = 0; i < propertyNames.length; i++) {
+				String propertyName = propertyNames[i];
+				if (propertyName.startsWith(CP_USERLIBRARY_PREFERENCES_PREFIX)) {
+					try {
+						recreatePersistedUserLibraryEntry(propertyName, preferences.getString(propertyName), false, false);
+					} catch (JavaModelException e) {
+						// won't happen: no rebinding
+					}
+				}
+			}
+		}
+		return userLibraries;
+	}
+	
+	static void recreatePersistedUserLibraryEntry(String propertyName, String savedString, boolean save, boolean rebind) throws JavaModelException {
+		String libName= propertyName.substring(CP_USERLIBRARY_PREFERENCES_PREFIX.length());
+		if (savedString == null || savedString.equals(CP_ENTRY_IGNORE)) {
+			internalSetUserLibrary(libName, null, save, rebind, null);
+		} else {
+			try {
+				StringReader reader = new StringReader(savedString);
+				UserLibrary library= UserLibrary.createFromString(reader);
+				internalSetUserLibrary(libName, library, save, rebind, null);
+			} catch (IOException e) {
+				if (logProblems) {
+					Util.log(e, "Exception while retrieving user library '"+ propertyName +"', library will be removed."); //$NON-NLS-1$ //$NON-NLS-2$
+				}
+				internalSetUserLibrary(libName, null, save, rebind, null);
+			}
+		}
+	}
+
+
+
+	static void internalSetUserLibrary(String name, UserLibrary library, boolean save, boolean rebind, IProgressMonitor monitor) throws JavaModelException {
+		if (library == null) {
+			Object previous= getLibraryMap().remove(name);
+			if (previous == null) {
+				return; // no change
+			}
+		} else {
+			Object previous= getLibraryMap().put(name, library);
+			if (library.equals(previous)) {
+				return; // no change
+			}
+		}
+		
+		Preferences preferences = JavaCore.getPlugin().getPluginPreferences();
+		String containerKey = CP_USERLIBRARY_PREFERENCES_PREFIX+name;
+		String containerString = CP_ENTRY_IGNORE;
+		if (library != null) {
+			try {
+				containerString= library.serialize();
+			} catch (IOException e) {
+				// could not encode entry: leave it as CP_ENTRY_IGNORE
+			}
+		}
+		preferences.removePropertyChangeListener(listener);
+		try {
+			preferences.setDefault(containerKey, CP_ENTRY_IGNORE); // use this default to get rid of removed ones
+			preferences.setValue(containerKey, containerString);
+			if (save) {
+				JavaCore.getPlugin().savePluginPreferences();
+			}
+			if (rebind) {
+				rebindClasspathEntries(name, monitor);
+			}
+			
+		} finally {
+			preferences.addPropertyChangeListener(listener);
+		}
+	}
+
+	private static void rebindClasspathEntries(String name, IProgressMonitor monitor) throws JavaModelException {
+		IWorkspaceRoot root= ResourcesPlugin.getWorkspace().getRoot();
+		IJavaProject[] projects= JavaCore.create(root).getJavaProjects();
+		IPath containerPath= new Path(JavaCore.USER_LIBRARY_CONTAINER_ID).append(name);
+		
+		ArrayList affectedProjects= new ArrayList();
+		
+		for (int i= 0; i < projects.length; i++) {
+			IJavaProject project= projects[i];
+			IClasspathEntry[] entries= project.getRawClasspath();
+			for (int k= 0; k < entries.length; k++) {
+				IClasspathEntry curr= entries[k];
+				if (curr.getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
+					if (containerPath.equals(curr.getPath())) {
+						affectedProjects.add(project);
+						break;
+					}				
+				}
+			}
+		}
+		if (!affectedProjects.isEmpty()) {
+			IJavaProject[] affected= (IJavaProject[]) affectedProjects.toArray(new IJavaProject[affectedProjects.size()]);
+			IClasspathContainer[] containers= new IClasspathContainer[affected.length];
+			
+			JavaCore.setClasspathContainer(containerPath, affected, containers, monitor);
+		} else {
+			if (monitor != null) {
+				monitor.done();
+			}
+		}
+	}
+
+
+	
+}
diff --git a/model/org/eclipse/jdt/internal/core/hierarchy/IndexBasedHierarchyBuilder.java b/model/org/eclipse/jdt/internal/core/hierarchy/IndexBasedHierarchyBuilder.java
index fc7a790..69a85a0 100644
--- a/model/org/eclipse/jdt/internal/core/hierarchy/IndexBasedHierarchyBuilder.java
+++ b/model/org/eclipse/jdt/internal/core/hierarchy/IndexBasedHierarchyBuilder.java
@@ -31,6 +31,7 @@
 import org.eclipse.jdt.internal.core.search.SubTypeSearchJob;
 import org.eclipse.jdt.internal.core.search.indexing.IIndexConstants;
 import org.eclipse.jdt.internal.core.search.indexing.IndexManager;
+import org.eclipse.jdt.internal.core.search.matching.MatchLocator;
 import org.eclipse.jdt.internal.core.search.matching.SuperTypeReferencePattern;
 import org.eclipse.jdt.internal.core.util.HandleFactory;
 
@@ -463,7 +464,7 @@
 
 	SuperTypeReferencePattern pattern =
 		new SuperTypeReferencePattern(null, null, false, SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE);
-	pattern.focus = type;
+	MatchLocator.setFocus(pattern, type);
 	SubTypeSearchJob job = new SubTypeSearchJob(
 		pattern, 
 		new JavaSearchParticipant(), // java search only
diff --git a/model/org/eclipse/jdt/internal/core/util/MementoTokenizer.java b/model/org/eclipse/jdt/internal/core/util/MementoTokenizer.java
new file mode 100644
index 0000000..d053a83
--- /dev/null
+++ b/model/org/eclipse/jdt/internal/core/util/MementoTokenizer.java
@@ -0,0 +1,112 @@
+/*******************************************************************************
+ * Copyright (c) 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.util;
+
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.core.JavaElement;
+
+public class MementoTokenizer {
+	private static final String COUNT = Character.toString(JavaElement.JEM_COUNT);
+	private static final String JAVAPROJECT = Character.toString(JavaElement.JEM_JAVAPROJECT);
+	private static final String PACKAGEFRAGMENTROOT = Character.toString(JavaElement.JEM_PACKAGEFRAGMENTROOT);
+	private static final String PACKAGEFRAGMENT = Character.toString(JavaElement.JEM_PACKAGEFRAGMENT);
+	private static final String FIELD = Character.toString(JavaElement.JEM_FIELD);
+	private static final String METHOD = Character.toString(JavaElement.JEM_METHOD);
+	private static final String INITIALIZER = Character.toString(JavaElement.JEM_INITIALIZER);
+	private static final String COMPILATIONUNIT = Character.toString(JavaElement.JEM_COMPILATIONUNIT);
+	private static final String CLASSFILE = Character.toString(JavaElement.JEM_CLASSFILE);
+	private static final String TYPE = Character.toString(JavaElement.JEM_TYPE);
+	private static final String PACKAGEDECLARATION = Character.toString(JavaElement.JEM_PACKAGEDECLARATION);
+	private static final String IMPORTDECLARATION = Character.toString(JavaElement.JEM_IMPORTDECLARATION);
+	private static final String LOCALVARIABLE = Character.toString(JavaElement.JEM_LOCALVARIABLE);
+
+	private final char[] memento;
+	private final int length;
+	private int index = 0;
+	
+	public MementoTokenizer(String memento) {
+		this.memento = memento.toCharArray();
+		this.length = this.memento.length;
+	}
+	
+	public boolean hasMoreTokens() {
+		return this.index < this.length;
+	}
+	
+	public String nextToken() {
+		int start = this.index;
+		StringBuffer buffer = null;
+		switch (this.memento[this.index++]) {
+			case JavaElement.JEM_ESCAPE:
+				buffer = new StringBuffer();
+				buffer.append(this.memento[this.index]);
+				start = ++this.index;
+				break;
+			case JavaElement.JEM_COUNT:
+				return COUNT;
+			case JavaElement.JEM_JAVAPROJECT:
+				return JAVAPROJECT;
+			case JavaElement.JEM_PACKAGEFRAGMENTROOT:
+				return PACKAGEFRAGMENTROOT;
+			case JavaElement.JEM_PACKAGEFRAGMENT:
+				return PACKAGEFRAGMENT;
+			case JavaElement.JEM_FIELD:
+				return FIELD;
+			case JavaElement.JEM_METHOD:
+				return METHOD;
+			case JavaElement.JEM_INITIALIZER:
+				return INITIALIZER;
+			case JavaElement.JEM_COMPILATIONUNIT:
+				return COMPILATIONUNIT;
+			case JavaElement.JEM_CLASSFILE:
+				return CLASSFILE;
+			case JavaElement.JEM_TYPE:
+				return TYPE;
+			case JavaElement.JEM_PACKAGEDECLARATION:
+				return PACKAGEDECLARATION;
+			case JavaElement.JEM_IMPORTDECLARATION:
+				return IMPORTDECLARATION;
+			case JavaElement.JEM_LOCALVARIABLE:
+				return LOCALVARIABLE;
+		}
+		loop: while (this.index < this.length) {
+			switch (this.memento[this.index]) {
+				case JavaElement.JEM_ESCAPE:
+					if (buffer == null) buffer = new StringBuffer();
+					buffer.append(CharOperation.subarray(this.memento, start, this.index));
+					start = ++this.index;
+					break;
+				case JavaElement.JEM_COUNT:
+				case JavaElement.JEM_JAVAPROJECT:
+				case JavaElement.JEM_PACKAGEFRAGMENTROOT:
+				case JavaElement.JEM_PACKAGEFRAGMENT:
+				case JavaElement.JEM_FIELD:
+				case JavaElement.JEM_METHOD:
+				case JavaElement.JEM_INITIALIZER:
+				case JavaElement.JEM_COMPILATIONUNIT:
+				case JavaElement.JEM_CLASSFILE:
+				case JavaElement.JEM_TYPE:
+				case JavaElement.JEM_PACKAGEDECLARATION:
+				case JavaElement.JEM_IMPORTDECLARATION:
+				case JavaElement.JEM_LOCALVARIABLE:
+					break loop;
+			}
+			this.index++;
+		}
+		if (buffer != null) {
+			buffer.append(CharOperation.subarray(this.memento, start, this.index));
+			return buffer.toString();
+		} else {
+			return new String(CharOperation.subarray(this.memento, start, this.index));
+		}
+	}
+	
+}
diff --git a/search/org/eclipse/jdt/core/search/FieldDeclarationMatch.java b/search/org/eclipse/jdt/core/search/FieldDeclarationMatch.java
index da4b78a..d20c332 100644
--- a/search/org/eclipse/jdt/core/search/FieldDeclarationMatch.java
+++ b/search/org/eclipse/jdt/core/search/FieldDeclarationMatch.java
@@ -26,14 +26,12 @@
 	 * 
 	 * @param element the field declaration
 	 * @param accuracy one of A_ACCURATE or A_INACCURATE
-	 * @param sourceStart the start position of the match, -1 if it is unknown
-	 * @param sourceEnd the end position of the match, -1 if it is unknown;
-	 * 	the ending offset is exclusive, meaning that the actual range of characters 
-	 * 	covered is <code>[start, end]</code>
+	 * @param offset the offset the match starts at, or -1 if unknown
+	 * @param length the length of the match, or -1 if unknown
 	 * @param participant the search participant that created the match
 	 * @param resource the resource of the element
 	 */
-	public FieldDeclarationMatch(IJavaElement element, int accuracy, int sourceStart, int sourceEnd, SearchParticipant participant, IResource resource) {
-		super(element, accuracy, sourceStart, sourceEnd, participant, resource);
+	public FieldDeclarationMatch(IJavaElement element, int accuracy, int offset, int length, SearchParticipant participant, IResource resource) {
+		super(element, accuracy, offset, length, participant, resource);
 	}
 }
diff --git a/search/org/eclipse/jdt/core/search/FieldReferenceMatch.java b/search/org/eclipse/jdt/core/search/FieldReferenceMatch.java
index b46a829..0a1b98a 100644
--- a/search/org/eclipse/jdt/core/search/FieldReferenceMatch.java
+++ b/search/org/eclipse/jdt/core/search/FieldReferenceMatch.java
@@ -30,27 +30,25 @@
 	 * 
 	 * @param enclosingElement the inner-most enclosing member that references this field
 	 * @param accuracy one of A_ACCURATE or A_INACCURATE
-	 * @param sourceStart the start position of the match, -1 if it is unknown
-	 * @param sourceEnd the end position of the match, -1 if it is unknown;
-	 * 	the ending offset is exclusive, meaning that the actual range of characters 
-	 * 	covered is <code>[start, end]</code>
+	 * @param offset the offset the match starts at, or -1 if unknown
+	 * @param length the length of the match, or -1 if unknown
 	 * @param isReadAccess whether the match represents a read access
 	 * @param isWriteAccess whethre the match represents a write access
 	 * @param insideDocComment whether the match is inside a doc comment
 	 * @param participant the search participant that created the match
 	 * @param resource the resource of the element
 	 */
-	public FieldReferenceMatch(IJavaElement enclosingElement, int accuracy, int sourceStart, int sourceEnd, boolean isReadAccess, boolean isWriteAccess, boolean insideDocComment, SearchParticipant participant, IResource resource) {
-		super(enclosingElement, accuracy, sourceStart, sourceEnd, participant, resource);
+	public FieldReferenceMatch(IJavaElement enclosingElement, int accuracy, int offset, int length, boolean isReadAccess, boolean isWriteAccess, boolean insideDocComment, SearchParticipant participant, IResource resource) {
+		super(enclosingElement, accuracy, offset, length, participant, resource);
 		this.isReadAccess = isReadAccess;
 		this.isWriteAccess = isWriteAccess;
 		this.insideDocComment = insideDocComment;
 	}
 	
 	/**
-	 * @see org.eclipse.jdt.core.search.SearchMatch#insideDocComment()
+	 * @see org.eclipse.jdt.core.search.SearchMatch#isInsideDocComment()
 	 */
-	public boolean insideDocComment() {
+	public boolean isInsideDocComment() {
 		return this.insideDocComment;
 	}
 
diff --git a/search/org/eclipse/jdt/core/search/IJavaSearchConstants.java b/search/org/eclipse/jdt/core/search/IJavaSearchConstants.java
index eb7794e..8793220 100644
--- a/search/org/eclipse/jdt/core/search/IJavaSearchConstants.java
+++ b/search/org/eclipse/jdt/core/search/IJavaSearchConstants.java
@@ -126,15 +126,18 @@
 	/**
 	 * The search pattern matches exactly the search result,
 	 * that is, the source of the search result equals the search pattern.
+	 * @deprecated Use {@link SearchPattern#R_EXACT_MATCH} instead.
 	 */
 	int EXACT_MATCH = 0;
 	/**
 	 * The search pattern is a prefix of the search result.
+	 * @deprecated Use {@link SearchPattern#R_PREFIX_MATCH} instead.
 	 */
 	int PREFIX_MATCH = 1;
 	/**
 	 * The search pattern contains one or more wild cards ('*') where a 
 	 * wild-card can replace 0 or more characters in the search result.
+	 * @deprecated Use {@link SearchPattern#R_PATTERN_MATCH} instead.
 	 */
 	int PATTERN_MATCH = 2;
 
@@ -144,10 +147,12 @@
 	/**
 	 * The search pattern matches the search result only
 	 * if cases are the same.
+	 * @deprecated Use {@link SearchPattern#R_CASE_SENSITIVE} instead.
 	 */
 	boolean CASE_SENSITIVE = true;
 	/**
 	 * The search pattern ignores cases in the search result.
+	 * @deprecated Use {@link SearchPattern#R_CASE_SENSITIVE} instead.
 	 */
 	boolean CASE_INSENSITIVE = false;
 	
diff --git a/search/org/eclipse/jdt/core/search/IJavaSearchResultCollector.java b/search/org/eclipse/jdt/core/search/IJavaSearchResultCollector.java
index 24b38fe..8035883 100644
--- a/search/org/eclipse/jdt/core/search/IJavaSearchResultCollector.java
+++ b/search/org/eclipse/jdt/core/search/IJavaSearchResultCollector.java
@@ -39,11 +39,14 @@
  * </p>
  *
  * @see SearchEngine
- * @deprecated use SearchRequestor instead
+ * @deprecated Since 3.0, the class
+ * {@link org.eclipse.jdt.core.search.SearchRequestor} replaces this interface.
  */
 public interface IJavaSearchResultCollector {
 	/**
 	 * The search result corresponds exactly to the search pattern.
+	 * 
+     * @deprecated Use {@link SearchMatch#A_ACCURATE} instead.
 	 */
 	int EXACT_MATCH = 0;
 
@@ -51,11 +54,15 @@
 	 * The search result is potentially a match for the search pattern,
 	 * but a problem prevented the search engine from being more accurate
 	 * (typically because of the classpath was not correctly set).
+	 * 
+     * @deprecated Use {@link SearchMatch#A_INACCURATE} instead.
 	 */
 	 int POTENTIAL_MATCH = 1;
 
 /**
  * Called before the actual search starts.
+ * 
+ * @deprecated Replaced by {@link SearchRequestor#beginReporting()}.
  */
 public void aboutToStart();
 /**
@@ -72,6 +79,7 @@
  * @param accuracy the level of accuracy the search result has; either
  *  <code>EXACT_MATCH</code> or <code>POTENTIAL_MATCH</code>
  * @exception CoreException if this collector had a problem accepting the search result
+ * @deprecated Replaced by {@link SearchRequestor#acceptSearchMatch(SearchMatch)}.
  */
 public void accept(
 	IResource resource,
@@ -82,6 +90,8 @@
 	throws CoreException;
 /**
  * Called when the search has ended.
+ * 
+ * @deprecated Replaced by {@link SearchRequestor#endReporting()}.
  */
 public void done();
 /**
diff --git a/search/org/eclipse/jdt/core/search/IJavaSearchScope.java b/search/org/eclipse/jdt/core/search/IJavaSearchScope.java
index 37b3774..49eb03e 100644
--- a/search/org/eclipse/jdt/core/search/IJavaSearchScope.java
+++ b/search/org/eclipse/jdt/core/search/IJavaSearchScope.java
@@ -92,8 +92,9 @@
  * in folders or within JARs).
  * 
  * @return whether this scope contains any <code>.class</code> files
- * @deprecated Use SearchEngine.createJavaSearchScope(IJavaElement[]) with the package fragment
- * 				roots that correspond to the binaries instead
+ * @deprecated Use
+ * {@link org.eclipse.jdt.core.search.SearchEngine#createJavaSearchScope(IJavaElement[]))
+ * with the package fragment roots that correspond to the binaries instead.
  */
 boolean includesBinaries();
 /**
@@ -101,8 +102,9 @@
  * the projects of the resources of this search scope.
  * 
  * @return whether this scope includes classpaths
- * @deprecated Use SearchEngine.createJavaSearchScope(IJavaElement[]) 
- * 				with a Java project instead
+ * @deprecated Use
+ * {@link org.eclipse.jdt.core.search.SearchEngine#createJavaSearchScope(IJavaElement[]))
+ * with a Java project instead.
  */
 boolean includesClasspaths();
 /**
@@ -110,8 +112,9 @@
  * in folders or within JARs).
  * 
  * @param includesBinaries whether this scope contains any <code>.class</code> files
- * @deprecated Use SearchEngine.createJavaSearchScope(IJavaElement[]) with the package fragment
- * 				roots that correspond to the binaries instead
+ * @deprecated Use
+ * {@link org.eclipse.jdt.core.search.SearchEngine#createJavaSearchScope(IJavaElement[]))
+ * with the package fragment roots that correspond to the binaries instead.
  */
 public void setIncludesBinaries(boolean includesBinaries);
 /**
@@ -119,8 +122,9 @@
  * the projects of the resources of this search scope.
  * 
  * @param includesClasspaths whether this scope includes classpaths
- * @deprecated Use SearchEngine.createJavaSearchScope(IJavaElement[]) 
- * 				with a Java project instead
+ * @deprecated Use
+ * {@link org.eclipse.jdt.core.search.SearchEngine#createJavaSearchScope(IJavaElement[]))
+ * with a Java project instead.
  */
 public void setIncludesClasspaths(boolean includesClasspaths);
 }
diff --git a/search/org/eclipse/jdt/core/search/ISearchPattern.java b/search/org/eclipse/jdt/core/search/ISearchPattern.java
index ba19c5a..a893aa6 100644
--- a/search/org/eclipse/jdt/core/search/ISearchPattern.java
+++ b/search/org/eclipse/jdt/core/search/ISearchPattern.java
@@ -16,7 +16,8 @@
  *
  * @see SearchEngine#createSearchPattern(org.eclipse.jdt.core.IJavaElement, int)
  * @see SearchEngine#createSearchPattern(String, int, int, boolean)
- * @deprecated use SearchPattern instead
+ * @deprecated Since 3.0, the class
+ * {@link org.eclipse.jdt.core.search.SearchPattern} replaces this interface.
  */
 public interface ISearchPattern {
 	// used as a marker interface: contains no methods
diff --git a/search/org/eclipse/jdt/core/search/LocalVariableDeclarationMatch.java b/search/org/eclipse/jdt/core/search/LocalVariableDeclarationMatch.java
index fa84b28..dfe410c 100644
--- a/search/org/eclipse/jdt/core/search/LocalVariableDeclarationMatch.java
+++ b/search/org/eclipse/jdt/core/search/LocalVariableDeclarationMatch.java
@@ -26,15 +26,13 @@
 	 * 
 	 * @param element the local variable declaration
 	 * @param accuracy one of A_ACCURATE or A_INACCURATE
-	 * @param sourceStart the start position of the match, -1 if it is unknown
-	 * @param sourceEnd the end position of the match, -1 if it is unknown;
-	 * 	the ending offset is exclusive, meaning that the actual range of characters 
-	 * 	covered is <code>[start, end]</code>
+	 * @param offset the offset the match starts at, or -1 if unknown
+	 * @param length the length of the match, or -1 if unknown
 	 * @param participant the search participant that created the match
 	 * @param resource the resource of the element
 	 */
-	public LocalVariableDeclarationMatch(IJavaElement element, int accuracy, int sourceStart, int sourceEnd, SearchParticipant participant, IResource resource) {
-		super(element, accuracy, sourceStart, sourceEnd, participant, resource);
+	public LocalVariableDeclarationMatch(IJavaElement element, int accuracy, int offset, int length, SearchParticipant participant, IResource resource) {
+		super(element, accuracy, offset, length, participant, resource);
 	}
 
 }
diff --git a/search/org/eclipse/jdt/core/search/LocalVariableReferenceMatch.java b/search/org/eclipse/jdt/core/search/LocalVariableReferenceMatch.java
index fe5bbef..f925431 100644
--- a/search/org/eclipse/jdt/core/search/LocalVariableReferenceMatch.java
+++ b/search/org/eclipse/jdt/core/search/LocalVariableReferenceMatch.java
@@ -26,15 +26,13 @@
 	 * 
 	 * @param enclosingElement the inner-most enclosing member that references this local variable
 	 * @param accuracy one of A_ACCURATE or A_INACCURATE
-	 * @param sourceStart the start position of the match, -1 if it is unknown
-	 * @param sourceEnd the end position of the match, -1 if it is unknown;
-	 * 	the ending offset is exclusive, meaning that the actual range of characters 
-	 * 	covered is <code>[start, end]</code>
+	 * @param offset the offset the match starts at, or -1 if unknown
+	 * @param length the length of the match, or -1 if unknown
 	 * @param participant the search participant that created the match
 	 * @param resource the resource of the element
 	 */
-	public LocalVariableReferenceMatch(IJavaElement enclosingElement, int accuracy, int sourceStart, int sourceEnd, SearchParticipant participant, IResource resource) {
-		super(enclosingElement, accuracy, sourceStart, sourceEnd, participant, resource);
+	public LocalVariableReferenceMatch(IJavaElement enclosingElement, int accuracy, int offset, int length, SearchParticipant participant, IResource resource) {
+		super(enclosingElement, accuracy, offset, length, participant, resource);
 	}
 
 }
diff --git a/search/org/eclipse/jdt/core/search/MethodDeclarationMatch.java b/search/org/eclipse/jdt/core/search/MethodDeclarationMatch.java
index 57c173c..1c08aa0 100644
--- a/search/org/eclipse/jdt/core/search/MethodDeclarationMatch.java
+++ b/search/org/eclipse/jdt/core/search/MethodDeclarationMatch.java
@@ -26,15 +26,13 @@
 	 * 
 	 * @param element the method declaration
 	 * @param accuracy one of A_ACCURATE or A_INACCURATE
-	 * @param sourceStart the start position of the match, -1 if it is unknown
-	 * @param sourceEnd the end position of the match, -1 if it is unknown;
-	 * 	the ending offset is exclusive, meaning that the actual range of characters 
-	 * 	covered is <code>[start, end]</code>
+	 * @param offset the offset the match starts at, or -1 if unknown
+	 * @param length the length of the match, or -1 if unknown
 	 * @param participant the search participant that created the match
 	 * @param resource the resource of the element
 	 */
-	public MethodDeclarationMatch(IJavaElement element, int accuracy, int sourceStart, int sourceEnd, SearchParticipant participant, IResource resource) {
-		super(element, accuracy, sourceStart, sourceEnd, participant, resource);
+	public MethodDeclarationMatch(IJavaElement element, int accuracy, int offset, int length, SearchParticipant participant, IResource resource) {
+		super(element, accuracy, offset, length, participant, resource);
 	}
 
 }
diff --git a/search/org/eclipse/jdt/core/search/MethodReferenceMatch.java b/search/org/eclipse/jdt/core/search/MethodReferenceMatch.java
index 0600d23..b1eb613 100644
--- a/search/org/eclipse/jdt/core/search/MethodReferenceMatch.java
+++ b/search/org/eclipse/jdt/core/search/MethodReferenceMatch.java
@@ -28,23 +28,21 @@
 	 * 
 	 * @param enclosingElement the inner-most enclosing member that references this method
 	 * @param accuracy one of A_ACCURATE or A_INACCURATE
-	 * @param sourceStart the start position of the match, -1 if it is unknown
-	 * @param sourceEnd the end position of the match, -1 if it is unknown;
-	 * 	the ending offset is exclusive, meaning that the actual range of characters 
-	 * 	covered is <code>[start, end]</code>
+	 * @param offset the offset the match starts at, or -1 if unknown
+	 * @param length the length of the match, or -1 if unknown
 	 * @param insideDocComment whether the match is inside a doc comment
 	 * @param participant the search participant that created the match
 	 * @param resource the resource of the element
 	 */
-	public MethodReferenceMatch(IJavaElement enclosingElement, int accuracy, int sourceStart, int sourceEnd, boolean insideDocComment, SearchParticipant participant, IResource resource) {
-		super(enclosingElement, accuracy, sourceStart, sourceEnd, participant, resource);
+	public MethodReferenceMatch(IJavaElement enclosingElement, int accuracy, int offset, int length, boolean insideDocComment, SearchParticipant participant, IResource resource) {
+		super(enclosingElement, accuracy, offset, length, participant, resource);
 		this.insideDocComment = insideDocComment;
 	}
 
 	/**
-	 * @see org.eclipse.jdt.core.search.SearchMatch#insideDocComment()
+	 * @see org.eclipse.jdt.core.search.SearchMatch#isInsideDocComment()
 	 */
-	public boolean insideDocComment() {
+	public boolean isInsideDocComment() {
 		return this.insideDocComment;
 	}
 	
diff --git a/search/org/eclipse/jdt/core/search/PackageDeclarationMatch.java b/search/org/eclipse/jdt/core/search/PackageDeclarationMatch.java
index 1cf0703..967a445 100644
--- a/search/org/eclipse/jdt/core/search/PackageDeclarationMatch.java
+++ b/search/org/eclipse/jdt/core/search/PackageDeclarationMatch.java
@@ -26,15 +26,13 @@
 	 * 
 	 * @param element the package declaration
 	 * @param accuracy one of A_ACCURATE or A_INACCURATE
-	 * @param sourceStart the start position of the match, -1 if it is unknown
-	 * @param sourceEnd the end position of the match, -1 if it is unknown;
-	 * 	the ending offset is exclusive, meaning that the actual range of characters 
-	 * 	covered is <code>[start, end]</code>
+	 * @param offset the offset the match starts at, or -1 if unknown
+	 * @param length the length of the match, or -1 if unknown
 	 * @param participant the search participant that created the match
 	 * @param resource the resource of the element
 	 */
-	public PackageDeclarationMatch(IJavaElement element, int accuracy, int sourceStart, int sourceEnd, SearchParticipant participant, IResource resource) {
-		super(element, accuracy, sourceStart, sourceEnd, participant, resource);
+	public PackageDeclarationMatch(IJavaElement element, int accuracy, int offset, int length, SearchParticipant participant, IResource resource) {
+		super(element, accuracy, offset, length, participant, resource);
 	}
 
 }
diff --git a/search/org/eclipse/jdt/core/search/PackageReferenceMatch.java b/search/org/eclipse/jdt/core/search/PackageReferenceMatch.java
index e928fbb..43da758 100644
--- a/search/org/eclipse/jdt/core/search/PackageReferenceMatch.java
+++ b/search/org/eclipse/jdt/core/search/PackageReferenceMatch.java
@@ -26,15 +26,13 @@
 	 * 
 	 * @param enclosingElement the inner-most enclosing member that references this package
 	 * @param accuracy one of A_ACCURATE or A_INACCURATE
-	 * @param sourceStart the start position of the match, -1 if it is unknown
-	 * @param sourceEnd the end position of the match, -1 if it is unknown;
-	 * 	the ending offset is exclusive, meaning that the actual range of characters 
-	 * 	covered is <code>[start, end]</code>
+	 * @param offset the offset the match starts at, or -1 if unknown
+	 * @param length the length of the match, or -1 if unknown
 	 * @param participant the search participant that created the match
 	 * @param resource the resource of the element
 	 */
-	public PackageReferenceMatch(IJavaElement enclosingElement, int accuracy, int sourceStart, int sourceEnd, SearchParticipant participant, IResource resource) {
-		super(enclosingElement, accuracy, sourceStart, sourceEnd, participant, resource);
+	public PackageReferenceMatch(IJavaElement enclosingElement, int accuracy, int offset, int length, SearchParticipant participant, IResource resource) {
+		super(enclosingElement, accuracy, offset, length, participant, resource);
 	}
 
 }
diff --git a/search/org/eclipse/jdt/core/search/SearchEngine.java b/search/org/eclipse/jdt/core/search/SearchEngine.java
index dd32a5c..6ac779c 100644
--- a/search/org/eclipse/jdt/core/search/SearchEngine.java
+++ b/search/org/eclipse/jdt/core/search/SearchEngine.java
@@ -44,11 +44,11 @@
  * <p>
  * This class may be instantiated; it is not intended to be subclassed.
  * </p>
- * TODO remove IWorkspace argument on the search methods before 3.0
  */
 public class SearchEngine {
 
 	/**
+	 * Internal adapter class.
 	 * @deprecated marking deprecated as it uses deprecated ISearchPattern
 	 */
 	static class SearchPatternAdapter implements ISearchPattern {
@@ -58,6 +58,7 @@
 		}
 	}
 	/**
+	 * Internal adapter class.
 	 * @deprecated marking deprecated as it uses deprecated IJavaSearchResultCollector
 	 */
 	class ResultCollectorAdapter extends SearchRequestor {
@@ -89,18 +90,6 @@
 		public void endReporting() {
 			this.resultCollector.done();
 		}
-		/**
-		 * @see org.eclipse.jdt.core.search.SearchRequestor#enterParticipant(org.eclipse.jdt.core.search.SearchParticipant)
-		 */
-		public void enterParticipant(SearchParticipant participant) {
-			// Nothing to do since only one Java search participant
-		}
-		/**
-		 * @see org.eclipse.jdt.core.search.SearchRequestor#exitParticipant(org.eclipse.jdt.core.search.SearchParticipant)
-		 */
-		public void exitParticipant(SearchParticipant participant) {
-			// Nothing to do since only one Java search participant
-		}
 	}
 		
 	/*
@@ -159,7 +148,7 @@
 	 * 
 	 * @param workingCopies the working copies that take precedence over their original compilation units
 	 * @since 2.0
-	 * @deprecated use #SearchEngine(ICompilationUnit[]) instead
+	 * @deprecated Use {@link #SearchEngine(ICompilationUnit[])} instead.
 	 */
 	public SearchEngine(IWorkingCopy[] workingCopies) {
 		int length = workingCopies.length;
@@ -219,7 +208,7 @@
 	 *
 	 * @param resources the resources the scope is limited to
 	 * @return a new Java search scope
-	 * @deprecated Use createJavaSearchScope(IJavaElement[]) instead
+	 * @deprecated Use {@link #createJavaSearchScope(IJavaElement[])} instead.
 	 */
 	public static IJavaSearchScope createJavaSearchScope(IResource[] resources) {
 		int length = resources.length;
@@ -307,11 +296,11 @@
 	 * @param elements the Java elements the scope is limited to
 	 * @param includeMask the bit-wise OR of all include types of interest
 	 * @return a new Java search scope
-	 * @since 3.0
 	 * @see IJavaSearchScope#SOURCES
 	 * @see IJavaSearchScope#APPLICATION_LIBRARIES
 	 * @see IJavaSearchScope#SYSTEM_LIBRARIES
 	 * @see IJavaSearchScope#REFERENCED_PROJECTS
+	 * @since 3.0
 	 */
 	public static IJavaSearchScope createJavaSearchScope(IJavaElement[] elements, int includeMask) {
 		JavaSearchScope scope = new JavaSearchScope();
@@ -340,7 +329,7 @@
 	 * @param leftPattern the left pattern
 	 * @param rightPattern the right pattern
 	 * @return a "or" pattern
-	 * @deprecated use SearchPattern.createOrPattern(SearchPattern, SearchPattern) instead
+	 * @deprecated Use {@link SearchPattern#createOrPattern(SearchPattern, SearchPattern)} instead.
 	 */
 	public static ISearchPattern createOrSearchPattern(ISearchPattern leftPattern, ISearchPattern rightPattern) {
 		SearchPattern left = ((SearchPatternAdapter) leftPattern).pattern;
@@ -390,7 +379,7 @@
 	 *
 	 * @param isCaseSensitive indicates whether the search is case sensitive or not.
 	 * @return a search pattern on the given string pattern, or <code>null</code> if the string pattern is ill-formed.
-	 * @deprecated use SearchPattern.createPattern(String, int, int, int, boolean) instead
+	 * @deprecated Use {@link SearchPattern#createPattern(String, int, int, int, boolean)} instead.
 	 */
 	public static ISearchPattern createSearchPattern(String stringPattern, int searchFor, int limitTo, boolean isCaseSensitive) {
 		int matchMode = stringPattern.indexOf('*') != -1 || stringPattern.indexOf('?') != -1
@@ -419,6 +408,7 @@
 	 *	</ul>
 	 * @return a search pattern for a Java element or <code>null</code> if the given element is ill-formed
 	 * @deprecated use SearchPattern.createPattern(IJavaElement, int) instead
+	 * @deprecated Use {@link SearchPattern#createPattern(IJavaElement, int)} instead.
 	 */
 	public static ISearchPattern createSearchPattern(IJavaElement element, int limitTo) {
 		return new SearchPatternAdapter(SearchPattern.createPattern(element, limitTo));
@@ -434,7 +424,61 @@
 	}
 	
 	/**
-	 * Returns a new default Java search participant
+	 * 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
+	 */
+	private void findMatches(SearchPattern pattern, 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$
+		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 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(pattern, 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 j = 0; j < indexMatchLength; j++)
+						indexMatches[j] = participant.getDocument(indexMatchPaths[j]);
+					SearchDocument[] matches = MatchLocator.addWorkingCopies(pattern, indexMatches, getWorkingCopies(), participant);
+					participant.locateMatches(matches, pattern, scope, requestor, monitor);
+				} finally {		
+					requestor.exitParticipant(participant);
+					participant.doneSearching();
+				}
+			}
+		} finally {
+			requestor.endReporting();
+			if (monitor != null)
+				monitor.done();
+		}
+	}
+	/**
+	 * Returns a new default Java search participant.
 	 * 
 	 * @return a new default Java search participant
 	 * @since 3.0
@@ -612,7 +656,7 @@
 	 *	<ul>
 	 *		<li>the classpath is incorrectly set</li>
 	 *	</ul>
-	 * @deprecated use search(SearchPattern, SearchParticipant[], IJavaSearchScope, SearchRequestor, IProgressMonitor) instead
+	 * @deprecated Use {@link  #search(SearchPattern, SearchParticipant[], IJavaSearchScope, SearchRequestor, IProgressMonitor)} instead.
 	 */
 	public void search(IWorkspace workspace, String patternString, int searchFor, int limitTo, IJavaSearchScope scope, IJavaSearchResultCollector resultCollector) throws JavaModelException {
 		try {
@@ -658,7 +702,7 @@
 	 *		<li>the element doesn't exist</li>
 	 *		<li>the classpath is incorrectly set</li>
 	 *	</ul>
-	 * @deprecated use search(SearchPattern, SearchParticipant[], IJavaSearchScope, SearchRequestor, IProgressMonitor) instead
+	 * @deprecated Use {@link #search(SearchPattern, SearchParticipant[], IJavaSearchScope, SearchRequestor, IProgressMonitor)} instead.
 	 */
 	public void search(IWorkspace workspace, IJavaElement element, int limitTo, IJavaSearchScope scope, IJavaSearchResultCollector resultCollector) throws JavaModelException {
 		search(workspace, createSearchPattern(element, limitTo), scope, resultCollector);
@@ -677,7 +721,7 @@
 	 *	<ul>
 	 *		<li>the classpath is incorrectly set</li>
 	 *	</ul>
-	 * @deprecated use search(SearchPattern, SearchParticipant[], IJavaSearchScope, SearchRequestor, IProgressMonitor) instead
+	 * @deprecated Use {@link  #search(SearchPattern, SearchParticipant[], IJavaSearchScope, SearchRequestor, IProgressMonitor)} instead.
 	 */
 	public void search(IWorkspace workspace, ISearchPattern searchPattern, IJavaSearchScope scope, IJavaSearchResultCollector resultCollector) throws JavaModelException {
 		try {
@@ -713,7 +757,7 @@
 	 *@since 3.0
 	 */
 	public void search(SearchPattern pattern, SearchParticipant[] participants, IJavaSearchScope scope, SearchRequestor requestor, IProgressMonitor monitor) throws CoreException {
-		pattern.findMatches(participants, getWorkingCopies(), scope, requestor, monitor);
+		findMatches(pattern, participants, scope, requestor, monitor);
 	}
 
 	/**
@@ -945,7 +989,8 @@
 					System.out.println("Searching for " + pattern + " in " + resource.getFullPath()); //$NON-NLS-1$//$NON-NLS-2$
 				}
 				SearchParticipant participant = getDefaultSearchParticipant();
-				SearchDocument[] documents = pattern.addWorkingCopies(
+				SearchDocument[] documents = MatchLocator.addWorkingCopies(
+					pattern,
 					new SearchDocument[] {new JavaSearchDocument(enclosingElement.getPath().toString(), participant)},
 					getWorkingCopies(enclosingElement),
 					participant);
@@ -1049,7 +1094,7 @@
 	 *		<li>the element doesn't exist</li>
 	 *		<li>the classpath is incorrectly set</li>
 	 *	</ul>
-	 * @deprecated use searchDeclarationsOfAccessedFields(IJavaElement, SearchRequestor, IProgressMonitor) instead
+	 * @deprecated Use {@link  #searchDeclarationsOfAccessedFields(IJavaElement, SearchRequestor, IProgressMonitor)} instead.
 	 */	
 	public void searchDeclarationsOfAccessedFields(IWorkspace workspace, IJavaElement enclosingElement, IJavaSearchResultCollector resultCollector) throws JavaModelException {
 		SearchPattern pattern = new DeclarationOfAccessedFieldsPattern(enclosingElement);
@@ -1133,7 +1178,7 @@
 	 *		<li>the element doesn't exist</li>
 	 *		<li>the classpath is incorrectly set</li>
 	 *	</ul>
-	 * @deprecated use searchDeclarationsOfReferencedTypes(IJavaElement, SearchRequestor, IProgressMonitor) instead
+	 * @deprecated Use {@link #searchDeclarationsOfReferencedTypes(IJavaElement, SearchRequestor, IProgressMonitor)} instead.
 	 */	
 	public void searchDeclarationsOfReferencedTypes(IWorkspace workspace, IJavaElement enclosingElement, IJavaSearchResultCollector resultCollector) throws JavaModelException {
 		SearchPattern pattern = new DeclarationOfReferencedTypesPattern(enclosingElement);
@@ -1223,7 +1268,7 @@
 	 *		<li>the element doesn't exist</li>
 	 *		<li>the classpath is incorrectly set</li>
 	 *	</ul>
-	 * @deprecated use searchDeclarationsOfSentMessages(IJavaElement, SearchRequestor, IProgressMonitor) instead
+	 * @deprecated Use {@link #searchDeclarationsOfSentMessages(IJavaElement, SearchRequestor, IProgressMonitor)} instead.
 	 */	
 	public void searchDeclarationsOfSentMessages(IWorkspace workspace, IJavaElement enclosingElement, IJavaSearchResultCollector resultCollector) throws JavaModelException {
 		SearchPattern pattern = new DeclarationOfReferencedMethodsPattern(enclosingElement);
diff --git a/search/org/eclipse/jdt/core/search/SearchMatch.java b/search/org/eclipse/jdt/core/search/SearchMatch.java
index 0f28333..605582a 100644
--- a/search/org/eclipse/jdt/core/search/SearchMatch.java
+++ b/search/org/eclipse/jdt/core/search/SearchMatch.java
@@ -16,20 +16,26 @@
 /**
  * A search match represents the result of a search query.
  * 
+ * Search matches may be accurate (<code>A_ACCURATE</code>) or they might be
+ * merely potential matches (<code>A_INACCURATE</code>). The latter occurs when
+ * a compile-time problem prevents the search engine from completely resolving
+ * the match.
+ * </p>
+ * 
  * @see SearchEngine#search(SearchPattern, SearchParticipant[], IJavaSearchScope, SearchRequestor, org.eclipse.core.runtime.IProgressMonitor)
  * @since 3.0
  */
 public class SearchMatch {
 	
 	/**
-	 * The search result corresponds exactly to the search pattern.
+	 * The search result corresponds an exact match of the search pattern.
 	 */
 	public static final int A_ACCURATE = 0;
 
 	/**
 	 * The search result is potentially a match for the search pattern,
-	 * but a problem prevented the search engine from being more accurate
-	 * (typically because of the classpath was not correctly set).
+	 * but the search engine is unable to fully check it (for example, because
+	 * there are errors in the code or the classpath are not correctly set).
 	 */
 	public static final int A_INACCURATE = 1;
 	
@@ -45,35 +51,22 @@
 	 * Creates a new search match.
 	 * 
 	 * @param element the element that encloses or corresponds to the match
-	 * @param offset the offset the match starts at
-	 * @param length the length of the match
-	 */
-	public SearchMatch(Object element, int offset, 	int length) {
-		this.element = element;
-		this.offset = offset;
-		this.length = length;
-	}
-	
-	/**
-	 * Creates a new search match.
-	 * 
-	 * @param element the element that encloses or corresponds to the match
 	 * @param accuracy one of A_ACCURATE or A_INACCURATE
-	 * @param sourceStart the start position of the match, -1 if it is unknown
-	 * @param sourceEnd the end position of the match, -1 if it is unknown;
-	 * 	the ending offset is exclusive, meaning that the actual range of characters 
-	 * 	covered is <code>[start, end]</code>
+	 * @param offset the offset the match starts at, or -1 if unknown
+	 * @param length the length of the match, or -1 if unknown
 	 * @param participant the search participant that created the match
-	 * @param resource the resource of the element
+	 * @param resource the resource of the element, or <code>null</code> if none
 	 */
 	public SearchMatch(
 			IJavaElement element,
 			int accuracy,
-			int sourceStart,  
-			int sourceEnd,
+			int offset,  
+			int length,
 			SearchParticipant participant, 
 			IResource resource) {
-		this(element, sourceStart, sourceEnd-sourceStart);
+		this.element = element;
+		this.offset = offset;
+		this.length = length;
 		this.accuracy = accuracy;
 		this.participant = participant;
 		this.resource = resource;
@@ -82,80 +75,94 @@
 	/**
 	 * Returns the accuracy of this search match.
 	 * 
-	 * @return one of A_ACCURATE or A_INACCURATE
+	 * @return one of {@link #A_ACCURATE} or {@link #A_INACCURATE}
 	 */
 	public int getAccuracy() {
 		return this.accuracy;
 	}
 
 	/**
-	 * Returns the element of this match.
+	 * Returns the element of this search match.
 	 * 
-	 * @return the element of the match
+	 * @return the element of the search match
 	 */
 	public Object getElement() {
 		return this.element;
 	}
 
 	/**
-	 * Returns the length of this match.
+	 * Returns the length of this search match.
 	 * 
-	 * @return the length of this match.
+	 * @return the length of this search match, or -1 if unknown
 	 */
 	public int getLength() {
 		return this.length;
 	}
 	
 	/**
-	 * Returns the offset of this match.
+	 * Returns the offset of this search match.
 	 * 
-	 * @return the offset of this match.
+	 * @return the offset of this search match, or -1 if unknown
 	 */
 	public int getOffset() {
 		return this.offset;
 	}
 	
 	/**
-	 * Returns the participant which issued this match
+	 * Returns the search participant which issued this search match.
 	 * 
-	 * @return the participant which issued this match
+	 * @return the participant which issued this search match
 	 */
 	public SearchParticipant getParticipant() {
 		return this.participant;
 	}
 	
 	/**
-	 * Returns the resource containing the match or <code>null</code> if it has no resource.
+	 * Returns the resource containing this search match.
 	 * 
-	 * @return the resource of the match or <code>null</code> if it has no resource
+	 * @return the resource of the match, or <code>null</code> if none
 	 */
 	public IResource getResource() {
 		return this.resource;
 	}
 	
 	/**
-	 * Returns whether this Java search match is inside a doc comment.
+	 * Returns whether this search match is inside a doc comment of a Java
+	 * source file.
 	 * 
-	 * @return whether this Java search match is inside a doc comment
+	 * @return <code>true</code> if this search match is inside a Java doc
+	 * comment, and <code>false</code> otherwise
+	 * @deprecated Use {@link #isInsideDocComment()} instead.
 	 */
 	public boolean insideDocComment() {
+		return isInsideDocComment();
+	}
+
+	/**
+	 * Returns whether this search match is inside a doc comment of a Java
+	 * source file.
+	 * 
+	 * @return <code>true</code> if this search match is inside a Java doc
+	 * comment, and <code>false</code> otherwise
+	 */
+	public boolean isInsideDocComment() {
 		// default is outside a doc comment
 		return false;
 	}
 
 	/**
-	 * Sets the length of this match.
+	 * Sets the length of this search match.
 	 * 
-	 * @param length the new length of this match
+	 * @param length the length of this match, or -1 if unknown
 	 */
 	public void setLength(int length) {
 		this.length = length;
 	}
 	
 	/**
-	 * Sets the offset of this match
+	 * Sets the offset of this search match.
 	 * 
-	 * @param offset the new offset of this match
+	 * @param offset the offset of this match, or -1 if unknown
 	 */
 	public void setOffset(int offset) {
 		this.offset = offset;
diff --git a/search/org/eclipse/jdt/core/search/SearchPattern.java b/search/org/eclipse/jdt/core/search/SearchPattern.java
index 27cb2d5..1c4fd24 100644
--- a/search/org/eclipse/jdt/core/search/SearchPattern.java
+++ b/search/org/eclipse/jdt/core/search/SearchPattern.java
@@ -18,7 +18,6 @@
 import org.eclipse.jdt.internal.core.LocalVariable;
 import org.eclipse.jdt.internal.core.search.indexing.IIndexConstants;
 import org.eclipse.jdt.internal.core.search.matching.*;
-import org.eclipse.jdt.internal.core.search.pattern.InternalSearchPattern;
 
 /**
  * A search pattern defines how search results are found. Use <code>SearchPattern.createPattern</code>
@@ -28,7 +27,7 @@
  * @see #createPattern(String, int, int, int, boolean)
  * @since 3.0
  */
-public abstract class SearchPattern extends InternalSearchPattern implements IIndexConstants, IJavaSearchConstants {
+public abstract class SearchPattern extends InternalSearchPattern {
 
 	/**
 	 * Rules for pattern matching: (exact, prefix, pattern) [ | case sensitive]
@@ -37,16 +36,16 @@
 	 * Match rule: The search pattern matches exactly the search result,
 	 * that is, the source of the search result equals the search pattern.
 	 */
-	public static final int R_EXACT_MATCH = EXACT_MATCH;
+	public static final int R_EXACT_MATCH = 0;
 	/**
 	 * Match rule: The search pattern is a prefix of the search result.
 	 */
-	public static final int R_PREFIX_MATCH = PREFIX_MATCH;
+	public static final int R_PREFIX_MATCH = 1;
 	/**
 	 * Match rule: The search pattern contains one or more wild cards ('*') where a 
 	 * wild-card can replace 0 or more characters in the search result.
 	 */
-	public static final int R_PATTERN_MATCH = PATTERN_MATCH;
+	public static final int R_PATTERN_MATCH = 2;
 	/**
 	 * Match rule: The search pattern contains a regular expression.
 	 */
@@ -60,17 +59,12 @@
 	/**
 	 * Whether this pattern is case sensitive.
 	 */
-	public final boolean isCaseSensitive;
+	private final boolean isCaseSensitive;
 	
 	/**
 	 * One of R_EXACT_MATCH, R_PREFIX_MATCH, R_PATTERN_MATCH, R_REGEXP_MATCH.
 	 */
-	public final int matchMode;
-
-	/**
-	 *  The focus element (used for reference patterns)
-	 */
-	public IJavaElement focus;
+	private final int matchMode;
 
 	protected SearchPattern(int patternKind, int matchRule) {
 		super(patternKind);
@@ -86,23 +80,8 @@
 	 * @param rightPattern the right pattern
 	 * @return a "and" pattern
 	 */
-	public static SearchPattern createAndPattern(final SearchPattern leftPattern, final SearchPattern rightPattern) {
-		return new AndPattern(0/*no kind*/, 0/*no rule*/) {
-			SearchPattern current = leftPattern;
-			public SearchPattern currentPattern() {
-				return current;
-			}
-			protected boolean hasNextQuery() {
-				if (current == leftPattern) {
-					current = rightPattern;
-					return true;
-				}
-				return false; 
-			}
-			protected void resetQuery() {
-				current = leftPattern;
-			}
-		};
+	public static SearchPattern createAndPattern(SearchPattern leftPattern, SearchPattern rightPattern) {
+		return MatchLocator.createAndPattern(leftPattern, rightPattern);
 	}
 	
 	/**
@@ -217,7 +196,7 @@
 						parameterTypeQualifications[i] = null;
 					} else {
 						// prefix with a '*' as the full qualification could be bigger (because of an import)
-						parameterTypeQualifications[i] = CharOperation.concat(ONE_STAR, parameterTypeQualifications[i]);
+						parameterTypeQualifications[i] = CharOperation.concat(IIndexConstants.ONE_STAR, parameterTypeQualifications[i]);
 					}
 					parameterTypeSimpleNames[i] = CharOperation.subarray(parameterTypePart, lastDotPosition+1, parameterTypePart.length);
 				} else {
@@ -363,7 +342,7 @@
 					typeQualification = null;
 				} else {
 					// prefix with a '*' as the full qualification could be bigger (because of an import)
-					typeQualification = CharOperation.concat(ONE_STAR, typeQualification);
+					typeQualification = CharOperation.concat(IIndexConstants.ONE_STAR, typeQualification);
 				}
 				typeSimpleName = CharOperation.subarray(typePart, lastDotPosition+1, typePart.length);
 			} else {
@@ -581,7 +560,7 @@
 						parameterTypeQualifications[i] = null;
 					} else {
 						// prefix with a '*' as the full qualification could be bigger (because of an import)
-						parameterTypeQualifications[i] = CharOperation.concat(ONE_STAR, parameterTypeQualifications[i]);
+						parameterTypeQualifications[i] = CharOperation.concat(IIndexConstants.ONE_STAR, parameterTypeQualifications[i]);
 					}
 					parameterTypeSimpleNames[i] = CharOperation.subarray(parameterTypePart, lastDotPosition+1, parameterTypePart.length);
 				} else {
@@ -602,7 +581,7 @@
 					returnTypeQualification = null;
 				} else {
 					// because of an import
-					returnTypeQualification = CharOperation.concat(ONE_STAR, returnTypeQualification);
+					returnTypeQualification = CharOperation.concat(IIndexConstants.ONE_STAR, returnTypeQualification);
 				}			
 				returnTypeSimpleName = CharOperation.subarray(returnTypePart, lastDotPosition+1, returnTypePart.length);
 			} else {
@@ -785,7 +764,7 @@
 						typeQualification = field.isBinary()
 							? typeSignature.substring(0, lastDot).toCharArray()
 							// prefix with a '*' as the full qualification could be bigger (because of an import)
-							: CharOperation.concat(ONE_STAR, typeSignature.substring(0, lastDot).toCharArray());
+							: CharOperation.concat(IIndexConstants.ONE_STAR, typeSignature.substring(0, lastDot).toCharArray());
 					}
 				} catch (JavaModelException e) {
 					return null;
@@ -951,7 +930,7 @@
 						returnQualification = method.isBinary()
 							? returnType.substring(0, lastDot).toCharArray()
 							// prefix with a '*' as the full qualification could be bigger (because of an import)
-							: CharOperation.concat(ONE_STAR, returnType.substring(0, lastDot).toCharArray());
+							: CharOperation.concat(IIndexConstants.ONE_STAR, returnType.substring(0, lastDot).toCharArray());
 					}
 				} catch (JavaModelException e) {
 					return null;
@@ -970,7 +949,7 @@
 						parameterQualifications[i] = method.isBinary()
 							? signature.substring(0, lastDot).toCharArray()
 							// prefix with a '*' as the full qualification could be bigger (because of an import)
-							: CharOperation.concat(ONE_STAR, signature.substring(0, lastDot).toCharArray());
+							: CharOperation.concat(IIndexConstants.ONE_STAR, signature.substring(0, lastDot).toCharArray());
 				}
 				}
 				switch (limitTo) {
@@ -1072,7 +1051,7 @@
 				break;
 		}
 		if (searchPattern != null)
-			searchPattern.focus = element;
+			MatchLocator.setFocus(searchPattern, element);
 		return searchPattern;
 	}
 	private static SearchPattern createTypePattern(char[] simpleName, char[] packageName, char[][] enclosingTypeNames, int limitTo) {
@@ -1082,7 +1061,7 @@
 					packageName, 
 					enclosingTypeNames, 
 					simpleName, 
-					TYPE_SUFFIX,
+					IIndexConstants.TYPE_SUFFIX,
 					R_EXACT_MATCH | R_CASE_SENSITIVE);
 			case IJavaSearchConstants.REFERENCES :
 				return new TypeReferencePattern(
@@ -1101,7 +1080,7 @@
 						packageName, 
 						enclosingTypeNames, 
 						simpleName, 
-						TYPE_SUFFIX,
+						IIndexConstants.TYPE_SUFFIX,
 						R_EXACT_MATCH | R_CASE_SENSITIVE), 
 					new TypeReferencePattern(
 						CharOperation.concatWith(packageName, enclosingTypeNames, '.'), 
@@ -1167,14 +1146,14 @@
 		}
 		switch (limitTo) {
 			case IJavaSearchConstants.DECLARATIONS : // cannot search for explicit member types
-				return new QualifiedTypeDeclarationPattern(qualificationChars, typeChars, TYPE_SUFFIX, matchRule);
+				return new QualifiedTypeDeclarationPattern(qualificationChars, typeChars, IIndexConstants.TYPE_SUFFIX, matchRule);
 			case IJavaSearchConstants.REFERENCES :
 				return new TypeReferencePattern(qualificationChars, typeChars, matchRule);
 			case IJavaSearchConstants.IMPLEMENTORS : 
 				return new SuperTypeReferencePattern(qualificationChars, typeChars, true, matchRule);
 			case IJavaSearchConstants.ALL_OCCURRENCES :
 				return new OrPattern(
-					new QualifiedTypeDeclarationPattern(qualificationChars, typeChars, TYPE_SUFFIX, matchRule),// cannot search for explicit member types
+					new QualifiedTypeDeclarationPattern(qualificationChars, typeChars, IIndexConstants.TYPE_SUFFIX, matchRule),// cannot search for explicit member types
 					new TypeReferencePattern(qualificationChars, typeChars, matchRule));
 		}
 		return null;
@@ -1201,7 +1180,7 @@
 				IType declaringClass = ((IMember) parent).getDeclaringType();
 				return CharOperation.arrayConcat(
 					enclosingTypeNames(declaringClass),
-					new char[][] {declaringClass.getElementName().toCharArray(), ONE_STAR});
+					new char[][] {declaringClass.getElementName().toCharArray(), IIndexConstants.ONE_STAR});
 			case IJavaElement.TYPE:
 				return CharOperation.arrayConcat(
 					enclosingTypeNames((IType)parent), 
@@ -1260,6 +1239,17 @@
 		return CharOperation.NO_CHAR_CHAR; // called from queryIn(), override as necessary
 	}
 	/**
+	 * Returns the match mode.
+	 * 
+	 * @return one of {@link IJavaSearchConstants#EXACT_MATCH},
+	 * {@link IJavaSearchConstants#PREFIX_MATCH},
+	 * {@link IJavaSearchConstants#PATTERN_MATCH},
+	 * {@link IJavaSearchConstants#REGEXP_MATCH}}
+	 */
+	public final int getMatchMode() {
+		return this.matchMode;
+	}
+	/**
 	 * 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.
 	 * 
@@ -1269,6 +1259,15 @@
 		return this.matchMode + (this.isCaseSensitive ? SearchPattern.R_CASE_SENSITIVE : 0);
 	}
 	/**
+	 * Returns whether this pattern is case-sensitive.
+	 * 
+	 * @return <code>true</code> if this pattern is case-sensitive, and
+	 * <code>false</code> otherwise
+	 */
+	public final boolean isCaseSensitive () {
+		return this.isCaseSensitive;
+	}
+	/**
 	 * Returns whether this pattern matches the given pattern (representing a decoded index key).
 	 * 
 	 * @param decodedPattern a pattern representing a decoded index key
diff --git a/search/org/eclipse/jdt/core/search/SearchRequestor.java b/search/org/eclipse/jdt/core/search/SearchRequestor.java
index 4c52e2e..b7e514b 100644
--- a/search/org/eclipse/jdt/core/search/SearchRequestor.java
+++ b/search/org/eclipse/jdt/core/search/SearchRequestor.java
@@ -13,21 +13,17 @@
 import org.eclipse.core.runtime.CoreException;
 
 /**
- * A <code>SearchRequestor</code> collects search results from a <code>search</code>
- * query to a <code>SearchEngine</code>. Clients must implement this interface and pass
- * an instance to the <code>search(...)</code> methods. When a search starts, the <code>beginReporting()</code>
- * method is called, then 0 or more call to <code>acceptSearchMatch(...)</code> are done, finally the
- * <code>endReporting()</code> method is called.
+ * Collects the results from a search engine query. 
+ * Clients implement a subclass to pass to <code>SearchEngine.search</code>
+ * and implement the {@link #acceptSearchMatch(SearchMatch)} method, and
+ * possibly override other life cycle methods.
  * <p>
- * Results provided to this collector may be accurate - in this case they have an <code>A_ACCURATE</code> accuracy -
- * or they might be potential matches only - they have a <code>A_INACCURATE</code> accuracy. This last
- * case can occur when a problem prevented the <code>SearchEngine</code> from resolving the match.
- * </p>
- * <p>
- * The order of the results is unspecified. Clients must not rely on this order to display results, 
- * but they should sort these results (for example, in syntactical order).
- * <p>
- * Clients may subclass this class.
+ * The search engine calls <code>beginReporting()</code> when a search starts,
+ * then calls <code>acceptSearchMatch(...)</code> for each search result, and
+ * finally calls <code>endReporting()</code>. The order of the search results
+ * is unspecified and may vary from request to request; when displaying results,
+ * clients should not rely on the order but should instead arrange the results
+ * in an order that would be more meaningful to the user.
  * </p>
  *
  * @see SearchEngine
@@ -39,35 +35,61 @@
 	 * Accepts the given search match.
 	 *
 	 * @param match the found match
-	 * @exception CoreException if this collector had a problem accepting the search result
 	 */
+	// TODO (jerome) - remove throws CoreException
 	public abstract void acceptSearchMatch(SearchMatch match) throws CoreException;
 
 	/**
 	 * Notification sent before starting the search action.
-	 * Typically, this would tell a search requestor to clear previously recorded search results.
+	 * Typically, this would tell a search requestor to clear previously
+	 * recorded search results.
+	 * <p>
+	 * The default implementation of this method does nothing. Subclasses
+	 * may override.
+	 * </p>
 	 */
-	public abstract void beginReporting();
+	public void beginReporting() {
+		// do nothing
+	}
 
 	/**
 	 * Notification sent after having completed the search action.
 	 * Typically, this would tell a search requestor collector that no more results  should be expected in this
 	 * iteration.
+	 * <p>
+	 * The default implementation of this method does nothing. Subclasses
+	 * may override.
+	 * </p>
 	 */
-	public abstract void endReporting();
+	public void endReporting() {
+		// do nothing
+	}
 
 	/**
-	 * Intermediate notification sent when a given participant is starting to contribute.
+	 * Intermediate notification sent when a given participant is starting to
+	 * contribute.
+	 * <p>
+	 * The default implementation of this method does nothing. Subclasses
+	 * may override.
+	 * </p>
 	 * 
 	 * @param participant the participant that is starting to contribute
 	 */
-	public abstract void enterParticipant(SearchParticipant participant);
+	public void enterParticipant(SearchParticipant participant) {
+		// do nothing
+	}
 
 	/**
-	 * Intermediate notification sent when a given participant is finished contributing.
+	 * Intermediate notification sent when a given participant is finished
+	 * contributing.
+	 * <p>
+	 * The default implementation of this method does nothing. Subclasses
+	 * may override.
+	 * </p>
 	 * 
 	 * @param participant the participant that finished contributing
 	 */
-	public abstract void exitParticipant(SearchParticipant participant);
-
+	public void exitParticipant(SearchParticipant participant) {
+		// do nothing
+	}
 }
diff --git a/search/org/eclipse/jdt/core/search/TypeDeclarationMatch.java b/search/org/eclipse/jdt/core/search/TypeDeclarationMatch.java
index a98a378..b2042d9 100644
--- a/search/org/eclipse/jdt/core/search/TypeDeclarationMatch.java
+++ b/search/org/eclipse/jdt/core/search/TypeDeclarationMatch.java
@@ -26,15 +26,13 @@
 	 * 
 	 * @param element the type declaration
 	 * @param accuracy one of A_ACCURATE or A_INACCURATE
-	 * @param sourceStart the start position of the match, -1 if it is unknown
-	 * @param sourceEnd the end position of the match, -1 if it is unknown;
-	 * 	the ending offset is exclusive, meaning that the actual range of characters 
-	 * 	covered is <code>[start, end]</code>
+	 * @param offset the offset the match starts at, or -1 if unknown
+	 * @param length the length of the match, or -1 if unknown
 	 * @param participant the search participant that created the match
 	 * @param resource the resource of the element
 	 */
-	public TypeDeclarationMatch(IJavaElement element, int accuracy, int sourceStart, int sourceEnd, SearchParticipant participant, IResource resource) {
-		super(element, accuracy, sourceStart, sourceEnd, participant, resource);
+	public TypeDeclarationMatch(IJavaElement element, int accuracy, int offset, int length, SearchParticipant participant, IResource resource) {
+		super(element, accuracy, offset, length, participant, resource);
 	}
 
 }
diff --git a/search/org/eclipse/jdt/core/search/TypeReferenceMatch.java b/search/org/eclipse/jdt/core/search/TypeReferenceMatch.java
index ff3027c..91a1c6e 100644
--- a/search/org/eclipse/jdt/core/search/TypeReferenceMatch.java
+++ b/search/org/eclipse/jdt/core/search/TypeReferenceMatch.java
@@ -28,23 +28,21 @@
 	 * 
 	 * @param enclosingElement the inner-most enclosing member that references this type
 	 * @param accuracy one of A_ACCURATE or A_INACCURATE
-	 * @param sourceStart the start position of the match, -1 if it is unknown
-	 * @param sourceEnd the end position of the match, -1 if it is unknown;
-	 * 	the ending offset is exclusive, meaning that the actual range of characters 
-	 * 	covered is <code>[start, end]</code>
+	 * @param offset the offset the match starts at, or -1 if unknown
+	 * @param length the length of the match, or -1 if unknown
 	 * @param insideDocComment whether the match is inside a doc comment
 	 * @param participant the search participant that created the match
 	 * @param resource the resource of the element
 	 */
-	public TypeReferenceMatch(IJavaElement enclosingElement, int accuracy,	int sourceStart, int sourceEnd, boolean insideDocComment, SearchParticipant participant, IResource resource) {
-		super(enclosingElement, accuracy, sourceStart, sourceEnd, participant, resource);
+	public TypeReferenceMatch(IJavaElement enclosingElement, int accuracy,	int offset, int length, boolean insideDocComment, SearchParticipant participant, IResource resource) {
+		super(enclosingElement, accuracy, offset, length, participant, resource);
 		this.insideDocComment = insideDocComment;
 	}
 	
 	/**
-	 * @see org.eclipse.jdt.core.search.SearchMatch#insideDocComment()
+	 * @see org.eclipse.jdt.core.search.SearchMatch#isInsideDocComment()
 	 */
-	public boolean insideDocComment() {
+	public boolean isInsideDocComment() {
 		return this.insideDocComment;
 	}
 }
diff --git a/search/org/eclipse/jdt/internal/core/search/IndexSelector.java b/search/org/eclipse/jdt/internal/core/search/IndexSelector.java
index db7f6fe..5e6ceaf 100644
--- a/search/org/eclipse/jdt/internal/core/search/IndexSelector.java
+++ b/search/org/eclipse/jdt/internal/core/search/IndexSelector.java
@@ -24,6 +24,7 @@
 import org.eclipse.jdt.core.search.SearchPattern;
 import org.eclipse.jdt.internal.core.JarPackageFragmentRoot;
 import org.eclipse.jdt.internal.core.JavaProject;
+import org.eclipse.jdt.internal.core.search.matching.MatchLocator;
 
 /**
  * Selects the indexes that correspond to projects in a given search scope
@@ -125,8 +126,8 @@
 	ArrayList requiredIndexKeys = new ArrayList();
 	IPath[] projectsAndJars = this.searchScope.enclosingProjectsAndJars();
 	IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
-	IJavaElement projectOrJarFocus = this.pattern == null || this.pattern.focus == null ? null : getProjectOrJar(this.pattern.focus);
-	boolean isPolymorphicSearch = this.pattern == null ? false : this.pattern.isPolymorphicSearch();
+	IJavaElement projectOrJarFocus = MatchLocator.projectOrJarFocus(this.pattern);
+	boolean isPolymorphicSearch = this.pattern == null ? false : MatchLocator.isPolymorphicSearch(this.pattern);
 	for (int i = 0; i < projectsAndJars.length; i++) {
 		IPath location;
 		IPath path = projectsAndJars[i];
@@ -165,10 +166,4 @@
 		return null;
 	}
 }
-public static IJavaElement getProjectOrJar(IJavaElement element) {
-	while (!(element instanceof IJavaProject) && !(element instanceof JarPackageFragmentRoot)) {
-		element = element.getParent();
-	}
-	return element;
-}
 }
diff --git a/search/org/eclipse/jdt/internal/core/search/PatternSearchJob.java b/search/org/eclipse/jdt/internal/core/search/PatternSearchJob.java
index 4c59e14..a02cfb6 100644
--- a/search/org/eclipse/jdt/internal/core/search/PatternSearchJob.java
+++ b/search/org/eclipse/jdt/internal/core/search/PatternSearchJob.java
@@ -20,6 +20,7 @@
 import org.eclipse.jdt.internal.core.index.Index;
 import org.eclipse.jdt.internal.core.search.indexing.IndexManager;
 import org.eclipse.jdt.internal.core.search.indexing.ReadWriteMonitor;
+import org.eclipse.jdt.internal.core.search.matching.MatchLocator;
 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.Util;
@@ -103,7 +104,7 @@
 	try {
 		monitor.enterRead(); // ask permission to read
 		long start = System.currentTimeMillis();
-		pattern.findIndexMatches(index, requestor, this.participant, this.scope, progressMonitor);
+		MatchLocator.findIndexMatches(this.pattern, index, requestor, this.participant, this.scope, progressMonitor);
 		executionTime += System.currentTimeMillis() - start;
 		return COMPLETE;
 	} catch (IOException e) {
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 992cbb8..7fe9a62 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/AndPattern.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/AndPattern.java
@@ -35,8 +35,8 @@
 	try {
 		index.startQuery();
 		do {
-			SearchPattern pattern = currentPattern();
-			EntryResult[] entries = pattern.queryIn(index);
+			SearchPattern pattern = ((InternalSearchPattern) this).currentPattern();
+			EntryResult[] entries = ((InternalSearchPattern)pattern).queryIn(index);
 			if (entries == null) return;
 
 			SearchPattern decodedResult = pattern.getBlankPattern();
@@ -70,7 +70,7 @@
 	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
+			((InternalSearchPattern) this).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 8bbd3f6..f837a92 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/ClassFileMatchLocator.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/ClassFileMatchLocator.java
@@ -66,7 +66,7 @@
 		locator.reportBinaryMemberDeclaration(null, binaryType, info, SearchMatch.A_ACCURATE);
 
 	int accuracy = SearchMatch.A_ACCURATE;
-	if (pattern.mustResolve) {
+	if (((InternalSearchPattern)pattern).mustResolve) {
 		try {
 			BinaryTypeBinding binding = locator.cacheBinaryType(binaryType);
 			if (binding != null) {
@@ -131,7 +131,7 @@
  * Default is to return false.
  */
 boolean matchBinary(SearchPattern pattern, Object binaryInfo, IBinaryType enclosingBinaryType) {
-	switch (pattern.kind) {
+	switch (((InternalSearchPattern)pattern).kind) {
 		case CONSTRUCTOR_PATTERN :
 			return matchConstructor((ConstructorPattern) pattern, binaryInfo, enclosingBinaryType);
 		case FIELD_PATTERN :
@@ -155,11 +155,11 @@
 
 	IBinaryMethod method = (IBinaryMethod) binaryInfo;
 	if (!method.isConstructor()) return false;
-	if (!checkDeclaringType(enclosingBinaryType, pattern.declaringSimpleName, pattern.declaringQualification, pattern.isCaseSensitive))
+	if (!checkDeclaringType(enclosingBinaryType, pattern.declaringSimpleName, pattern.declaringQualification, pattern.isCaseSensitive()))
 		return false;
 	if (pattern.parameterSimpleNames != null) {
 		char[] methodDescriptor = convertClassFileFormat(method.getMethodDescriptor());
-		if (!checkParameters(methodDescriptor, pattern.parameterSimpleNames, pattern.parameterQualifications, pattern.isCaseSensitive))
+		if (!checkParameters(methodDescriptor, pattern.parameterSimpleNames, pattern.parameterQualifications, pattern.isCaseSensitive()))
 			return false;
 	}
 	return true;
@@ -170,11 +170,11 @@
 
 	IBinaryField field = (IBinaryField) binaryInfo;
 	if (!pattern.matchesName(pattern.name, field.getName())) return false;
-	if (!checkDeclaringType(enclosingBinaryType, pattern.declaringSimpleName, pattern.declaringQualification, pattern.isCaseSensitive))
+	if (!checkDeclaringType(enclosingBinaryType, pattern.declaringSimpleName, pattern.declaringQualification, pattern.isCaseSensitive()))
 		return false;
 
 	char[] fieldTypeSignature = Signature.toCharArray(convertClassFileFormat(field.getTypeName()));
-	return checkTypeName(pattern.typeSimpleName, pattern.typeQualification, fieldTypeSignature, pattern.isCaseSensitive);
+	return checkTypeName(pattern.typeSimpleName, pattern.typeQualification, fieldTypeSignature, pattern.isCaseSensitive());
 }
 boolean matchMethod(MethodPattern pattern, Object binaryInfo, IBinaryType enclosingBinaryType) {
 	if (!pattern.findDeclarations) return false; // only relevant when finding declarations
@@ -182,7 +182,7 @@
 
 	IBinaryMethod method = (IBinaryMethod) binaryInfo;
 	if (!pattern.matchesName(pattern.selector, method.getSelector())) return false;
-	if (!checkDeclaringType(enclosingBinaryType, pattern.declaringSimpleName, pattern.declaringQualification, pattern.isCaseSensitive))
+	if (!checkDeclaringType(enclosingBinaryType, pattern.declaringSimpleName, pattern.declaringQualification, pattern.isCaseSensitive()))
 		return false;
 
 	// look at return type only if declaring type is not specified
@@ -192,10 +192,10 @@
 		char[] methodDescriptor = convertClassFileFormat(method.getMethodDescriptor());
 		if (checkReturnType) {
 			char[] returnTypeSignature = Signature.toCharArray(Signature.getReturnType(methodDescriptor));
-			if (!checkTypeName(pattern.returnSimpleName, pattern.returnQualification, returnTypeSignature, pattern.isCaseSensitive))
+			if (!checkTypeName(pattern.returnSimpleName, pattern.returnQualification, returnTypeSignature, pattern.isCaseSensitive()))
 				return false;
 		}
-		if (checkParameters &&  !checkParameters(methodDescriptor, pattern.parameterSimpleNames, pattern.parameterQualifications, pattern.isCaseSensitive))
+		if (checkParameters &&  !checkParameters(methodDescriptor, pattern.parameterSimpleNames, pattern.parameterQualifications, pattern.isCaseSensitive()))
 			return false;
 	}
 	return true;
@@ -208,7 +208,7 @@
 		char[] vmName = type.getSuperclassName();
 		if (vmName != null) {
 			char[] superclassName = convertClassFileFormat(vmName);
-			if (checkTypeName(pattern.superSimpleName, pattern.superQualification, superclassName, pattern.isCaseSensitive))
+			if (checkTypeName(pattern.superSimpleName, pattern.superQualification, superclassName, pattern.isCaseSensitive()))
 				return true;
 		}
 	}
@@ -217,7 +217,7 @@
 	if (superInterfaces != null) {
 		for (int i = 0, max = superInterfaces.length; i < max; i++) {
 			char[] superInterfaceName = convertClassFileFormat(superInterfaces[i]);
-			if (checkTypeName(pattern.superSimpleName, pattern.superQualification, superInterfaceName, pattern.isCaseSensitive))
+			if (checkTypeName(pattern.superSimpleName, pattern.superQualification, superInterfaceName, pattern.isCaseSensitive()))
 				return true;
 		}
 	}
@@ -229,13 +229,13 @@
 	IBinaryType type = (IBinaryType) binaryInfo;
 	char[] fullyQualifiedTypeName = convertClassFileFormat(type.getName());
 	if (pattern.enclosingTypeNames == null || pattern instanceof QualifiedTypeDeclarationPattern) {
-		if (!checkTypeName(pattern.simpleName, pattern.pkg, fullyQualifiedTypeName, pattern.isCaseSensitive)) return false;
+		if (!checkTypeName(pattern.simpleName, pattern.pkg, fullyQualifiedTypeName, pattern.isCaseSensitive())) return false;
 	} else {
 		char[] enclosingTypeName = CharOperation.concatWith(pattern.enclosingTypeNames, '.');
 		char[] patternString = pattern.pkg == null
 			? enclosingTypeName
 			: CharOperation.concat(pattern.pkg, enclosingTypeName, '.');
-		if (!checkTypeName(pattern.simpleName, patternString, fullyQualifiedTypeName, pattern.isCaseSensitive)) return false;
+		if (!checkTypeName(pattern.simpleName, patternString, fullyQualifiedTypeName, pattern.isCaseSensitive())) return false;
 	}
 
 	switch (pattern.classOrInterface) {
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 e239cbb..96b266e 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/ConstructorLocator.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/ConstructorLocator.java
@@ -35,7 +35,7 @@
 		if (length != argsLength) return IMPOSSIBLE_MATCH;
 	}
 
-	return nodeSet.addMatch(node, this.pattern.mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
+	return nodeSet.addMatch(node, ((InternalSearchPattern)this.pattern).mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
 }
 public int match(ConstructorDeclaration node, MatchingNodeSet nodeSet) {
 	int referencesLevel = this.pattern.findReferences ? matchLevelForReferences(node) : IMPOSSIBLE_MATCH;
@@ -60,7 +60,7 @@
 		if (length != argsLength) return IMPOSSIBLE_MATCH;
 	}
 
-	return nodeSet.addMatch(node, this.pattern.mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
+	return nodeSet.addMatch(node, ((InternalSearchPattern)this.pattern).mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
 }
 //public int match(FieldDeclaration node, MatchingNodeSet nodeSet) - SKIP IT
 //public int match(MethodDeclaration node, MatchingNodeSet nodeSet) - SKIP IT
@@ -70,7 +70,7 @@
 	if (!this.pattern.findReferences) return IMPOSSIBLE_MATCH;
 
 	// need to look for a generated default constructor
-	return nodeSet.addMatch(node, this.pattern.mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
+	return nodeSet.addMatch(node, ((InternalSearchPattern)this.pattern).mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
 }
 //public int match(TypeReference node, MatchingNodeSet nodeSet) - SKIP IT
 
@@ -95,7 +95,7 @@
 		int argsLength = args == null ? 0 : args.length;
 		if (length != argsLength) return IMPOSSIBLE_MATCH;
 	}
-	return this.pattern.mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH;
+	return ((InternalSearchPattern)this.pattern).mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH;
 }
 protected int matchLevelForDeclarations(ConstructorDeclaration constructor) {
 	// constructor name is stored in selector field
@@ -113,7 +113,7 @@
 				return IMPOSSIBLE_MATCH;
 	}
 
-	return this.pattern.mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH;
+	return ((InternalSearchPattern)this.pattern).mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH;
 }
 public int resolveLevel(ASTNode node) {
 	if (this.pattern.findReferences) {
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 fe234a4..2862741 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/ConstructorPattern.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/ConstructorPattern.java
@@ -15,8 +15,9 @@
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.search.SearchPattern;
 import org.eclipse.jdt.internal.core.index.*;
+import org.eclipse.jdt.internal.core.search.indexing.IIndexConstants;
 
-public class ConstructorPattern extends SearchPattern {
+public class ConstructorPattern extends SearchPattern implements IIndexConstants {
 
 protected boolean findDeclarations;
 protected boolean findReferences;
@@ -57,21 +58,21 @@
 	this.findDeclarations = findDeclarations;
 	this.findReferences = findReferences;
 
-	this.declaringQualification = this.isCaseSensitive ? declaringQualification : CharOperation.toLowerCase(declaringQualification);
-	this.declaringSimpleName = this.isCaseSensitive ? declaringSimpleName : CharOperation.toLowerCase(declaringSimpleName);
+	this.declaringQualification = isCaseSensitive() ? declaringQualification : CharOperation.toLowerCase(declaringQualification);
+	this.declaringSimpleName = isCaseSensitive() ? declaringSimpleName : CharOperation.toLowerCase(declaringSimpleName);
 	if (parameterSimpleNames != null) {
 		this.parameterCount = parameterSimpleNames.length;
 		this.parameterQualifications = new char[this.parameterCount][];
 		this.parameterSimpleNames = new char[this.parameterCount][];
 		for (int i = 0; i < this.parameterCount; i++) {
-			this.parameterQualifications[i] = this.isCaseSensitive ? parameterQualifications[i] : CharOperation.toLowerCase(parameterQualifications[i]);
-			this.parameterSimpleNames[i] = this.isCaseSensitive ? parameterSimpleNames[i] : CharOperation.toLowerCase(parameterSimpleNames[i]);
+			this.parameterQualifications[i] = isCaseSensitive() ? parameterQualifications[i] : CharOperation.toLowerCase(parameterQualifications[i]);
+			this.parameterSimpleNames[i] = isCaseSensitive() ? parameterSimpleNames[i] : CharOperation.toLowerCase(parameterSimpleNames[i]);
 		}
 	} else {
 		this.parameterCount = -1;
 	}
 
-	this.mustResolve = mustResolve();
+	((InternalSearchPattern)this).mustResolve = mustResolve();
 }
 ConstructorPattern(int matchRule) {
 	super(CONSTRUCTOR_PATTERN, matchRule);
@@ -108,11 +109,11 @@
 			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 {
+EntryResult[] queryIn(Index index) throws IOException {
 	char[] key = this.declaringSimpleName; // can be null
 	int matchRule = getMatchRule();
 
-	switch(this.matchMode) {
+	switch(getMatchMode()) {
 		case R_EXACT_MATCH :
 			if (this.declaringSimpleName != null && this.parameterCount >= 0)
 				key = createIndexKey(this.declaringSimpleName, this.parameterCount);
@@ -161,7 +162,7 @@
 	}
 	buffer.append(')');
 	buffer.append(", "); //$NON-NLS-1$
-	switch(this.matchMode) {
+	switch(getMatchMode()) {
 		case R_EXACT_MATCH : 
 			buffer.append("exact match, "); //$NON-NLS-1$
 			break;
@@ -172,7 +173,7 @@
 			buffer.append("pattern match, "); //$NON-NLS-1$
 			break;
 	}
-	buffer.append(this.isCaseSensitive ? "case sensitive" : "case insensitive"); //$NON-NLS-1$ //$NON-NLS-2$
+	buffer.append(isCaseSensitive() ? "case sensitive" : "case insensitive"); //$NON-NLS-1$ //$NON-NLS-2$
 	return buffer.toString();
 }
 }
\ No newline at end of file
diff --git a/search/org/eclipse/jdt/internal/core/search/matching/DeclarationOfAccessedFieldsPattern.java b/search/org/eclipse/jdt/internal/core/search/matching/DeclarationOfAccessedFieldsPattern.java
index 83cee4e..287758a 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/DeclarationOfAccessedFieldsPattern.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/DeclarationOfAccessedFieldsPattern.java
@@ -23,6 +23,6 @@
 
 	this.enclosingElement = enclosingElement;
 	this.knownFields = new SimpleSet();
-	this.mustResolve = true;
+	((InternalSearchPattern)this).mustResolve = true;
 }
 }
diff --git a/search/org/eclipse/jdt/internal/core/search/matching/DeclarationOfReferencedMethodsPattern.java b/search/org/eclipse/jdt/internal/core/search/matching/DeclarationOfReferencedMethodsPattern.java
index 4f29829..2828f21 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/DeclarationOfReferencedMethodsPattern.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/DeclarationOfReferencedMethodsPattern.java
@@ -25,6 +25,6 @@
 
 	this.enclosingElement = enclosingElement;
 	this.knownMethods = new SimpleSet();
-	this.mustResolve = true;
+	((InternalSearchPattern)this).mustResolve = true;
 }
 }
diff --git a/search/org/eclipse/jdt/internal/core/search/matching/DeclarationOfReferencedTypesPattern.java b/search/org/eclipse/jdt/internal/core/search/matching/DeclarationOfReferencedTypesPattern.java
index 300c490..cb98f4e 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/DeclarationOfReferencedTypesPattern.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/DeclarationOfReferencedTypesPattern.java
@@ -23,6 +23,6 @@
 
 	this.enclosingElement = enclosingElement;
 	this.knownTypes = new SimpleSet();
-	this.mustResolve = true;
+	((InternalSearchPattern)this).mustResolve = true;
 }
 }
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 6a29e6f..8cf71fb 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/FieldLocator.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/FieldLocator.java
@@ -38,14 +38,14 @@
 		// must be a write only access with an initializer
 		if (this.pattern.writeAccess && !this.pattern.readAccess && node.initialization != null)
 			if (matchesName(this.pattern.name, node.name))
-				referencesLevel = this.pattern.mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH;
+				referencesLevel = ((InternalSearchPattern)this.pattern).mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH;
 
 	int declarationsLevel = IMPOSSIBLE_MATCH;
 	if (this.pattern.findDeclarations)
 		if (node.isField()) // ignore field initializers
 			if (matchesName(this.pattern.name, node.name))
 				if (matchesTypeReference(((FieldPattern)this.pattern).typeSimpleName, node.type))
-					declarationsLevel = this.pattern.mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH;
+					declarationsLevel = ((InternalSearchPattern)this.pattern).mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH;
 
 	return nodeSet.addMatch(node, referencesLevel >= declarationsLevel ? referencesLevel : declarationsLevel); // use the stronger match
 }
@@ -90,7 +90,7 @@
 protected int matchReference(Reference node, MatchingNodeSet nodeSet, boolean writeOnlyAccess) {
 	if (node instanceof FieldReference) {
 		if (matchesName(this.pattern.name, ((FieldReference) node).token))
-			return nodeSet.addMatch(node, this.pattern.mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
+			return nodeSet.addMatch(node, ((InternalSearchPattern)this.pattern).mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
 		return IMPOSSIBLE_MATCH;
 	}
 	return super.matchReference(node, nodeSet, writeOnlyAccess);
@@ -122,10 +122,13 @@
 	} else if (reference instanceof FieldReference) {
 		FieldReference fieldReference = (FieldReference) reference;
 		long position = fieldReference.nameSourcePosition;
-		SearchMatch match = locator.newFieldReferenceMatch(element, accuracy, ((int) (position >>> 32)), ((int) position)+1, fieldReference);
+		int start = (int) (position >>> 32);
+		int end = (int) position;
+		SearchMatch match = locator.newFieldReferenceMatch(element, accuracy, start, end-start+1, fieldReference);
 		locator.report(match);
 	} else if (reference instanceof SingleNameReference) {
-		SearchMatch match = locator.newFieldReferenceMatch(element, accuracy, reference.sourceStart, reference.sourceEnd+1, reference);
+		int offset = reference.sourceStart;
+		SearchMatch match = locator.newFieldReferenceMatch(element, accuracy, offset, reference.sourceEnd-offset+1, reference);
 		locator.report(match);
 	} else if (reference instanceof QualifiedNameReference) {
 		QualifiedNameReference qNameRef = (QualifiedNameReference) reference;
@@ -215,7 +218,8 @@
 				}
 			} 
 			if (fieldDecl != null) {
-				SearchMatch match = new FieldDeclarationMatch(field, SearchMatch.A_ACCURATE, fieldDecl.sourceStart, fieldDecl.sourceEnd+1, locator.getParticipant(), resource);
+				int offset = fieldDecl.sourceStart;
+				SearchMatch match = new FieldDeclarationMatch(field, SearchMatch.A_ACCURATE, offset, fieldDecl.sourceEnd-offset+1, locator.getParticipant(), resource);
 				locator.report(match);
 
 			}
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 2ca6c0b..dd2acae 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/FieldPattern.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/FieldPattern.java
@@ -12,8 +12,9 @@
 
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.search.SearchPattern;
+import org.eclipse.jdt.internal.core.search.indexing.IIndexConstants;
 
-public class FieldPattern extends VariablePattern {
+public class FieldPattern extends VariablePattern implements IIndexConstants {
 
 // declaring type
 protected char[] declaringQualification;
@@ -44,12 +45,12 @@
 
 	super(FIELD_PATTERN, findDeclarations, readAccess, writeAccess, name, matchRule);
 
-	this.declaringQualification = this.isCaseSensitive ? declaringQualification : CharOperation.toLowerCase(declaringQualification);
-	this.declaringSimpleName = this.isCaseSensitive ? declaringSimpleName : CharOperation.toLowerCase(declaringSimpleName);
-	this.typeQualification = this.isCaseSensitive ? typeQualification : CharOperation.toLowerCase(typeQualification);
-	this.typeSimpleName = this.isCaseSensitive ? typeSimpleName : CharOperation.toLowerCase(typeSimpleName);
+	this.declaringQualification = isCaseSensitive() ? declaringQualification : CharOperation.toLowerCase(declaringQualification);
+	this.declaringSimpleName = isCaseSensitive() ? declaringSimpleName : CharOperation.toLowerCase(declaringSimpleName);
+	this.typeQualification = isCaseSensitive() ? typeQualification : CharOperation.toLowerCase(typeQualification);
+	this.typeSimpleName = isCaseSensitive() ? typeSimpleName : CharOperation.toLowerCase(typeSimpleName);
 
-	this.mustResolve = mustResolve();
+	((InternalSearchPattern)this).mustResolve = mustResolve();
 }
 public void decodeIndexKey(char[] key) {
 	this.name = key;
@@ -58,7 +59,7 @@
 	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);
+	return encodeIndexKey(this.name, getMatchMode());
 }
 public char[][] getMatchCategories() {
 	if (this.findReferences)
@@ -101,7 +102,7 @@
 		buffer.append(typeSimpleName);
 	else if (typeQualification != null) buffer.append("*"); //$NON-NLS-1$
 	buffer.append(", "); //$NON-NLS-1$
-	switch(this.matchMode) {
+	switch(getMatchMode()) {
 		case R_EXACT_MATCH : 
 			buffer.append("exact match, "); //$NON-NLS-1$
 			break;
@@ -112,7 +113,7 @@
 			buffer.append("pattern match, "); //$NON-NLS-1$
 			break;
 	}
-	buffer.append(this.isCaseSensitive ? "case sensitive" : "case insensitive"); //$NON-NLS-1$ //$NON-NLS-2$
+	buffer.append(isCaseSensitive() ? "case sensitive" : "case insensitive"); //$NON-NLS-1$ //$NON-NLS-2$
 	return buffer.toString();
 }
 }
diff --git a/search/org/eclipse/jdt/internal/core/search/matching/InternalSearchPattern.java b/search/org/eclipse/jdt/internal/core/search/matching/InternalSearchPattern.java
new file mode 100644
index 0000000..2e4cd16
--- /dev/null
+++ b/search/org/eclipse/jdt/internal/core/search/matching/InternalSearchPattern.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * 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.search.matching;
+
+import java.io.IOException;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.internal.core.index.*;
+import org.eclipse.jdt.internal.core.search.*;
+
+/**
+ * Internal search pattern implementation
+ */
+public abstract class InternalSearchPattern {
+
+	/**
+	 *  The focus element (used for reference patterns)
+	 */
+	IJavaElement focus;
+
+	final int kind;
+	boolean mustResolve = true;
+	
+	public InternalSearchPattern(int kind) {
+		this.kind = kind;
+	}
+	
+	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();
+	}
+	SearchPattern currentPattern() {
+		return (SearchPattern) this;
+	}
+	/**
+	 * Query a given index for matching entries. Assumes the sender has opened the index and will close when finished.
+	 */
+	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 = ((InternalSearchPattern)pattern).queryIn(index);
+			if (entries == null) return;
+		
+			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();
+		}
+	}
+	boolean isPolymorphicSearch() {
+		return false;
+	}
+	EntryResult[] queryIn(Index index) throws IOException {
+		SearchPattern pattern = (SearchPattern) this;
+		return index.query(pattern.getMatchCategories(), pattern.getIndexKey(), pattern.getMatchRule());
+	}
+
+}
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 c0bb821..dc9a6fd 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/LocalVariableLocator.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/LocalVariableLocator.java
@@ -29,13 +29,13 @@
 		// must be a write only access with an initializer
 		if (this.pattern.writeAccess && !this.pattern.readAccess && node.initialization != null)
 			if (matchesName(this.pattern.name, node.name))
-				referencesLevel = this.pattern.mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH;
+				referencesLevel = ((InternalSearchPattern)this.pattern).mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH;
 
 	int declarationsLevel = IMPOSSIBLE_MATCH;
 	if (this.pattern.findDeclarations)
 		if (matchesName(this.pattern.name, node.name))
 			if (node.declarationSourceStart == getLocalVariable().declarationSourceStart)
-				declarationsLevel = this.pattern.mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH;
+				declarationsLevel = ((InternalSearchPattern)this.pattern).mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH;
 
 	return nodeSet.addMatch(node, referencesLevel >= declarationsLevel ? referencesLevel : declarationsLevel); // use the stronger match
 }
@@ -44,16 +44,20 @@
 }
 protected void matchReportReference(ASTNode reference, IJavaElement element, int accuracy, MatchLocator locator) throws CoreException {
 	if (reference instanceof SingleNameReference) {
-		SearchMatch match = locator.newLocalVariableReferenceMatch(element, accuracy, reference.sourceStart, reference.sourceEnd+1, reference);
+		int offset = reference.sourceStart;
+		SearchMatch match = locator.newLocalVariableReferenceMatch(element, accuracy, offset, reference.sourceEnd-offset+1, reference);
 		locator.report(match);
 	} else if (reference instanceof QualifiedNameReference) {
 		QualifiedNameReference qNameRef = (QualifiedNameReference) reference;
 		long sourcePosition = qNameRef.sourcePositions[0];
-		SearchMatch match = locator.newLocalVariableReferenceMatch(element, accuracy, ((int) (sourcePosition >>> 32)), ((int) sourcePosition)+1, reference);
+		int start = (int) (sourcePosition >>> 32);
+		int end = (int) sourcePosition;
+		SearchMatch match = locator.newLocalVariableReferenceMatch(element, accuracy, start, end-start+1, reference);
 		locator.report(match);
 	} else if (reference instanceof LocalDeclaration) {
 		LocalVariable localVariable = getLocalVariable();
-		SearchMatch match = locator.newLocalVariableReferenceMatch(localVariable, accuracy, localVariable.nameStart, localVariable.nameEnd+1, reference);
+		int offset = localVariable.nameStart;
+		SearchMatch match = locator.newLocalVariableReferenceMatch(localVariable, accuracy, offset, localVariable.nameEnd-offset+1, reference);
 		locator.report(match);
 	}
 }
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 8a2fa5e..c9834c8 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/LocalVariablePattern.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/LocalVariablePattern.java
@@ -18,8 +18,9 @@
 import org.eclipse.jdt.internal.core.LocalVariable;
 import org.eclipse.jdt.internal.core.index.Index;
 import org.eclipse.jdt.internal.core.search.IndexQueryRequestor;
+import org.eclipse.jdt.internal.core.search.indexing.IIndexConstants;
 
-public class LocalVariablePattern extends VariablePattern {
+public class LocalVariablePattern extends VariablePattern implements IIndexConstants {
 	
 LocalVariable localVariable;
 
@@ -52,7 +53,7 @@
 	}
 	buffer.append(this.localVariable.toStringWithAncestors());
 	buffer.append(", "); //$NON-NLS-1$
-	switch(this.matchMode) {
+	switch(getMatchMode()) {
 		case R_EXACT_MATCH : 
 			buffer.append("exact match, "); //$NON-NLS-1$
 			break;
@@ -63,7 +64,7 @@
 			buffer.append("pattern match, "); //$NON-NLS-1$
 			break;
 	}
-	buffer.append(this.isCaseSensitive ? "case sensitive" : "case insensitive"); //$NON-NLS-1$ //$NON-NLS-2$
+	buffer.append(isCaseSensitive() ? "case sensitive" : "case insensitive"); //$NON-NLS-1$ //$NON-NLS-2$
 	return buffer.toString();
 }
 }
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 8abd02a..da7388f 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java
@@ -12,6 +12,8 @@
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
 import java.util.zip.ZipFile;
 
 import org.eclipse.core.resources.IResource;
@@ -36,8 +38,11 @@
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
 import org.eclipse.jdt.internal.core.*;
 import org.eclipse.jdt.internal.core.hierarchy.HierarchyResolver;
+import org.eclipse.jdt.internal.core.index.Index;
+import org.eclipse.jdt.internal.core.search.*;
 import org.eclipse.jdt.internal.core.search.HierarchyScope;
-import org.eclipse.jdt.internal.core.search.pattern.InternalSearchPattern;
+import org.eclipse.jdt.internal.core.search.IndexSelector;
+import org.eclipse.jdt.internal.core.search.JavaSearchDocument;
 import org.eclipse.jdt.internal.core.util.HandleFactory;
 import org.eclipse.jdt.internal.core.util.SimpleSet;
 import org.eclipse.jdt.internal.core.util.Util;
@@ -119,6 +124,18 @@
 	}
 }
 
+public static class WorkingCopyDocument extends JavaSearchDocument {
+	public org.eclipse.jdt.core.ICompilationUnit workingCopy;
+	WorkingCopyDocument(org.eclipse.jdt.core.ICompilationUnit workingCopy, SearchParticipant participant) {
+		super(workingCopy.getPath().toString(), participant);
+		this.charContents = ((CompilationUnit)workingCopy).getContents();
+		this.workingCopy = workingCopy;
+	}
+	public String toString() {
+		return "WorkingCopyDocument for " + getPath(); //$NON-NLS-1$
+	}
+}
+	
 public class WrappedCoreException extends RuntimeException {
 	public CoreException coreException;
 	public WrappedCoreException(CoreException coreException) {
@@ -126,6 +143,66 @@
 	}
 }
 
+public static SearchDocument[] addWorkingCopies(InternalSearchPattern pattern, SearchDocument[] indexMatches, org.eclipse.jdt.core.ICompilationUnit[] copies, SearchParticipant participant) {
+	// working copies take precedence over corresponding compilation units
+	HashMap workingCopyDocuments = workingCopiesThatCanSeeFocus(copies, pattern.focus, pattern.isPolymorphicSearch(), participant);
+	SearchDocument[] matches = null;
+	int length = indexMatches.length;
+	for (int i = 0; i < length; i++) {
+		SearchDocument searchDocument = indexMatches[i];
+		if (searchDocument.getParticipant() == participant) {
+			SearchDocument workingCopyDocument = (SearchDocument) workingCopyDocuments.remove(searchDocument.getPath());
+			if (workingCopyDocument != null) {
+				if (matches == null) {
+					System.arraycopy(indexMatches, 0, matches = new SearchDocument[length], 0, length);
+				}
+				matches[i] = workingCopyDocument;
+			}
+		}
+	}
+	if (matches == null) { // no working copy
+		matches = indexMatches;
+	}
+	int remainingWorkingCopiesSize = workingCopyDocuments.size();
+	if (remainingWorkingCopiesSize != 0) {
+		System.arraycopy(matches, 0, matches = new SearchDocument[length+remainingWorkingCopiesSize], 0, length);
+		Iterator iterator = workingCopyDocuments.values().iterator();
+		int index = length;
+		while (iterator.hasNext()) {
+			matches[index++] = (SearchDocument) iterator.next();
+		}
+	}
+	return matches;
+}
+
+public static void setFocus(InternalSearchPattern pattern, IJavaElement focus) {
+	pattern.focus = focus;
+}
+
+/*
+ * Returns the working copies that can see the given focus.
+ */
+private static HashMap workingCopiesThatCanSeeFocus(org.eclipse.jdt.core.ICompilationUnit[] copies, IJavaElement focus, boolean isPolymorphicSearch, SearchParticipant participant) {
+	if (copies == null) return new HashMap();
+	if (focus != null) {
+		while (!(focus instanceof IJavaProject) && !(focus instanceof JarPackageFragmentRoot)) {
+			focus = focus.getParent();
+		}
+	}
+	HashMap result = new HashMap();
+	for (int i=0, length = copies.length; i<length; i++) {
+		org.eclipse.jdt.core.ICompilationUnit workingCopy = copies[i];
+		IPath projectOrJar = MatchLocator.getProjectOrJar(workingCopy).getPath();
+		if (focus == null || IndexSelector.canSeeFocus(focus, isPolymorphicSearch, projectOrJar)) {
+			result.put(
+				workingCopy.getPath().toString(),
+				new WorkingCopyDocument(workingCopy, participant)
+			);
+		}
+	}
+	return result;
+}
+
 public static ClassFileReader classFileReader(IType type) {
 	IClassFile classFile = type.getClassFile(); 
 	JavaModelManager manager = JavaModelManager.getJavaModelManager();
@@ -163,6 +240,47 @@
 	return null;
 }
 
+public static SearchPattern createAndPattern(final SearchPattern leftPattern, final SearchPattern rightPattern) {
+	return new AndPattern(0/*no kind*/, 0/*no rule*/) {
+		SearchPattern current = leftPattern;
+		public SearchPattern currentPattern() {
+			return current;
+		}
+		protected boolean hasNextQuery() {
+			if (current == leftPattern) {
+				current = rightPattern;
+				return true;
+			}
+			return false; 
+		}
+		protected void resetQuery() {
+			current = leftPattern;
+		}
+	};
+}
+
+/**
+ * Query a given index for matching entries. Assumes the sender has opened the index and will close when finished.
+ */
+public static void findIndexMatches(InternalSearchPattern pattern, Index index, IndexQueryRequestor requestor, SearchParticipant participant, IJavaSearchScope scope, IProgressMonitor monitor) throws IOException {
+	pattern.findIndexMatches(index, requestor, participant, scope, monitor);
+}
+
+public static IJavaElement getProjectOrJar(IJavaElement element) {
+	while (!(element instanceof IJavaProject) && !(element instanceof JarPackageFragmentRoot)) {
+		element = element.getParent();
+	}
+	return element;
+}
+
+public static boolean isPolymorphicSearch(InternalSearchPattern pattern) {
+	return pattern.isPolymorphicSearch();
+}
+
+public static IJavaElement projectOrJarFocus(InternalSearchPattern pattern) {
+	return pattern == null || pattern.focus == null ? null : getProjectOrJar(pattern.focus);
+}
+
 public MatchLocator(
 	SearchPattern pattern,
 	SearchRequestor requestor,
@@ -668,8 +786,8 @@
 	ArrayList copies = new ArrayList();
 	for (int i = 0, length = searchDocuments.length; i < length; i++) {
 		SearchDocument document = searchDocuments[i];
-		if (document instanceof InternalSearchPattern.WorkingCopyDocument) {
-			copies.add(((InternalSearchPattern.WorkingCopyDocument)document).workingCopy);
+		if (document instanceof WorkingCopyDocument) {
+			copies.add(((WorkingCopyDocument)document).workingCopy);
 		}
 	}
 	int copiesLength = copies.size();
@@ -687,7 +805,7 @@
 
 		if (this.progressMonitor != null) {
 			// 1 for file path, 4 for parsing and binding creation, 5 for binding resolution? //$NON-NLS-1$
-			this.progressMonitor.beginTask("", searchDocuments.length * (this.pattern.mustResolve ? 10 : 5)); //$NON-NLS-1$
+			this.progressMonitor.beginTask("", searchDocuments.length * (((InternalSearchPattern)this.pattern).mustResolve ? 10 : 5)); //$NON-NLS-1$
 		}
 
 		// initialize pattern for polymorphic search (ie. method reference pattern)
@@ -711,8 +829,8 @@
 
 			Openable openable;
 			org.eclipse.jdt.core.ICompilationUnit workingCopy = null;
-			if (searchDocument instanceof InternalSearchPattern.WorkingCopyDocument) {
-				workingCopy = ((InternalSearchPattern.WorkingCopyDocument)searchDocument).workingCopy;
+			if (searchDocument instanceof WorkingCopyDocument) {
+				workingCopy = ((WorkingCopyDocument)searchDocument).workingCopy;
 				openable = (Openable) workingCopy;
 			} else {
 				openable = this.handleFactory.createOpenable(pathString, this.scope);
@@ -775,13 +893,13 @@
 		for (int i = 0, length = patterns.length; i < length; i++)
 			locatePackageDeclarations(patterns[i], participant);
 	} else if (searchPattern instanceof PackageDeclarationPattern) {
-		if (searchPattern.focus != null) {
-			IResource resource = searchPattern.focus.getResource();
+		IJavaElement focus = ((InternalSearchPattern) searchPattern).focus;
+		if (focus != null) {
+			IResource resource = focus.getResource();
 			SearchDocument document = participant.getDocument(resource.getFullPath().toString());
 			this.currentPossibleMatch = new PossibleMatch(this, resource, null, document);
-			IJavaElement element = searchPattern.focus;
-			if (encloses(element)) {
-				SearchMatch match = newDeclarationMatch(element, SearchMatch.A_ACCURATE, -1, -1);
+			if (encloses(focus)) {
+				SearchMatch match = newDeclarationMatch(focus, SearchMatch.A_ACCURATE, -1, -1);
 				report(match);
 			}
 			return;
@@ -858,31 +976,31 @@
 public SearchMatch newDeclarationMatch(
 		IJavaElement element,
 		int accuracy,
-		int sourceStart,  
-		int sourceEnd) {
+		int offset,  
+		int length) {
 	SearchParticipant participant = getParticipant(); 
 	IResource resource = this.currentPossibleMatch.resource;
-	return newDeclarationMatch(element, accuracy, sourceStart, sourceEnd, participant, resource);
+	return newDeclarationMatch(element, accuracy, offset, length, participant, resource);
 }
 
 public SearchMatch newDeclarationMatch(
 		IJavaElement element,
 		int accuracy,
-		int sourceStart,  
-		int sourceEnd,
+		int offset,  
+		int length,
 		SearchParticipant participant, 
 		IResource resource) {
 	switch (element.getElementType()) {
 		case IJavaElement.PACKAGE_FRAGMENT:
-			return new PackageDeclarationMatch(element, accuracy, sourceStart, sourceEnd, participant, resource);
+			return new PackageDeclarationMatch(element, accuracy, offset, length, participant, resource);
 		case IJavaElement.TYPE:
-			return new TypeDeclarationMatch(element, accuracy, sourceStart, sourceEnd, participant, resource);
+			return new TypeDeclarationMatch(element, accuracy, offset, length, participant, resource);
 		case IJavaElement.FIELD:
-			return new FieldDeclarationMatch(element, accuracy, sourceStart, sourceEnd, participant, resource);
+			return new FieldDeclarationMatch(element, accuracy, offset, length, participant, resource);
 		case IJavaElement.METHOD:
-			return new MethodDeclarationMatch(element, accuracy, sourceStart, sourceEnd, participant, resource);
+			return new MethodDeclarationMatch(element, accuracy, offset, length, participant, resource);
 		case IJavaElement.LOCAL_VARIABLE:
-			return new LocalVariableDeclarationMatch(element, accuracy, sourceStart, sourceEnd, participant, resource);
+			return new LocalVariableDeclarationMatch(element, accuracy, offset, length, participant, resource);
 		default:
 			return null;
 	}
@@ -891,8 +1009,8 @@
 public SearchMatch newFieldReferenceMatch(
 		IJavaElement enclosingElement,
 		int accuracy,
-		int sourceStart,  
-		int sourceEnd,
+		int offset,  
+		int length,
 		ASTNode reference) {
 	int bits = reference.bits;
 	boolean isCoupoundAssigned = (bits & ASTNode.IsCompoundAssignedMASK) != 0;
@@ -901,53 +1019,53 @@
 	boolean insideDocComment = (reference.bits & ASTNode.InsideJavadoc) != 0;
 	SearchParticipant participant = getParticipant(); 
 	IResource resource = this.currentPossibleMatch.resource;
-	return new FieldReferenceMatch(enclosingElement, accuracy, sourceStart, sourceEnd, isReadAccess, isWriteAccess, insideDocComment, participant, resource);
+	return new FieldReferenceMatch(enclosingElement, accuracy, offset, length, isReadAccess, isWriteAccess, insideDocComment, participant, resource);
 }
 
 public SearchMatch newLocalVariableReferenceMatch(
 		IJavaElement enclosingElement,
 		int accuracy,
-		int sourceStart,  
-		int sourceEnd,
+		int offset,  
+		int length,
 		ASTNode reference) {
 	SearchParticipant participant = getParticipant(); 
 	IResource resource = this.currentPossibleMatch.resource;
-	return new LocalVariableReferenceMatch(enclosingElement, accuracy, sourceStart, sourceEnd, participant, resource);
+	return new LocalVariableReferenceMatch(enclosingElement, accuracy, offset, length, participant, resource);
 }
 
 public SearchMatch newMethodReferenceMatch(
 		IJavaElement enclosingElement,
 		int accuracy,
-		int sourceStart,  
-		int sourceEnd,
+		int offset,  
+		int length,
 		ASTNode reference) {
 	SearchParticipant participant = getParticipant(); 
 	IResource resource = this.currentPossibleMatch.resource;
 	boolean insideDocComment = (reference.bits & ASTNode.InsideJavadoc) != 0;
-	return new MethodReferenceMatch(enclosingElement, accuracy, sourceStart, sourceEnd, insideDocComment, participant, resource);
+	return new MethodReferenceMatch(enclosingElement, accuracy, offset, length, insideDocComment, participant, resource);
 }
 
 public SearchMatch newPackageReferenceMatch(
 		IJavaElement enclosingElement,
 		int accuracy,
-		int sourceStart,  
-		int sourceEnd,
+		int offset,  
+		int length,
 		ASTNode reference) {
 	SearchParticipant participant = getParticipant(); 
 	IResource resource = this.currentPossibleMatch.resource;
-	return new PackageReferenceMatch(enclosingElement, accuracy, sourceStart, sourceEnd, participant, resource);
+	return new PackageReferenceMatch(enclosingElement, accuracy, offset, length, participant, resource);
 }
 
 public SearchMatch newTypeReferenceMatch(
 		IJavaElement enclosingElement,
 		int accuracy,
-		int sourceStart,  
-		int sourceEnd,
+		int offset,  
+		int length,
 		ASTNode reference) {
 	SearchParticipant participant = getParticipant(); 
 	IResource resource = this.currentPossibleMatch.resource;
 	boolean insideDocComment = (reference.bits & ASTNode.InsideJavadoc) != 0;
-	return new TypeReferenceMatch(enclosingElement, accuracy, sourceStart, sourceEnd, insideDocComment, participant, resource);
+	return new TypeReferenceMatch(enclosingElement, accuracy, offset, length, insideDocComment, participant, resource);
 }
 
 /*
@@ -970,7 +1088,7 @@
 
 		getMethodBodies(unit);
 
-		if (bindingsWereCreated && this.pattern.mustResolve && unit.types != null) {
+		if (bindingsWereCreated && ((InternalSearchPattern)this.pattern).mustResolve && unit.types != null) {
 			if (SearchEngine.VERBOSE)
 				System.out.println("Resolving " + this.currentPossibleMatch.openable.toStringWithAncestors()); //$NON-NLS-1$
 
@@ -982,7 +1100,7 @@
 
 			reportMatching(unit, true);
 		} else {
-			reportMatching(unit, this.pattern.mustResolve);
+			reportMatching(unit, ((InternalSearchPattern)this.pattern).mustResolve);
 		}
 	} catch (AbortCompilation e) {
 		// could not resolve: report innacurate matches
@@ -1078,12 +1196,13 @@
 			// ignore
 		}
 		if (token == TerminalTokens.TokenNameIdentifier && this.pattern.matchesName(name, scanner.getCurrentTokenSource())) {
-			SearchMatch match = newTypeReferenceMatch(element, accuracy, currentPosition, scanner.currentPosition, typeRef);
+			int length = scanner.currentPosition-currentPosition;
+			SearchMatch match = newTypeReferenceMatch(element, accuracy, currentPosition, length, typeRef);
 			report(match);
 			return;
 		}
 	} while (token != TerminalTokens.TokenNameEOF);
-	SearchMatch match = newTypeReferenceMatch(element, accuracy, sourceStart, sourceEnd+1, typeRef);
+	SearchMatch match = newTypeReferenceMatch(element, accuracy, sourceStart, sourceEnd-sourceStart+1, typeRef);
 	report(match);
 }
 /**
@@ -1141,10 +1260,10 @@
 		if (accuracies[accuracyIndex] != -1) {
 			// accept reference
 			if (refSourceStart != -1) {
-				SearchMatch match = newFieldReferenceMatch(element, accuracies[accuracyIndex], refSourceStart, refSourceEnd+1, qNameRef);
+				SearchMatch match = newFieldReferenceMatch(element, accuracies[accuracyIndex], refSourceStart, refSourceEnd-refSourceStart+1, qNameRef);
 				report(match);
 			} else {
-				SearchMatch match = newFieldReferenceMatch(element, accuracies[accuracyIndex], sourceStart, sourceEnd+1, qNameRef);
+				SearchMatch match = newFieldReferenceMatch(element, accuracies[accuracyIndex], sourceStart, sourceEnd-sourceStart+1, qNameRef);
 				report(match);
 			}
 			i = 0;
@@ -1171,10 +1290,8 @@
 			}
 		}
 	}
-	int startIndex = range.getOffset();
-	int endIndex = startIndex + range.getLength();
 	if (resource == null) resource =  this.currentPossibleMatch.resource;
-	SearchMatch match = newDeclarationMatch(binaryMember, accuracy, startIndex, endIndex, getParticipant(), resource);
+	SearchMatch match = newDeclarationMatch(binaryMember, accuracy, range.getOffset(), range.getLength(), getParticipant(), resource);
 	report(match);
 }
 /**
@@ -1197,9 +1314,9 @@
 			} catch (InvalidInputException e) {
 				// ignore
 			}
-			int nameSourceEnd = scanner.currentPosition - 1;
 			if (encloses(enclosingElement)) {
-				SearchMatch match = newDeclarationMatch(enclosingElement, accuracy, nameSourceStart, nameSourceEnd+1);
+				int length = scanner.currentPosition - nameSourceStart;
+				SearchMatch match = newDeclarationMatch(enclosingElement, accuracy, nameSourceStart, length);
 				report(match);
 			}
 		}
@@ -1306,7 +1423,8 @@
 	if (accuracy > -1) {
 		enclosingElement = createHandle(field, type, parent);
 		if (encloses(enclosingElement)) {
-			SearchMatch match = newDeclarationMatch(enclosingElement, accuracy, field.sourceStart, field.sourceEnd+1);
+			int offset = field.sourceStart;
+			SearchMatch match = newDeclarationMatch(enclosingElement, accuracy, offset, field.sourceEnd-offset+1);
 			report(match);
 		}
 	}
@@ -1364,7 +1482,8 @@
 
 	// report the type declaration
 	if (accuracy > -1 && encloses(enclosingElement)) {
-		SearchMatch match = newDeclarationMatch(enclosingElement, accuracy, type.sourceStart, type.sourceEnd+1);
+		int offset = type.sourceStart;
+		SearchMatch match = newDeclarationMatch(enclosingElement, accuracy, offset, type.sourceEnd-offset+1);
 		report(match);
 	}
 
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 1c02c31..0943f27 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java
@@ -75,7 +75,7 @@
 	}
 	if (!matchesTypeReference(this.pattern.returnSimpleName, node.returnType)) return IMPOSSIBLE_MATCH;
 
-	return nodeSet.addMatch(node, this.pattern.mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
+	return nodeSet.addMatch(node, ((InternalSearchPattern)this.pattern).mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
 }
 public int match(MessageSend node, MatchingNodeSet nodeSet) {
 	if (!this.pattern.findReferences) return IMPOSSIBLE_MATCH;
@@ -88,7 +88,7 @@
 		if (length != argsLength) return IMPOSSIBLE_MATCH;
 	}
 
-	return nodeSet.addMatch(node, this.pattern.mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
+	return nodeSet.addMatch(node, ((InternalSearchPattern)this.pattern).mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
 }
 //public int match(Reference node, MatchingNodeSet nodeSet) - SKIP IT
 //public int match(TypeDeclaration node, MatchingNodeSet nodeSet) - SKIP IT
@@ -144,11 +144,12 @@
 		if (element != null)
 			reportDeclaration(((MessageSend) reference).binding, locator, declPattern.knownMethods);
 	} else if (this.pattern.findReferences && reference instanceof MessageSend) {
-		int sourceStart = (int) (((MessageSend) reference).nameSourcePosition >>> 32);
-		SearchMatch match = locator.newMethodReferenceMatch(element, accuracy, sourceStart, reference.sourceEnd+1, reference);
+		int offset = (int) (((MessageSend) reference).nameSourcePosition >>> 32);
+		SearchMatch match = locator.newMethodReferenceMatch(element, accuracy, offset, reference.sourceEnd-offset+1, reference);
 		locator.report(match);
 	} else {
-		SearchMatch match = locator.newMethodReferenceMatch(element, accuracy, reference.sourceStart, reference.sourceEnd+1, reference);
+		int offset = reference.sourceStart;
+		SearchMatch match = locator.newMethodReferenceMatch(element, accuracy, offset, reference.sourceEnd-offset+1, reference);
 		locator.report(match);
 	}
 }
@@ -191,7 +192,8 @@
 				}
 			} 
 			if (methodDecl != null) {
-				SearchMatch match = new MethodDeclarationMatch(method, SearchMatch.A_ACCURATE, methodDecl.sourceStart, methodDecl.sourceEnd+1, locator.getParticipant(), resource);
+				int offset = methodDecl.sourceStart;
+				SearchMatch match = new MethodDeclarationMatch(method, SearchMatch.A_ACCURATE, offset, methodDecl.sourceEnd-offset+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 f307c63..86f0409 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/MethodPattern.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/MethodPattern.java
@@ -16,8 +16,9 @@
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.search.SearchPattern;
 import org.eclipse.jdt.internal.core.index.*;
+import org.eclipse.jdt.internal.core.search.indexing.IIndexConstants;
 
-public class MethodPattern extends SearchPattern {
+public class MethodPattern extends SearchPattern implements IIndexConstants {
 
 protected boolean findDeclarations;
 protected boolean findReferences;
@@ -70,25 +71,25 @@
 	this.findDeclarations = findDeclarations;
 	this.findReferences = findReferences;
 
-	this.selector = this.isCaseSensitive ? selector : CharOperation.toLowerCase(selector);
-	this.declaringQualification = this.isCaseSensitive ? declaringQualification : CharOperation.toLowerCase(declaringQualification);
-	this.declaringSimpleName = this.isCaseSensitive ? declaringSimpleName : CharOperation.toLowerCase(declaringSimpleName);
-	this.returnQualification = this.isCaseSensitive ? returnQualification : CharOperation.toLowerCase(returnQualification);
-	this.returnSimpleName = this.isCaseSensitive ? returnSimpleName : CharOperation.toLowerCase(returnSimpleName);
+	this.selector = isCaseSensitive() ? selector : CharOperation.toLowerCase(selector);
+	this.declaringQualification = isCaseSensitive() ? declaringQualification : CharOperation.toLowerCase(declaringQualification);
+	this.declaringSimpleName = isCaseSensitive() ? declaringSimpleName : CharOperation.toLowerCase(declaringSimpleName);
+	this.returnQualification = isCaseSensitive() ? returnQualification : CharOperation.toLowerCase(returnQualification);
+	this.returnSimpleName = isCaseSensitive() ? returnSimpleName : CharOperation.toLowerCase(returnSimpleName);
 	if (parameterSimpleNames != null) {
 		this.parameterCount = parameterSimpleNames.length;
 		this.parameterQualifications = new char[this.parameterCount][];
 		this.parameterSimpleNames = new char[this.parameterCount][];
 		for (int i = 0; i < this.parameterCount; i++) {
-			this.parameterQualifications[i] = this.isCaseSensitive ? parameterQualifications[i] : CharOperation.toLowerCase(parameterQualifications[i]);
-			this.parameterSimpleNames[i] = this.isCaseSensitive ? parameterSimpleNames[i] : CharOperation.toLowerCase(parameterSimpleNames[i]);
+			this.parameterQualifications[i] = isCaseSensitive() ? parameterQualifications[i] : CharOperation.toLowerCase(parameterQualifications[i]);
+			this.parameterSimpleNames[i] = isCaseSensitive() ? parameterSimpleNames[i] : CharOperation.toLowerCase(parameterSimpleNames[i]);
 		}
 	} else {
 		this.parameterCount = -1;
 	}
 
 	this.declaringType = declaringType;
-	this.mustResolve = mustResolve();
+	((InternalSearchPattern)this).mustResolve = mustResolve();
 }
 MethodPattern(int matchRule) {
 	super(METHOD_PATTERN, matchRule);
@@ -110,7 +111,7 @@
 		return DECL_CATEGORIES;
 	return CharOperation.NO_CHAR_CHAR;
 }
-public boolean isPolymorphicSearch() {
+boolean isPolymorphicSearch() {
 	return this.findReferences;
 }
 public boolean matchesDecodedKey(SearchPattern decodedPattern) {
@@ -138,11 +139,11 @@
 			if (parameterQualifications[i] != null) return true;
 	return false;
 }
-public EntryResult[] queryIn(Index index) throws IOException {
+EntryResult[] queryIn(Index index) throws IOException {
 	char[] key = this.selector; // can be null
 	int matchRule = getMatchRule();
 
-	switch(this.matchMode) {
+	switch(getMatchMode()) {
 		case R_EXACT_MATCH :
 			if (this.selector != null && this.parameterCount >= 0)
 				key = createIndexKey(this.selector, this.parameterCount);
@@ -203,7 +204,7 @@
 	else if (returnQualification != null)
 		buffer.append("*"); //$NON-NLS-1$
 	buffer.append(", "); //$NON-NLS-1$
-	switch(this.matchMode) {
+	switch(getMatchMode()) {
 		case R_EXACT_MATCH : 
 			buffer.append("exact match, "); //$NON-NLS-1$
 			break;
@@ -214,7 +215,7 @@
 			buffer.append("pattern match, "); //$NON-NLS-1$
 			break;
 	}
-	buffer.append(this.isCaseSensitive ? "case sensitive" : "case insensitive"); //$NON-NLS-1$ //$NON-NLS-2$
+	buffer.append(isCaseSensitive() ? "case sensitive" : "case insensitive"); //$NON-NLS-1$ //$NON-NLS-2$
 	return buffer.toString();
 }
 }
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 db5b279..0902138 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/OrPattern.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/OrPattern.java
@@ -16,14 +16,15 @@
 import org.eclipse.jdt.core.search.*;
 import org.eclipse.jdt.internal.core.index.Index;
 import org.eclipse.jdt.internal.core.search.IndexQueryRequestor;
+import org.eclipse.jdt.internal.core.search.indexing.IIndexConstants;
 
-public class OrPattern extends SearchPattern {
+public class OrPattern extends SearchPattern implements IIndexConstants {
 
 protected SearchPattern[] patterns;
 
 public OrPattern(SearchPattern leftPattern, SearchPattern rightPattern) {
 	super(OR_PATTERN, Math.max(leftPattern.getMatchRule(), rightPattern.getMatchRule()));
-	this.mustResolve = leftPattern.mustResolve || rightPattern.mustResolve;
+	((InternalSearchPattern)this).mustResolve = ((InternalSearchPattern) leftPattern).mustResolve || ((InternalSearchPattern) rightPattern).mustResolve;
 
 	SearchPattern[] leftPatterns = leftPattern instanceof OrPattern ? ((OrPattern) leftPattern).patterns : null;
 	SearchPattern[] rightPatterns = rightPattern instanceof OrPattern ? ((OrPattern) rightPattern).patterns : null;
@@ -40,19 +41,19 @@
 	else
 		System.arraycopy(rightPatterns, 0, this.patterns, leftSize, rightSize);
 }
-public void findIndexMatches(Index index, IndexQueryRequestor requestor, SearchParticipant participant, IJavaSearchScope scope, IProgressMonitor progressMonitor) throws IOException {
+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)
 	try {
 		index.startQuery();
 		for (int i = 0, length = this.patterns.length; i < length; i++)
-			this.patterns[i].findIndexMatches(index, requestor, participant, scope, progressMonitor);
+			((InternalSearchPattern)this.patterns[i]).findIndexMatches(index, requestor, participant, scope, progressMonitor);
 	} finally {
 		index.stopQuery();
 	}
 }
-public boolean isPolymorphicSearch() {
+boolean isPolymorphicSearch() {
 	for (int i = 0, length = this.patterns.length; i < length; i++)
-		if (this.patterns[i].isPolymorphicSearch()) return true;
+		if (((InternalSearchPattern) this.patterns[i]).isPolymorphicSearch()) return true;
 	return false;
 }
 public String toString() {
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 ddb1fd9..3f77a3a 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/PackageDeclarationPattern.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/PackageDeclarationPattern.java
@@ -12,8 +12,9 @@
 
 import org.eclipse.jdt.core.search.*;
 import org.eclipse.jdt.internal.core.index.*;
+import org.eclipse.jdt.internal.core.search.indexing.IIndexConstants;
 
-public class PackageDeclarationPattern extends SearchPattern {
+public class PackageDeclarationPattern extends SearchPattern implements IIndexConstants {
 
 protected char[] pkgName;
 
@@ -21,7 +22,7 @@
 	super(PKG_DECL_PATTERN, matchRule);
 	this.pkgName = pkgName;
 }
-public EntryResult[] queryIn(Index index) {
+EntryResult[] queryIn(Index index) {
 	// package declarations are not indexed
 	return null;
 }
@@ -33,7 +34,7 @@
 	else
 		buffer.append("*"); //$NON-NLS-1$
 	buffer.append(">, "); //$NON-NLS-1$
-	switch(this.matchMode) {
+	switch(getMatchMode()) {
 		case R_EXACT_MATCH : 
 			buffer.append("exact match, "); //$NON-NLS-1$
 			break;
@@ -44,7 +45,7 @@
 			buffer.append("pattern match, "); //$NON-NLS-1$
 			break;
 	}
-	if (this.isCaseSensitive)
+	if (isCaseSensitive())
 		buffer.append("case sensitive"); //$NON-NLS-1$
 	else
 		buffer.append("case insensitive"); //$NON-NLS-1$
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 bd1b9a7..23a97d8 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/PackageReferenceLocator.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/PackageReferenceLocator.java
@@ -128,7 +128,9 @@
 				if (pkgBinding != null)
 					last = pkgBinding.compoundName.length;
 			}
-			SearchMatch match = locator.newPackageReferenceMatch(element, accuracy, ((int) (positions[0] >>> 32)), ((int) positions[last - 1])+1, importRef);
+			int start = (int) (positions[0] >>> 32);
+			int end = (int) positions[last - 1];
+			SearchMatch match = locator.newPackageReferenceMatch(element, accuracy, start, end-start+1, importRef);
 			locator.report(match);
 		}
 	}
@@ -188,8 +190,8 @@
 		if (last > positions.length) last = positions.length;
 	}
 	int sourceStart = (int) (positions[0] >>> 32);
-	int sourceEnd = ((int) positions[last - 1])+1;
-	SearchMatch match = locator.newPackageReferenceMatch(element, accuracy, sourceStart, sourceEnd, reference);
+	int sourceEnd = ((int) positions[last - 1]);
+	SearchMatch match = locator.newPackageReferenceMatch(element, accuracy, sourceStart, sourceEnd-sourceStart+1, reference);
 	locator.report(match);
 }
 protected int referenceType() {
@@ -223,9 +225,9 @@
 		}
 	}
 	if (compoundName != null && matchesName(this.pattern.pkgName, CharOperation.concatWith(compoundName, '.'))) {
-		if (this.pattern.focus instanceof IPackageFragment && binding instanceof ReferenceBinding) {
+		if (((InternalSearchPattern) this.pattern).focus instanceof IPackageFragment && binding instanceof ReferenceBinding) {
 			// check that type is located inside this instance of a package fragment
-			if (!isDeclaringPackageFragment((IPackageFragment)this.pattern.focus, (ReferenceBinding)binding)) return IMPOSSIBLE_MATCH;
+			if (!isDeclaringPackageFragment((IPackageFragment)((InternalSearchPattern) this.pattern).focus, (ReferenceBinding)binding)) return IMPOSSIBLE_MATCH;
 		}				
 		return ACCURATE_MATCH;
 	} else {
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 81200c7..4c89362 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/PackageReferencePattern.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/PackageReferencePattern.java
@@ -12,8 +12,9 @@
 
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.search.SearchPattern;
+import org.eclipse.jdt.internal.core.search.indexing.IIndexConstants;
 
-public class PackageReferencePattern extends AndPattern {
+public class PackageReferencePattern extends AndPattern implements IIndexConstants {
 
 protected char[] pkgName;
 
@@ -28,11 +29,11 @@
 	if (pkgName == null || pkgName.length == 0) {
 		this.pkgName = null;
 		this.segments = new char[][] {CharOperation.NO_CHAR};
-		this.mustResolve = false;
+		((InternalSearchPattern)this).mustResolve = false;
 	} else {
-		this.pkgName = this.isCaseSensitive ? pkgName : CharOperation.toLowerCase(pkgName);
+		this.pkgName = isCaseSensitive() ? pkgName : CharOperation.toLowerCase(pkgName);
 		this.segments = CharOperation.splitOn('.', this.pkgName);
-		this.mustResolve = true;
+		((InternalSearchPattern)this).mustResolve = true;
 	}
 }
 PackageReferencePattern(int matchRule) {
@@ -48,7 +49,7 @@
 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 encodeIndexKey(this.segments[this.currentSegment], getMatchMode());
 	return null;
 }
 public char[][] getMatchCategories() {
@@ -74,7 +75,7 @@
 	else
 		buffer.append("*"); //$NON-NLS-1$
 	buffer.append(">, "); //$NON-NLS-1$
-	switch(this.matchMode) {
+	switch(getMatchMode()) {
 		case R_EXACT_MATCH : 
 			buffer.append("exact match, "); //$NON-NLS-1$
 			break;
@@ -87,7 +88,7 @@
 		case R_REGEXP_MATCH :
 			buffer.append("regexp match, "); //$NON-NLS-1$
 	}
-	if (this.isCaseSensitive)
+	if (isCaseSensitive())
 		buffer.append("case sensitive"); //$NON-NLS-1$
 	else
 		buffer.append("case insensitive"); //$NON-NLS-1$
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 b21bef7..8c59ba6 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/PatternLocator.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/PatternLocator.java
@@ -38,7 +38,7 @@
 	COMPILATION_UNIT_CONTAINER | CLASS_CONTAINER | METHOD_CONTAINER | FIELD_CONTAINER;
 
 public static PatternLocator patternLocator(SearchPattern pattern) {
-	switch (pattern.kind) {
+	switch (((InternalSearchPattern)pattern).kind) {
 		case IIndexConstants.PKG_REF_PATTERN :
 			return new PackageReferenceLocator((PackageReferencePattern) pattern);
 		case IIndexConstants.PKG_DECL_PATTERN :
@@ -86,8 +86,8 @@
 
 
 public PatternLocator(SearchPattern pattern) {
-	this.matchMode = pattern.matchMode;
-	this.isCaseSensitive = pattern.isCaseSensitive;
+	this.matchMode = pattern.getMatchMode();
+	this.isCaseSensitive = pattern.isCaseSensitive();
 }
 /**
  * Initializes this search pattern so that polymorphic search can be performed.
@@ -228,21 +228,22 @@
 protected void matchReportReference(ASTNode reference, IJavaElement element, int accuracy, MatchLocator locator) throws CoreException {
 	SearchMatch match = null;
 	int referenceType = referenceType();
+	int offset = reference.sourceStart;
 	switch (referenceType) {
 		case IJavaElement.PACKAGE_FRAGMENT:
-			match = locator.newPackageReferenceMatch(element, accuracy, reference.sourceStart, reference.sourceEnd+1, reference);
+			match = locator.newPackageReferenceMatch(element, accuracy, offset, reference.sourceEnd-offset+1, reference);
 			break;
 		case IJavaElement.TYPE:
-			match = locator.newTypeReferenceMatch(element, accuracy, reference.sourceStart, reference.sourceEnd+1, reference);
+			match = locator.newTypeReferenceMatch(element, accuracy, offset, reference.sourceEnd-offset+1, reference);
 			break;
 		case IJavaElement.FIELD:
-			match = locator.newFieldReferenceMatch(element, accuracy, reference.sourceStart, reference.sourceEnd+1, reference);
+			match = locator.newFieldReferenceMatch(element, accuracy, offset, reference.sourceEnd-offset+1, reference);
 			break;
 		case IJavaElement.METHOD:
-			match = locator.newMethodReferenceMatch(element, accuracy, reference.sourceStart, reference.sourceEnd+1, reference);
+			match = locator.newMethodReferenceMatch(element, accuracy, offset, reference.sourceEnd-offset+1, reference);
 			break;
 		case IJavaElement.LOCAL_VARIABLE:
-			match = locator.newLocalVariableReferenceMatch(element, accuracy, reference.sourceStart, reference.sourceEnd+1, reference);
+			match = locator.newLocalVariableReferenceMatch(element, accuracy, offset, reference.sourceEnd-offset+1, reference);
 			break;
 	}
 	if (match != null) {
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 d40bfd8..c807f27 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/QualifiedTypeDeclarationPattern.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/QualifiedTypeDeclarationPattern.java
@@ -12,19 +12,20 @@
 
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.internal.core.search.indexing.IIndexConstants;
 
-public class QualifiedTypeDeclarationPattern extends TypeDeclarationPattern {
+public class QualifiedTypeDeclarationPattern extends TypeDeclarationPattern implements IIndexConstants {
 
 protected char[] qualification;
 
 public QualifiedTypeDeclarationPattern(char[] qualification, char[] simpleName, char classOrInterface, int matchRule) {
 	this(matchRule);
 
-	this.qualification = this.isCaseSensitive ? qualification : CharOperation.toLowerCase(qualification);
-	this.simpleName = this.isCaseSensitive ? simpleName : CharOperation.toLowerCase(simpleName);
+	this.qualification = isCaseSensitive() ? qualification : CharOperation.toLowerCase(qualification);
+	this.simpleName = isCaseSensitive() ? simpleName : CharOperation.toLowerCase(simpleName);
 	this.classOrInterface = classOrInterface;
 
-	this.mustResolve = this.qualification != null;
+	((InternalSearchPattern)this).mustResolve = this.qualification != null;
 }
 QualifiedTypeDeclarationPattern(int matchRule) {
 	super(matchRule);
@@ -83,7 +84,7 @@
 	else
 		buffer.append("*"); //$NON-NLS-1$
 	buffer.append(">, "); //$NON-NLS-1$
-	switch(this.matchMode) {
+	switch(getMatchMode()) {
 		case R_EXACT_MATCH : 
 			buffer.append("exact match, "); //$NON-NLS-1$
 			break;
@@ -94,7 +95,7 @@
 			buffer.append("pattern match, "); //$NON-NLS-1$
 			break;
 	}
-	if (this.isCaseSensitive)
+	if (isCaseSensitive())
 		buffer.append("case sensitive"); //$NON-NLS-1$
 	else
 		buffer.append("case insensitive"); //$NON-NLS-1$
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 82a247e..3f8b2dd 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeReferenceLocator.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeReferenceLocator.java
@@ -33,7 +33,7 @@
 //public int match(TypeDeclaration node, MatchingNodeSet nodeSet) - SKIP IT
 public int match(TypeReference node, MatchingNodeSet nodeSet) {
 	if (this.pattern.superSimpleName == null)
-		return nodeSet.addMatch(node, this.pattern.mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
+		return nodeSet.addMatch(node, ((InternalSearchPattern)this.pattern).mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
 
 	char[] typeRefSimpleName = null;
 	if (node instanceof SingleTypeReference) {
@@ -43,7 +43,7 @@
 		typeRefSimpleName = tokens[tokens.length-1];
 	}				
 	if (matchesName(this.pattern.superSimpleName, typeRefSimpleName))
-		return nodeSet.addMatch(node, this.pattern.mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
+		return nodeSet.addMatch(node, ((InternalSearchPattern)this.pattern).mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
 
 	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 599a265..2f889ea 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeReferencePattern.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeReferencePattern.java
@@ -17,7 +17,7 @@
 import org.eclipse.jdt.internal.core.search.indexing.IIndexConstants;
 import org.eclipse.jdt.internal.core.index.*;
 
-public class SuperTypeReferencePattern extends SearchPattern {
+public class SuperTypeReferencePattern extends SearchPattern implements IIndexConstants {
 
 public char[] superQualification;
 public char[] superSimpleName;
@@ -120,9 +120,9 @@
 
 	this(matchRule);
 
-	this.superQualification = this.isCaseSensitive ? superQualification : CharOperation.toLowerCase(superQualification);
-	this.superSimpleName = this.isCaseSensitive ? superSimpleName : CharOperation.toLowerCase(superSimpleName);
-	this.mustResolve = superQualification != null;
+	this.superQualification = isCaseSensitive() ? superQualification : CharOperation.toLowerCase(superQualification);
+	this.superSimpleName = isCaseSensitive() ? superSimpleName : CharOperation.toLowerCase(superSimpleName);
+	((InternalSearchPattern)this).mustResolve = superQualification != null;
 	this.checkOnlySuperinterfaces = checkOnlySuperinterfaces; // ie. skip the superclass
 }
 SuperTypeReferencePattern(int matchRule) {
@@ -179,12 +179,12 @@
 
 	return matchesName(this.superSimpleName, pattern.superSimpleName);
 }
-public EntryResult[] queryIn(Index index) throws IOException {
+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) {
+	switch(getMatchMode()) {
 		case R_EXACT_MATCH :
 			// do a prefix query with the superSimpleName
 			matchRule = matchRule - R_EXACT_MATCH + R_PREFIX_MATCH;
@@ -212,7 +212,7 @@
 	else
 		buffer.append("*"); //$NON-NLS-1$
 	buffer.append(">, "); //$NON-NLS-1$
-	switch(this.matchMode) {
+	switch(getMatchMode()) {
 		case R_EXACT_MATCH : 
 			buffer.append("exact match, "); //$NON-NLS-1$
 			break;
@@ -223,7 +223,7 @@
 			buffer.append("pattern match, "); //$NON-NLS-1$
 			break;
 	}
-	if (this.isCaseSensitive)
+	if (isCaseSensitive())
 		buffer.append("case sensitive"); //$NON-NLS-1$
 	else
 		buffer.append("case insensitive"); //$NON-NLS-1$
diff --git a/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationLocator.java b/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationLocator.java
index 430f06a..58ee864 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationLocator.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationLocator.java
@@ -33,7 +33,7 @@
 //public int match(Reference node, MatchingNodeSet nodeSet) - SKIP IT
 public int match(TypeDeclaration node, MatchingNodeSet nodeSet) {
 	if (this.pattern.simpleName == null || matchesName(this.pattern.simpleName, node.name))
-		return nodeSet.addMatch(node, this.pattern.mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
+		return nodeSet.addMatch(node, ((InternalSearchPattern)this.pattern).mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
 
 	return IMPOSSIBLE_MATCH;
 }
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 343ce72..e884d0c 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationPattern.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationPattern.java
@@ -15,8 +15,9 @@
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.search.SearchPattern;
 import org.eclipse.jdt.internal.core.index.*;
+import org.eclipse.jdt.internal.core.search.indexing.IIndexConstants;
 
-public class TypeDeclarationPattern extends SearchPattern {
+public class TypeDeclarationPattern extends SearchPattern implements IIndexConstants {
 
 public char[] simpleName;
 public char[] pkg;
@@ -77,8 +78,8 @@
 
 	this(matchRule);
 
-	this.pkg = this.isCaseSensitive ? pkg : CharOperation.toLowerCase(pkg);
-	if (this.isCaseSensitive || enclosingTypeNames == null) {
+	this.pkg = isCaseSensitive() ? pkg : CharOperation.toLowerCase(pkg);
+	if (isCaseSensitive() || enclosingTypeNames == null) {
 		this.enclosingTypeNames = enclosingTypeNames;
 	} else {
 		int length = enclosingTypeNames.length;
@@ -86,10 +87,10 @@
 		for (int i = 0; i < length; i++)
 			this.enclosingTypeNames[i] = CharOperation.toLowerCase(enclosingTypeNames[i]);
 	}
-	this.simpleName = this.isCaseSensitive ? simpleName : CharOperation.toLowerCase(simpleName);
+	this.simpleName = isCaseSensitive() ? simpleName : CharOperation.toLowerCase(simpleName);
 	this.classOrInterface = classOrInterface;
 
-	this.mustResolve = this.pkg != null && this.enclosingTypeNames != null;
+	((InternalSearchPattern)this).mustResolve = this.pkg != null && this.enclosingTypeNames != null;
 }
 TypeDeclarationPattern(int matchRule) {
 	super(TYPE_DECL_PATTERN, matchRule);
@@ -136,7 +137,7 @@
 		return false;
 
 	// check package - exact match only
-	if (this.pkg != null && !CharOperation.equals(this.pkg, pattern.pkg, this.isCaseSensitive))
+	if (this.pkg != null && !CharOperation.equals(this.pkg, pattern.pkg, isCaseSensitive()))
 		return false;
 
 	// check enclosingTypeNames - exact match only
@@ -144,18 +145,18 @@
 		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);
+			return CharOperation.equals(this.enclosingTypeNames[0], pattern.enclosingTypeNames[0], 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 CharOperation.equals(this.enclosingTypeNames, pattern.enclosingTypeNames, isCaseSensitive());
 	}
 	return true;
 }
-public EntryResult[] queryIn(Index index) throws IOException {
+EntryResult[] queryIn(Index index) throws IOException {
 	char[] key = this.simpleName; // can be null
 	int matchRule = getMatchRule();
 
-	switch(this.matchMode) {
+	switch(getMatchMode()) {
 		case R_PREFIX_MATCH :
 			// do a prefix query with the simpleName
 			break;
@@ -220,7 +221,7 @@
 	else
 		buffer.append("*"); //$NON-NLS-1$
 	buffer.append(">, "); //$NON-NLS-1$
-	switch(this.matchMode){
+	switch(getMatchMode()){
 		case R_EXACT_MATCH : 
 			buffer.append("exact match, "); //$NON-NLS-1$
 			break;
@@ -231,7 +232,7 @@
 			buffer.append("pattern match, "); //$NON-NLS-1$
 			break;
 	}
-	if (this.isCaseSensitive)
+	if (isCaseSensitive())
 		buffer.append("case sensitive"); //$NON-NLS-1$
 	else
 		buffer.append("case insensitive"); //$NON-NLS-1$
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 0eb9bce..de89e5a 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/TypeReferenceLocator.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/TypeReferenceLocator.java
@@ -55,7 +55,7 @@
 	if (!(node instanceof NameReference)) return IMPOSSIBLE_MATCH;
 
 	if (this.pattern.simpleName == null)
-		return nodeSet.addMatch(node, this.pattern.mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
+		return nodeSet.addMatch(node, ((InternalSearchPattern)this.pattern).mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
 
 	if (node instanceof SingleNameReference) {
 		if (matchesName(this.pattern.simpleName, ((SingleNameReference) node).token))
@@ -72,11 +72,11 @@
 //public int match(TypeDeclaration node, MatchingNodeSet nodeSet) - SKIP IT
 public int match(TypeReference node, MatchingNodeSet nodeSet) {
 	if (this.pattern.simpleName == null)
-		return nodeSet.addMatch(node, this.pattern.mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
+		return nodeSet.addMatch(node, ((InternalSearchPattern)this.pattern).mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
 
 	if (node instanceof SingleTypeReference) {
 		if (matchesName(this.pattern.simpleName, ((SingleTypeReference) node).token))
-			return nodeSet.addMatch(node, this.pattern.mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
+			return nodeSet.addMatch(node, ((InternalSearchPattern)this.pattern).mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
 	} else {
 		char[][] tokens = ((QualifiedTypeReference) node).tokens;
 		for (int i = 0, max = tokens.length; i < max; i++)
@@ -137,7 +137,9 @@
 			if (resolveLevelForType(this.pattern.simpleName, this.pattern.qualification, typeBinding) == ACCURATE_MATCH) {
 				if (locator.encloses(element)) {
 					long[] positions = importRef.sourcePositions;
-					SearchMatch match = locator.newTypeReferenceMatch(element, accuracy, ((int) ((positions[this.pattern.qualification == null ? lastIndex : 0]) >>> 32)), ((int) positions[lastIndex])+1, importRef);
+					int start = (int) ((positions[this.pattern.qualification == null ? lastIndex : 0]) >>> 32);
+					int end = (int) positions[lastIndex];
+					SearchMatch match = locator.newTypeReferenceMatch(element, accuracy, start, end-start+1, importRef);
 					locator.report(match);
 				}
 				return;
@@ -151,7 +153,8 @@
 protected void matchReportReference(ArrayTypeReference arrayRef, IJavaElement element, int accuracy, MatchLocator locator) throws CoreException {
 	if (this.pattern.simpleName == null) {
 		if (locator.encloses(element)) {
-			SearchMatch match = locator.newTypeReferenceMatch(element, accuracy, arrayRef.sourceStart, arrayRef.sourceEnd+1, arrayRef);
+			int offset = arrayRef.sourceStart;
+			SearchMatch match = locator.newTypeReferenceMatch(element, accuracy, offset, arrayRef.sourceEnd-offset+1, arrayRef);
 			locator.report(match);
 		}
 	} else
@@ -171,7 +174,8 @@
 	else if (reference instanceof ArrayTypeReference)
 		matchReportReference((ArrayTypeReference) reference, element, accuracy, locator);
 	else {
-		SearchMatch match = locator.newTypeReferenceMatch(element, accuracy, reference.sourceStart, reference.sourceEnd+1, reference);
+		int offset = reference.sourceStart;
+		SearchMatch match = locator.newTypeReferenceMatch(element, accuracy, offset, reference.sourceEnd-offset+1, reference);
 		locator.report(match);
 	}
 }
@@ -212,7 +216,9 @@
 			if (resolveLevelForType(this.pattern.simpleName, this.pattern.qualification, refBinding) == ACCURATE_MATCH) {
 				if (locator.encloses(element)) {
 					long[] positions = qNameRef.sourcePositions;
-					SearchMatch match = locator.newTypeReferenceMatch(element, accuracy, ((int) ((positions[this.pattern.qualification == null ? lastIndex : 0]) >>> 32)), ((int) positions[lastIndex])+1, qNameRef);
+					int start = (int) ((positions[this.pattern.qualification == null ? lastIndex : 0]) >>> 32);
+					int end = (int) positions[lastIndex];
+					SearchMatch match = locator.newTypeReferenceMatch(element, accuracy, start, end-start+1, qNameRef);
 					locator.report(match);
 				}
 				return;
@@ -240,7 +246,9 @@
 			if (resolveLevelForType(this.pattern.simpleName, this.pattern.qualification, refBinding) == ACCURATE_MATCH) {
 				if (locator.encloses(element)) {
 					long[] positions = qTypeRef.sourcePositions;
-					SearchMatch match = locator.newTypeReferenceMatch(element, accuracy, ((int) ((positions[this.pattern.qualification == null ? lastIndex : 0]) >>> 32)), ((int) positions[lastIndex])+1, qTypeRef);
+					int start = (int) ((positions[this.pattern.qualification == null ? lastIndex : 0]) >>> 32);
+					int end = (int) positions[lastIndex];
+					SearchMatch match = locator.newTypeReferenceMatch(element, accuracy, start, end-start+1, qTypeRef);
 					locator.report(match);
 				}
 				return;
@@ -319,7 +327,8 @@
 				ClassScope scope = ((SourceTypeBinding) typeBinding).scope;
 				if (scope != null) {
 					TypeDeclaration typeDecl = scope.referenceContext;
-					SearchMatch match = new TypeDeclarationMatch(type, SearchMatch.A_ACCURATE, typeDecl.sourceStart, typeDecl.sourceEnd+1, locator.getParticipant(), resource);
+					int offset = typeDecl.sourceStart;
+					SearchMatch match = new TypeDeclarationMatch(type, SearchMatch.A_ACCURATE, offset, typeDecl.sourceEnd-offset+1, locator.getParticipant(), resource);
 					locator.report(match);
 				}
 			}
@@ -353,8 +362,8 @@
 	if (typeBinding instanceof ProblemReferenceBinding)
 		typeBinding = ((ProblemReferenceBinding) typeBinding).original;
 
-	if (this.pattern.focus instanceof IType && typeBinding instanceof ReferenceBinding) {
-		IPackageFragment pkg = ((IType) this.pattern.focus).getPackageFragment();
+	if (((InternalSearchPattern) this.pattern).focus instanceof IType && typeBinding instanceof ReferenceBinding) {
+		IPackageFragment pkg = ((IType) ((InternalSearchPattern) this.pattern).focus).getPackageFragment();
 		// check that type is located inside this instance of a package fragment
 		if (!PackageReferenceLocator.isDeclaringPackageFragment(pkg, (ReferenceBinding) typeBinding))
 			return IMPOSSIBLE_MATCH;
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 2d6c142..fff42df 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/TypeReferencePattern.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/TypeReferencePattern.java
@@ -12,8 +12,9 @@
 
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.search.SearchPattern;
+import org.eclipse.jdt.internal.core.search.indexing.IIndexConstants;
 
-public class TypeReferencePattern extends AndPattern {
+public class TypeReferencePattern extends AndPattern implements IIndexConstants {
 
 protected char[] qualification;
 protected char[] simpleName;
@@ -29,15 +30,15 @@
 public TypeReferencePattern(char[] qualification, char[] simpleName, int matchRule) {
 	this(matchRule);
 
-	this.qualification = this.isCaseSensitive ? qualification : CharOperation.toLowerCase(qualification);
-	this.simpleName = this.isCaseSensitive ? simpleName : CharOperation.toLowerCase(simpleName);
+	this.qualification = isCaseSensitive() ? qualification : CharOperation.toLowerCase(qualification);
+	this.simpleName = isCaseSensitive() ? simpleName : CharOperation.toLowerCase(simpleName);
 
 	if (simpleName == null)
 		this.segments = this.qualification == null ? ONE_STAR_CHAR : CharOperation.splitOn('.', this.qualification);
 	else
 		this.segments = null;
 
-	this.mustResolve = true; // always resolve (in case of a simple name reference being a potential match)
+	((InternalSearchPattern)this).mustResolve = true; // always resolve (in case of a simple name reference being a potential match)
 }
 TypeReferencePattern(int matchRule) {
 	super(TYPE_REF_PATTERN, matchRule);
@@ -50,11 +51,11 @@
 }
 public char[] getIndexKey() {
 	if (this.simpleName != null)
-		return encodeIndexKey(this.simpleName, this.matchMode);
+		return encodeIndexKey(this.simpleName, getMatchMode());
 
 	// Optimization, eg. type reference is 'org.eclipse.jdt.core.*'
 	if (this.currentSegment >= 0) 
-		return encodeIndexKey(this.segments[this.currentSegment], this.matchMode);
+		return encodeIndexKey(this.segments[this.currentSegment], getMatchMode());
 	return null;
 }
 public char[][] getMatchCategories() {
@@ -89,7 +90,7 @@
 	else
 		buffer.append("*"); //$NON-NLS-1$
 	buffer.append(">, "); //$NON-NLS-1$
-	switch(this.matchMode) {
+	switch(getMatchMode()) {
 		case R_EXACT_MATCH : 
 			buffer.append("exact match, "); //$NON-NLS-1$
 			break;
@@ -100,7 +101,7 @@
 			buffer.append("pattern match, "); //$NON-NLS-1$
 			break;
 	}
-	if (this.isCaseSensitive)
+	if (isCaseSensitive())
 		buffer.append("case sensitive"); //$NON-NLS-1$
 	else
 		buffer.append("case insensitive"); //$NON-NLS-1$
diff --git a/search/org/eclipse/jdt/internal/core/search/matching/VariableLocator.java b/search/org/eclipse/jdt/internal/core/search/matching/VariableLocator.java
index 11aea50..c8a7f9c 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/VariableLocator.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/VariableLocator.java
@@ -49,7 +49,7 @@
 protected int matchReference(Reference node, MatchingNodeSet nodeSet, boolean writeOnlyAccess) {
 	if (node instanceof NameReference) {
 		if (this.pattern.name == null) {
-			return nodeSet.addMatch(node, this.pattern.mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
+			return nodeSet.addMatch(node, ((InternalSearchPattern)this.pattern).mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
 		} else if (node instanceof SingleNameReference) {
 			if (matchesName(this.pattern.name, ((SingleNameReference) node).token))
 				return nodeSet.addMatch(node, POSSIBLE_MATCH);
diff --git a/search/org/eclipse/jdt/internal/core/search/matching/VariablePattern.java b/search/org/eclipse/jdt/internal/core/search/matching/VariablePattern.java
index 8c39aa6..c3bddb0 100644
--- a/search/org/eclipse/jdt/internal/core/search/matching/VariablePattern.java
+++ b/search/org/eclipse/jdt/internal/core/search/matching/VariablePattern.java
@@ -30,7 +30,7 @@
 	this.writeAccess = writeAccess; // set to find any reference, write only references & all occurences
 	this.findReferences = readAccess || writeAccess;
 
-	this.name = this.isCaseSensitive ? name : CharOperation.toLowerCase(name);
+	this.name = isCaseSensitive() ? name : CharOperation.toLowerCase(name);
 }
 /*
  * Returns whether a method declaration or message send will need to be resolved to 
diff --git a/search/org/eclipse/jdt/internal/core/search/pattern/InternalSearchPattern.java b/search/org/eclipse/jdt/internal/core/search/pattern/InternalSearchPattern.java
deleted file mode 100644
index 7a70cf9..0000000
--- a/search/org/eclipse/jdt/internal/core/search/pattern/InternalSearchPattern.java
+++ /dev/null
@@ -1,208 +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.search.pattern;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Iterator;
-
-import org.eclipse.core.runtime.*;
-import org.eclipse.jdt.core.ICompilationUnit;
-import org.eclipse.jdt.core.IJavaElement;
-import org.eclipse.jdt.core.IJavaProject;
-import org.eclipse.jdt.core.search.*;
-import org.eclipse.jdt.internal.core.CompilationUnit;
-import org.eclipse.jdt.internal.core.JarPackageFragmentRoot;
-import org.eclipse.jdt.internal.core.JavaModelManager;
-import org.eclipse.jdt.internal.core.index.*;
-import org.eclipse.jdt.internal.core.search.*;
-import org.eclipse.jdt.internal.core.search.indexing.IndexManager;
-import org.eclipse.jdt.internal.core.util.Util;
-
-/**
- * Internal search pattern implementation
- */
-public abstract class InternalSearchPattern {
-
-	public class WorkingCopyDocument extends JavaSearchDocument {
-		public ICompilationUnit workingCopy;
-		WorkingCopyDocument(ICompilationUnit workingCopy, SearchParticipant participant) {
-			super(workingCopy.getPath().toString(), participant);
-			this.charContents = ((CompilationUnit)workingCopy).getContents();
-			this.workingCopy = workingCopy;
-		}
-		public String toString() {
-			return "WorkingCopyDocument for " + getPath(); //$NON-NLS-1$
-		}
-	}
-	
-	public final int kind;
-	public boolean mustResolve = true;
-	
-	public InternalSearchPattern(int kind) {
-		this.kind = kind;
-	}
-	
-	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();
-	}
-	public SearchDocument[] addWorkingCopies(SearchDocument[] indexMatches, ICompilationUnit[] copies, SearchParticipant participant) {
-		// working copies take precedence over corresponding compilation units
-		SearchPattern pattern = (SearchPattern) this;
-		HashMap workingCopyDocuments = workingCopiesThatCanSeeFocus(copies, pattern.focus, pattern.isPolymorphicSearch(), participant);
-		SearchDocument[] matches = null;
-		int length = indexMatches.length;
-		for (int i = 0; i < length; i++) {
-			SearchDocument searchDocument = indexMatches[i];
-			if (searchDocument.getParticipant() == participant) {
-				SearchDocument workingCopyDocument = (SearchDocument) workingCopyDocuments.remove(searchDocument.getPath());
-				if (workingCopyDocument != null) {
-					if (matches == null) {
-						System.arraycopy(indexMatches, 0, matches = new SearchDocument[length], 0, length);
-					}
-					matches[i] = workingCopyDocument;
-				}
-			}
-		}
-		if (matches == null) { // no working copy
-			matches = indexMatches;
-		}
-		int remainingWorkingCopiesSize = workingCopyDocuments.size();
-		if (remainingWorkingCopiesSize != 0) {
-			System.arraycopy(matches, 0, matches = new SearchDocument[length+remainingWorkingCopiesSize], 0, length);
-			Iterator iterator = workingCopyDocuments.values().iterator();
-			int index = length;
-			while (iterator.hasNext()) {
-				matches[index++] = (SearchDocument) iterator.next();
-			}
-		}
-		return matches;
-	}
-	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;
-		
-			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, ICompilationUnit[] workingCopies, 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$
-		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 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();
-	
-					// 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]);
-					SearchDocument[] matches = addWorkingCopies(indexMatches, workingCopies, participant);
-					participant.locateMatches(matches, (SearchPattern) this, scope, requestor, monitor);
-				} finally {		
-					requestor.exitParticipant(participant);
-					participant.doneSearching();
-				}
-			}
-		} 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());
-	}
-	
-	/*
-	 * Returns the working copies that can see the given focus.
-	 */
-	private HashMap workingCopiesThatCanSeeFocus(ICompilationUnit[] copies, IJavaElement focus, boolean isPolymorphicSearch, SearchParticipant participant) {
-		if (copies == null) return new HashMap();
-		if (focus != null) {
-			while (!(focus instanceof IJavaProject) && !(focus instanceof JarPackageFragmentRoot)) {
-				focus = focus.getParent();
-			}
-		}
-		HashMap result = new HashMap();
-		for (int i=0, length = copies.length; i<length; i++) {
-			ICompilationUnit workingCopy = copies[i];
-			IPath projectOrJar = IndexSelector.getProjectOrJar(workingCopy).getPath();
-			if (focus == null || IndexSelector.canSeeFocus(focus, isPolymorphicSearch, projectOrJar)) {
-				result.put(
-					workingCopy.getPath().toString(),
-					new WorkingCopyDocument(workingCopy, participant)
-				);
-			}
-		}
-		return result;
-	}
-
-}