v_494a_head_before_30_maintenance  (3.0 final version)
diff --git a/org.eclipse.jdt.core/.classpath b/org.eclipse.jdt.core/.classpath
index ca033a4..fed27a0 100644
--- a/org.eclipse.jdt.core/.classpath
+++ b/org.eclipse.jdt.core/.classpath
@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <classpath>
-	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
 	<classpathentry output="antbin" kind="src" path="antadapter"/>
 	<classpathentry kind="src" path="batch"/>
 	<classpathentry kind="src" path="codeassist"/>
@@ -10,10 +9,7 @@
 	<classpathentry kind="src" path="formatter"/>
 	<classpathentry kind="src" path="model"/>
 	<classpathentry kind="src" path="search"/>
-	<classpathentry kind="src" path="/org.eclipse.core.resources"/>
-	<classpathentry kind="src" path="/org.eclipse.text"/>
-	<classpathentry kind="src" path="/org.eclipse.core.runtime"/>
-	<classpathentry kind="src" path="/org.apache.ant"/>
-	<classpathentry kind="src" path="/org.eclipse.core.runtime.compatibility"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
 	<classpathentry kind="output" path="bin"/>
 </classpath>
diff --git a/org.eclipse.jdt.core/.cvsignore b/org.eclipse.jdt.core/.cvsignore
new file mode 100644
index 0000000..da63a8f
--- /dev/null
+++ b/org.eclipse.jdt.core/.cvsignore
@@ -0,0 +1,2 @@
+bin
+antbin
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/.options b/org.eclipse.jdt.core/.options
index 5ceebe9..41b29e1 100644
--- a/org.eclipse.jdt.core/.options
+++ b/org.eclipse.jdt.core/.options
@@ -24,6 +24,7 @@
 

 # Print notified Java element deltas

 org.eclipse.jdt.core/debug/javadelta=false

+org.eclipse.jdt.core/debug/javadelta/verbose=false

 

 # Reports Java model elements opening/closing

 org.eclipse.jdt.core/debug/javamodel=false

diff --git a/org.eclipse.jdt.core/.project b/org.eclipse.jdt.core/.project
index d1eabac..1de109a 100644
--- a/org.eclipse.jdt.core/.project
+++ b/org.eclipse.jdt.core/.project
@@ -1,13 +1,8 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <projectDescription>
-	<name>org.eclipse.jdt.core</name>
+	<name>shadows.org.eclipse.jdt.core</name>
 	<comment></comment>
 	<projects>
-		<project>org.apache.ant</project>
-		<project>org.eclipse.core.resources</project>
-		<project>org.eclipse.core.runtime</project>
-		<project>org.eclipse.core.runtime.compatibility</project>
-		<project>org.eclipse.text</project>
 	</projects>
 	<buildSpec>
 		<buildCommand>
@@ -15,6 +10,16 @@
 			<arguments>
 			</arguments>
 		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
 	</buildSpec>
 	<natures>
 		<nature>org.eclipse.jdt.core.javanature</nature>
diff --git a/org.eclipse.jdt.core/build.properties b/org.eclipse.jdt.core/build.properties
index a3f5c3f..35243e8 100644
--- a/org.eclipse.jdt.core/build.properties
+++ b/org.eclipse.jdt.core/build.properties
@@ -1,5 +1,5 @@
 ###############################################################################
-# Copyright (c) 2000, 2003 IBM Corporation and others.
+# 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
@@ -14,10 +14,12 @@
                *.jar,\
                .options
 javadoc.packages = org.eclipse.jdt.core.*,\
+                   org.eclipse.jdt.core.formatter.*,\
                    org.eclipse.jdt.core.compiler.*,\
                    org.eclipse.jdt.core.eval.*,\
                    org.eclipse.jdt.core.jdom.*,\
                    org.eclipse.jdt.core.dom.*,\
+                   org.eclipse.jdt.core.dom.rewrite.*,\
                    org.eclipse.jdt.core.search.*
 source.jdtcore.jar = batch/,\
                      codeassist/,\
diff --git a/org.eclipse.jdt.core/buildnotes_jdt-core.html b/org.eclipse.jdt.core/buildnotes_jdt-core.html
index a2cc5f9..5d7dced 100644
--- a/org.eclipse.jdt.core/buildnotes_jdt-core.html
+++ b/org.eclipse.jdt.core/buildnotes_jdt-core.html
@@ -33,6 +33,1956 @@
   </tr>
 </table>
 
+<a name="v_450"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0.1 Build - ?th June 2004
+<br>Project org.eclipse.jdt.core v_450
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_450">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=68772">68772</a>
+IDOMMember.getComments() sometimes returns wrong results.
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=68863">68863</a>
+Missing entry in local variable attribute
+
+
+<a name="v_449"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0RC4 Build - 24th June 2004 - 3.0 RELEASE CANDIDATE 4
+<br>Project org.eclipse.jdt.core v_449
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_449">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+<li>Fixed schema copyrights.</li>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=44068">44068</a>
+[DOC] Need more project configuration tutorials
+
+<a name="v_448"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0RC4 Build - 24th June 2004
+<br>Project org.eclipse.jdt.core v_448
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_448">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+<li>Fixed mixed line delimiters.</li>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+
+<a name="v_447"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0RC4 Build - 23rd June 2004
+<br>Project org.eclipse.jdt.core v_447
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_447">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+<li>Copyright update to 2004.</li>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+
+<a name="v_446"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0RC4 Build - 22nd June 2004
+<br>Project org.eclipse.jdt.core v_446
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_446">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=67769">67769</a>
+Internal StackOverflowError occurred during project build
+
+<a name="v_445"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0RC3 Build - 18th June 2004 - 3.0 RELEASE CANDIDATE 3
+<br>Project org.eclipse.jdt.core v_445
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_445">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=66898">66898</a>
+refactor-rename: encoding is not preserved
+
+<a name="v_444"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0RC3 Build - 18th June 2004
+<br>Project org.eclipse.jdt.core v_444
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_444">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=67297">67297</a>
+Renaming included package folder throws JME 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=67786">67786</a>
+OutOfMemoryError searching for reference to Object 
+
+<a name="v_443"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0RC3 Build - 18th June 2004
+<br>Project org.eclipse.jdt.core v_443
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_443">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=67717">67717</a>
+NPE disassembling .class file
+
+<a name="v_442"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0RC3 Build - 17th June 2004
+<br>Project org.eclipse.jdt.core v_442
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_442">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=67600">67600</a>
+String Index out of bounds when searching for all types 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=67599">67599</a>
+NPE when cancelling search 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=66271">66271</a>
+No need to resolve type names when selecting declaration
+
+<a name="v_441"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0RC3 Build - 16th June 2004
+<br>Project org.eclipse.jdt.core v_441
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_441">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=67324">67324</a>
+Package Explorer doesn't update included package after moving contents of source folder 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=41434">41434</a>
+[msic] Slow Down using classes with many methods
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=64646">64646</a>
+[Navigator] Navigator popup causes Eclipse to hang. 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=65186">65186</a>
+Can't attach source from project directory [build path] 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=65831">65831</a>
+search for all types slow/memory intensive [search] 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=66675">66675</a>
+Extra period in the doc in 200406110010
+
+<a name="v_440"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0RC2 Build - 10th June 2004 - 3.0 RELEASE CANDIDATE 2
+<br>Project org.eclipse.jdt.core v_440
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_440">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=66551">66551</a>
+Error in org.eclipse.swt project on class PrinterData
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=66573">66573</a>
+Shouldn't bind to local constructs
+
+<a name="v_439"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0RC2 Build - 10th June 2004
+<br>Project org.eclipse.jdt.core v_439
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_439">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=66216">66216</a>
+Sort Members is broken.
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=66437">66437</a>
+Canceling search leads to broken workspace 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=65266">65266</a>
+JarPackageFragmentInfo has unnecessary field 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=66098">66098</a>
+MatchLocatorParser does not need advanced syntax diagnosis
+
+<a name="v_438"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0RC2 Build - 9th June 2004
+<br>Project org.eclipse.jdt.core v_438
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_438">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=66026">66026</a>
+Large amount of garbage created by DefaultCommentMapper
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=64646">64646</a>
+[Navigator] Navigator popup causes Eclipse to hang. 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=65288">65288</a>
+Javadoc: tag gets mangled when javadoc closing on same line without whitespace
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=65253">65253</a>
+[Javadoc] @@tag is wrongly parsed as @tag
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=65180">65180</a>
+Spurious "Javadoc: xxx cannot be resolved or is not a field" error with inner classes
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=65174">65174</a>
+Spurious "Javadoc: Missing reference" error
+
+<a name="v_437"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0RC2 Build - 8th June 2004
+<br>Project org.eclipse.jdt.core v_437
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_437">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=66142">66142</a>
+SearchParticipant#scheduleDocumentIndexing() fails silently if index doesn't exist 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=65795">65795</a>
+source inclusion mechanism breaks type lookups 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=66099">66099</a>
+Persisted container/variable values are leaked throughout a session
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=65250">65250</a>
+Problem selection does not choose first n errors
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=65259">65259</a>
+CodeSelect should only find one match for dup methods
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=65737">65737</a>
+Strange completion by code assist 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=65871">65871</a>
+Missing SUPER_INTERFACE_TYPES_PROPERTY in EnumDeclaration 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=53072">53072</a>
+[DOC] Search for fully qualified constructor name reports nothing 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=65116">65116</a>
+IProjectDescription.getBuildSpec copies commands 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=65234">65234</a>
+Inclusion filter not working 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=64657">64657</a>
+better documentation for IType#resolveType behavior 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=65693">65693</a>
+Package Explorer shows .class files instead of .java 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=64750">64750</a>
+NPE in Java AST Creation - editing some random file 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=65562">65562</a>
+Java AST creation failure
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=65531">65531</a>
+out of the box formatter settings need to be improved
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=65677">65677</a>
+Creating hierarchy failed. See log for details. 0 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=65090">65090</a>
+ASTParser with kind == K_STATEMENTS doesn't work unless source range specified
+	  	
+<a name="v_436"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0RC1 Build - 28th May 2004 - 3.0 RELEASE CANDIDATE 1
+<br>Project org.eclipse.jdt.core v_436
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_436">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=63534">63534</a>
+ConcurrentModificationException after "catching up" 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=62131">62131</a>
+CodeStream should do bounds checks
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=64470">64470</a>
+&lt;packages prefixes=..../&gt; should be removed
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=64299">64299</a>
+NullPointerException when OverrideIndicatorLabelDecorator is decorating
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=63550">63550</a>
+NPE "Java AST Creation"
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=64421">64421</a>
+ArrayIndexOutOfBoundsException in PackageReferenceLocator.matchReportReference()
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=62453">62453</a>
+Large File: Java builder not reacting on cancel
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=64377">64377</a>
+CRASH: An internal error occurred during: "Java AST creation"
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=64378">64378</a>
+Wording of error message
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=64332">64332</a>
+Javadoc errors in non-API doc comments
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=64329">64329</a>
+Missing Javadoc tags declaration in API methods
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=64170">64170</a>
+Classpath reentrance protection is not thread-safe 
+
+<a name="v_435"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0RC1 Build - 27th May 2004
+<br>Project org.eclipse.jdt.core v_435
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_435">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+<li>API polish on search matches (org.eclipse.jdt.core.search.SearchMatch hierarchy):
+<ul>
+<li>added setters for all match properties (not just length & offset)</li>
+<li>add insideDocComment argument to PackageReferenceMatch constructor (for 
+being consistent with other reference matches)</li>
+</ul>
+See bug <a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=62697">62697</a> for more details.
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=62854">62854</a>
+refactoring does not trigger reconcile 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=62697">62697</a>
+Need to know if a package reference match is in Javadoc or in Code
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=63756">63756</a>
+multiple builds early
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=63077">63077</a>
+IllegalArgumentException in Openable.codeSelect 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=62861">62861</a>
+ArrayIndexOutOfBoundsException in SearchableEnvironment 
+
+
+<a name="v_434"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0RC1 Build - 26th May 2004
+<br>Project org.eclipse.jdt.core v_434
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_434">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=56870">56870</a>
+copied file not shown in package explorer / java browser [ccp] 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=63748">63748</a>
+Type Hierarchy: null pointer when pressing F4 on ListCellRenderer 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=38839">38839</a>
+org.eclipse.jdt.internal.compiler.parser.Scanner throws thousands of Exceptions
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=62869">62869</a>
+[navigation] 'Go to Next Annotation' doesn't find next error
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=63871">63871</a>
+Using M9, -warn: option crashes the batch compiler
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=63434">63434</a>
+NPE during checkout/build 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=62737">62737</a>
+Code formatter doesn't work on some files
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=62639">62639</a>
+[1.5] Cheetah and extending Vector
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=62769">62769</a>
+Javadoc errors in 200405180816
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=62952">62952</a>
+Ant adapter behavior is a little strange
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=62704">62704</a>
+Using 05180816, //toto is a task if //toto is a task tag.
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=51660">51660</a>
+[DOM/AST] AST.parse* should handle all legal doc tags
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=51606">51606</a>
+Javadoc - {@inheritDoc} should be inefficient when not in first text element
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=62713">62713</a>
+should not be able to nest output folders [build path]
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=63245">63245</a>
+findPackageFragment won't return default package 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=62698">62698</a>
+NPE while searching for declaration of binary package 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=61017">61017</a>
+Refactoring - test case that results in uncompilable source 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=63044">63044</a>
+Reference to a constructor inside a javadoc should point to a type binding and not a constructor binding
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=62812">62812</a>
+Some malformed javadoc tags are not reported as malformed
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=62810">62810</a>
+Deadlock when closing editors and save 
+
+
+<a name="v_433"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M9 Build - 21st May 2004 - 3.0 MILESTONE-9 / 3.0 RELEASE CANDIDATE 0
+<br>Project org.eclipse.jdt.core v_433
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_433">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>Put back test org.eclipse.jdt.core.tests.model.JavaElementDeltaTests.testBuildProjectUsedAsLib()
+after bug <a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=62927">62927</a> was fixed.
+</ul>
+
+<a name="v_432"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M9 Build - 20th May 2004
+<br>Project org.eclipse.jdt.core v_432
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_432">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>Excluded test org.eclipse.jdt.core.tests.model.JavaElementDeltaTests.testBuildProjectUsedAsLib()
+</ul>
+
+<a name="v_431"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M9 Build - 20th May 2004
+<br>Project org.eclipse.jdt.core v_431
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_431">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=62881">62881</a>
+JDT/Core could be contributing a content type for JAR manifests
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=58580">58580</a>
+VariableBinding.getVariableId() returns wrong IDs for nested types
+
+<a name="v_430"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M9 Build - 18th May 2004
+<br>Project org.eclipse.jdt.core v_430
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_430">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=62608">62608</a>
+Include pattern ending with slash should include all subtree 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=59933">59933</a>
+applying exclusion filter to opened java file makes it appear twice [build path]
+
+
+<a name="v_429"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M9 Build - 18th May 2004
+<br>Project org.eclipse.jdt.core v_429
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_429">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=39499">39499</a>
+keyword completion does not work in anonymous inner classes 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=59282">59282</a>
+Unable to include an external folder with class files to project classpath 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=52422">52422</a>
+F3 can't find method def'n inside inner (anonymous) class
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=62463">62463</a>
+Wrong length for ExpressionStatement after conversion
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=61831">61831</a>
+Full build happens on every start of Eclipse 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=62201">62201</a>
+NPE in MethodScope
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=61872">61872</a>
+library looses content when setting source attachment
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=54962">54962</a>
+plain reference to package not found in (@see) javadoc
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=54424">54424</a>
+AST has structural problems with incomplete javadoc tags
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=51951">51951</a>
+codeComplete finds no completion in method of local class inside static method 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50686">50686</a>
+NPE in MethodScope.createMethod 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=61952">61952</a>
+Bad deprecation -- IJavaSearchConstants#CASE_SENSITIVE 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=62068">62068</a>
+Index manager should use client's index location 
+
+<a name="v_428"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M9 Build - 13th May 2004
+<br>Project org.eclipse.jdt.core v_428
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_428">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+<li> Due to an implementation cleanup, the optional diagnosis for unnecessary empty statement or empty control-flow
+statement, will be reverted to ignore by default. If you did set it differently in the past, you will have to manually
+set it back. We now conform to the spec for this option (until JDT/UI converted, the old option ID was 
+incorrectly used: "org.eclipse.jdt.core.compiler.problem.superfluousSemicolon"):
+<pre>
+* COMPILER / Reporting Empty Statements and Unnecessary Semicolons
+*    When enabled, the compiler will issue an error or a warning if an empty statement or a
+*    unnecessary semicolon is encountered.
+*     - option id:         "org.eclipse.jdt.core.compiler.problem.emptyStatement"
+*     - possible values:   { "error", "warning", "ignore" }
+*     - default:           "ignore"
+</pre>	 
+</li>
+<li>Improved error location when type indirectly referenced from required .class files.</li>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=61959">61959</a>
+dangerous practice of catching Throwable
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=61882">61882</a>
+Inconsistency between build errors and reconcile errors
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=35356">35356</a>
+Convert local variable to field refactoring proposes weird name 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=53555">53555</a>
+SourceType#get*QualifiedName() methods return unusable/invalid names for local types 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=48752">48752</a>
+Completion: relevance could be improved for non static field
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=61877">61877</a>
+ClassCastException in DefaultBindingResolver
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=59769">59769</a>
+Javadoc of SearchMatch#getElement(): is *enclosing* element 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=58440">58440</a>
+type hierarchy incomplete when implementing fully qualified interface 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=61719">61719</a>
+Incorrect fine grain delta after method copy-rename 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=61075">61075</a>
+[Compiler] implementation uses numerous ArrayIndexOutOfBoundsException
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=19898">19898</a>
+StackOverflowError in BinaryExpression
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=61706">61706</a>
+Improve error message when unbound reference from binaries
+
+<a name="v_427"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M9 Build - 11th May 2004
+<br>Project org.eclipse.jdt.core v_427
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_427">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+<li>A system job now reports progress when the indexer is running.</li>
+<li>The org.eclipse.jdt.core.jdom package has been deprecated. The JDOM was made obsolete by 
+      the addition in 2.0 of the more powerful, fine-grained DOM/AST API found in the 
+      org.eclipse.jdt.core.dom package.</li>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=60689">60689</a>
+AST on reconcile: AST without Javadoc comments created
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=60365">60365</a>
+hierarchy view shows some interfaces as classes [type hierarchy] 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=53290">53290</a>
+[Javadoc] Compiler should complain when tag name is not correct
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=53279">53279</a>
+[Javadoc] Compiler should complain when inline tag is not terminated
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=51600">51600</a>
+Javadoc: tags with errors are not stored in DOM AST Javadoc hierarchy
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=59751">59751</a>
+No Feedback/information from indexing 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=42402">42402</a>
+OuterClass.this does not appear in code assist of the InnerClass
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=61390">61390</a>
+Indexing thread grabbing resource lock 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=61408">61408</a>
+Incorrect parsing
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=58859">58859</a>
+[encoding] Editor does not detect BOM on .txt files
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=61148">61148</a>
+deprecate JDOM API 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=61270">61270</a>
+Wrong delta when copying a package that overrides another package 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=61181">61181</a>
+Task tag starting with double-/ (//) causes compile error
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=61040">61040</a>
+Should add protect for reentrance to #getResolvedClasspath 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=61214">61214</a>
+The classpath computation inside the Java builder should get rid of duplicates entries
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=60867">60867</a>
+LocalVariableReferenceMatch should offer isReadAccess(), etc. 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=59638">59638</a>
+ConcurrentModificationException in JavaModelManager.saving 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=61052">61052</a>
+Flatten cp container initialization 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=60848">60848</a>
+[reconciling] Unclosed Comment in Java Texteditor
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=60822">60822</a>
+Reacting to Project > Clean... 
+	  	
+<a name="v_426"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M9 Build - 4th May 2004
+<br>Project org.eclipse.jdt.core v_426
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_426">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+<li>Added new flag IJavaElementDelta.F_PRIMARY_RESOURCE that is set when the resource of a primary working copy 
+     changes (or when it is added or removed).</li>
+<li>Removed dependency on org.eclipse.runtime.compatibility.</li>
+<li>Tuned the diagnosis for unnecessary else statements to tolerate else-if constructs.</li>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=60687">60687</a>
+NPE in JavaCore.getEncoding
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=60581">60581</a>
+"Java AST creation" error.
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=48502">48502</a>
+Exception during "Java AST creation"
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=59750">59750</a>
+DCR: Code Assist: Hook to add getter and setters
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=47227">47227</a>
+Syntax error diagnosis shouldn't expose internal goal tokens
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=60595">60595</a>
+AST: AST from reconcile does not have 'ORIGINAL' bit set
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=59500">59500</a>
+Java Model Notification needs notification that a java class was physically saved 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=60459">60459</a>
+AST: 'malformed' flag overwrites other flags
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=60367">60367</a>
+dynamic project references not maintained
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=60257">60257</a>
+SearchPattern API: R_CASE_SENSITIVE vs. boolean isCaseSensitive 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=58565">58565</a>
+code formatter doesn't format blocks with a return statement correctly
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=58724">58724</a>
+Java code formatter should add space between imports and class definition
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=60418">60418</a>
+remove warnings from core runtime deprecations 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=57749">57749</a>
+Search in working copies doesn't find all matches 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=60235">60235</a>
+WorkingCopyOwner needs clarification on
+
+
+<a name="v_425"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M9 Build - 28th April 2004
+<br>Project org.eclipse.jdt.core v_425
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_425">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+<li>Added API to register/deregister a pre-processing resource change listener:
+<pre>
+/**
+ * Adds the given listener for POST_CHANGE resource change events to the Java core. 
+ * The listener is guarantied to be notified of the POST_CHANGE resource change event before
+ * the Java core starts processing the resource change event itself.
+ * 
+ * Has no effect if an identical listener is already registered.
+ * 
+ * @param listener the listener
+ * @see #removePreResourceChangeListener(IResourceChangeListener)
+ * @since 3.0
+ */
+public static void addPreProcessingResourceChangedListener(IResourceChangeListener listener);
+	
+/**
+ * Removes the given pre-processing resource changed listener.
+ *
+ * Has no affect if an identical listener is not registered.
+ *
+ * @param listener the listener
+ * @since 3.0
+ */
+public static void removePreProcessingResourceChangedListener(IResourceChangeListener listener);
+</pre>
+</li>
+<li>When diagnostic for unnecessary semicolon is enabled, the compiler will also flag empty
+control-flow statement: e.g. if (bool);.  Note that the naming of the option is going soon
+to be revised to better reflect this evolution.
+Empty control-flow statement problem ID is: <tt>IProblem.EmptyControlFlowStatement</tt>.
+</li>
+<li>Added compiler style option to report situation where a statement is unnecessarily nested
+in else clause, e.g.: 
+<pre>
+ if (bool) 
+   return;
+ else
+   System.out.println();   // no need to be inside else
+</pre>    
+Associated problem ID is: <tt>IProblem.UnnecessaryElse</tt>.
+<pre>
+* COMPILER / Reporting Unnecessary Else
+*    When enabled, the compiler will issue an error or a warning when a statement is unnecessarily
+*    nested within an else clause (in situation where then clause is not completing normally).
+*     - option id:         "org.eclipse.jdt.core.compiler.problem.unnecessaryElse"
+*     - possible values:   { "error", "warning", "ignore" }
+*     - default:           "ignore"
+</pre>
+</li>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=42493">42493</a>
+Error message when evaluating: Expressionopt?
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=32061">32061</a>
+No code assist in instance variable inner class
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49904">49904</a>
+[DCR] Quick Assist : unneeded else
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=60081">60081</a>
+[Compiler] java.lang.VerifyError: Illegal target of jump or branch
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=52805">52805</a>
+[DCR] Compiler should warn when using if (test);
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=58652">58652</a>
+ImageBuilderInternalException during auto build
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=60108">60108</a>
+SearchMatch should implement toString() 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=60078">60078</a>
+NPE in ASTConverter
+
+<a name="v_424"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M9 Build - 27th April 2004
+<br>Project org.eclipse.jdt.core v_424
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_424">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=54108">54108</a>
+Weird piece of source code in SourceTypeConverter.java
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=51500">51500</a>
+[DOM AST] Quick fix "Add unimplemented methods" fails on static variable initialized using anonymous constructor
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=59843">59843</a>
+Eclipse 3.0M8 generates ambiguous keys from ITypeBindings for nested classes with the same name
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=59937">59937</a>
+Should not process saved state delta during startup 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=58069">58069</a>
+Compilation ERROR: Missing code implementation in the compiler
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=51911">51911</a>
+@see method w/out ()
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49025">49025</a>
+Util.bind(String, String[]) can be optimized a little bit
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=59743">59743</a>
+[Compiler] Incorrect diagnosis of ambiguous method when inheriting
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=57871">57871</a>
+Override Indicator: blocks editor from opening when error occurs in java compiler
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=59421">59421</a>
+Bad error message from Eclipse Java Compiler when file is missing
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=58946">58946</a>
+Standalone compiler help text is incorrect on Unix
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=59084">59084</a>
+[content type] ensure content types/file associations are contributed by the right plugins
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=59716">59716</a>
+Using 200404201300, one more blank line is inserted in front of import declarations when no package is defined
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=59575">59575</a>
+invalid formatting
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=51213">51213</a>
+Unable to resolve conflict between type and package name in binaries
+
+<a name="v_423"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M9 Build - 22nd April 2004
+<br>Project org.eclipse.jdt.core v_423
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_423">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=59363">59363</a>
+Should surface cancellation exceptions 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=51075">51075</a>
+Compiler warning "is hiding a field" given for static inner class
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=38658">38658</a>
+Search for existing type fails
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=59291">59291</a>
+Deadlock between AllTypes cache and setClasspathContainer
+
+
+<a name="v_422"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+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=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
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=57689">57689</a>
+ArrayIndexOutOfBoundsException when creating a new class
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=55004">55004</a>
+[DCR] IVariableBinding should have a method returning the constant value
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=58606">58606</a>
+Inner class in child calling protected method in parent
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=55979">55979</a>
+There are still deprecated formatter constants without new way
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=57117">57117</a>
+Ant adapter preserves all deprecation when using compiler arg even if deprecation is set to off
+
+<a name="v_421"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M9 Build - 13th April 2004
+<br>Project org.eclipse.jdt.core v_421
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_421">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=57829">57829</a>
+Should optimize assert true case
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=57294">57294</a>
+Ignore serialVersionUID hiding another field
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=41395">41395</a>
+StackOverflowError when pasting code 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=57414">57414</a>
+Summary: GB18030: Can not open Java Search dialog. 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=57886">57886</a>
+Concurrency issue while initializing containers and variables 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=57858">57858</a>
+[Compiler] Marking a field deprecated still report deprecated usage #46973
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=57743">57743</a>
+[Compiler] invalid byte code produced when catching Throwable
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=57235">57235</a>
+DCR: AST Name.getQualifiedName()
+
+<a name="v_420"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M9 Build - 6th April 2004
+<br>Project org.eclipse.jdt.core v_420
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_420">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+<li>Added inclusion patterns support. See <code>JavaCore.newSourceEntry(IPath,IPath[],IPath[],IPath)</code> 
+	 and <code>IClasspathEntry.getInclusionPatterns()</code> for details.</li>
+<li>Added API on WorkingCopyOwner to set the primary buffer provider (for internal use by the jdt-related plug-ins only).
+<pre>
+/**
+ * Sets the buffer provider of the primary working copy owner. Note that even if the
+ * buffer provider is a working copy owner, only its createBuffer(ICompilationUnit)
+ * method is used by the primary working copy owner. It doesn't replace the internal primary 
+ * working owner.
+ * 
+ * This method is for internal use by the jdt-related plug-ins.
+ * Clients outside of the jdt should not reference this method.
+ * 
+ * @param primaryBufferProvider the primary buffer provider
+ */
+public static void setPrimaryBufferProvider(WorkingCopyOwner primaryBufferProvider);
+</pre></li>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=54009">54009</a>
+jardesc should be known to Team/File Content
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=51867">51867</a>
+An anonymous type is missing in type hierarchy when editor is modified 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=54763">54763</a>
+[Compiler] Unnecessary cast not detected
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=52347">52347</a>
+NPE in LaunchingPlugin.shutdown 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=55992">55992</a>
+AssertionFailed during preference import
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=29964">29964</a>
+Add inclusion filter 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=55088">55088</a>
+IAE when using ICU.reconcile(GET_AST_TRUE, ...) 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=56462">56462</a>
+[formatter] java profile; array initializer before closing brace
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=56449">56449</a>
+Need to know if a reference match is in Javadoc or in Code 
+
+<a name="v_419"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M9 Build - 30th March 2004
+<br>Project org.eclipse.jdt.core v_419
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_419">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+<li>Replaced "name" property of ParameterizedType node (DOM/AST) 
+with "type" property. The old methods and fields (added earlier in 3.0 cycle)
+are deprecated and will be removed shortly.</li>
+<li>Added typeParameters property to ClassInstanceCreation node (DOM/AST).</li>
+<li>Package org.eclipse.jdt.core.internal.dom.rewrite renamed to org.eclipse.jdt.internal.core.dom.rewrite.</li>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=56316">56316</a>
+JavaProject exists should not populate 
+	  	
+<a name="v_418"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M8 Build - 25th March 2004 - 3.0 MILESTONE-8
+<br>Project org.eclipse.jdt.core v_418
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_418">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=55930">55930</a>
+File encoding should be used on save
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=55478">55478</a>
+Unused import not reported in IDE
+	  	
+<a name="v_417"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M8 Build - 24th March 2004
+<br>Project org.eclipse.jdt.core v_417
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_417">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+<li>Removed failing tests re: encoding support.
+</li>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+
+<a name="v_416"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M8 Build - 23rd March 2004
+<br>Project org.eclipse.jdt.core v_416
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_416">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul> 
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=55504">55504</a>
+@<tasktag> should not be reported
+
+<a name="v_415"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M8 Build - 23rd March 2004
+<br>Project org.eclipse.jdt.core v_415
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_415">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul> 
+<li> Added rewriting support to DOM AST.
+There are two set of API to perform rewriting.
+<ul> 
+<li>An AST-modifying rewrite API<br>
+To use the AST-modifying rewrite the client must create an AST from an existing
+compilation unit (ASTParser#createAST(...)).
+Then the client need to start the record process of the AST changes (CompilationUnit#recordModifications())
+and modify the AST after. When modifications are done, the client can call a method to
+compute a text edit tree containing all the text changes (CompilationUnit#rewrite()).
+
+<pre>
+CompilationUnit
+	public void recordModifications()
+	public TextEdit rewrite(IDocument document, Map options) throws RewriteException
+</pre>
+</li>
+<li>A describing rewrite API<br>
+To use the describing AST rewrite, the client starts with creating an instance of NewASTRewrite. Then the client
+must not modify the AST directly but use NewASTRewrite instead. When modifications are done, the client can call
+a method to compute a text edit tree containing all the text changes (NewASTRewrite#rewrite()).
+<pre>
+NewASTRewrite
+	public final void markAsRemoved(ASTNode node, TextEditGroup editGroup)
+	public final void markAsReplaced(ASTNode node, ASTNode replacingNode, TextEditGroup editGroup)
+	public ListRewriter getListRewrite(ASTNode parent, ChildListPropertyDescriptor childProperty)
+	public TextEdit rewriteAST(IDocument document, Map options) throws RewriteException
+	...
+	
+ListRewriter
+	remove(ASTNode, TextEditGroup)
+	public void replace(ASTNode, ASTNode, TextEditGroup)
+	public void insertAfter(ASTNode, ASTNode, TextEditGroup)
+	public void insertBefore(ASTNode, ASTNode, TextEditGroup)
+	public void insertFirst(ASTNode, TextEditGroup)
+	public void insertLast(ASTNode, TextEditGroup)
+	public void insertAt(ASTNode, int, TextEditGroup)
+	...
+</pre>
+</li>
+</ul>
+</li>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=39068">39068</a>
+Adopt new core API for encoding on a per file basis
+
+<a name="v_414"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M8 Build - 22nd March 2004
+<br>Project org.eclipse.jdt.core v_414
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_414">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul> 
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=46668">46668</a>
+Changes to class path containers should not change .project 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=55421">55421</a>
+Cannot save a .java file in a non-java project anymore 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=55223">55223</a>
+Bug in comment mapper: Same comment mapped to 2 statements
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=54044">54044</a>
+Ant log does not use system newline character
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=55372">55372</a>
+Should not assume that Preferences.defaultPropertyNames() returns default-default properties 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=55221">55221</a>
+Bug in comment mapper: Grabs next node's Javadoc
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=55102">55102</a>
+NPE when using ICU.reconcile(GET_AST_TRUE, ...) 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49986">49986</a>
+setRawClasspath(...) should fire a F_CLASSPATH_CHANGED delta 
+
+<a name="v_413"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M8 Build - 15th March 2004
+<br>Project org.eclipse.jdt.core v_413
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_413">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul> 
+<li> Added compiler option JavaCore.COMPILER_TASK_CASE_SENSITIVE to control whether the task detection
+should be case sensitive or not. By default, it is.
+<pre>
+ * COMPILER / Determine whether task tags are case-sensitive
+ *    When enabled, task tags are considered in a case-sensitive way.
+ *     - option id:         "org.eclipse.jdt.core.compiler.taskCaseSensitive"
+ *     - possible values:   { "enabled", "disabled" }
+ *     - default:           "enabled"
+</pre>
+</li>
+<li> Added 2 default task tags: "FIXME" and "XXX".
+</li>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=54776">54776</a>
+DefaultCommentMapper: different behaviour
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=54431">54431</a>
+ASTParser should honor set compiler options in all cases
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=54043">54043</a>
+Problems with type hierarchy for binary types
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=53095">53095</a>
+I20040225: Won't accept breakpoint on NoClassDefFoundError
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=54294">54294</a>
+No default for JavaCore.COMPILER_CODEGEN_INLINE_JSR_BYTECODE
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=48435">48435</a>
+Java Search for OR-pattern finds too much in strange project setup
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=40921">40921</a>
+Task tags should be case-insensitive
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49266">49266</a>
+FIXME task tag
+
+
+<a name="v_412"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M8 Build - 8th March 2004
+<br>Project org.eclipse.jdt.core v_412
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_412">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+<li> Added new global JavaCore.COMPILER_DOC_COMMENT_SUPPORT option for doc comment (Javadoc) support. By default, this option is enabled for backward compatibility.
+<pre>
+ * COMPILER / Javadoc Comment Support
+ *    When this support is disabled, the compiler will ignore all javadoc problems options settings
+ *    and will not report any javadoc problem. It will also not find any reference in javadoc comment and
+ *    DOM AST Javadoc node will be only a flat text instead of having structured tag elements.
+ *     - option id:         "org.eclipse.jdt.core.compiler.doc.comment.support"
+ *     - possible values:   { "enabled", "disabled" }
+ *     - default:           "enabled"
+</pre>
+See bug <a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=52264">52264</a>.
+</li>
+<li> Added new JavaCore.COMPILER_CODEGEN_INLINE_JSR_BYTECODE option to allow user to inline subroutine code instead of generating JSR instructions. By default, this option is disabled.
+<pre>
+ * COMPILER / Inline JSR Bytecode Instruction
+ *    When enabled, the compiler will no longer generate JSR instructions, but rather inline corresponding
+ *    subroutine code sequences (mostly corresponding to try finally blocks). The generated code will thus
+ *    get bigger, but will load faster on virtual machines since the verification process is then much simpler. 
+ *    This mode is anticipating support for the Java Specification Request 202.
+ *     - option id:         "org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode"
+ *     - possible values:   { "enabled", "disabled" }
+ *     - default:           "disabled"
+ * 
+</pre>
+Corresponding command line compiler option <code>-noJSR</code> has been renamed to:
+<pre>
+    <code>-inlineJSR</code> : inline JSR bytecode
+</pre>
+which means that when specified, the compiler will no longer generate JSR bytecodes, but instead inlining the corresponding subroutine (e.g. finally block).
+</li>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=53757">53757</a>
+Javadoc tag @transient  ignored
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=530757">53075</a>
+https://bugs.eclipse.org/bugs/show_bug.cgi?id=53075
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=53357">53357</a>
+Java AST creation error
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=52264">52264</a>
+Need a global preference to enable Javadoc support
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=51529">51529</a>
+"Organize imports" is confused by references inside Javadoc
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=53477">53477</a>
+AnonymousClassDeclaration has wrong range
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=53624">53624</a>
+StackOverFlow in Code assist 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50433">50433</a>
+Rationalize signatures of AST.parse* methods 
+
+<a name="v_411"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M8 Build - 3rd March 2004
+<br>Project org.eclipse.jdt.core v_411
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_411">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+<li>Added new constant <code>IJavaElementDelta.F_CLASSPATH_CHANGED</code> that indicates that
+	  the project's raw classpath has changed.
+</li>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49986">49986</a>
+setRawClasspath(...) should fire a F_CLASSPATH_CHANGED delta 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=53242">53242</a>
+Consitent Out of Memory problems indexing (with multiple Java libraries)
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=52474">52474</a>
+UI Blocked when opening Java Perspective during CVS check out 
+
+<a name="v_410"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M8 Build - 2nd March 2004
+<br>Project org.eclipse.jdt.core v_410
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_410">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+<li>Added following APIs to <code>org.eclipse.jdt.core.dom.CompilationUnit</code>:
+<ul>
+<li><code>getCommentList()</code>: Returns a list of the comments encountered while parsing the compilation unit.</li>
+<li><code>getExtendedStartPosition(ASTNode)</code>: Returns the extended start position of the given node.</li>
+<li><code>getExtendedLength(ASTNode)</code>: Returns the extended source length of the given node.</li>
+</li>
+</ul>
+Unlike <code>ASTNode#getStartPosition()</code> and <code>ASTNode#getLength()</code>, the extended source range may include
+comments and whitespace immediately before or after the normal source range for the node.
+<br>
+See bug <a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=53445">53445</a> for more details on heuristic to find leading and trailing comments.
+</li>
+<li>Added API <code>FieldReferenceMatch.isReadAccess()</code> and <code>isWriteAccess()</code>.
+<li>Added API <code>JavaCore.run(IWorkspaceRunnable action, ISchedulingRule rule, IProgressMonitor monitor)</code> 
+	 to control the scheduling rule during a Java batch operation.
+</li>
+<li>Added API <code>SearchEngine.createJavaSearchScope(IJavaElement[], int)</code> that allows to filter the
+     classpath entries added in the scope: SOURCES, APPLICATION_LIBRARIES, SYSTEM_LIBRARIES and REQUIRED_PROJECTS.
+</li>
+<li> New command line options for batch compiler:
+  <ul>
+  <li> <code>-maxProblems &lt;n&gt;</code> :  max number of problems per compilation unit (100 by default) </li>
+  <li> <code>-noJSR</code> : do not use JSR bytecode </li>
+  </ul>
+</li>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=53445">53445</a>
+[DCR] [DOM Comments] Provide extended ranges including leading/trailing comments for AST nodes
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=53276">53276</a>
+[DOM Comments] Wrong text element length when containing '\' character
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=52908">52908</a>
+[DOM Comments] Wrong text element positions when starting/ending with { or }
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=48337">48337</a>
+[Search] FieldReferenceMatch should report read/write access 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=52691">52691</a>
+Add batch compiler option for maxProblemsPerUnit
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=51045">51045</a>
+Offer to call JavaCore.run with scheduling rule 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=52273">52273</a>
+Add option on predefined search scope to include/exclude system contain libraries 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49809">49809</a>
+NPE from MethodVerifier 
+
+<a name="v_409"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M8 Build - 24th February 2004
+<br>Project org.eclipse.jdt.core v_409
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_409">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+<li>Added new API to create a DOM AST while reconciling 
+	 <code>ICompilationUnit.reconcile(boolean, boolean, WorkingCopyOwner, IProgressMonitor)</code>.
+</li>
+<li>Removed compiler support for deprecating jsr bytecode in 1.5 compliant mode (turned off until future release).
+</li>
+<li>The constant DefaultCodeFormatterConstants.FORMATTER_PRESERVE_USER_LINEBREAKS will be removed. It has been deprecated for now and
+has no effect in the UI anymore.
+</li>
+<li>The constant DefaultCodeFormatterConstants.FORMATTER_FILLING_SPACE will be removed. It has been deprecated for now and
+has no effect in the UI anymore.
+</li>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=52916">52916</a>
+Strang error message when using jre1.5.0 libraries
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50586">50586</a>
+[Code Formatter] trim trailing blanks/whitespace
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=52851">52851</a>
+Space before else should be removed in some cases
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=52283">52283</a>
+do <single-statement> while(<condition>) is ill-formatted
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=52479">52479</a>
+Code Format fails on not on-demand imports
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=52246">52246</a>
+M7 Source formatter fails silently when assert present in source
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=52429">52429</a>
+code formatter seems to ignore settings
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=51623">51623</a>
+[formatter] Wrong formatting when "Preserve existing line breaks" switched on
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=52305">52305</a>
+Code Formatter strips blank lines in methods and field definitions when I try to tell it not to
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=52746">52746</a>
+Formatter - preserve line breaks conflicts with keep blank lines
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=52804">52804</a>
+Deprecated formatter constant should indicate new way
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=52619">52619</a>
+NPE running Java model tests
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=36889">36889</a>
+[DCR] Keep AST created in reconcile for active editor 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=52384">52384</a>
+OutOfMemoryError opening hierarchy on Object 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=52355">52355</a>
+Not present exception trying to create a class in excluded package
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49809">49809</a>
+NPE from MethodVerifier
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=22104">22104</a>
+[infrastructure] NPE from IndexSummary.read(...)
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=31013">31013</a>
+ [infrastructure] npe in index crash recovery
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=31014">31014</a>
+[infrastructure] exception in indexer
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=51447">51447</a>
+[infrastructure] NPE running JDT Core tests
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=52221">52221</a>
+[Compiler] should reject Local type usage when defined in other switch case block
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=52216">52216</a>
+[regression in M7] javadoc: @see <a href> shows a warning
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=51990">51990</a>
+'parameter' vs 'argument' in compiler errors/settings
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=52012">52012</a>
+Special 'serialPersistentFields' marked as 'never used locally'
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=51353">51353</a>
+The type AbstractStringBuilder is not visible
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49259">49259</a>
+Task tags starting with TODO don't correctly display their priority in Tasks View
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49879">49879</a>
+java.lang.ClassCastException (SourceTypeBinding to a BinaryTypeBinding) in 30M6 within jdt.core.dom.TypeBinding.getKey(TypeBinding.java:411)
+
+<a name="v_408"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M7 Build - 12th February 2004 - 3.0 MILESTONE-7
+<br>Project org.eclipse.jdt.core v_408
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_408">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=51603">51603</a>
+[preferences] Code formatter line wrapping preference inconsistent preview behaviour
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=51476">51476</a>
+Javadoc: String or URL @see references are not stored in DOM AST Javadoc structure
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=51478">51478</a>
+Javadoc: @deprecated/@inheritDoc tags are not stored in DOM AST Javadoc structure
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=51508">51508</a>
+Javadoc: Package references DOM AST nodes binding is null
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=51626">51626</a>
+Javadoc - DOM/AST is not correct after a @see tag
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=51650">51650</a>
+Incorrected deprecation check
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=51770">51770</a>
+Javadoc AST Node: wrong binding on qualified name part
+
+
+<a name="v_407"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M7 Build - 11th February 2004
+<br>Project org.eclipse.jdt.core v_407
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_407">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+<li>Fixed most of the API Java doc comments. 
+</li>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=51659">51659</a>
+New Code Formatter: minor problem with "White spaces/Array Initializers" option
+
+
+<a name="v_406"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M7 Build - 10th February 2004
+<br>Project org.eclipse.jdt.core v_406
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_406">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=51035">51035</a>
+[Formatter] endline comment in case of simple if-then statement
+
+
+<a name="v_405"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M7 Build - 9th February 2004
+<br>Project org.eclipse.jdt.core v_405
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_405">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=51363">51363</a>
+Wrong comment positions inside the Scanner.
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=51201">51201</a>
+Code formatter missing 'between empty brackets' option in Whitespace Array allocation configuration
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50695">50695</a>
+Javadoc: package reference in @see tags is wrongly warned
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49994">49994</a>
+Strange matches with start=0, end=1 in type reference search
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=51300">51300</a>
+VerifyError when using a array reference assigned to null
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=51128">51128</a>
+[Code Formatter] Indent statements within blocks and methods
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=51241">51241</a>
+IllegalArgumentException while creating a DOM/AST
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=51249">51249</a>
+Performance problems in PackageFragment.getPath 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50276">50276</a>
+Function call line wrapping fails on chained calls
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=51190">51190</a>
+comment after else block goes to next line
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=51226">51226</a>
+Javadoc inside DOM AST does not support starting characters in unicode
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=51104">51104</a>
+Comments are not recorded when inside a method body
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50858">50858</a>
+Javadoc IProblem constant not defined
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50898">50898</a>
+Javadoc AST: Missing binding for reference to non-visible type
+
+<a name="v_404"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M7 Build - 3rd February 2004
+<br>Project org.eclipse.jdt.core v_404
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_404">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50938">50938</a>
+Javadoc AST: Still invalid range for embedded tag
+
+<a name="v_403"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M7 Build - 3rd February 2004
+<br>Project org.eclipse.jdt.core v_403
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_403">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+<li>Updated porting guide to introduce search participant story (see <a href="http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/org.eclipse.jdt.core/notes/porting_guide.html">porting guide</a>)</li>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=51089">51089</a>
+Java AST creation failure 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50571">50571</a>
+search sender in hierarchy hangs 
+
+<a name="v_402"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M7 Build - 30th January 2004
+<br>Project org.eclipse.jdt.core v_402
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_402">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50883">50883</a>
+Javadoc AST node: Range problem with embedded tags
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50884">50884</a>
+Compiler crashes without a trace in the log leaving workspace in unhappy state
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50831">50831</a>
+DCR Javadoc AST: Offer well known tag names as constants 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50880">50880</a>
+JavadocAST Nodes: Wrong ranges on link
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50877">50877</a>
+Javadoc AST Nodes: Wrong ranges
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=47396">47396</a>
+JAVA AST Creation failure
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50844">50844</a>
+AbortCompilation thrown from Name#resolveBinding() 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50746">50746</a>
+Searching for variable references can cause an internal error
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50838">50838</a>
+Javadoc bindings: No bindings in constructor ref parameter
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50840">50840</a>
+Javadoc AST: wrong start position on MemberRef
+
+<a name="v_401"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M7 Build - 29th January 2004
+<br>Project org.eclipse.jdt.core v_401
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_401">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=46126">46126</a>
+[DCR] IBinding should have a method to check @since javadoc tag
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50785">50785</a>
+Javadoc bindings: No bindings member refs
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50784">50784</a>
+Javadoc bindings: No binding in {@link } and link disturbs other bindings
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50781">50781</a>
+Javadoc bindings: No bindings for qualified names
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50736">50736</a>
+Out of bounds exception while formatting
+
+<a name="v_400"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M7 Build - 28th January 2004
+<br>Project org.eclipse.jdt.core v_400
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_400">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50694">50694</a>
+Javadoc: Cannot find DOM AST bindings for types in @see tags
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50692">50692</a>
+Javadoc: Cannot find DOM AST bindings for inline link tags references
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50719">50719</a>
+wrong formatting for java coding conventions
+
+<a name="v_399"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M7 Build - 27th January 2004
+<br>Project org.eclipse.jdt.core v_399
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_399">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+<li>Improve DOM/AST support for doc comments.
+<br>Following changes have been made to the DOM/AST API:
+<ul>
+<li>added Javadoc.tags() to represent structure of the doc comments</li>
+<li>deprecated Javadoc.get/setComment</li>
+<li>added 5 new node types that occur only within doc comments: TagElement, TextElement, MemberRef, MethodRef, MethodRefParameter</li>
+<li>tag elements like MemberRef, MethodRef, and Name can carry binding information (must be requested like elsewhere)</li>
+<li>added ASTVisitor(boolean) for controlling whether Javadoc.tags() are visited by default</li>
+<li>added ASTMatcher(boolean) for controlling whether Javadoc.tags() are compared vs. only Javadoc.getComment()</li>
+<li>AST.parse*(...) now returns structured doc comments (for compatibility, Javadoc.getComment() is also set as before)</li>
+</ul>
+See bugs <a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50683">50683</a>.
+</li>
+<li>
+Improve DOM/AST support for locating all comments.
+<br>Following changes have been made to the DOM/AST API:
+<ul>
+<li>added CompilationUnit.getCommentTable() to record locations of all comments found in the source</li>
+<li>added 2 new node types, LineComment and BlockComment, to represent end-of-line and traditional comments respectively</li>
+<li>these new nodes are placeholders for comments</li>
+<li>these new node types only occur in the comment table (since they can occur anywhere (lexically), there is no way to properly parent them in the regular AST nodes that reflects their position)</li>
+<li>AST.parse*(...) now returns sets the comment table on the compilation unit to include all comments (including attached and free-floating doc comments)</li>
+</ul>
+See bug <a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50697">50697</a>.
+</li>
+<li> Added option to control whether diagnosis for unused thrown exceptions should be enabled when overriding another
+method. By default, it is disabled.
+<pre>
+* COMPILER / Reporting Unused Declared Thrown Exception in Overridind Method
+*    When disabled, the compiler will not include overriding methods in its diagnosis for unused declared
+*    thrown exceptions.
+*    The severity of the problem is controlled with option "org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException".
+*     - option id:         "org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding"
+*     - possible values:   { "enabled", "disabled" }
+*     - default:           "disabled"
+</pre>
+</li>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50644">50644</a>
+Deprecation check doesn't check that the @deprecated is at the beginning of the line
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=27134">27134</a>
+Add a ASTNode for non-Javadoc comments
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50683">50683</a>
+Improve DOM/AST support for doc comments
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50697">50697</a>
+Improve DOM/AST support for locating all comments
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50667">50667</a>
+Deadlock on Refactor -> Extract method
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=47430">47430</a>
+the immutable bit is copied from the original resource to the ouput directory
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50601">50601</a>
+Blank lines before package declaration is one fewer than specified
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=48292">48292</a>
+[DCR] Need AST.parsePartialClassFile(....)
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50320">50320</a>
+Java model operations should use IResourceRuleFactory 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50207">50207</a>
+Compile errors fixed by 'refresh' do not reset problem list or package explorer error states 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49691">49691</a>
+JavaProject looses property listeners on preferences
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50265">50265</a>
+Emulate old formatter with the new formatter
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50225">50225</a>
+Calling the default formatter with an empty string returns an invalid Edit 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=44876">44876</a>
+"Unnecessary declaration of thrown exception" problems
+
+
+<a name="v_398"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M7 Build - 20th January 2004
+<br>Project org.eclipse.jdt.core v_398
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_398">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+<li>Major renaming of constants in the code formatter. See <code>org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants</code>. See bug <a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49908">49908</a>.
+The old constants have been deprecated and will be removed before M7. So we encourage you to save your code formatter preferences if
+you modified the default settings. The UI will provide an automatic conversion to the new options.
+</li>
+<li>Added API for alignment options in the code formatter.  See <code>org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants</code>. See bug <a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49968">49968</a>.
+</li>
+<li>Changed 3.0 APIs on <code>org.eclipse.jdt.core.dom.AST</code> to take an <code>IProgressMonitor</code>. This progress monitor is checked for the cancelation of the AST creation only.
+</li>
+<li>Added API on <code>org.eclipse.jdt.core.dom.AST</code> to parse an expression or statements or class body declarations without requiring the parsing
+of the whole compilation unit. This is still subject to change before 3.0.
+<pre>
+	/**
+	 * Parses the given source between the bounds specified by the given offset (inclusive)
+	 * and the given length and creates and returns a corresponding abstract syntax tree.
+	 * 
+	 * The root node of the new AST depends on the given kind.
+	 * - <code>org.eclipse.jdt.core.dom.AST.K_CLASS_BODY_DECLARATIONS</code>: The root node is an instance of
+	 * <code>org.eclipse.jdt.core.dom.TypeDeclaration</code>. The type declaration itself doesn't contain any information.
+	 * It is simply used to return all class body declarations inside the bodyDeclaratins() collection.
+	 * - <code>org.eclipse.jdt.core.dom.AST.K_STATEMENTS</code>: The root node is an instance of
+	 * <code>org.eclipse.jdt.core.dom.Block</code>. The block itself doesn't contain any information.
+	 * It is simply used to return all the statements.
+	 * - <code>org.eclipse.jdt.core.dom.AST.K_EXPRESSION</code>: The root node is an instance of a subclass of
+	 * <code>org.eclipse.jdt.core.dom.Expression</code>.
+	 *  
+	 * Each node in the subtree carries source range(s) information relating back
+	 * to positions in the given source (the given source itself
+	 * is not remembered with the AST). 
+	 * The source range usually begins at the first character of the first token 
+	 * corresponding to the node; leading whitespace and comments are <b>not</b>
+	 * included. The source range usually extends through the last character of
+	 * the last token corresponding to the node; trailing whitespace and
+	 * comments are <b>not</b> included. There are a handful of exceptions
+	 * (including compilation units and the various body declarations); the
+	 * specification for these node type spells out the details.
+	 * Source ranges nest properly: the source range for a child is always
+	 * within the source range of its parent, and the source ranges of sibling
+	 * nodes never overlap.
+	 * 
+	 * This method does not compute binding information; all <code>resolveBinding</code>
+	 * methods applied to nodes of the resulting AST return <code>null</code>.
+	 * 
+	 * <code>null</code> is returned:
+	 * 1. If a syntax error is detected while parsing,
+	 * 2. If the given source doesn't correspond to the given kind.
+	 *  
+	 * @param kind the given kind to parse
+	 * @param source the string to be parsed
+	 * @param offset the given offset
+	 * @param length the given length
+	 * @param options the given options. If null, <code>JavaCore.getOptions()</code> is used.
+	 * @param monitor the progress monitor used to check if the AST creation needs to be canceled
+	 * 
+	 * @return ASTNode
+	 * @see ASTNode#getStartPosition()
+	 * @see ASTNode#getLength()
+	 * @see AST#K_CLASS_BODY_DECLARATIONS
+	 * @see AST#K_EXPRESSION
+	 * @see AST#K_STATEMENTS
+	 * @see JavaCore#getOptions()
+	 * @since 3.0
+	 */
+	public static ASTNode parse(int kind, char[] source, int offset, int length, Map options, IProgressMonitor monitor);
+</pre>
+</li>
+<li>Added API on <code>org.eclipse.jdt.core.dom.AST</code> to parse a compilation unit and specify
+the set of options to use. This is still subject to change before 3.0. The previous API was directly
+using <code>JavaCore.getOptions()</code>. This could be problematic in case you want to parse assert
+statements.
+<pre>
+	/**
+	 * Parses the given string as a Java compilation unit and creates and 
+	 * returns a corresponding abstract syntax tree.
+	 * 
+	 * The given options are used to find out the compiler options to use while parsing.
+	 * This could implies the settings for the assertion support. See the <code>JavaCore.getOptions()</code>
+	 * methods for further details.
+	 * 
+	 * 
+	 * The returned compilation unit node is the root node of a new AST.
+	 * Each node in the subtree carries source range(s) information relating back
+	 * to positions in the given source string (the given source string itself
+	 * is not remembered with the AST). 
+	 * The source range usually begins at the first character of the first token 
+	 * corresponding to the node; leading whitespace and comments are <b>not</b>
+	 * included. The source range usually extends through the last character of
+	 * the last token corresponding to the node; trailing whitespace and
+	 * comments are <b>not</b> included. There are a handful of exceptions
+	 * (including compilation units and the various body declarations); the
+	 * specification for these node type spells out the details.
+	 * Source ranges nest properly: the source range for a child is always
+	 * within the source range of its parent, and the source ranges of sibling
+	 * nodes never overlap.
+	 * If a syntax error is detected while parsing, the relevant node(s) of the
+	 * tree will be flagged as <code>MALFORMED</code>.
+	 * 
+	 * 
+	 * This method does not compute binding information; all <code>resolveBinding</code>
+	 * methods applied to nodes of the resulting AST return <code>null</code>.
+	 * 
+	 * 
+	 * @param source the string to be parsed as a Java compilation unit
+	 * @param options options to use while parsing the file. If null, <code>JavaCore.getOptions()</code> is used.
+	 * @param monitor the progress monitor used to check if the AST creation needs to be canceled
+	 * @return CompilationUnit
+	 * @see ASTNode#getFlags()
+	 * @see ASTNode#MALFORMED
+	 * @see ASTNode#getStartPosition()
+	 * @see ASTNode#getLength()
+	 * @see JavaCore#getOptions()
+	 * @since 3.0
+	 */
+	public static CompilationUnit parseCompilationUnit(char[] source, Map options, IProgressMonitor monitor);
+</pre>
+</li>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50258">50258</a>
+AST.parseCompilationUnit(... IWorkingCopyOwner..) should allow null 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49937">49937</a>
+JavaDoc of ITypeBinding#isLocal() talks about local interfaces 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49845">49845</a>
+DCR: Allow to cancel the AST creation 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=48489">48489</a>
+[DCR] AST support for a single expression (vs. CU)
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49327">49327</a>
+formatter can return null TextEdit when parsing valid java
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49908">49908</a>
+Renaming of DefaultCodeFormatterConstants.java
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49968">49968</a>
+[formatter] Alignment API
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49953">49953</a>
+[Code Formatter] Cannot customize the spaces around brackets in array allocation expression
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=50025">50025</a>
+uppercase ZIP and JAR classpath entries ignored
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=45060">45060</a>
+Missing external jar prevents build, but jar still in Java model 
+
+<a name="v_397"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.0M7 Build - 13th January 2004
+<br>Project org.eclipse.jdt.core v_397
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_397">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+<li>Added API to get the scheduling rule for a Java element:
+<pre>
+	/**
+	 * Returns the scheduling rule associated with this Java element.
+	 * This is a handle-only method.
+	 * 
+	 * @return the scheduling rule associated with this Java element
+	 * @since 3.0
+	 */
+	ISchedulingRule getSchedulingRule();
+</pre>
+</li>
+<li>Code formatter: If you did change the value of the setting controlling the insertion of a white space between empty arguments of a method declaration,
+then you have to change it again. Indeed, a spelling mistake has been fixed in the constant name. See bug <a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49530">49530</a>.</li>
+<li>Inline tags are now supported in Javadoc comments:
+<ul><li>{@link} and {@linkplain} tags are now parsed using same rules as for @see tag. See bug <a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=48385">48385</a>.
+<br>Because references declared in these tags should be now found during search operation,  the index format had to be changed. Indexes will be automatically regenerated upon subsequent search queries (accounting for indexing notification in search progress dialogs).</li>
+<li>{@inheritDoc} tag is now parsed. When this tag is present in a method javadoc comment, all missing tags errors are ignored.
+See bug <a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=45782">45782</a>.</li>
+</ul>
+</li>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49843">49843</a>
+Not reporting error on constructor with no body
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49491">49491</a>
+Add option to toggle warning for Javadoc multiple same name @throws tags
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49260">49260</a>
+Malformed Javadoc Compiler option sensitive to line breaks
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=45782">45782</a>
+[DCR] Compiler should take into account {@inheritDoc} tag
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=48385">48385</a>
+[DCR] Need Javadoc warning for {@link }
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49760">49760</a>
+Splitting up FORMATTER_INSERT_SPACE_WITHIN_MESSAGE_SEND
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49763">49763</a>
+New formatter: Problem with empty statement in while
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=48701">48701</a>
+NPE evaluating watch expression 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49290">49290</a>
+NullpointerException in TypeBinding.getInterfaces(). 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49660">49660</a>
+Code formatter line wrapping indentation ignores whitespace settings
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=48293">48293</a>
+[DCR] IJavaElement should implement ISchedulingRule 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=48459">48459</a>
+NPE in Type hierarchy 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49653">49653</a>
+Unnecessary white space is added after last semicolon in for statement without increments
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49351">49351</a>
+New code formatter: left curly brace placement
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49530">49530</a>
+Spelling mistake in the FORMATTER_INSERT_SPACE_BETWEEN_EMPTY_ARGUMENTS string constant
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49298">49298</a>
+Code formatter does not correctly space closing bracket on method calls
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=48395">48395</a>
+Hierarchy on region misses local classes 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=47743">47743</a>
+Open type hiearchy problems [type hierarchy] 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49571">49571</a>
+White space options for method and constructor declarations
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49577">49577</a>
+Add an option to specify the number of blank lines between two type declarations
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49551">49551</a>
+formatter fails on empty statement between package and imports
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=39943">39943</a>
+[navigation] outliner auto-changes selection (multi-fields) 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49490">49490</a>
+New Code Formatter; Java Coding Conventions; Blank Lines; Before first declaration
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49561">49561</a>
+Commit should only lock parent's folder 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=47699">47699</a>
+Make org.eclipse.core.runtime.compatibility non optional 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=41444">41444</a>
+[navigation] error dialog on opening class file 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=48350">48350</a>
+IType#resolveType(String) fails on local types 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49120">49120</a>
+search doesn't find references to anonymous inner methods 
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49482">49482</a>
+New Code Formatter; if/else without curly braces; guardian clause (2)
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49481">49481</a>
+New Code Formatter; if/else without curly braces; guardian clause (1)
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49361">49361</a>
+FORMATTER_INSERT_SPACE_BETWEEN_EMPTY_ARRAY_INITIALIZER
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49243">49243</a>
+New code formatter: missing feature
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=49429">49429</a>
+error during build
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=48404">48404</a>
+formatter: no edit returned
+
 <a name="v_396"></a>
 <p><hr><h1>
 Eclipse Platform Build Notes&nbsp;<br>
@@ -297,9 +2247,7 @@
 Indirect static proposal: Wrong compiler positions
 <br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=48141">48141</a>
 Formatter: Java Conventions/WS/Expressions/Operators 
-<br><!-- a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=48143">48143</a>
-Formatter: Line Wrapping/Conditionals
-<br --><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=45157">45157</a>
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=45157">45157</a>
 Source Formatter: Clear all Blank lines needs to have the ability to set a number of lines to keep.
 <br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=44673">44673</a>
 Formatting
@@ -411,8 +2359,6 @@
 New formatter not properly formatting long method invocation
 <br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=44653">44653</a>
 // $NON-NLS-1$ comments not kept on same line of the string while formatting
-<!-- br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=44642">44642</a>
-New formatter should better handle cascaded message -->
 <br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=46699">46699</a>
 IBinding.isSynthetic() returns false for compiler-generated constructor
 <br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=47415">47415</a>
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/parser/SourceConstructorDeclaration.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/parser/SourceConstructorDeclaration.java
new file mode 100644
index 0000000..c57cee9
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/parser/SourceConstructorDeclaration.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.parser;
+
+import org.eclipse.jdt.internal.compiler.CompilationResult;
+import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
+
+public class SourceConstructorDeclaration extends ConstructorDeclaration {
+	public int selectorSourceEnd;
+
+	public SourceConstructorDeclaration(CompilationResult compilationResult){
+		super(compilationResult);
+	}
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/parser/SourceFieldDeclaration.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/parser/SourceFieldDeclaration.java
new file mode 100644
index 0000000..c1e2c37
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/parser/SourceFieldDeclaration.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.parser;
+
+import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
+
+public class SourceFieldDeclaration extends FieldDeclaration {
+	public int fieldEndPosition;
+public SourceFieldDeclaration(
+	char[] name, 
+	int sourceStart, 
+	int sourceEnd) {
+	super(name, sourceStart, sourceEnd);
+}
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/parser/SourceMethodDeclaration.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/parser/SourceMethodDeclaration.java
new file mode 100644
index 0000000..3ea92a7
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/parser/SourceMethodDeclaration.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.parser;
+
+import org.eclipse.jdt.internal.compiler.CompilationResult;
+import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
+
+public class SourceMethodDeclaration extends MethodDeclaration {
+	public int selectorSourceEnd;
+	
+	public SourceMethodDeclaration(CompilationResult compilationResult){
+		super(compilationResult);
+	}
+	
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/parser/SourceTypeConverter.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/parser/SourceTypeConverter.java
new file mode 100644
index 0000000..c3ccb87
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/parser/SourceTypeConverter.java
@@ -0,0 +1,391 @@
+/*******************************************************************************
+ * 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.compiler.parser;
+
+/**
+ * Converter from source element type to parsed compilation unit.
+ *
+ * Limitation:
+ * | The source element field does not carry any information for its constant part, thus
+ * | the converted parse tree will not include any field initializations.
+ * | Therefore, any binary produced by compiling against converted source elements will
+ * | not take advantage of remote field constant inlining.
+ * | Given the intended purpose of the conversion is to resolve references, this is not
+ * | a problem.
+ *
+ */
+
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.CompilationResult;
+import org.eclipse.jdt.internal.compiler.ast.ASTNode;
+import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.Argument;
+import org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.ImportReference;
+import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.TypeReference;
+import org.eclipse.jdt.internal.compiler.env.ISourceField;
+import org.eclipse.jdt.internal.compiler.env.ISourceImport;
+import org.eclipse.jdt.internal.compiler.env.ISourceMethod;
+import org.eclipse.jdt.internal.compiler.env.ISourceType;
+
+import org.eclipse.jdt.internal.compiler.lookup.CompilerModifiers;
+import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
+
+public class SourceTypeConverter implements CompilerModifiers {
+	
+	public static final int FIELD = 0x01;
+	public static final int CONSTRUCTOR = 0x02;
+	public static final int METHOD = 0x04;
+	public static final int MEMBER_TYPE = 0x08;
+	public static final int FIELD_INITIALIZATION = 0x10;
+	public static final int FIELD_AND_METHOD = FIELD | CONSTRUCTOR | METHOD;
+	public static final int NONE = 0;
+	
+	private int flags;
+	private CompilationUnitDeclaration unit;
+	private Parser parser;
+	private ProblemReporter problemReporter;
+	
+	private SourceTypeConverter(int flags, ProblemReporter problemReporter) {
+		this.flags = flags;
+		this.problemReporter = problemReporter;
+	}
+
+	/*
+	 * Convert a set of source element types into a parsed compilation unit declaration
+	 * The argument types are then all grouped in the same unit. The argument types must 
+	 * at least contain one type.
+	 * Can optionally ignore fields & methods or member types or field initialization
+	 */
+	public static CompilationUnitDeclaration buildCompilationUnit(
+		ISourceType[] sourceTypes,
+		int flags,
+		ProblemReporter problemReporter,
+		CompilationResult compilationResult) {
+			
+		return 
+			new SourceTypeConverter(flags, problemReporter).convert(sourceTypes, compilationResult);
+	}
+
+	/*
+	 * Convert a set of source element types into a parsed compilation unit declaration
+	 * The argument types are then all grouped in the same unit. The argument types must 
+	 * at least contain one type.
+	 */
+	private CompilationUnitDeclaration convert(ISourceType[] sourceTypes, CompilationResult compilationResult) {
+		this.unit = new CompilationUnitDeclaration(this.problemReporter, compilationResult, 0);
+		// not filled at this point
+
+		if (sourceTypes.length == 0) return this.unit;
+		ISourceType sourceType = sourceTypes[0];
+		if (sourceType.getName() == null)
+		    // TODO (jerome) investigate when this can happen : if this can happen, fix clients to protect themselves
+			return null; // do a basic test that the sourceType is valid
+
+		/* only positions available */
+		int start = sourceType.getNameSourceStart();
+		int end = sourceType.getNameSourceEnd();
+
+		/* convert package and imports */
+		if (sourceType.getPackageName() != null
+			&& sourceType.getPackageName().length > 0)
+			// if its null then it is defined in the default package
+			this.unit.currentPackage =
+				createImportReference(sourceType.getPackageName(), start, end, false, AccDefault);
+		ISourceImport[]  sourceImports = sourceType.getImports();
+		int importCount = sourceImports == null ? 0 : sourceImports.length;
+		this.unit.imports = new ImportReference[importCount];
+		for (int i = 0; i < importCount; i++) {
+			ISourceImport sourceImport = sourceImports[i];
+			this.unit.imports[i] = createImportReference(
+				sourceImport.getName(), 
+				sourceImport.getDeclarationSourceStart(),
+				sourceImport.getDeclarationSourceEnd(),
+				sourceImport.onDemand(),
+				sourceImport.getModifiers());
+		}
+		/* convert type(s) */
+		int typeCount = sourceTypes.length;
+		this.unit.types = new TypeDeclaration[typeCount];
+		for (int i = 0; i < typeCount; i++) {
+			this.unit.types[i] =
+				convert(sourceTypes[i], compilationResult);
+		}
+		return this.unit;
+	}
+	
+	/*
+	 * Convert a field source element into a parsed field declaration
+	 */
+	private FieldDeclaration convert(ISourceField sourceField, TypeDeclaration type) {
+
+		FieldDeclaration field = new FieldDeclaration();
+
+		int start = sourceField.getNameSourceStart();
+		int end = sourceField.getNameSourceEnd();
+
+		field.name = sourceField.getName();
+		field.sourceStart = start;
+		field.sourceEnd = end;
+		field.type = createTypeReference(sourceField.getTypeName(), start, end);
+		field.declarationSourceStart = sourceField.getDeclarationSourceStart();
+		field.declarationSourceEnd = sourceField.getDeclarationSourceEnd();
+		field.modifiers = sourceField.getModifiers();
+
+		if ((this.flags & FIELD_INITIALIZATION) != 0) {
+			/* conversion of field constant */
+			char[] initializationSource = sourceField.getInitializationSource();
+			if (initializationSource != null) {
+				if (this.parser == null) {
+					this.parser = new Parser(this.problemReporter, true);
+				}
+				this.parser.parse(field, type, this.unit, initializationSource);
+			}
+		}
+		
+		return field;
+	}
+
+	/*
+	 * Convert a method source element into a parsed method/constructor declaration 
+	 */
+	private AbstractMethodDeclaration convert(ISourceMethod sourceMethod, CompilationResult compilationResult) {
+
+		AbstractMethodDeclaration method;
+
+		/* only source positions available */
+		int start = sourceMethod.getNameSourceStart();
+		int end = sourceMethod.getNameSourceEnd();
+
+		if (sourceMethod.isConstructor()) {
+			ConstructorDeclaration decl = new ConstructorDeclaration(compilationResult);
+			decl.isDefaultConstructor = false;
+			method = decl;
+		} else {
+			MethodDeclaration decl = new MethodDeclaration(compilationResult);
+			/* convert return type */
+			decl.returnType =
+				createTypeReference(sourceMethod.getReturnTypeName(), start, end);
+			method = decl;
+		}
+		method.selector = sourceMethod.getSelector();
+		method.modifiers = sourceMethod.getModifiers();
+		method.sourceStart = start;
+		method.sourceEnd = end;
+		method.declarationSourceStart = sourceMethod.getDeclarationSourceStart();
+		method.declarationSourceEnd = sourceMethod.getDeclarationSourceEnd();
+
+		/* convert arguments */
+		char[][] argumentTypeNames = sourceMethod.getArgumentTypeNames();
+		char[][] argumentNames = sourceMethod.getArgumentNames();
+		int argumentCount = argumentTypeNames == null ? 0 : argumentTypeNames.length;
+		long position = (long) start << 32 + end;
+		method.arguments = new Argument[argumentCount];
+		for (int i = 0; i < argumentCount; i++) {
+			method.arguments[i] =
+				new Argument(
+					argumentNames[i],
+					position,
+					createTypeReference(argumentTypeNames[i], start, end),
+					AccDefault);
+			// do not care whether was final or not
+		}
+
+		/* convert thrown exceptions */
+		char[][] exceptionTypeNames = sourceMethod.getExceptionTypeNames();
+		int exceptionCount = exceptionTypeNames == null ? 0 : exceptionTypeNames.length;
+		method.thrownExceptions = new TypeReference[exceptionCount];
+		for (int i = 0; i < exceptionCount; i++) {
+			method.thrownExceptions[i] =
+				createTypeReference(exceptionTypeNames[i], start, end);
+		}
+		return method;
+	}
+
+	/*
+	 * Convert a source element type into a parsed type declaration
+	 */
+	private TypeDeclaration convert(ISourceType sourceType, CompilationResult compilationResult) {
+		/* create type declaration - can be member type */
+		TypeDeclaration type = new TypeDeclaration(compilationResult);
+		if (sourceType.getEnclosingType() != null) {
+			type.bits |= ASTNode.IsMemberTypeMASK;
+		}
+		type.name = sourceType.getName();
+		int start, end; // only positions available
+		type.sourceStart = start = sourceType.getNameSourceStart();
+		type.sourceEnd = end = sourceType.getNameSourceEnd();
+		type.modifiers = sourceType.getModifiers();
+		type.declarationSourceStart = sourceType.getDeclarationSourceStart();
+		type.declarationSourceEnd = sourceType.getDeclarationSourceEnd();
+		type.bodyEnd = type.declarationSourceEnd;
+
+		/* set superclass and superinterfaces */
+		if (sourceType.getSuperclassName() != null)
+			type.superclass =
+				createTypeReference(sourceType.getSuperclassName(), start, end);
+		char[][] interfaceNames = sourceType.getInterfaceNames();
+		int interfaceCount = interfaceNames == null ? 0 : interfaceNames.length;
+		type.superInterfaces = new TypeReference[interfaceCount];
+		for (int i = 0; i < interfaceCount; i++) {
+			type.superInterfaces[i] = createTypeReference(interfaceNames[i], start, end);
+		}
+		/* convert member types */
+		if ((this.flags & MEMBER_TYPE) != 0) {
+			ISourceType[] sourceMemberTypes = sourceType.getMemberTypes();
+			int sourceMemberTypeCount =
+				sourceMemberTypes == null ? 0 : sourceMemberTypes.length;
+			type.memberTypes = new TypeDeclaration[sourceMemberTypeCount];
+			for (int i = 0; i < sourceMemberTypeCount; i++) {
+				type.memberTypes[i] = convert(sourceMemberTypes[i], compilationResult);
+			}
+		}
+
+		/* convert fields */
+		if ((this.flags & FIELD) != 0) {
+			ISourceField[] sourceFields = sourceType.getFields();
+			int sourceFieldCount = sourceFields == null ? 0 : sourceFields.length;
+			type.fields = new FieldDeclaration[sourceFieldCount];
+			for (int i = 0; i < sourceFieldCount; i++) {
+				type.fields[i] = convert(sourceFields[i], type);
+			}
+		}
+
+		/* convert methods - need to add default constructor if necessary */
+		boolean needConstructor = (this.flags & CONSTRUCTOR) != 0;
+		boolean needMethod = (this.flags & METHOD) != 0;
+		if (needConstructor || needMethod) {
+			
+			ISourceMethod[] sourceMethods = sourceType.getMethods();
+			int sourceMethodCount = sourceMethods == null ? 0 : sourceMethods.length;
+	
+			/* source type has a constructor ?           */
+			/* by default, we assume that one is needed. */
+			int extraConstructor = 0;
+			int methodCount = 0;
+			boolean isInterface = type.isInterface();
+			if (!isInterface) {
+				extraConstructor = needConstructor ? 1 : 0;
+				for (int i = 0; i < sourceMethodCount; i++) {
+					if (sourceMethods[i].isConstructor()) {
+						if (needConstructor) {
+							extraConstructor = 0; // Does not need the extra constructor since one constructor already exists.
+							methodCount++;
+						}
+					} else if (needMethod) {
+						methodCount++;
+					}
+				}
+			} else {
+				methodCount = needMethod ? sourceMethodCount : 0;
+			}
+			type.methods = new AbstractMethodDeclaration[methodCount + extraConstructor];
+			if (extraConstructor != 0) { // add default constructor in first position
+				type.methods[0] = type.createsInternalConstructor(false, false);
+			}
+			int index = 0;
+			for (int i = 0; i < sourceMethodCount; i++) {
+				ISourceMethod sourceMethod = sourceMethods[i];
+				boolean isConstructor = sourceMethod.isConstructor();
+				if ((isConstructor && needConstructor) || (!isConstructor && needMethod)) {
+					AbstractMethodDeclaration method =convert(sourceMethod, compilationResult);
+					if (isInterface || method.isAbstract()) { // fix-up flag 
+						method.modifiers |= AccSemicolonBody;
+					}
+					type.methods[extraConstructor + index++] = method;
+				}
+			}
+		}
+		
+		return type;
+	}
+
+	/*
+	 * Build an import reference from an import name, e.g. java.lang.*
+	 */
+	private ImportReference createImportReference(
+		char[] importName,
+		int start,
+		int end, 
+		boolean onDemand,
+		int modifiers) {
+	
+		char[][] qImportName = CharOperation.splitOn('.', importName);
+		long[] positions = new long[qImportName.length];
+		long position = (long) start << 32 + end;
+		for (int i = 0; i < qImportName.length; i++) {
+			positions[i] = position; // dummy positions
+		}
+		return new ImportReference(
+			qImportName,
+			positions,
+			onDemand,
+			modifiers);
+	}
+
+	/*
+	 * Build a type reference from a readable name, e.g. java.lang.Object[][]
+	 */
+	private TypeReference createTypeReference(
+		char[] typeSignature,
+		int start,
+		int end) {
+
+		/* count identifiers and dimensions */
+		int max = typeSignature.length;
+		int dimStart = max;
+		int dim = 0;
+		int identCount = 1;
+		for (int i = 0; i < max; i++) {
+			switch (typeSignature[i]) {
+				case '[' :
+					if (dim == 0)
+						dimStart = i;
+					dim++;
+					break;
+				case '.' :
+					identCount++;
+					break;
+			}
+		}
+		/* rebuild identifiers and dimensions */
+		if (identCount == 1) { // simple type reference
+			if (dim == 0) {
+				return new SingleTypeReference(typeSignature, (((long) start )<< 32) + end);
+			} else {
+				char[] identifier = new char[dimStart];
+				System.arraycopy(typeSignature, 0, identifier, 0, dimStart);
+				return new ArrayTypeReference(identifier, dim, (((long) start) << 32) + end);
+			}
+		} else { // qualified type reference
+			long[] positions = new long[identCount];
+			long pos = (((long) start) << 32) + end;
+			for (int i = 0; i < identCount; i++) {
+				positions[i] = pos;
+			}
+			char[][] identifiers =
+				CharOperation.splitOn('.', typeSignature, 0, dimStart);
+			if (dim == 0) {
+				return new QualifiedTypeReference(identifiers, positions);
+			} else {
+				return new ArrayQualifiedTypeReference(identifiers, dim, positions);
+			}
+		}
+	}
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/Int.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ASTHolderCUInfo.java
similarity index 65%
rename from org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/Int.java
rename to org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ASTHolderCUInfo.java
index 20a048c..685f560 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/Int.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ASTHolderCUInfo.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -8,14 +8,11 @@
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
+package org.eclipse.jdt.internal.core;
 
-public class Int {
-	public int value;
-	/**
-	 * Int constructor comment.
-	 */
-	public Int(int i) {
-		value= i;
-	}
+import org.eclipse.jdt.core.dom.CompilationUnit;
+
+public class ASTHolderCUInfo extends CompilationUnitElementInfo {
+	int astLevel;
+	CompilationUnit ast;
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Assert.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Assert.java
index 7560dc5..0d8fef3 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Assert.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Assert.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BasicCompilationUnit.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BasicCompilationUnit.java
index a1aaf84..215025c 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BasicCompilationUnit.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BasicCompilationUnit.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -13,6 +13,11 @@
 import java.io.File;
 import java.io.IOException;
 
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
 import org.eclipse.jdt.internal.compiler.util.Util;
@@ -28,8 +33,8 @@
 	protected char[][] packageName;
 	protected char[] mainTypeName;
 	protected String encoding;
-	
-public BasicCompilationUnit(char[] contents, char[][] packageName, String fileName, String encoding) {
+
+public BasicCompilationUnit(char[] contents, char[][] packageName, String fileName) {
 	this.contents = contents;
 	this.fileName = fileName.toCharArray();
 	this.packageName = packageName;
@@ -43,8 +48,54 @@
 		end = fileName.length();
 
 	this.mainTypeName = fileName.substring(start, end).toCharArray();
+	this.encoding = null;
+}
+
+public BasicCompilationUnit(char[] contents, char[][] packageName, String fileName, String encoding) {
+	this(contents, packageName, fileName);
 	this.encoding = encoding;
 }
+
+public BasicCompilationUnit(char[] contents, char[][] packageName, String fileName, IJavaElement javaElement) {
+	this(contents, packageName, fileName);
+	initEncoding(javaElement);
+}
+
+/*
+ * Initialize compilation unit encoding.
+ * If we have a project, then get file name corresponding IFile and retrieve its encoding using
+ * new API for encoding.
+ * In case of a class file, then go through project in order to let the possibility to retrieve
+ * a corresponding source file resource.
+ * If we have a compilation unit, then get encoding from its resource directly...
+ */
+private void initEncoding(IJavaElement javaElement) {
+	if (javaElement != null) {
+		try {
+			IJavaProject javaProject = javaElement.getJavaProject();
+			switch (javaElement.getElementType()) {
+				case IJavaElement.COMPILATION_UNIT:
+					IFile file = (IFile) javaElement.getResource();
+					if (file != null) {
+						this.encoding = file.getCharset();
+						break;
+					}
+					// if no file, then get project encoding
+				default:
+					IProject project = (IProject) javaProject.getResource();
+					if (project != null) {
+						this.encoding = project.getDefaultCharset();
+					}
+					break;
+			}
+		} catch (CoreException e1) {
+			this.encoding = null;
+		}
+	} else  {
+		this.encoding = null;
+	}
+}
+
 public char[] getContents() {
 	if (this.contents != null)
 		return this.contents;   // answer the cached source
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BatchOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BatchOperation.java
index d01fef5..ffe2d20 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BatchOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BatchOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BecomeWorkingCopyOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BecomeWorkingCopyOperation.java
index e9ae186..6ca089f 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BecomeWorkingCopyOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BecomeWorkingCopyOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -10,7 +10,6 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
-import org.eclipse.core.runtime.IPath;
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.JavaModelException;
@@ -21,23 +20,21 @@
  */
 public class BecomeWorkingCopyOperation extends JavaModelOperation {
 	
-	IPath path;
 	IProblemRequestor problemRequestor;
 	
 	/*
 	 * Creates a BecomeWorkingCopyOperation for the given working copy.
 	 * perOwnerWorkingCopies map is not null if the working copy is a shared working copy.
 	 */
-	public BecomeWorkingCopyOperation(CompilationUnit workingCopy, IPath path, IProblemRequestor problemRequestor) {
+	public BecomeWorkingCopyOperation(CompilationUnit workingCopy, IProblemRequestor problemRequestor) {
 		super(new IJavaElement[] {workingCopy});
-		this.path = path;
 		this.problemRequestor = problemRequestor;
 	}
 	protected void executeOperation() throws JavaModelException {
 
 		// open the working copy now to ensure contents are that of the current state of this element
 		CompilationUnit workingCopy = getWorkingCopy();
-		JavaModelManager.getJavaModelManager().getPerWorkingCopyInfo(workingCopy, this.path, true/*create if needed*/, true/*record usage*/, this.problemRequestor);
+		JavaModelManager.getJavaModelManager().getPerWorkingCopyInfo(workingCopy, true/*create if needed*/, true/*record usage*/, this.problemRequestor);
 		workingCopy.openWhenClosed(workingCopy.createElementInfo(), this.progressMonitor);
 
 		if (!workingCopy.isPrimary()) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryField.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryField.java
index c5f08dd..52ce1c0 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryField.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryField.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -70,15 +70,15 @@
 protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
 	buffer.append(this.tabString(tab));
 	if (info == null) {
-		buffer.append(getElementName());
+		toStringName(buffer);
 		buffer.append(" (not open)"); //$NON-NLS-1$
 	} else if (info == NO_INFO) {
-		buffer.append(getElementName());
+		toStringName(buffer);
 	} else {
 		try {
 			buffer.append(Signature.toString(this.getTypeSignature()));
 			buffer.append(" "); //$NON-NLS-1$
-			buffer.append(this.getElementName());
+			toStringName(buffer);
 		} catch (JavaModelException e) {
 			buffer.append("<JavaModelException in toString of " + getElementName()); //$NON-NLS-1$
 		}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryMember.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryMember.java
index 3ea9865..9b20412 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryMember.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryMember.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryMethod.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryMethod.java
index a3c58bd..1c16666 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryMethod.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryMethod.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -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) {
@@ -215,6 +216,16 @@
 public String[] getParameterTypes() {
 	return this.parameterTypes;
 }
+
+/**
+ * @see IMethod#getTypeParameterSignatures()
+ * @since 3.0
+ */
+public String[] getTypeParameterSignatures() throws JavaModelException {
+	// TODO (jerome) - missing implementation
+	return new String[0];
+}
+
 /*
  * @see IMethod
  */
@@ -233,6 +244,16 @@
 	IBinaryMethod info = (IBinaryMethod) getElementInfo();
 	return new String(info.getMethodDescriptor());
 }
+/**
+ * @see org.eclipse.jdt.internal.core.JavaElement#hashCode()
+ */
+public int hashCode() {
+   int hash = super.hashCode();
+	for (int i = 0, length = parameterTypes.length; i < length; i++) {
+	    hash = Util.combineHashCodes(hash, parameterTypes[i].hashCode());
+	}
+	return hash;
+}
 /*
  * @see IMethod
  */
@@ -281,12 +302,10 @@
 protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
 	buffer.append(this.tabString(tab));
 	if (info == null) {
-		buffer.append(getElementName());
-		toStringParameters(buffer);
+		toStringName(buffer);
 		buffer.append(" (not open)"); //$NON-NLS-1$
 	} else if (info == NO_INFO) {
-		buffer.append(getElementName());
-		toStringParameters(buffer);
+		toStringName(buffer);
 	} else {
 		try {
 			if (Flags.isStatic(this.getFlags())) {
@@ -296,14 +315,14 @@
 				buffer.append(Signature.toString(this.getReturnType()));
 				buffer.append(' ');
 			}
-			buffer.append(this.getElementName());
-			toStringParameters(buffer);
+			toStringName(buffer);
 		} catch (JavaModelException e) {
 			buffer.append("<JavaModelException in toString of " + getElementName()); //$NON-NLS-1$
 		}
 	}
 }
-private void toStringParameters(StringBuffer buffer) {
+protected void toStringName(StringBuffer buffer) {
+	buffer.append(getElementName());
 	buffer.append('(');
 	String[] parameters = this.getParameterTypes();
 	int length;
@@ -316,5 +335,9 @@
 		}
 	}
 	buffer.append(')');
+	if (this.occurrenceCount > 1) {
+		buffer.append("#"); //$NON-NLS-1$
+		buffer.append(this.occurrenceCount);
+	}
 }
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryType.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryType.java
index 50c07b0..6ec52aa 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryType.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryType.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -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;
 
 /**
@@ -50,12 +50,14 @@
 	ClassFileInfo cfi = getClassFileInfo();
 	cfi.removeBinaryChildren();
 }
+
 /*
  * @see IType#codeComplete(char[], int, int, char[][], char[][], int[], boolean, ICompletionRequestor)
  */
 public void codeComplete(char[] snippet,int insertion,int position,char[][] localVariableTypeNames,char[][] localVariableNames,int[] localVariableModifiers,boolean isStatic,ICompletionRequestor requestor) throws JavaModelException {
 	codeComplete(snippet, insertion, position, localVariableTypeNames, localVariableNames, localVariableModifiers, isStatic, requestor, DefaultWorkingCopyOwner.PRIMARY);
 }
+
 /*
  * @see IType#codeComplete(char[], int, int, char[][], char[][], int[], boolean, ICompletionRequestor, WorkingCopyOwner)
  */
@@ -64,44 +66,32 @@
 		throw new IllegalArgumentException("Completion requestor cannot be null"); //$NON-NLS-1$
 	}
 	JavaProject project = (JavaProject) getJavaProject();
-	SearchableEnvironment environment = (SearchableEnvironment) project.getSearchableNameEnvironment();
-	NameLookup nameLookup = project.getNameLookup();
-	CompletionRequestorWrapper requestorWrapper = new CompletionRequestorWrapper(requestor,nameLookup);
+	SearchableEnvironment environment = (SearchableEnvironment) project.newSearchableNameEnvironment(owner);
+	CompletionRequestorWrapper requestorWrapper = new CompletionRequestorWrapper(requestor, environment.nameLookup);
 	CompletionEngine engine = new CompletionEngine(environment, requestorWrapper, project.getOptions(true), project);
 	requestorWrapper.completionEngine = engine;
 
 	String source = getClassFile().getSource();
 	if (source != null && insertion > -1 && insertion < source.length()) {
-		try {
-			// set the units to look inside
-			JavaModelManager manager = JavaModelManager.getJavaModelManager();
-			ICompilationUnit[] workingCopies = manager.getWorkingCopies(owner, true/*add primary WCs*/);
-			nameLookup.setUnitsToLookInside(workingCopies);
-	
-			// code complete
-			String encoding = project.getOption(JavaCore.CORE_ENCODING, true); 
-			
-			char[] prefix = CharOperation.concat(source.substring(0, insertion).toCharArray(), new char[]{'{'});
-			char[] suffix =  CharOperation.concat(new char[]{'}'}, source.substring(insertion).toCharArray());
-			char[] fakeSource = CharOperation.concat(prefix, snippet, suffix);
-			
-			BasicCompilationUnit cu = 
-				new BasicCompilationUnit(
-					fakeSource, 
-					null,
-					getElementName(),
-					encoding); 
-	
-			engine.complete(cu, prefix.length + position, prefix.length);
-		} finally {
-			if (nameLookup != null) {
-				nameLookup.setUnitsToLookInside(null);
-			}
-		}
+		// code complete
+		
+		char[] prefix = CharOperation.concat(source.substring(0, insertion).toCharArray(), new char[]{'{'});
+		char[] suffix =  CharOperation.concat(new char[]{'}'}, source.substring(insertion).toCharArray());
+		char[] fakeSource = CharOperation.concat(prefix, snippet, suffix);
+		
+		BasicCompilationUnit cu = 
+			new BasicCompilationUnit(
+				fakeSource, 
+				null,
+				getElementName(),
+				project); // use project to retrieve corresponding .java IFile
+
+		engine.complete(cu, prefix.length + position, prefix.length);
 	} else {
 		engine.complete(this, snippet, position, localVariableTypeNames, localVariableNames, localVariableModifiers, isStatic);
 	}
 }
+
 /*
  * @see IType#createField(String, IJavaElement, boolean, IProgressMonitor)
  */
@@ -277,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);
@@ -396,6 +386,20 @@
 	Assert.isTrue(false);  // should not happen
 	return null;
 }
+
+/**
+ * @see IType#getSuperclassTypeSignature()
+ * @since 3.0
+ */
+public String getSuperclassTypeSignature() throws JavaModelException {
+	IBinaryType info = (IBinaryType) getElementInfo();
+	char[] superclassName = info.getSuperclassName();
+	if (superclassName == null) {
+		return null;
+	}
+	return new String(Signature.createTypeSignature(ClassFile.translatedName(superclassName), true));
+}
+
 /*
  * @see IType#getSuperclassName()
  */
@@ -424,6 +428,35 @@
 	}
 	return strings;
 }
+
+/**
+ * @see IType#getSuperInterfaceTypeSignatures()
+ * @since 3.0
+ */
+public String[] getSuperInterfaceTypeSignatures() throws JavaModelException {
+	IBinaryType info = (IBinaryType) getElementInfo();
+	char[][] names= info.getInterfaceNames();
+	int length;
+	if (names == null || (length = names.length) == 0) {
+		return NO_STRINGS;
+	}
+	names= ClassFile.translatedNames(names);
+	String[] strings= new String[length];
+	for (int i= 0; i < length; i++) {
+		strings[i]= new String(Signature.createTypeSignature(names[i], true));
+	}
+	return strings;
+}
+
+/**
+ * @see IType#getTypeParameterSignatures()
+ * @since 3.0
+ */
+public String[] getTypeParameterSignatures() throws JavaModelException {
+	// TODO (jerome) - missing implementation
+	return new String[0];
+}
+
 /*
  * @see IType#getType(String)
  */
@@ -472,12 +505,7 @@
 		return array;
 	}
 }
-/*
- * @see IParent#hasChildren()
- */
-public boolean hasChildren() throws JavaModelException {
-	return getChildren().length > 0;
-}
+
 /*
  * @see IType#isAnonymous()
  */
@@ -489,16 +517,37 @@
  * @see IType#isClass()
  */
 public boolean isClass() throws JavaModelException {
+	// TODO (jerome) - isClass should only return true for classes other than enum classes
 	return !isInterface();
 }
+
+/**
+ * @see IType#isEnum()
+ * @since 3.0
+ */
+public boolean isEnum() throws JavaModelException {
+	// TODO (jerome) - missing implementation - should only return true for enum classes
+	return false;
+}
+
 /*
  * @see IType#isInterface()
  */
 public boolean isInterface() throws JavaModelException {
 	IBinaryType info = (IBinaryType) getElementInfo();
+	// TODO (jerome) - isInterface should not return true for annotation types
 	return info.isInterface();
 }
 
+/**
+ * @see IType#isAnnotation()
+ * @since 3.0
+ */
+public boolean isAnnotation() throws JavaModelException {
+	// TODO (jerome) - missing implementation - should only return true for annotation types
+	return false;
+}
+
 /*
  * @see IType#isLocal()
  */
@@ -540,7 +589,7 @@
 	throws JavaModelException {
 	
 	CreateTypeHierarchyOperation op= new CreateTypeHierarchyOperation(this, workingCopies, SearchEngine.createWorkspaceScope(), false);
-	runOperation(op, monitor);
+	op.runOperation(monitor);
 	return op.getResult();
 }
 /**
@@ -577,7 +626,7 @@
 
 	ICompilationUnit[] workingCopies = JavaModelManager.getJavaModelManager().getWorkingCopies(owner, true/*add primary working copies*/);
 	CreateTypeHierarchyOperation op= new CreateTypeHierarchyOperation(this, workingCopies, SearchEngine.createWorkspaceScope(), false);
-	runOperation(op, monitor);
+	op.runOperation(monitor);
 	return op.getResult();
 }
 /*
@@ -614,7 +663,7 @@
 		projectWCs,
 		project, 
 		true);
-	runOperation(op, monitor);
+	op.runOperation(monitor);
 	return op.getResult();
 }
 /**
@@ -638,7 +687,7 @@
 	throws JavaModelException {
 
 	CreateTypeHierarchyOperation op= new CreateTypeHierarchyOperation(this, workingCopies, SearchEngine.createWorkspaceScope(), true);
-	runOperation(op, monitor);
+	op.runOperation(monitor);
 	return op.getResult();
 }
 /**
@@ -669,7 +718,7 @@
 		
 	ICompilationUnit[] workingCopies = JavaModelManager.getJavaModelManager().getWorkingCopies(owner, true/*add primary working copies*/);
 	CreateTypeHierarchyOperation op= new CreateTypeHierarchyOperation(this, workingCopies, SearchEngine.createWorkspaceScope(), true);
-	runOperation(op, monitor);
+	op.runOperation(monitor);
 	return op.getResult();	
 }
 /*
@@ -692,10 +741,10 @@
 protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
 	buffer.append(this.tabString(tab));
 	if (info == null) {
-		buffer.append(this.getElementName());
+		toStringName(buffer);
 		buffer.append(" (not open)"); //$NON-NLS-1$
 	} else if (info == NO_INFO) {
-		buffer.append(getElementName());
+		toStringName(buffer);
 	} else {
 		try {
 			if (this.isInterface()) {
@@ -703,7 +752,7 @@
 			} else {
 				buffer.append("class "); //$NON-NLS-1$
 			}
-			buffer.append(this.getElementName());
+			toStringName(buffer);
 		} catch (JavaModelException e) {
 			buffer.append("<JavaModelException in toString of " + getElementName()); //$NON-NLS-1$
 		}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Buffer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Buffer.java
index e9f96ec..aeb8e49 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Buffer.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Buffer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -333,7 +333,13 @@
 		
 	// use a platform operation to update the resource contents
 	try {
-		String encoding = ((IJavaElement)this.owner).getJavaProject().getOption(JavaCore.CORE_ENCODING, true);
+		String encoding = null;
+		try {
+			encoding = this.file.getCharset();
+		}
+		catch (CoreException ce) {
+			// use no encoding
+		}
 		String stringContents = this.getContents();
 		if (stringContents == null) return;
 		byte[] bytes = encoding == null 
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BufferCache.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BufferCache.java
index b17beec..fc4211d 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BufferCache.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BufferCache.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BufferFactoryWrapper.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BufferFactoryWrapper.java
index 377dc90..44538e2 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BufferFactoryWrapper.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BufferFactoryWrapper.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -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/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BufferManager.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BufferManager.java
index 0c176f0..86afb40 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BufferManager.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BufferManager.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java
index f106563..c44f9ed 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -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;
 
@@ -39,13 +38,14 @@
 import org.eclipse.jdt.core.IParent;
 import org.eclipse.jdt.core.ISourceRange;
 import org.eclipse.jdt.core.IType;
-import org.eclipse.jdt.core.JavaCore;
+//import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.compiler.IProblem;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
 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;
 
 /**
@@ -102,17 +102,33 @@
 public void codeComplete(int offset, ICompletionRequestor requestor, WorkingCopyOwner owner) throws JavaModelException {
 	String source = getSource();
 	if (source != null) {
-		String encoding = this.getJavaProject().getOption(JavaCore.CORE_ENCODING, true);
 		String elementName = getElementName();
 		BasicCompilationUnit cu = 
 			new BasicCompilationUnit(
 				getSource().toCharArray(), 
 				null,
 				elementName.substring(0, elementName.length()-SUFFIX_STRING_class.length()) + SUFFIX_STRING_java,
-				encoding); 
+				getJavaProject()); // use project to retrieve corresponding .java IFile
 		codeComplete(cu, cu, offset, requestor, owner);
 	}
 }
+
+/* (non-Javadoc)
+ * @see org.eclipse.jdt.core.ICodeAssist#codeComplete(int, org.eclipse.jdt.core.CompletionRequestor)
+ */
+public void codeComplete(int offset, CompletionRequestor requestor) throws JavaModelException {
+	// TODO (jerome) - Missing implementation
+	throw new RuntimeException("Not implemented yet");  //$NON-NLS-1$
+}
+
+/* (non-Javadoc)
+ * @see org.eclipse.jdt.core.ICodeAssist#codeComplete(int, org.eclipse.jdt.core.CompletionRequestor, org.eclipse.jdt.core.WorkingCopyOwner)
+ */
+public void codeComplete(int offset, CompletionRequestor requestor, WorkingCopyOwner wcowner) throws JavaModelException {
+	// TODO (jerome) - Missing implementation
+	throw new RuntimeException("Not implemented yet");  //$NON-NLS-1$
+}
+
 /**
  * @see ICodeAssist#codeSelect(int, int)
  */
@@ -127,7 +143,7 @@
 	char[] contents;
 	if (buffer != null && (contents = buffer.getCharacters()) != null) {
 	    String topLevelTypeName = getTopLevelTypeName();
-		BasicCompilationUnit cu = new BasicCompilationUnit(contents, null, topLevelTypeName + SUFFIX_STRING_java, null);
+		BasicCompilationUnit cu = new BasicCompilationUnit(contents, null, topLevelTypeName + SUFFIX_STRING_java);
 		return super.codeSelect(cu, offset, length, owner);
 	} else {
 		//has no associated souce
@@ -145,8 +161,7 @@
 	return super.equals(o);
 }
 public boolean exists() {
-	if (!isValidClassFile()) return false;
-	return super.exists();
+	return super.exists() && isValidClassFile();
 }
 
 /**
@@ -213,6 +228,9 @@
 			return info;
 		} catch (ClassFormatException cfe) {
 			//the structure remains unknown
+			if (JavaCore.getPlugin().isDebugging()) {
+				cfe.printStackTrace(System.err);
+			}
 			return null;
 		} catch (IOException ioe) {
 			throw new JavaModelException(ioe, IJavaModelStatusConstants.IO_EXCEPTION);
@@ -233,6 +251,14 @@
 		}
 	}
 }
+public IBuffer getBuffer() throws JavaModelException {
+	if (isValidClassFile()) {
+		return super.getBuffer();
+	} else {
+		// .class file not on classpath, create a new buffer to be nice (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=41444)
+		return openBuffer(null, null);
+	}
+}
 /**
  * @see IMember
  */
@@ -282,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);
@@ -303,11 +329,11 @@
  * @see IJavaElement
  */
 public IPath getPath() {
-	PackageFragmentRoot root = this.getPackageFragmentRoot();
+	PackageFragmentRoot root = getPackageFragmentRoot();
 	if (root.isArchive()) {
 		return root.getPath();
 	} else {
-		return this.getParent().getPath().append(this.getElementName());
+		return getParent().getPath().append(getElementName());
 	}
 }
 /*
@@ -414,18 +440,6 @@
 	return true;
 }
 /**
- * If I am not open, return true to avoid parsing.
- *
- * @see IParent 
- */
-public boolean hasChildren() throws JavaModelException {
-	if (isOpen()) {
-		return getChildren().length > 0;
-	} else {
-		return true;
-	}
-}
-/**
  * @see IClassFile
  */
 public boolean isClass() throws JavaModelException {
@@ -506,7 +520,7 @@
 		} else {
 			// Attempts to find the corresponding java file
 			String qualifiedName = getType().getFullyQualifiedName();
-			NameLookup lookup = ((JavaProject) getJavaProject()).getNameLookup();
+			NameLookup lookup = ((JavaProject) getJavaProject()).newNameLookup(DefaultWorkingCopyOwner.PRIMARY);
 			ICompilationUnit cu = lookup.findCompilationUnit(qualifiedName);
 			if (cu != null) {
 				return cu.getBuffer();
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFileInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFileInfo.java
index e952972..33458c5 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFileInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFileInfo.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -100,6 +100,9 @@
 	}
 	for (int i = 0, methodCount = methods.length; i < methodCount; i++) {
 		IBinaryMethod methodInfo = methods[i];
+		// TODO (jerome) filter out synthetic members
+		//                        indexer should not index them as well
+		// if ((methodInfo.getModifiers() & IConstants.AccSynthetic) != 0) continue; // skip synthetic
 		String[] pNames= Signature.getParameterTypes(new String(methodInfo.getMethodDescriptor()));
 		char[][] paramNames= new char[pNames.length][];
 		for (int j= 0; j < pNames.length; j++) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFileWorkingCopy.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFileWorkingCopy.java
index 51ccef7..9676fae 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFileWorkingCopy.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFileWorkingCopy.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -14,6 +14,7 @@
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.IBuffer;
 import org.eclipse.jdt.core.ICompilationUnit;
@@ -30,6 +31,7 @@
 import org.eclipse.jdt.core.ISourceRange;
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.dom.CompilationUnit;
 
 /**
  * A working copy on an <code>IClassFile</code>.
@@ -59,6 +61,19 @@
 	}
 
 	/*
+	 * @see ICompilationUnit#createImport(String, IJavaElement, int, IProgressMonitor)
+     * @since 3.0
+	 */
+	public IImportDeclaration createImport(
+		String name,
+		IJavaElement sibling,
+		int flags,
+		IProgressMonitor monitor)
+		throws JavaModelException {
+		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
+	}
+
+	/*
 	 * @see ICompilationUnit#createPackageDeclaration(String, IProgressMonitor)
 	 */
 	public IPackageDeclaration createPackageDeclaration(
@@ -262,6 +277,13 @@
 	}
 
 	/*
+	 * @see IJavaElement
+	 */
+	public ISchedulingRule getSchedulingRule() {
+		return null;
+	}
+	
+	/*
 	 * @see IJavaElement#getUnderlyingResource()
 	 */
 	public IResource getUnderlyingResource() throws JavaModelException {
@@ -431,7 +453,7 @@
 	}
 
 	/**
-	 * @see IWorkingCopy#getSharedWorkingCopy(IProgressMonitor, IBufferFactory)
+	 * @see IWorkingCopy#getSharedWorkingCopy(IProgressMonitor, IBufferFactory, IProblemRequestor)
 	 * @deprecated
 	 */
 	public IJavaElement getSharedWorkingCopy(
@@ -465,8 +487,8 @@
 		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
 	}
 
-	/**
-	 * @see IWorkingCopy#getWorkingCopy(WorkingCopyOwner, IProblemRequestor, IProgressMonitor)
+	/* (non-Javadoc)
+	 * @see org.eclipse.jdt.core.ICompilationUnit#getWorkingCopy(org.eclipse.jdt.core.WorkingCopyOwner, org.eclipse.jdt.core.IProblemRequestor, org.eclipse.core.runtime.IProgressMonitor)
 	 */
 	public ICompilationUnit getWorkingCopy(WorkingCopyOwner owner, IProblemRequestor problemRequestor, IProgressMonitor monitor) throws JavaModelException {
 		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
@@ -496,27 +518,29 @@
 	}
 
 	/**
-	 * @see ICompilationUnit#reconcile(boolean, IProgressMonitor)
+	 * @see ICompilationUnit#reconcile(int, boolean, WorkingCopyOwner, IProgressMonitor)
+	 * @since 3.0
 	 */
-	public void reconcile(
-		boolean forceProblemDetection,
-		IProgressMonitor monitor)
-		throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-
-	/**
-	 * @see ICompilationUnit#reconcile(boolean, WorkingCopyOwner, IProgressMonitor)
-	 */
-	public void reconcile(
+	public CompilationUnit reconcile(
+		int astLevel,
 		boolean forceProblemDetection,
 		WorkingCopyOwner owner,
 		IProgressMonitor monitor)
 		throws JavaModelException {
 		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
 	}
+	
+	/* (non-Javadoc)
+	 * @see org.eclipse.jdt.core.IWorkingCopy#reconcile(boolean, org.eclipse.core.runtime.IProgressMonitor)
+	 */
+	public void reconcile(
+		boolean forceProblemDetection,
+		IProgressMonitor monitor)
+		throws JavaModelException {
+		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
+	}
 
-	/**
+	/* (non-Javadoc)
 	 * @see org.eclipse.jdt.core.IWorkingCopy#restore()
 	 */
 	public void restore() throws JavaModelException {
@@ -606,6 +630,22 @@
 		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
 	}
 
+	/* (non-Javadoc)
+	 * @see org.eclipse.jdt.core.ICodeAssist#codeComplete(int, org.eclipse.jdt.core.CompletionRequestor)
+	 */
+	public void codeComplete(int offset, CompletionRequestor requestor) throws JavaModelException {
+		// TODO (jerome) - Missing implementation
+		throw new RuntimeException("Not implemented yet");  //$NON-NLS-1$
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.jdt.core.ICodeAssist#codeComplete(int, org.eclipse.jdt.core.CompletionRequestor, org.eclipse.jdt.core.WorkingCopyOwner)
+	 */
+	public void codeComplete(int offset, CompletionRequestor requestor, WorkingCopyOwner wcowner) throws JavaModelException {
+		// TODO (jerome) - Missing implementation
+		throw new RuntimeException("Not implemented yet");  //$NON-NLS-1$
+	}
+
 	/**
 	 * @see org.eclipse.core.runtime.IAdaptable#getAdapter(Class)
 	 */
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java
index 84ed52a..41ef429 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -75,19 +75,25 @@
 	public IPath path;
 
 	/**
-	 * Patterns allowing to exclude portions of the resource tree denoted by this entry path.
+	 * Patterns allowing to include/exclude portions of the resource tree denoted by this entry path.
 	 */
-	
+	public IPath[] inclusionPatterns;
+	private char[][] fullCharInclusionPatterns;
 	public IPath[] exclusionPatterns;
 	private char[][] fullCharExclusionPatterns;
 	private final static char[][] UNINIT_PATTERNS = new char[][] { "Non-initialized yet".toCharArray() }; //$NON-NLS-1$
 
 	private String rootID;
 	
-	/**
+	/*
+	 * Default inclusion pattern set
+	 */
+	public final static IPath[] INCLUDE_ALL = {};
+				
+	/*
 	 * Default exclusion pattern set
 	 */
-	public final static IPath[] NO_EXCLUSION_PATTERNS = {};
+	public final static IPath[] EXCLUDE_NONE = {};
 				
 	/**
 	 * Describes the path to the source archive associated with this
@@ -133,6 +139,7 @@
 		int contentKind,
 		int entryKind,
 		IPath path,
+		IPath[] inclusionPatterns,
 		IPath[] exclusionPatterns,
 		IPath sourceAttachmentPath,
 		IPath sourceAttachmentRootPath,
@@ -142,10 +149,18 @@
 		this.contentKind = contentKind;
 		this.entryKind = entryKind;
 		this.path = path;
+		this.inclusionPatterns = inclusionPatterns;
+	    if (inclusionPatterns != INCLUDE_ALL && inclusionPatterns.length > 0) {
+			this.fullCharInclusionPatterns = UNINIT_PATTERNS;
+	    } else {
+			this.fullCharInclusionPatterns = null; // empty inclusion pattern means everything is included
+	    }
 		this.exclusionPatterns = exclusionPatterns;
-		if (exclusionPatterns.length > 0) {
+	    if (exclusionPatterns.length > 0) {
 			this.fullCharExclusionPatterns = UNINIT_PATTERNS;
-		}
+	    } else {
+			this.fullCharExclusionPatterns = null; // empty exclusion pattern means nothing is excluded
+	    }
 		this.sourceAttachmentPath = sourceAttachmentPath;
 		this.sourceAttachmentRootPath = sourceAttachmentRootPath;
 		this.specificOutputLocation = specificOutputLocation;
@@ -169,6 +184,23 @@
 		return this.fullCharExclusionPatterns;
 	}
 	
+	/*
+	 * Returns a char based representation of the exclusions patterns full path.
+	 */
+	public char[][] fullInclusionPatternChars() {
+
+		if (this.fullCharInclusionPatterns == UNINIT_PATTERNS) {
+			int length = this.inclusionPatterns.length;
+			this.fullCharInclusionPatterns = new char[length][];
+			IPath prefixPath = this.path.removeTrailingSeparator();
+			for (int i = 0; i < length; i++) {
+				this.fullCharInclusionPatterns[i] = 
+					prefixPath.append(this.inclusionPatterns[i]).toString().toCharArray();
+			}
+		}
+		return this.fullCharInclusionPatterns;
+	}
+
 	/**
 	 * Returns the XML encoding of the class path.
 	 */
@@ -210,8 +242,15 @@
 		if (this.isExported) {
 			parameters.put("exported", "true");//$NON-NLS-1$//$NON-NLS-2$
 		}
-		
-		if (this.exclusionPatterns.length > 0) {
+		if (this.inclusionPatterns != null && this.inclusionPatterns.length > 0) {
+			StringBuffer includeRule = new StringBuffer(10);
+			for (int i = 0, max = this.inclusionPatterns.length; i < max; i++){
+				if (i > 0) includeRule.append('|');
+				includeRule.append(this.inclusionPatterns[i]);
+			}
+			parameters.put("including", String.valueOf(includeRule));//$NON-NLS-1$
+		}
+		if (this.exclusionPatterns != null && this.exclusionPatterns.length > 0) {
 			StringBuffer excludeRule = new StringBuffer(10);
 			for (int i = 0, max = this.exclusionPatterns.length; i < max; i++){
 				if (i > 0) excludeRule.append('|');
@@ -257,9 +296,23 @@
 		// exported flag (optional)
 		boolean isExported = element.getAttribute("exported").equals("true"); //$NON-NLS-1$ //$NON-NLS-2$
 
+		// inclusion patterns (optional)
+		String inclusion = element.getAttribute("including"); //$NON-NLS-1$ 
+		IPath[] inclusionPatterns = INCLUDE_ALL;
+		if (!inclusion.equals("")) { //$NON-NLS-1$ 
+			char[][] patterns = CharOperation.splitOn('|', inclusion.toCharArray());
+			int patternCount;
+			if ((patternCount  = patterns.length) > 0) {
+				inclusionPatterns = new IPath[patternCount];
+				for (int j = 0; j < patterns.length; j++){
+					inclusionPatterns[j] = new Path(new String(patterns[j]));
+				}
+			}
+		}
+
 		// exclusion patterns (optional)
 		String exclusion = element.getAttribute("excluding"); //$NON-NLS-1$ 
-		IPath[] exclusionPatterns = ClasspathEntry.NO_EXCLUSION_PATTERNS;
+		IPath[] exclusionPatterns = EXCLUDE_NONE;
 		if (!exclusion.equals("")) { //$NON-NLS-1$ 
 			char[][] patterns = CharOperation.splitOn('|', exclusion.toCharArray());
 			int patternCount;
@@ -291,7 +344,7 @@
 				// must be an entry in this project or specify another project
 				String projSegment = path.segment(0);
 				if (projSegment != null && projSegment.equals(project.getElementName())) { // this project
-					return JavaCore.newSourceEntry(path, exclusionPatterns, outputLocation);
+					return JavaCore.newSourceEntry(path, inclusionPatterns, exclusionPatterns, outputLocation);
 				} else { // another project
 					return JavaCore.newProjectEntry(path, isExported);
 				}
@@ -314,7 +367,8 @@
 						ClasspathEntry.K_OUTPUT,
 						IClasspathEntry.CPE_LIBRARY,
 						path,
-						ClasspathEntry.NO_EXCLUSION_PATTERNS, 
+						ClasspathEntry.INCLUDE_ALL, 
+						ClasspathEntry.EXCLUDE_NONE, 
 						null, // source attachment
 						null, // source attachment root
 						null, // custom output location
@@ -364,10 +418,25 @@
 					return false;
 			}
 
+			IPath[] otherIncludes = otherEntry.getInclusionPatterns();
+			if (this.inclusionPatterns != otherIncludes){
+			    if (this.inclusionPatterns == null) return false;
+				int includeLength = this.inclusionPatterns.length;
+				if (otherIncludes == null || otherIncludes.length != includeLength) 
+					return false;
+				for (int i = 0; i < includeLength; i++) {
+					// compare toStrings instead of IPaths 
+					// since IPath.equals is specified to ignore trailing separators
+					if (!this.inclusionPatterns[i].toString().equals(otherIncludes[i].toString()))
+						return false;
+				}
+			}
+
 			IPath[] otherExcludes = otherEntry.getExclusionPatterns();
 			if (this.exclusionPatterns != otherExcludes){
+			    if (this.exclusionPatterns == null) return false;
 				int excludeLength = this.exclusionPatterns.length;
-				if (otherExcludes.length != excludeLength) 
+				if (otherExcludes == null || otherExcludes.length != excludeLength) 
 					return false;
 				for (int i = 0; i < excludeLength; i++) {
 					// compare toStrings instead of IPaths 
@@ -413,6 +482,13 @@
 	}
 
 	/**
+	 * @see IClasspathEntry#getExclusionPatterns()
+	 */
+	public IPath[] getInclusionPatterns() {
+		return this.inclusionPatterns;
+	}
+
+	/**
 	 * @see IClasspathEntry#getOutputLocation()
 	 */
 	public IPath getOutputLocation() {
@@ -547,9 +623,20 @@
 		buffer.append("[isExported:"); //$NON-NLS-1$
 		buffer.append(this.isExported);
 		buffer.append(']');
-		IPath[] patterns = getExclusionPatterns();
+		IPath[] patterns = getInclusionPatterns();
 		int length;
-		if ((length = patterns.length) > 0) {
+		if ((length = patterns == null ? 0 : patterns.length) > 0) {
+			buffer.append("[including:"); //$NON-NLS-1$
+			for (int i = 0; i < length; i++) {
+				buffer.append(patterns[i]);
+				if (i != length-1) {
+					buffer.append('|');
+				}
+			}
+			buffer.append(']');
+		}
+		patterns = getExclusionPatterns();
+		if ((length = patterns == null ? 0 : patterns.length) > 0) {
 			buffer.append("[excluding:"); //$NON-NLS-1$
 			for (int i = 0; i < length; i++) {
 				buffer.append(patterns[i]);
@@ -631,8 +718,8 @@
 	 *  be performed during the classpath setting operation (if validation fails, the classpath setting will not complete).
 	 *  <p>
 	 * @param javaProject the given java project
-	 * @param classpath a given classpath
-	 * @param outputLocation a given output location
+	 * @param rawClasspath a given classpath
+	 * @param projectOutputLocation a given output location
 	 * @return a status object with code <code>IStatus.OK</code> if
 	 *		the given classpath and output location are compatible, otherwise a status 
 	 *		object indicating what is wrong with the classpath or output location
@@ -689,7 +776,9 @@
 				case IClasspathEntry.CPE_SOURCE :
 					sourceEntryCount++;
 
-					if (disableExclusionPatterns && resolvedEntry.getExclusionPatterns() != null && resolvedEntry.getExclusionPatterns().length > 0) {
+					if (disableExclusionPatterns &&
+					        ((resolvedEntry.getInclusionPatterns() != null && resolvedEntry.getInclusionPatterns().length > 0) 
+					        || (resolvedEntry.getExclusionPatterns() != null && resolvedEntry.getExclusionPatterns().length > 0))) {
 						return new JavaModelStatus(IJavaModelStatusConstants.DISABLED_CP_EXCLUSION_PATTERNS, javaProject, resolvedEntry.getPath());
 					}
 					IPath customOutput; 
@@ -708,26 +797,29 @@
 						}
 						
 						// ensure custom output doesn't conflict with other outputs
-						int index;
-						
 						// check exact match
-						if ((index = Util.indexOfMatchingPath(customOutput, outputLocations, outputCount)) != -1) {
+						if (Util.indexOfMatchingPath(customOutput, outputLocations, outputCount) != -1) {
 							continue; // already found
 						}
-						
-						// check nesting
-						if ((index = Util.indexOfEnclosingPath(customOutput, outputLocations, outputCount)) != -1) {
-							if (index == 0) {
-								// custom output is nested in project's output: need to check if all source entries have a custom
-								// output before complaining
-								if (potentialNestedOutput == null) potentialNestedOutput = customOutput;
-							} else {
-								return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.cannotNestOutputInOutput", customOutput.makeRelative().toString(), outputLocations[index].makeRelative().toString())); //$NON-NLS-1$
-							}
-						}
+						// accumulate all outputs, will check nesting once all available (to handle ordering issues)
 						outputLocations[outputCount++] = customOutput;
 					}
-			}	
+			}
+		}
+		// check nesting across output locations
+		for (int i = 1 /*no check for default output*/ ; i < outputCount; i++) {
+		    IPath customOutput = outputLocations[i];
+		    int index;
+			// check nesting
+			if ((index = Util.indexOfEnclosingPath(customOutput, outputLocations, outputCount)) != -1 && index != i) {
+				if (index == 0) {
+					// custom output is nested in project's output: need to check if all source entries have a custom
+					// output before complaining
+					if (potentialNestedOutput == null) potentialNestedOutput = customOutput;
+				} else {
+					return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.cannotNestOutputInOutput", customOutput.makeRelative().toString(), outputLocations[index].makeRelative().toString())); //$NON-NLS-1$
+				}
+			}
 		}	
 		// allow custom output nesting in project's output if all source entries have a custom output
 		if (sourceEntryCount <= outputCount-1) {
@@ -800,13 +892,12 @@
 						&& (otherKind == IClasspathEntry.CPE_SOURCE 
 								|| (otherKind == IClasspathEntry.CPE_LIBRARY 
 										&& !org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(otherPath.lastSegment())))){
-						char[][] exclusionPatterns;
+						char[][] inclusionPatterns, exclusionPatterns;
 						if (otherPath.isPrefixOf(entryPath) 
 								&& !otherPath.equals(entryPath)
-								&& !Util.isExcluded(entryPath.append("*"), exclusionPatterns = ((ClasspathEntry)otherEntry).fullExclusionPatternChars())) { //$NON-NLS-1$
-									
+								&& !Util.isExcluded(entryPath.append("*"), inclusionPatterns = ((ClasspathEntry)otherEntry).fullInclusionPatternChars(), exclusionPatterns = ((ClasspathEntry)otherEntry).fullExclusionPatternChars(), false)) { //$NON-NLS-1$
 							String exclusionPattern = entryPath.removeFirstSegments(otherPath.segmentCount()).segment(0);
-							if (Util.isExcluded(entryPath, exclusionPatterns)) {
+							if (Util.isExcluded(entryPath, inclusionPatterns, exclusionPatterns, false)) {
 								return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.mustEndWithSlash", exclusionPattern, entryPath.makeRelative().toString())); //$NON-NLS-1$
 							} else {
 								if (otherKind == IClasspathEntry.CPE_SOURCE) {
@@ -822,12 +913,13 @@
 			}
 			
 			// prevent nesting output location inside entry unless enclosing is a source entry which explicitly exclude the output location
+		    char[][] inclusionPatterns = ((ClasspathEntry)entry).fullInclusionPatternChars();
 		    char[][] exclusionPatterns = ((ClasspathEntry)entry).fullExclusionPatternChars();
 		    for (int j = 0; j < outputCount; j++){
 		        IPath currentOutput = outputLocations[j];
     			if (entryPath.equals(currentOutput)) continue;
 				if (entryPath.isPrefixOf(currentOutput)) {
-				    if (kind != IClasspathEntry.CPE_SOURCE || !Util.isExcluded(currentOutput, exclusionPatterns)) {
+				    if (kind != IClasspathEntry.CPE_SOURCE || !Util.isExcluded(currentOutput, inclusionPatterns, exclusionPatterns, true)) {
 						return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.cannotNestOutputInEntry", currentOutput.makeRelative().toString(), entryPath.makeRelative().toString())); //$NON-NLS-1$
 				    }
 				}
@@ -891,7 +983,7 @@
 	 * a status object with code <code>IStatus.OK</code> if the entry is fine (that is, if the
 	 * given classpath entry denotes a valid element to be referenced onto a classpath).
 	 * 
-	 * @param javaProject the given java project
+	 * @param project the given java project
 	 * @param entry the given classpath entry
 	 * @param checkSourceAttachment a flag to determine if source attachement should be checked
 	 * @param recurseInContainers flag indicating whether validation should be applied to container entries recursively
@@ -901,22 +993,25 @@
 		
 		IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();			
 		IPath path = entry.getPath();
-
+	
 		// Build some common strings for status message
 		String projectName = project.getElementName();
 		boolean pathStartsWithProject = path.segment(0).toString().equals(projectName);
 		String entryPathMsg = pathStartsWithProject ? path.removeFirstSegments(1).toString() : path.makeRelative().toString();
-
+	
 		switch(entry.getEntryKind()){
 	
 			// container entry check
 			case IClasspathEntry.CPE_CONTAINER :
 				if (path != null && path.segmentCount() >= 1){
 					try {
-						IClasspathContainer container = JavaCore.getClasspathContainer(path, project);
+						IClasspathContainer container = JavaModelManager.getJavaModelManager().getClasspathContainer(path, project);
 						// container retrieval is performing validation check on container entry kinds.
 						if (container == null){
 							return new JavaModelStatus(IJavaModelStatusConstants.CP_CONTAINER_PATH_UNBOUND, project, path);
+						} else if (container == JavaModelManager.CONTAINER_INITIALIZATION_IN_PROGRESS) {
+							// don't create a marker if initialization is in progress (case of cp initialization batching)
+							return JavaModelStatus.VERIFIED_OK;
 						}
 						IClasspathEntry[] containerEntries = container.getClasspathEntries();
 						if (containerEntries != null){
@@ -950,7 +1045,13 @@
 			// variable entry check
 			case IClasspathEntry.CPE_VARIABLE :
 				if (path != null && path.segmentCount() >= 1){
-					entry = JavaCore.getResolvedClasspathEntry(entry);
+					try {
+						entry = JavaCore.getResolvedClasspathEntry(entry);
+					} catch (Assert.AssertionFailedException e) {
+						// Catch the assertion failure and throw java model exception instead
+						// see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=55992
+						return new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, e.getMessage());
+					}
 					if (entry == null){
 						return new JavaModelStatus(IJavaModelStatusConstants.CP_VARIABLE_PATH_UNBOUND, project, path);
 					}
@@ -958,7 +1059,7 @@
 				} else {
 					return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.illegalVariablePath", path.makeRelative().toString(), projectName));					 //$NON-NLS-1$
 				}
-
+	
 			// library entry check
 			case IClasspathEntry.CPE_LIBRARY :
 				if (path != null && path.isAbsolute() && !path.isEmpty()) {
@@ -975,13 +1076,15 @@
 						IResource resolvedResource = (IResource) target;
 						switch(resolvedResource.getType()){
 							case IResource.FILE :
-								if (org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(resolvedResource.getFileExtension())) {
+								if (org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(resolvedResource.getName())) {
 									if (checkSourceAttachment 
 										&& sourceAttachment != null
 										&& !sourceAttachment.isEmpty()
 										&& JavaModel.getTarget(workspaceRoot, sourceAttachment, true) == null){
 										return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.unboundSourceAttachment", new String [] {sourceAttachment.makeRelative().toString(), path.makeRelative().toString(), projectName})); //$NON-NLS-1$
 									}
+								} else {
+									return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.illegalLibraryArchive", entryPathMsg, projectName)); //$NON-NLS-1$
 								}
 								break;
 							case IResource.FOLDER :	// internal binary folder
@@ -993,12 +1096,17 @@
 								}
 						}
 					} else if (target instanceof File){
-						if (checkSourceAttachment 
-							&& sourceAttachment != null 
-							&& !sourceAttachment.isEmpty()
-							&& JavaModel.getTarget(workspaceRoot, sourceAttachment, true) == null){
-							return  new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.unboundSourceAttachment", new String [] {sourceAttachment.toString(), path.makeRelative().toString(), projectName})); //$NON-NLS-1$
-						}
+					    File file = (File) target;
+					    if (!file.isFile()) {
+							return  new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.illegalExternalFolder", path.toOSString(), projectName)); //$NON-NLS-1$
+					    } else if (!org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(file.getName())) {
+							return  new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.illegalLibraryArchive", path.toOSString(), projectName)); //$NON-NLS-1$
+					    } else if (checkSourceAttachment 
+								&& sourceAttachment != null 
+								&& !sourceAttachment.isEmpty()
+								&& JavaModel.getTarget(workspaceRoot, sourceAttachment, true) == null){
+								return  new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.unboundSourceAttachment", new String [] {sourceAttachment.toString(), path.makeRelative().toString(), projectName})); //$NON-NLS-1$
+					    }
 					} else {
 						return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.unboundLibrary", path.makeRelative().toString(), projectName)); //$NON-NLS-1$
 					}
@@ -1006,7 +1114,7 @@
 					return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.illegalLibraryPath", path.makeRelative().toString(), projectName)); //$NON-NLS-1$
 				}
 				break;
-
+	
 			// project entry check
 			case IClasspathEntry.CPE_PROJECT :
 				if (path != null && path.isAbsolute() && !path.isEmpty()) {
@@ -1033,11 +1141,11 @@
 					return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.illegalProjectPath", path.segment(0).toString(), projectName)); //$NON-NLS-1$
 				}
 				break;
-
+	
 			// project source folder
 			case IClasspathEntry.CPE_SOURCE :
-				if (entry.getExclusionPatterns() != null 
-						&& entry.getExclusionPatterns().length > 0
+				if (((entry.getInclusionPatterns() != null && entry.getInclusionPatterns().length > 0)
+				        	|| (entry.getExclusionPatterns() != null && entry.getExclusionPatterns().length > 0))
 						&& JavaCore.DISABLED.equals(project.getOption(JavaCore.CORE_ENABLE_CLASSPATH_EXCLUSION_PATTERNS, true))) {
 					return new JavaModelStatus(IJavaModelStatusConstants.DISABLED_CP_EXCLUSION_PATTERNS, project, path);
 				}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CommitWorkingCopyOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CommitWorkingCopyOperation.java
index 1c577b9..2d98c3a 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CommitWorkingCopyOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CommitWorkingCopyOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -15,8 +15,10 @@
 
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspace;
 import org.eclipse.core.runtime.CoreException;
-import org.eclipse.jdt.core.*;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+//import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.IBuffer;
 import org.eclipse.jdt.core.ICompilationUnit;
 import org.eclipse.jdt.core.IJavaElement;
@@ -71,9 +73,9 @@
 			boolean isPrimary = workingCopy.isPrimary();
 
 			JavaElementDeltaBuilder deltaBuilder = null;
-			
 			PackageFragmentRoot root = (PackageFragmentRoot)workingCopy.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
-			if (isPrimary || (root.isOnClasspath() && resource.isAccessible() && Util.isValidCompilationUnitName(workingCopy.getElementName()))) {
+			boolean isIncluded = !Util.isExcluded(workingCopy);
+			if (isPrimary || (root.isOnClasspath() && isIncluded && resource.isAccessible() && Util.isValidCompilationUnitName(workingCopy.getElementName()))) {
 				
 				// force opening so that the delta builder can get the old info
 				if (!isPrimary && !primary.isOpen()) {
@@ -83,7 +85,7 @@
 				// creates the delta builder (this remembers the content of the cu) if:
 				// - it is not excluded
 				// - and it is not a primary or it is a non-consistent primary
-				if (!Util.isExcluded(workingCopy) && (!isPrimary || !workingCopy.isConsistent())) {
+				if (isIncluded && (!isPrimary || !workingCopy.isConsistent())) {
 					deltaBuilder = new JavaElementDeltaBuilder(primary);
 				}
 			
@@ -113,7 +115,13 @@
 				}
 			} else {
 				// working copy on cu outside classpath OR resource doesn't exist yet
-				String encoding = workingCopy.getJavaProject().getOption(JavaCore.CORE_ENCODING, true);
+				String encoding = null;
+				try {
+					encoding = resource.getCharset();
+				}
+				catch (CoreException ce) {
+					// use no encoding
+				}
 				String contents = workingCopy.getSource();
 				if (contents == null) return;
 				try {
@@ -167,6 +175,15 @@
 	protected CompilationUnit getCompilationUnit() {
 		return (CompilationUnit)getElementToProcess();
 	}
+	protected ISchedulingRule getSchedulingRule() {
+		IResource resource = getElementToProcess().getResource();
+		IWorkspace workspace = resource.getWorkspace();
+		if (resource.exists()) {
+			return workspace.getRuleFactory().modifyRule(resource);
+		} else {
+			return workspace.getRuleFactory().createRule(resource);
+		}
+	}
 	/**
 	 * Possible failures: <ul>
 	 *	<li>INVALID_ELEMENT_TYPES - the compilation unit supplied to this
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnit.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnit.java
index da89ba7..1e13c5e 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnit.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnit.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -17,7 +17,8 @@
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.compiler.*;
 import org.eclipse.jdt.core.compiler.IProblem;
-import org.eclipse.jdt.core.jdom.IDOMNode;
+import org.eclipse.jdt.core.dom.AST;
+import org.eclipse.jdt.core.jdom.*;
 import org.eclipse.jdt.internal.compiler.ASTVisitor;
 import org.eclipse.jdt.internal.compiler.IProblemFactory;
 import org.eclipse.jdt.internal.compiler.SourceElementParser;
@@ -25,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;
@@ -68,14 +69,13 @@
  */
 public void becomeWorkingCopy(IProblemRequestor problemRequestor, IProgressMonitor monitor) throws JavaModelException {
 	JavaModelManager manager = JavaModelManager.getJavaModelManager();
-	IPath path = this.getPath();
-	JavaModelManager.PerWorkingCopyInfo perWorkingCopyInfo = manager.getPerWorkingCopyInfo(this, path, false/*don't create*/, true /*record usage*/, null/*no problem requestor needed*/);
+	JavaModelManager.PerWorkingCopyInfo perWorkingCopyInfo = manager.getPerWorkingCopyInfo(this, false/*don't create*/, true /*record usage*/, null/*no problem requestor needed*/);
 	if (perWorkingCopyInfo == null) {
 		// close cu and its children
 		close();
 
-		BecomeWorkingCopyOperation operation = new BecomeWorkingCopyOperation(this, path, problemRequestor);
-		runOperation(operation, null);
+		BecomeWorkingCopyOperation operation = new BecomeWorkingCopyOperation(this, problemRequestor);
+		operation.runOperation(monitor);
 	}
 }
 protected boolean buildStructure(OpenableElementInfo info, final IProgressMonitor pm, Map newElements, IResource underlyingResource) throws JavaModelException {
@@ -106,13 +106,16 @@
 	// generate structure and compute syntax problems if needed
 	CompilationUnitStructureRequestor requestor = new CompilationUnitStructureRequestor(this, unitInfo, newElements);
 	JavaModelManager.PerWorkingCopyInfo perWorkingCopyInfo = getPerWorkingCopyInfo();
-	boolean computeProblems = perWorkingCopyInfo != null && perWorkingCopyInfo.isActive();
+	IJavaProject project = getJavaProject();
+	boolean computeProblems = JavaProject.hasJavaNature(project.getProject()) && perWorkingCopyInfo != null && perWorkingCopyInfo.isActive();
 	IProblemFactory problemFactory = new DefaultProblemFactory();
+	Map options = project.getOptions(true);
 	SourceElementParser parser = new SourceElementParser(
 		requestor, 
 		problemFactory, 
-		new CompilerOptions(getJavaProject().getOptions(true)),
+		new CompilerOptions(options),
 		true/*report local declarations*/);
+	parser.reportOnlyOneSyntaxError = !computeProblems;
 	requestor.parser = parser;
 	CompilationUnitDeclaration unit = parser.parseCompilationUnit(new org.eclipse.jdt.internal.compiler.env.ICompilationUnit() {
 			public char[] getContents() {
@@ -136,10 +139,23 @@
 	unitInfo.timestamp = ((IFile)underlyingResource).getModificationStamp();
 	
 	// compute other problems if needed
-	if (computeProblems){
-		perWorkingCopyInfo.beginReporting();
-		CompilationUnitProblemFinder.process(unit, this, parser, perWorkingCopyInfo, problemFactory, pm);
-		perWorkingCopyInfo.endReporting();
+	CompilationUnitDeclaration compilationUnitDeclaration = null;
+	try {
+		if (computeProblems){
+			perWorkingCopyInfo.beginReporting();
+			compilationUnitDeclaration = CompilationUnitProblemFinder.process(unit, this, contents, parser, this.owner, perWorkingCopyInfo, problemFactory, false/*don't cleanup cu*/, pm);
+			perWorkingCopyInfo.endReporting();
+		}
+		
+		if (info instanceof ASTHolderCUInfo) {
+			int astLevel = ((ASTHolderCUInfo) info).astLevel;
+			org.eclipse.jdt.core.dom.CompilationUnit cu = AST.convertCompilationUnit(astLevel, unit, contents, options, computeProblems, pm);
+			((ASTHolderCUInfo) info).ast = cu;
+		}
+	} finally {
+	    if (compilationUnitDeclaration != null) {
+	        compilationUnitDeclaration.cleanUp();
+	    }
 	}
 	
 	return unitInfo.isStructureKnown();
@@ -255,6 +271,23 @@
 			}
 		});
 }
+
+/* (non-Javadoc)
+ * @see org.eclipse.jdt.core.ICodeAssist#codeComplete(int, org.eclipse.jdt.core.CompletionRequestor)
+ */
+public void codeComplete(int offset, CompletionRequestor requestor) throws JavaModelException {
+	// TODO (jerome) - Missing implementation
+	throw new RuntimeException("Not implemented yet");  //$NON-NLS-1$
+}
+
+/* (non-Javadoc)
+ * @see org.eclipse.jdt.core.ICodeAssist#codeComplete(int, org.eclipse.jdt.core.CompletionRequestor, org.eclipse.jdt.core.WorkingCopyOwner)
+ */
+public void codeComplete(int offset, CompletionRequestor requestor, WorkingCopyOwner wcowner) throws JavaModelException {
+	// TODO (jerome) - Missing implementation
+	throw new RuntimeException("Not implemented yet");  //$NON-NLS-1$
+}
+
 /**
  * @see ICodeAssist#codeSelect(int, int)
  */
@@ -279,7 +312,7 @@
  */
 public void commitWorkingCopy(boolean force, IProgressMonitor monitor) throws JavaModelException {
 	CommitWorkingCopyOperation op= new CommitWorkingCopyOperation(this, force);
-	runOperation(op, monitor);
+	op.runOperation(monitor);
 }
 /**
  * @see ISourceManipulation#copy(IJavaElement, IJavaElement, String, boolean, IProgressMonitor)
@@ -306,20 +339,30 @@
  * @see ICompilationUnit#createImport(String, IJavaElement, IProgressMonitor)
  */
 public IImportDeclaration createImport(String importName, IJavaElement sibling, IProgressMonitor monitor) throws JavaModelException {
+	return createImport(importName, sibling, Flags.AccDefault, monitor);
+}
+
+/**
+ * @see ICompilationUnit#createImport(String, IJavaElement, int, IProgressMonitor)
+ * @since 3.0
+ */
+public IImportDeclaration createImport(String importName, IJavaElement sibling, int flags, IProgressMonitor monitor) throws JavaModelException {
+	// TODO (jerome) - consult flags to create static imports
 	CreateImportOperation op = new CreateImportOperation(importName, this);
 	if (sibling != null) {
 		op.createBefore(sibling);
 	}
-	runOperation(op, monitor);
+	op.runOperation(monitor);
 	return getImport(importName);
 }
+
 /**
  * @see ICompilationUnit#createPackageDeclaration(String, IProgressMonitor)
  */
 public IPackageDeclaration createPackageDeclaration(String pkg, IProgressMonitor monitor) throws JavaModelException {
 	
 	CreatePackageDeclarationOperation op= new CreatePackageDeclarationOperation(pkg, this);
-	runOperation(op, monitor);
+	op.runOperation(monitor);
 	return getPackageDeclaration(pkg);
 }
 /**
@@ -335,13 +378,13 @@
 			source = "package " + pkg.getElementName() + ";"  + org.eclipse.jdt.internal.compiler.util.Util.LINE_SEPARATOR + org.eclipse.jdt.internal.compiler.util.Util.LINE_SEPARATOR; //$NON-NLS-1$ //$NON-NLS-2$
 		}
 		CreateCompilationUnitOperation op = new CreateCompilationUnitOperation(pkg, this.name, source, force);
-		runOperation(op, monitor);
+		op.runOperation(monitor);
 	}
 	CreateTypeOperation op = new CreateTypeOperation(this, content, force);
 	if (sibling != null) {
 		op.createBefore(sibling);
 	}
-	runOperation(op, monitor);
+	op.runOperation(monitor);
 	return (IType) op.getResultElements()[0];
 }
 /**
@@ -368,7 +411,7 @@
 public void discardWorkingCopy() throws JavaModelException {
 	// discard working copy and its children
 	DiscardWorkingCopyOperation op = new DiscardWorkingCopyOperation(this);
-	runOperation(op, null);
+	op.runOperation(null);
 }
 /**
  * Returns true if this handle represents the same Java element
@@ -383,7 +426,9 @@
 }
 /**
  * @see JavaElement#equalsDOMNode(IDOMNode)
+ * @deprecated JDOM is obsolete
  */
+// TODO - JDOM - remove once model ported off of JDOM
 protected boolean equalsDOMNode(IDOMNode node) {
 	String elementName = getElementName();
 	if (node.getNodeType() == IDOMNode.COMPILATION_UNIT && elementName != null ) {
@@ -409,13 +454,14 @@
 	return false;
 }
 public boolean exists() {
-	// working copy always exists in the model until it is gotten rid of
+	// working copy always exists in the model until it is gotten rid of (even if not on classpath)
 	if (getPerWorkingCopyInfo() != null) return true;	
 	
-	return super.exists();
+	// if not a working copy, it exists only if it is a primary compilation unit
+	return isPrimary() && super.exists() && isValidCompilationUnit();
 }
 /**
- * @see IWorkingCopy#findElements(IJavaElement)
+ * @see ICompilationUnit#findElements(IJavaElement)
  */
 public IJavaElement[] findElements(IJavaElement element) {
 	ArrayList children = new ArrayList();
@@ -471,7 +517,7 @@
 	}
 }
 /**
- * @see IWorkingCopy#findPrimaryType()
+ * @see ICompilationUnit#findPrimaryType()
  */
 public IType findPrimaryType() {
 	String typeName = Signature.getQualifier(this.getElementName());
@@ -587,10 +633,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);
@@ -608,6 +655,7 @@
 	}
 	return null;
 }
+
 /**
  * @see JavaElement#getHandleMementoDelimiter()
  */
@@ -721,7 +769,7 @@
  * Note: the use count of the per working copy info is NOT incremented.
  */
 public JavaModelManager.PerWorkingCopyInfo getPerWorkingCopyInfo() {
-	return JavaModelManager.getJavaModelManager().getPerWorkingCopyInfo(this, getPath(), false/*don't create*/, false/*don't record usage*/, null/*no problem requestor needed*/);
+	return JavaModelManager.getJavaModelManager().getPerWorkingCopyInfo(this, false/*don't create*/, false/*don't record usage*/, null/*no problem requestor needed*/);
 }
 /*
  * @see ICompilationUnit#getPrimary()
@@ -815,7 +863,7 @@
 	return getWorkingCopy(BufferFactoryWrapper.create(factory), problemRequestor, monitor);
 }
 /**
- * @see IWorkingCopy#getWorkingCopy(WorkingCopyOwner, IProblemRequestor, IProgressMonitor)
+ * @see ICompilationUnit#getWorkingCopy(WorkingCopyOwner, IProblemRequestor, IProgressMonitor)
  */
 public ICompilationUnit getWorkingCopy(WorkingCopyOwner workingCopyOwner, IProblemRequestor problemRequestor, IProgressMonitor monitor) throws JavaModelException {
 	if (!isPrimary()) return this;
@@ -823,14 +871,13 @@
 	JavaModelManager manager = JavaModelManager.getJavaModelManager();
 	
 	CompilationUnit workingCopy = new CompilationUnit((PackageFragment)getParent(), getElementName(), workingCopyOwner);
-	IPath path = getPath();
 	JavaModelManager.PerWorkingCopyInfo perWorkingCopyInfo = 
-		manager.getPerWorkingCopyInfo(workingCopy, path, false/*don't create*/, true/*record usage*/, null/*not used since don't create*/);
+		manager.getPerWorkingCopyInfo(workingCopy, false/*don't create*/, true/*record usage*/, null/*not used since don't create*/);
 	if (perWorkingCopyInfo != null) {
 		return perWorkingCopyInfo.getWorkingCopy(); // return existing handle instead of the one created above
 	}
-	BecomeWorkingCopyOperation op = new BecomeWorkingCopyOperation(workingCopy, path, problemRequestor);
-	runOperation(op, monitor);
+	BecomeWorkingCopyOperation op = new BecomeWorkingCopyOperation(workingCopy, problemRequestor);
+	op.runOperation(monitor);
 	return workingCopy;
 }
 /**
@@ -839,18 +886,6 @@
 protected boolean hasBuffer() {
 	return true;
 }
-/**
- * If I am not open, return true to avoid parsing.
- *
- * @see IParent#hasChildren()
- */
-public boolean hasChildren() throws JavaModelException {
-	if (isOpen()) {
-		return getChildren().length > 0;
-	} else {
-		return true;
-	}
-}
 /*
  * @see ICompilationUnit#hasResourceChanged()
  */
@@ -904,8 +939,9 @@
 	}
 	IResource resource = getResource();
 	if (resource != null) {
+		char[][] inclusionPatterns = ((PackageFragmentRoot)root).fullInclusionPatternChars();
 		char[][] exclusionPatterns = ((PackageFragmentRoot)root).fullExclusionPatternChars();
-		if (Util.isExcluded(resource, exclusionPatterns)) return false;
+		if (Util.isExcluded(resource, inclusionPatterns, exclusionPatterns)) return false;
 	}
 	if (!Util.isValidCompilationUnitName(getElementName())) return false;
 	return true;
@@ -922,15 +958,24 @@
  * @see IOpenable#makeConsistent(IProgressMonitor)
  */
 public void makeConsistent(IProgressMonitor monitor) throws JavaModelException {
-	if (isConsistent()) return;
+	makeConsistent(false/*don't create AST*/, 0, monitor);
+}
+public org.eclipse.jdt.core.dom.CompilationUnit makeConsistent(boolean createAST, int astLevel, IProgressMonitor monitor) throws JavaModelException {
+	if (isConsistent()) return null;
 		
-	// close
-	JavaModelManager manager = JavaModelManager.getJavaModelManager();
-	// working copy: remove info from cache, but keep buffer open
-	manager.removeInfoAndChildren(this);
-	
 	// create a new info and make it the current info
-	openWhenClosed(createElementInfo(), monitor);
+	// (this will remove the info and its children just before storing the new infos)
+	if (createAST) {
+		ASTHolderCUInfo info = new ASTHolderCUInfo();
+		info.astLevel = astLevel;
+		openWhenClosed(info, monitor);
+		org.eclipse.jdt.core.dom.CompilationUnit result = info.ast;
+		info.ast = null;
+		return result;
+	} else {
+		openWhenClosed(createElementInfo(), monitor);
+		return null;
+	}
 }
 /**
  * @see ISourceManipulation#move(IJavaElement, IJavaElement, String, boolean, IProgressMonitor)
@@ -950,7 +995,7 @@
 }
 
 /**
- * @see Openable#openBuffer(IProgressMonitor)
+ * @see Openable#openBuffer(IProgressMonitor, Object)
  */
 protected IBuffer openBuffer(IProgressMonitor pm, Object info) throws JavaModelException {
 
@@ -1012,48 +1057,48 @@
  * @deprecated
  */
 public IMarker[] reconcile() throws JavaModelException {
-	reconcile(false, null);
+	reconcile(NO_AST, false/*don't force problem detection*/, null/*use primary owner*/, null/*no progress monitor*/);
 	return null;
 }
 /**
- * @see ICompilationUnit#reconcile(boolean, IProgressMonitor)
+ * @see ICompilationUnit#reconcile(int, boolean, WorkingCopyOwner, IProgressMonitor)
  */
 public void reconcile(boolean forceProblemDetection, IProgressMonitor monitor) throws JavaModelException {
-	reconcile(forceProblemDetection, DefaultWorkingCopyOwner.PRIMARY, monitor);
+	reconcile(NO_AST, forceProblemDetection, null/*use primary owner*/, monitor);
 }
+
 /**
- * @see ICompilationUnit#reconcile(boolean, WorkingCopyOwner, IProgressMonitor)
+ * @see ICompilationUnit#reconcile(int, boolean, WorkingCopyOwner, IProgressMonitor)
+ * @since 3.0
  */
-public void reconcile(
+public org.eclipse.jdt.core.dom.CompilationUnit reconcile(
+	int astLevel,
 	boolean forceProblemDetection,
 	WorkingCopyOwner workingCopyOwner,
 	IProgressMonitor monitor)
 	throws JavaModelException {
-
-	if (!isWorkingCopy()) return; // Reconciling is not supported on non working copies
 	
-	NameLookup lookup = null;
-	try {
-		// set the units to look inside only for problem detection purpose (40322)
-		if (forceProblemDetection) {
-			try {
-				lookup = ((JavaProject)getJavaProject()).getNameLookup();
-				JavaModelManager manager = JavaModelManager.getJavaModelManager();
-				ICompilationUnit[] workingCopies = manager.getWorkingCopies(workingCopyOwner, true/*add primary WCs*/);
-				lookup.setUnitsToLookInside(workingCopies);
-			} catch(JavaModelException e) {
-				// simple project may not find its namelookup, simply ignore working copies (41583)
-			}
-		}			
-		// reconcile
-		ReconcileWorkingCopyOperation op = new ReconcileWorkingCopyOperation(this, forceProblemDetection);
-		runOperation(op, monitor);
-	} finally {
-		if (lookup != null) {
-			lookup.setUnitsToLookInside(null);
-		}
+	if (!isWorkingCopy()) return null; // Reconciling is not supported on non working copies
+	if (workingCopyOwner == null) workingCopyOwner = DefaultWorkingCopyOwner.PRIMARY;
+	
+	boolean createAST = false;
+	if (astLevel == AST.JLS2) {
+		// client asking for level 2 AST; these are supported
+		createAST = true;
+	} else if (astLevel == AST.JLS3) {
+		// client asking for level 3 ASTs; these are not supported
+		// TODO (jerome) - these should also be supported in 1.5 stream
+		createAST = false;
+	} else {
+		// client asking for no AST (0) or unknown ast level
+		// either way, request denied
+		createAST = false;
 	}
+	ReconcileWorkingCopyOperation op = new ReconcileWorkingCopyOperation(this, createAST, astLevel, forceProblemDetection, workingCopyOwner);
+	op.runOperation(monitor);
+	return op.ast;
 }
+
 /**
  * @see ISourceManipulation#rename(String, boolean, IProgressMonitor)
  */
@@ -1100,12 +1145,12 @@
 	if (!isPrimary()) {
 		buffer.append(this.tabString(tab));
 		buffer.append("[Working copy] "); //$NON-NLS-1$
-		buffer.append(getElementName());
+		toStringName(buffer);
 	} else {
 		if (isWorkingCopy()) {
 			buffer.append(this.tabString(tab));
 			buffer.append("[Working copy] "); //$NON-NLS-1$
-			buffer.append(getElementName());
+			toStringName(buffer);
 			if (info == null) {
 				buffer.append(" (not open)"); //$NON-NLS-1$
 			}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitElementInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitElementInfo.java
index 54a66a7..90b97fd 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitElementInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitElementInfo.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitProblemFinder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitProblemFinder.java
index f4dfee5..73f62fd 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitProblemFinder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitProblemFinder.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -30,6 +30,7 @@
 import org.eclipse.jdt.internal.compiler.parser.Parser;
 import org.eclipse.jdt.internal.compiler.parser.SourceTypeConverter;
 import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
+import org.eclipse.jdt.internal.core.util.CommentRecorderParser;
 import org.eclipse.jdt.internal.core.util.Util;
 
 /**
@@ -56,7 +57,7 @@
 	 *      specify the rules for handling problems (stop on first error or accumulate
 	 *      them all) and at the same time perform some actions such as opening a dialog
 	 *      in UI when compiling interactively.
-	 *      @see org.eclipse.jdt.internal.compiler.api.problem.DefaultErrorHandlingPolicies
+	 *      @see org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies
 	 * 
 	 *	@param settings The settings to use for the resolution.
 	 *      
@@ -64,7 +65,7 @@
 	 *      Component which will receive and persist all compilation results and is intended
 	 *      to consume them as they are produced. Typically, in a batch compiler, it is 
 	 *      responsible for writing out the actual .class files to the file system.
-	 *      @see org.eclipse.jdt.internal.compiler.api.CompilationResult
+	 *      @see org.eclipse.jdt.internal.compiler.CompilationResult
 	 *
 	 *  @param problemFactory org.eclipse.jdt.internal.compiler.api.problem.IProblemFactory
 	 *      Factory used inside the compiler to create problem descriptors. It allows the
@@ -117,12 +118,6 @@
 		return DefaultErrorHandlingPolicies.proceedWithAllProblems();
 	}
 
-	protected static INameEnvironment getNameEnvironment(ICompilationUnit sourceUnit)
-		throws JavaModelException {
-		return (SearchableEnvironment) ((JavaProject) sourceUnit.getJavaProject())
-			.getSearchableNameEnvironment();
-	}
-
 	/*
 	 * Answer the component to which will be handed back compilation results from the compiler
 	 */
@@ -137,18 +132,21 @@
 	public static CompilationUnitDeclaration process(
 		CompilationUnitDeclaration unit,
 		ICompilationUnit unitElement, 
+		char[] contents,
 		Parser parser,
+		WorkingCopyOwner workingCopyOwner,
 		IProblemRequestor problemRequestor,
 		IProblemFactory problemFactory,
+		boolean cleanupCU,
 		IProgressMonitor monitor)
 		throws JavaModelException {
 
 		char[] fileName = unitElement.getElementName().toCharArray();
 		
-		IJavaProject project = unitElement.getJavaProject();
+		JavaProject project = (JavaProject) unitElement.getJavaProject();
 		CompilationUnitProblemFinder problemFinder =
 			new CompilationUnitProblemFinder(
-				getNameEnvironment(unitElement),
+				project.newSearchableNameEnvironment(workingCopyOwner),
 				getHandlingPolicy(),
 				project.getOptions(true),
 				getRequestor(),
@@ -158,7 +156,6 @@
 		}
 
 		try {
-			String encoding = project.getOption(JavaCore.CORE_ENCODING, true);
 			
 			IPackageFragment packageFragment = (IPackageFragment)unitElement.getAncestor(IJavaElement.PACKAGE_FRAGMENT);
 			char[][] expectedPackageName = null;
@@ -168,10 +165,10 @@
 			if (unit == null) {
 				unit = problemFinder.resolve(
 					new BasicCompilationUnit(
-						unitElement.getSource().toCharArray(),
+						contents,
 						expectedPackageName,
 						new String(fileName),
-						encoding),
+						unitElement),
 					true, // verify methods
 					true, // analyze code
 					true); // generate code
@@ -190,7 +187,7 @@
 			Util.log(e, "Exception occurred during problem detection: "); //$NON-NLS-1$ 
 			throw new JavaModelException(e, IJavaModelStatusConstants.COMPILER_FAILURE);
 		} finally {
-			if (unit != null) {
+			if (cleanupCU && unit != null) {
 				unit.cleanUp();
 			}
 			problemFinder.lookupEnvironment.reset();			
@@ -199,11 +196,14 @@
 
 	public static CompilationUnitDeclaration process(
 		ICompilationUnit unitElement, 
+		char[] contents,
+		WorkingCopyOwner workingCopyOwner,
 		IProblemRequestor problemRequestor,
+		boolean cleanupCU,
 		IProgressMonitor monitor)
 		throws JavaModelException {
 			
-		return process(null/*no CompilationUnitDeclaration*/, unitElement, null/*use default Parser*/,problemRequestor, new DefaultProblemFactory(), monitor);
+		return process(null/*no CompilationUnitDeclaration*/, unitElement, contents, null/*use default Parser*/, workingCopyOwner, problemRequestor, new DefaultProblemFactory(), cleanupCU, monitor);
 	}
 
 	
@@ -219,5 +219,12 @@
 		}
 	}
 
+	/* (non-Javadoc)
+	 * Fix for bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=60689.
+	 * @see org.eclipse.jdt.internal.compiler.Compiler#initializeParser()
+	 */
+	public void initializeParser() {
+		this.parser = new CommentRecorderParser(this.problemReporter, this.options.parseLiteralExpressionsAsConstants);
+	}
 }	
 
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitStructureRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitStructureRequestor.java
index c5b005b..a61d387 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitStructureRequestor.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitStructureRequestor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -202,7 +202,7 @@
 }
 /**
  * Convert these type names to signatures.
- * @see Signature.
+ * @see Signature
  */
 /* default */ static String[] convertTypeNamesToSigs(char[][] typeNames) {
 	if (typeNames == null)
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitVisitor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitVisitor.java
index a950cb0..e34a1f8 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitVisitor.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitVisitor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -13,11 +13,10 @@
 import java.util.Locale;
 import java.util.Map;
 
-import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.ICompilationUnit;
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.IPackageFragment;
-import org.eclipse.jdt.core.JavaCore;
+//import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.compiler.*;
 import org.eclipse.jdt.core.compiler.IProblem;
@@ -117,12 +116,6 @@
 		};
 	}
 
-	protected static INameEnvironment getNameEnvironment(ICompilationUnit sourceUnit)
-		throws JavaModelException {
-		return (SearchableEnvironment) ((JavaProject) sourceUnit.getJavaProject())
-			.getSearchableNameEnvironment();
-	}
-
 	/*
 	 * Answer the component to which will be handed back compilation results from the compiler
 	 */
@@ -139,10 +132,10 @@
 		ASTVisitor visitor)
 		throws JavaModelException {
 
-		IJavaProject project = unitElement.getJavaProject();
+		JavaProject project = (JavaProject) unitElement.getJavaProject();
 		CompilationUnitVisitor compilationUnitVisitor =
 			new CompilationUnitVisitor(
-				getNameEnvironment(unitElement),
+				project.newSearchableNameEnvironment(unitElement.getOwner()),
 				getHandlingPolicy(),
 				project.getOptions(true),
 				getRequestor(),
@@ -150,7 +143,6 @@
 
 		CompilationUnitDeclaration unit = null;
 		try {
-			String encoding = project.getOption(JavaCore.CORE_ENCODING, true);
 
 			IPackageFragment packageFragment = (IPackageFragment)unitElement.getAncestor(IJavaElement.PACKAGE_FRAGMENT);
 			char[][] expectedPackageName = null;
@@ -163,7 +155,7 @@
 						unitElement.getSource().toCharArray(),
 						expectedPackageName,
 						unitElement.getElementName(),
-						encoding),
+						unitElement),
 					true, // method verification
 					false, // no flow analysis
 					false); // no code generation
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompletionRequestorWrapper.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompletionRequestorWrapper.java
index 10869ae..c58726e 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompletionRequestorWrapper.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompletionRequestorWrapper.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -18,8 +18,9 @@
 import org.eclipse.jdt.core.compiler.*;
 import org.eclipse.jdt.core.compiler.IProblem;
 import org.eclipse.jdt.internal.codeassist.CompletionEngine;
+import org.eclipse.jdt.internal.codeassist.IExtendedCompletionRequestor;
 
-public class CompletionRequestorWrapper implements ICompletionRequestor {
+public class CompletionRequestorWrapper implements IExtendedCompletionRequestor {
 	private static Object NO_ATTACHED_SOURCE = new Object();
 	
 	static final char[] ARG = "arg".toCharArray();  //$NON-NLS-1$
@@ -387,6 +388,30 @@
 	}
 	return parameterNames;
 }
+public void acceptPotentialMethodDeclaration(char[] declaringTypePackageName,
+		char[] declaringTypeName, char[] selector, int completionStart,
+		int completionEnd, int relevance) {
+	if(this.clientRequestor instanceof IExtendedCompletionRequestor) {
+		if(CompletionEngine.DEBUG) {
+			printDebug("acceptPotentialMethodDeclaration",  new String[]{ //$NON-NLS-1$
+				String.valueOf(declaringTypePackageName),
+				String.valueOf(declaringTypeName),
+				String.valueOf(selector),
+				String.valueOf(completionStart),
+				String.valueOf(completionEnd),
+				String.valueOf(relevance)
+			});
+		}
+		
+		((IExtendedCompletionRequestor)this.clientRequestor).acceptPotentialMethodDeclaration(
+			declaringTypePackageName,
+			declaringTypeName,
+			selector,
+			completionStart,
+			completionEnd,
+			relevance);
+	}
+}
 
 private void printDebug(String header, String[] param){
 	StringBuffer buffer = new StringBuffer();
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CopyElementsOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CopyElementsOperation.java
index 0d4befe..1198b66 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CopyElementsOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CopyElementsOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -21,9 +21,7 @@
 import org.eclipse.jdt.core.IParent;
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.JavaModelException;
-import org.eclipse.jdt.core.jdom.DOMFactory;
-import org.eclipse.jdt.core.jdom.IDOMCompilationUnit;
-import org.eclipse.jdt.core.jdom.IDOMNode;
+import org.eclipse.jdt.core.jdom.*;
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
 import org.eclipse.jdt.internal.compiler.util.Util;
 
@@ -126,14 +124,24 @@
 		IMember member = (IMember)element;
 		ICompilationUnit cu = member.getCompilationUnit();
 		String cuSource = cu.getSource();
-		IDOMCompilationUnit domCU = new DOMFactory().createCompilationUnit(cuSource, cu.getElementName());
-		IDOMNode node = ((JavaElement)element).findNode(domCU);
-		source = new String(node.getCharacters());
+		String cuName = cu.getElementName();
+		source = computeSourceForElement(element, cuSource, cuName);
 		this.sources.put(element, source);
 	}
 	return source;
 }
 /**
+ * @deprecated marked deprecated to suppress JDOM-related deprecation warnings
+ */
+// TODO - JDOM - remove once model ported off of JDOM
+private String computeSourceForElement(IJavaElement element, String cuSource, String cuName) {
+	String source;
+	IDOMCompilationUnit domCU = new DOMFactory().createCompilationUnit(cuSource, cuName);
+	IDOMNode node = ((JavaElement)element).findNode(domCU);
+	source = new String(node.getCharacters());
+	return source;
+}
+/**
  * Returns <code>true</code> if this element is the main type of its compilation unit.
  */
 protected boolean isRenamingMainType(IJavaElement element, IJavaElement dest) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CopyPackageFragmentRootOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CopyPackageFragmentRootOperation.java
index 32bc9dc..271ef41 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CopyPackageFragmentRootOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CopyPackageFragmentRootOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -191,13 +191,23 @@
 			case IClasspathEntry.CPE_CONTAINER:
 				return JavaCore.newContainerEntry(entry.getPath(), entry.isExported());
 			case IClasspathEntry.CPE_LIBRARY:
-				return JavaCore.newLibraryEntry(this.destination, entry.getSourceAttachmentPath(), entry.getSourceAttachmentRootPath(), entry.isExported());
+				try {
+					return JavaCore.newLibraryEntry(this.destination, entry.getSourceAttachmentPath(), entry.getSourceAttachmentRootPath(), entry.isExported());
+				} catch (Assert.AssertionFailedException e) {
+					IJavaModelStatus status = new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, e.getMessage());
+					throw new JavaModelException(status);
+				}
 			case IClasspathEntry.CPE_PROJECT:
 				return JavaCore.newProjectEntry(entry.getPath(), entry.isExported());
 			case IClasspathEntry.CPE_SOURCE:
-				return JavaCore.newSourceEntry(this.destination, entry.getExclusionPatterns(), entry.getOutputLocation());
+				return JavaCore.newSourceEntry(this.destination, entry.getInclusionPatterns(), entry.getExclusionPatterns(), entry.getOutputLocation());
 			case IClasspathEntry.CPE_VARIABLE:
-				return JavaCore.newVariableEntry(entry.getPath(), entry.getSourceAttachmentPath(), entry.getSourceAttachmentRootPath(), entry.isExported());
+				try {
+					return JavaCore.newVariableEntry(entry.getPath(), entry.getSourceAttachmentPath(), entry.getSourceAttachmentRootPath(), entry.isExported());
+				} catch (Assert.AssertionFailedException e) {
+					IJavaModelStatus status = new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, e.getMessage());
+					throw new JavaModelException(status);
+				}
 			default:
 				throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this.getElementToProcess()));
 		}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CopyResourceElementsOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CopyResourceElementsOperation.java
index a417f23..7fc4697 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CopyResourceElementsOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CopyResourceElementsOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -61,7 +61,9 @@
 	/**
 	 * The <code>DOMFactory</code> used to manipulate the source code of
 	 * <code>ICompilationUnit</code>.
+	 * @deprecated JDOM is obsolete
 	 */
+    // TODO - JDOM - remove once model ported off of JDOM
 	protected DOMFactory fFactory;
 	/**
 	 * A collection of renamed compilation units.  These cus do
@@ -83,6 +85,13 @@
 	 */
 	public CopyResourceElementsOperation(IJavaElement[] resourcesToCopy, IJavaElement[] destContainers, boolean force) {
 		super(resourcesToCopy, destContainers, force);
+		initializeDOMFactory();
+	}
+	/**
+	 * @deprecated marked deprecated to suppress JDOM-related deprecation warnings
+	 */
+    // TODO - JDOM - remove once model ported off of JDOM
+	private void initializeDOMFactory() {
 		fFactory = new DOMFactory();
 	}
 	/**
@@ -136,7 +145,8 @@
 		JavaElementDelta projectDelta = null;
 		String[] names = Util.getTrimmedSimpleNames(newFragName);
 		StringBuffer sideEffectPackageName = new StringBuffer();
-		char[][] exclusionsPatterns = ((PackageFragmentRoot)root).fullExclusionPatternChars();
+		char[][] inclusionPatterns = ((PackageFragmentRoot)root).fullInclusionPatternChars();
+		char[][] exclusionPatterns = ((PackageFragmentRoot)root).fullExclusionPatternChars();
 		for (int i = 0; i < names.length; i++) {
 			String subFolderName = names[i];
 			sideEffectPackageName.append(subFolderName);
@@ -153,7 +163,7 @@
 				}
 				IPackageFragment sideEffectPackage = root.getPackageFragment(sideEffectPackageName.toString());
 				if (i < names.length - 1 // all but the last one are side effect packages
-						&& !Util.isExcluded(parentFolder, exclusionsPatterns)) { 
+						&& !Util.isExcluded(parentFolder, inclusionPatterns, exclusionPatterns)) { 
 					if (projectDelta == null) {
 						projectDelta = getDeltaFor(root.getJavaProject());
 					}
@@ -223,8 +233,18 @@
 		String destName = (newCUName != null) ? newCUName : source.getElementName();
 		String newContent = updatedContent(source, dest, newCUName); // null if unchanged
 	
-		// copy resource
+		// TODO (frederic) remove when bug 67606 will be fixed (bug 67823)
+		// store encoding (fix bug 66898)
 		IFile sourceResource = (IFile)source.getResource();
+		String sourceEncoding = null;
+		try {
+			sourceEncoding = sourceResource.getCharset(false);
+		}
+		catch (CoreException ce) {
+			// no problem, use default encoding
+		}
+		// end todo
+		// copy resource
 		IContainer destFolder = (IContainer)dest.getResource(); // can be an IFolder or an IProject
 		IFile destFile = destFolder.getFile(new Path(destName));
 		if (!destFile.equals(sourceResource)) {
@@ -259,8 +279,17 @@
 			if (newContent != null){
 				boolean wasReadOnly = destFile.isReadOnly();
 				try {
-					String encoding = source.getJavaProject().getOption(JavaCore.CORE_ENCODING, true);
-					
+					String encoding = null;
+					try {
+						// TODO (frederic) remove when bug 67606 will be fixed (bug 67823)
+						// fix bug 66898
+						if (sourceEncoding != null) destFile.setCharset(sourceEncoding, this.progressMonitor);
+						// end todo
+						encoding = destFile.getCharset();
+					}
+					catch (CoreException ce) {
+						// use no encoding
+					}
 					// when the file was copied, its read-only flag was preserved -> temporary set it to false
 					// note this doesn't interfer with repository providers as this is a new resource that cannot be under
 					// version control yet
@@ -301,7 +330,17 @@
 			// see http://dev.eclipse.org/bugs/show_bug.cgi?id=9351
 			try {
 				if (newContent != null){
-					String encoding = source.getJavaProject().getOption(JavaCore.CORE_ENCODING, true);
+					String encoding = null;
+					try {
+						// TODO (frederic) remove when bug 67606 will be fixed (bug 67823)
+						// fix bug 66898
+						if (sourceEncoding != null) destFile.setCharset(sourceEncoding, this.progressMonitor);
+						// end todo
+						encoding = destFile.getCharset();
+					}
+					catch (CoreException ce) {
+						// use no encoding
+					}
 					destFile.setContents(
 						new ByteArrayInputStream(encoding == null ? newContent.getBytes() : newContent.getBytes(encoding)), 
 						force ? IResource.FORCE | IResource.KEEP_HISTORY : IResource.KEEP_HISTORY, 
@@ -365,7 +404,9 @@
 	 *
 	 * @exception JavaModelException if the operation is unable to
 	 * complete
+	 * @deprecated marked deprecated to suppress JDOM-related deprecation warnings
 	 */
+    // TODO - JDOM - remove once model ported off of JDOM
 	private void processPackageFragmentResource(IPackageFragment source, IPackageFragmentRoot root, String newName) throws JavaModelException {
 		try {
 			String newFragName = (newName == null) ? source.getElementName() : newName;
@@ -450,10 +491,13 @@
 	
 			// Update package statement in compilation unit if needed
 			if (!newFrag.getElementName().equals(source.getElementName())) { // if package has been renamed, update the compilation units
+				char[][] inclusionPatterns = ((PackageFragmentRoot)root).fullInclusionPatternChars();
+				char[][] exclusionPatterns = ((PackageFragmentRoot)root).fullExclusionPatternChars();
 				for (int i = 0; i < resources.length; i++) {
 					if (resources[i].getName().endsWith(SUFFIX_STRING_java)) {
 						// we only consider potential compilation units
 						ICompilationUnit cu = newFrag.getCompilationUnit(resources[i].getName());
+						if (Util.isExcluded(cu.getPath(), inclusionPatterns, exclusionPatterns, false/*not a folder*/)) continue;
 						IDOMCompilationUnit domCU = fFactory.createCompilationUnit(cu.getSource(), cu.getElementName());
 						if (domCU != null) {
 							updatePackageStatement(domCU, newFragName);
@@ -512,8 +556,13 @@
 				// in case of a copy
 				updateReadOnlyPackageFragmentsForCopy((IContainer) source.getParent().getResource(), root, newFragName);
 			}
-			//register the correct change deltas
-			prepareDeltas(source, newFrag, isMove() && isEmpty);
+			// workaround for bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=24505
+			if (isEmpty && isMove() && !(Util.isExcluded(source) || Util.isExcluded(newFrag))) {
+				IJavaProject sourceProject = source.getJavaProject();
+				getDeltaFor(sourceProject).movedFrom(source, newFrag);
+				IJavaProject destProject = newFrag.getJavaProject();
+				getDeltaFor(destProject).movedTo(newFrag, source);
+			}
 		} catch (DOMException dom) {
 			throw new JavaModelException(dom, IJavaModelStatusConstants.DOM_EXCEPTION);
 		} catch (JavaModelException e) {
@@ -527,7 +576,9 @@
 	 * declaration as necessary.
 	 *
 	 * @return the new source
+	 * @deprecated marked deprecated to suppress JDOM-related deprecation warnings
 	 */
+    // TODO - JDOM - remove once model ported off of JDOM
 	private String updatedContent(ICompilationUnit cu, IPackageFragment dest, String newName) throws JavaModelException {
 		String currPackageName = cu.getParent().getElementName();
 		String destPackageName = dest.getElementName();
@@ -549,13 +600,15 @@
 	}
 	/**
 	 * Makes sure that <code>cu</code> declares to be in the <code>pkgName</code> package.
+	 * @deprecated marked deprecated to suppress JDOM-related deprecation warnings
 	 */
+    // TODO - JDOM - remove once model ported off of JDOM
 	private void updatePackageStatement(IDOMCompilationUnit domCU, String pkgName) {
 		boolean defaultPackage = pkgName.equals(IPackageFragment.DEFAULT_PACKAGE_NAME);
 		boolean seenPackageNode = false;
-		Enumeration enum = domCU.getChildren();
-		while (enum.hasMoreElements()) {
-			IDOMNode node = (IDOMNode) enum.nextElement();
+		Enumeration nodes = domCU.getChildren();
+		while (nodes.hasMoreElements()) {
+			IDOMNode node = (IDOMNode) nodes.nextElement();
 			if (node.getNodeType() == IDOMNode.PACKAGE) {
 				if (! defaultPackage) {
 					node.setName(pkgName);
@@ -612,7 +665,9 @@
 	}
 		/**
 		 * Renames the main type in <code>cu</code>.
+	     * @deprecated marked deprecated to suppress JDOM-related deprecation warnings
 		 */
+        // TODO - JDOM - remove once model ported off of JDOM
 		private void updateTypeName(ICompilationUnit cu, IDOMCompilationUnit domCU, String oldName, String newName) throws JavaModelException {
 			if (newName != null) {
 				if (fRenamedCompilationUnits == null) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateCompilationUnitOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateCompilationUnitOperation.java
index 025deca..042e3f7 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateCompilationUnitOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateCompilationUnitOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -14,11 +14,15 @@
 import java.io.IOException;
 import java.io.InputStream;
 
+import org.eclipse.core.resources.*;
 import org.eclipse.core.resources.IContainer;
 import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.NullProgressMonitor;
 import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
 import org.eclipse.jdt.core.IBuffer;
 import org.eclipse.jdt.core.ICompilationUnit;
 import org.eclipse.jdt.core.IJavaElement;
@@ -27,7 +31,7 @@
 import org.eclipse.jdt.core.IJavaModelStatusConstants;
 import org.eclipse.jdt.core.IPackageFragment;
 import org.eclipse.jdt.core.JavaConventions;
-import org.eclipse.jdt.core.JavaCore;
+//import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.internal.core.util.Util;
 
@@ -104,7 +108,13 @@
 			}
 		} else {
 			try {
-				String encoding = unit.getJavaProject().getOption(JavaCore.CORE_ENCODING, true);
+				String encoding = null;
+				try {
+					encoding = folder.getDefaultCharset(); // get folder encoding as file is not accessible
+				}
+				catch (CoreException ce) {
+					// use no encoding
+				}
 				InputStream stream = new ByteArrayInputStream(encoding == null ? fSource.getBytes() : fSource.getBytes(encoding));
 				createFile(folder, unit.getElementName(), stream, force);
 				resultElements = new IJavaElement[] {unit};
@@ -130,6 +140,15 @@
 protected ICompilationUnit getCompilationUnit() {
 	return ((IPackageFragment)getParentElement()).getCompilationUnit(fName);
 }
+protected ISchedulingRule getSchedulingRule() {
+	IResource resource  = getCompilationUnit().getResource();
+	IWorkspace workspace = resource.getWorkspace();
+	if (resource.exists()) {
+		return workspace.getRuleFactory().modifyRule(resource);
+	} else {
+		return workspace.getRuleFactory().createRule(resource);
+	}
+}
 /**
  * Possible failures: <ul>
  *  <li>NO_ELEMENTS_TO_PROCESS - the package fragment supplied to the operation is
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateElementInCUOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateElementInCUOperation.java
index 195f6a3..7b73f91 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateElementInCUOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateElementInCUOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -10,16 +10,17 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
 import org.eclipse.jdt.core.IBuffer;
 import org.eclipse.jdt.core.ICompilationUnit;
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.IJavaModelStatus;
 import org.eclipse.jdt.core.IJavaModelStatusConstants;
 import org.eclipse.jdt.core.JavaModelException;
-import org.eclipse.jdt.core.jdom.DOMFactory;
-import org.eclipse.jdt.core.jdom.IDOMCompilationUnit;
-import org.eclipse.jdt.core.jdom.IDOMNode;
-import org.eclipse.jdt.internal.core.jdom.DOMNode;
+import org.eclipse.jdt.core.jdom.*;
+import org.eclipse.jdt.internal.core.jdom.*;
 import org.eclipse.jdt.internal.core.util.Util;
 
 /**
@@ -36,7 +37,9 @@
 public abstract class CreateElementInCUOperation extends JavaModelOperation {
 	/**
 	 * The compilation unit DOM used for this operation
+	 * @deprecated JDOM is obsolete
 	 */
+    // TODO - JDOM - remove once model ported off of JDOM
 	protected IDOMCompilationUnit fCUDOM;
 	/**
 	 * A constant meaning to position the new element
@@ -76,7 +79,9 @@
 	protected boolean fCreationOccurred = true;
 	/**
 	 * The element that is being created.
+	 * @deprecated JDOM is obsolete
 	 */
+    // TODO - JDOM - remove once model ported off of JDOM
 	protected DOMNode fCreatedElement;
 	/**
 	 * The position of the element that is being created.
@@ -138,7 +143,7 @@
 				if (buffer  == null) return;
 				char[] bufferContents = buffer.getCharacters();
 				if (bufferContents == null) return;
-				char[] elementContents = Util.normalizeCRs(fCreatedElement.getCharacters(), bufferContents);
+				char[] elementContents = Util.normalizeCRs(getCreatedElementCharacters(), bufferContents);
 				switch (fReplacementLength) {
 					case -1 : 
 						// element is append at the end
@@ -173,12 +178,25 @@
 		}
 	}
 	/**
-	 * Returns a JDOM document fragment for the element being created.
+	 * Returns the current contents of the created document fragment as a
+	 * character array.
+	 * @deprecated marked deprecated to suppress JDOM-related deprecation warnings
 	 */
+    // TODO - JDOM - remove once model ported off of JDOM
+	private char[] getCreatedElementCharacters() {
+		return fCreatedElement.getCharacters();
+	}
+	/**
+	 * Returns a JDOM document fragment for the element being created.
+	 * @deprecated JDOM is obsolete
+	 */
+    // TODO - JDOM - remove once model ported off of JDOM
 	protected abstract IDOMNode generateElementDOM() throws JavaModelException;
 	/**
 	 * Returns the DOM with the new source to use for the given compilation unit.
+	 * @deprecated JDOM is obsolete
 	 */
+    // TODO - JDOM - remove once model ported off of JDOM
 	protected void generateNewCompilationUnitDOM(ICompilationUnit cu) throws JavaModelException {
 		IBuffer buffer = cu.getBuffer();
 		if (buffer == null) return;
@@ -222,6 +240,11 @@
 	 */
 	public abstract String getMainTaskName();
 
+	protected ISchedulingRule getSchedulingRule() {
+		IResource resource = getCompilationUnit().getResource();
+		IWorkspace workspace = resource.getWorkspace();
+		return workspace.getRuleFactory().modifyRule(resource);
+	}
 	/**
 	 * Sets the default position in which to create the new type
 	 * member. 
@@ -236,9 +259,11 @@
 	 * Inserts the given child into the given JDOM, 
 	 * based on the position settings of this operation.
 	 *
-	 * @see createAfter(IJavaElement)
-	 * @see createBefore(IJavaElement);
+	 * @see #createAfter(IJavaElement)
+	 * @see #createBefore(IJavaElement)
+	 * @deprecated JDOM is obsolete
 	 */
+    // TODO - JDOM - remove once model ported off of JDOM
 	protected void insertDOMNode(IDOMNode parent, IDOMNode child) {
 		if (fInsertionPolicy != INSERT_LAST) {
 			IDOMNode sibling = ((JavaElement)fAnchorElement).findNode(fCUDOM);
@@ -255,8 +280,8 @@
 		}
 		//add as the last element of the parent
 		parent.addChild(child);
-		fCreatedElement = (DOMNode)child;
-		fInsertionPosition = ((DOMNode)parent).getInsertionPosition();
+		fCreatedElement = (org.eclipse.jdt.internal.core.jdom.DOMNode)child;
+		fInsertionPosition = ((org.eclipse.jdt.internal.core.jdom.DOMNode)parent).getInsertionPosition();
 	//	fInsertionPosition = lastChild == null ? ((DOMNode)parent).getInsertionPosition() : lastChild.getInsertionPosition();
 		fReplacementLength = parent.getParent() == null ? -1 : 0;
 	}
@@ -293,7 +318,7 @@
 	 *  <li>INVALID_SIBLING - the sibling provided for positioning is not valid.
 	 * </ul>
 	 * @see IJavaModelStatus
-	 * @see JavaConventions
+	 * @see org.eclipse.jdt.core.JavaConventions
 	 */
 	public IJavaModelStatus verify() {
 		if (getParentElement() == null) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateFieldOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateFieldOperation.java
index a7f1415..43608d8 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateFieldOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateFieldOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -15,9 +15,7 @@
 import org.eclipse.jdt.core.IJavaModelStatusConstants;
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.JavaModelException;
-import org.eclipse.jdt.core.jdom.DOMFactory;
-import org.eclipse.jdt.core.jdom.IDOMField;
-import org.eclipse.jdt.core.jdom.IDOMNode;
+import org.eclipse.jdt.core.jdom.*;
 import org.eclipse.jdt.internal.core.util.Util;
 
 /**
@@ -42,8 +40,10 @@
 	super(parentElement, source, force);
 }
 /**
- * @see CreateTypeMemberOperation#generateElementDOM
+ * @see CreateTypeMemberOperation#generateSyntaxIncorrectDOM()
+ * @deprecated JDOM is obsolete
  */
+// TODO - JDOM - remove once model ported off of JDOM
 protected IDOMNode generateElementDOM() throws JavaModelException {
 	if (fDOMNode == null) {
 		fDOMNode = (new DOMFactory()).createField(fSource);
@@ -66,7 +66,7 @@
  * @see CreateElementInCUOperation#generateResultHandle
  */
 protected IJavaElement generateResultHandle() {
-	return getType().getField(fDOMNode.getName());
+	return getType().getField(getDOMNodeName());
 }
 /**
  * @see CreateElementInCUOperation#getMainTaskName()
@@ -100,11 +100,18 @@
  */
 protected IJavaModelStatus verifyNameCollision() {
 	IType type= getType();
-	if (type.getField(fDOMNode.getName()).exists()) {
+	if (type.getField(getDOMNodeName()).exists()) {
 		return new JavaModelStatus(
 			IJavaModelStatusConstants.NAME_COLLISION, 
-			Util.bind("status.nameCollision", fDOMNode.getName())); //$NON-NLS-1$
+			Util.bind("status.nameCollision", getDOMNodeName())); //$NON-NLS-1$
 	}
 	return JavaModelStatus.VERIFIED_OK;
 }
+/**
+ * @deprecated marked deprecated to suppress JDOM-related deprecation warnings
+ */
+// TODO - JDOM - remove once model ported off of JDOM
+private String getDOMNodeName() {
+	return fDOMNode.getName();
+}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateImportOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateImportOperation.java
index 5fb337f..80bbf37 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateImportOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateImportOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -19,9 +19,7 @@
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.JavaConventions;
 import org.eclipse.jdt.core.JavaModelException;
-import org.eclipse.jdt.core.jdom.DOMFactory;
-import org.eclipse.jdt.core.jdom.IDOMImport;
-import org.eclipse.jdt.core.jdom.IDOMNode;
+import org.eclipse.jdt.core.jdom.*;
 import org.eclipse.jdt.internal.core.util.Util;
 
 /**
@@ -56,8 +54,10 @@
 	fImportName = importName;
 }
 /**
- * @see CreateTypeMemberOperation#generateElementDOM
+ * @see CreateTypeMemberOperation
+ * @deprecated JDOM is obsolete
  */
+// TODO - JDOM - remove once model ported off of JDOM
 protected IDOMNode generateElementDOM() {
 	if (fCUDOM.getChild(fImportName) == null) {
 		DOMFactory factory = new DOMFactory();
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateInitializerOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateInitializerOperation.java
index ed7b3f7..e921420 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateInitializerOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateInitializerOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -14,9 +14,7 @@
 import org.eclipse.jdt.core.IJavaModelStatusConstants;
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.JavaModelException;
-import org.eclipse.jdt.core.jdom.DOMFactory;
-import org.eclipse.jdt.core.jdom.IDOMInitializer;
-import org.eclipse.jdt.core.jdom.IDOMNode;
+import org.eclipse.jdt.core.jdom.*;
 import org.eclipse.jdt.internal.core.util.Util;
 
 /**
@@ -46,8 +44,10 @@
 	super(parentElement, source, false);
 }
 /**
- * @see CreateTypeMemberOperation#generateElementDOM
+ * @see CreateTypeMemberOperation#generateSyntaxIncorrectDOM()
+ * @deprecated JDOM is obsolete
  */
+// TODO - JDOM - remove once model ported off of JDOM
 protected IDOMNode generateElementDOM() throws JavaModelException {
 	if (fDOMNode == null) {
 		fDOMNode = (new DOMFactory()).createInitializer(fSource);
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateMethodOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateMethodOperation.java
index 0212b62..322e3d6 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateMethodOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateMethodOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -16,9 +16,7 @@
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.Signature;
-import org.eclipse.jdt.core.jdom.DOMFactory;
-import org.eclipse.jdt.core.jdom.IDOMMethod;
-import org.eclipse.jdt.core.jdom.IDOMNode;
+import org.eclipse.jdt.core.jdom.*;
 import org.eclipse.jdt.internal.core.util.Util;
 
 /**
@@ -42,10 +40,12 @@
 /**
  * Returns the type signatures of the parameter types of the
  * current <code>DOMMethod</code>
+ * @deprecated JDOM is obsolete
  */
+// TODO - JDOM - remove once model ported off of JDOM
 protected String[] convertDOMMethodTypesToSignatures() {
 	if (fParameterTypes == null) {
-		if (fDOMNode != null) {
+		if (isDOMNodeNull()) {
 			String[] domParameterTypes = ((IDOMMethod)fDOMNode).getParameterTypes();
 			if (domParameterTypes != null) {
 				fParameterTypes = new String[domParameterTypes.length];
@@ -60,8 +60,10 @@
 	return fParameterTypes;
 }
 /**
- * @see CreateTypeMemberOperation#generateElementDOM
+ * @see CreateTypeMemberOperation#generateSyntaxIncorrectDOM()
+ * @deprecated JDOM is obsolete
  */
+// TODO - JDOM - remove once model ported off of JDOM
 protected IDOMNode generateElementDOM() throws JavaModelException {
 	if (fDOMNode == null) {
 		fDOMNode = (new DOMFactory()).createMethod(fSource);
@@ -72,7 +74,7 @@
 				throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.INVALID_CONTENTS));
 			}
 		}
-		if (fAlteredName != null && fDOMNode != null) {
+		if (fAlteredName != null && isDOMNodeNull()) {
 			fDOMNode.setName(fAlteredName);
 		}
 	}
@@ -86,13 +88,28 @@
  */
 protected IJavaElement generateResultHandle() {
 	String[] types = convertDOMMethodTypesToSignatures();
+	String name = computeName();
+	return getType().getMethod(name, types);
+}
+/**
+ * @deprecated marked deprecated to suppress JDOM-related deprecation warnings
+ */
+// TODO - JDOM - remove once model ported off of JDOM
+private String computeName() {
 	String name;
 	if (((IDOMMethod) fDOMNode).isConstructor()) {
 		name = fDOMNode.getParent().getName();
 	} else {
-		name = fDOMNode.getName();
+		name = getDOMNodeName();
 	}
-	return getType().getMethod(name, types);
+	return name;
+}
+/**
+ * @deprecated marked deprecated to suppress JDOM-related deprecation warnings
+ */
+// TODO - JDOM - remove once model ported off of JDOM
+private String getDOMNodeName() {
+	return fDOMNode.getName();
 }
 /**
  * @see CreateElementInCUOperation#getMainTaskName()
@@ -104,9 +121,9 @@
  * @see CreateTypeMemberOperation#verifyNameCollision
  */
 protected IJavaModelStatus verifyNameCollision() {
-	if (fDOMNode != null) {
+	if (isDOMNodeNull()) {
 		IType type = getType();
-		String name = fDOMNode.getName();
+		String name = getDOMNodeName();
 		if (name == null) { //constructor
 			name = type.getElementName();
 		}
@@ -119,4 +136,11 @@
 	}
 	return JavaModelStatus.VERIFIED_OK;
 }
+/**
+ * @deprecated marked deprecated to suppress JDOM-related deprecation warnings
+ */
+// TODO - JDOM - remove once model ported off of JDOM
+private boolean isDOMNodeNull() {
+	return fDOMNode != null;
+}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreatePackageDeclarationOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreatePackageDeclarationOperation.java
index 0e92abf..8c4474d 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreatePackageDeclarationOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreatePackageDeclarationOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -20,10 +20,8 @@
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.JavaConventions;
 import org.eclipse.jdt.core.JavaModelException;
-import org.eclipse.jdt.core.jdom.DOMFactory;
-import org.eclipse.jdt.core.jdom.IDOMNode;
-import org.eclipse.jdt.core.jdom.IDOMPackage;
-import org.eclipse.jdt.internal.core.jdom.DOMNode;
+import org.eclipse.jdt.core.jdom.*;
+import org.eclipse.jdt.internal.core.jdom.*;
 import org.eclipse.jdt.internal.core.util.Util;
 
 /**
@@ -49,8 +47,10 @@
 	fName= name;
 }
 /**
- * @see CreateTypeMemberOperation#generateElementDOM
+ * @see CreateTypeMemberOperation#generateSyntaxIncorrectDOM()
+ * @deprecated JDOM is obsolete
  */
+// TODO - JDOM - remove once model ported off of JDOM
 protected IDOMNode generateElementDOM() throws JavaModelException {
 	IJavaElement[] children = getCompilationUnit().getChildren();
 	//look for an existing package declaration
@@ -61,7 +61,7 @@
 			if (!pack.getName().equals(fName)) {
 				 // get the insertion position before setting the name, as this makes it a detailed node
 				 // thus the start position is always 0
-				DOMNode node = (DOMNode)pack;
+				DOMNode node = (org.eclipse.jdt.internal.core.jdom.DOMNode)pack;
 				fInsertionPosition = node.getStartPosition();
 				fReplacementLength = node.getEndPosition() - fInsertionPosition + 1;
 				pack.setName(fName);
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreatePackageFragmentOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreatePackageFragmentOperation.java
index eb926d1..b473182 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreatePackageFragmentOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreatePackageFragmentOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -72,6 +72,7 @@
 	IContainer parentFolder = (IContainer) root.getResource();
 	String sideEffectPackageName = ""; //$NON-NLS-1$
 	ArrayList results = new ArrayList(names.length);
+	char[][] inclusionPatterns = ((PackageFragmentRoot)root).fullInclusionPatternChars();
 	char[][] exclusionPatterns = ((PackageFragmentRoot)root).fullExclusionPatternChars();
 	int i;
 	for (i = 0; i < names.length; i++) {
@@ -82,7 +83,7 @@
 			createFolder(parentFolder, subFolderName, force);
 			parentFolder = parentFolder.getFolder(new Path(subFolderName));
 			IPackageFragment addedFrag = root.getPackageFragment(sideEffectPackageName);
-			if (!Util.isExcluded(parentFolder, exclusionPatterns)) {
+			if (!Util.isExcluded(parentFolder, inclusionPatterns, exclusionPatterns)) {
 				if (delta == null) {
 					delta = newJavaElementDelta();
 				}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateTypeHierarchyOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateTypeHierarchyOperation.java
index a37978e..97deaf5 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateTypeHierarchyOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateTypeHierarchyOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateTypeMemberOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateTypeMemberOperation.java
index f30ade4..912aec1 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateTypeMemberOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateTypeMemberOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -17,9 +17,7 @@
 import org.eclipse.jdt.core.IJavaModelStatusConstants;
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.JavaModelException;
-import org.eclipse.jdt.core.jdom.DOMFactory;
-import org.eclipse.jdt.core.jdom.IDOMCompilationUnit;
-import org.eclipse.jdt.core.jdom.IDOMNode;
+import org.eclipse.jdt.core.jdom.*;
 import org.eclipse.jdt.internal.compiler.util.Util;
 
 /**
@@ -39,8 +37,10 @@
 	protected String fAlteredName;
 	/**
 	 * The JDOM document fragment representing the element that
-	 * this operation created. 
+	 * this operation created.
+	 * @deprecated JDOM is obsolete
 	 */
+     // TODO - JDOM - remove once model ported off of JDOM
 	 protected IDOMNode fDOMNode;
 /**
  * When executed, this operation will create a type member
@@ -53,7 +53,9 @@
 }
 /**
  * @see CreateElementInCUOperation#generateNewCompilationUnitDOM
+ * @deprecated JDOM is obsolete
  */
+// TODO - JDOM - remove once model ported off of JDOM
 protected void generateNewCompilationUnitDOM(ICompilationUnit cu) throws JavaModelException {
 	IBuffer buffer = cu.getBuffer();
 	if (buffer == null) return;
@@ -67,7 +69,7 @@
 		//#findNode does not work for autogenerated CUs as the contents are empty
 		parent = fCUDOM;
 	}
-	IDOMNode child = generateElementDOM();
+	IDOMNode child = deprecatedGenerateElementDOM();
 	if (child != null) {
 		insertDOMNode(parent, child);
 	}
@@ -76,7 +78,9 @@
 /**
  * Generates a <code>IDOMNode</code> based on the source of this operation
  * when there is likely a syntax error in the source.
+ * @deprecated JDOM is obsolete
  */
+// TODO - JDOM - remove once model ported off of JDOM
 protected IDOMNode generateSyntaxIncorrectDOM() {
 	//create some dummy source to generate a dom node
 	StringBuffer buff = new StringBuffer();
@@ -129,7 +133,7 @@
 	if (!force) {
 		//check for name collisions
 		try {
-			generateElementDOM();
+			deprecatedGenerateElementDOM();
 		} catch (JavaModelException jme) {
 			return jme.getJavaModelStatus();
 		}
@@ -139,6 +143,13 @@
 	return JavaModelStatus.VERIFIED_OK;
 }
 /**
+ * @deprecated marked deprecated to suppress JDOM-related deprecation warnings
+ */
+// TODO - JDOM - remove once model ported off of JDOM
+private IDOMNode deprecatedGenerateElementDOM() throws JavaModelException {
+	return generateElementDOM();
+}
+/**
  * Verify for a name collision in the destination container.
  */
 protected IJavaModelStatus verifyNameCollision() {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateTypeOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateTypeOperation.java
index 86c498c..80c47c9 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateTypeOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateTypeOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -16,9 +16,7 @@
 import org.eclipse.jdt.core.IJavaModelStatusConstants;
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.JavaModelException;
-import org.eclipse.jdt.core.jdom.DOMFactory;
-import org.eclipse.jdt.core.jdom.IDOMNode;
-import org.eclipse.jdt.core.jdom.IDOMType;
+import org.eclipse.jdt.core.jdom.*;
 import org.eclipse.jdt.internal.core.util.Util;
 
 /**
@@ -40,7 +38,9 @@
 }
 /**
  * @see CreateElementInCUOperation#generateElementDOM()
+ * @deprecated JDOM is obsolete
  */
+// TODO - JDOM - remove once model ported off of JDOM
 protected IDOMNode generateElementDOM() throws JavaModelException {
 	if (fDOMNode == null) {
 		fDOMNode = (new DOMFactory()).createType(fSource);
@@ -67,9 +67,9 @@
 	IJavaElement parent= getParentElement();
 	switch (parent.getElementType()) {
 		case IJavaElement.COMPILATION_UNIT:
-			return ((ICompilationUnit)parent).getType(fDOMNode.getName());
+			return ((ICompilationUnit)parent).getType(getDOMNodeName());
 		case IJavaElement.TYPE:
-			return ((IType)parent).getType(fDOMNode.getName());
+			return ((IType)parent).getType(getDOMNodeName());
 		// Note: creating local/anonymous type is not supported 
 	}
 	return null;
@@ -97,21 +97,28 @@
 	IJavaElement parent = getParentElement();
 	switch (parent.getElementType()) {
 		case IJavaElement.COMPILATION_UNIT:
-			if (((ICompilationUnit) parent).getType(fDOMNode.getName()).exists()) {
+			if (((ICompilationUnit) parent).getType(getDOMNodeName()).exists()) {
 				return new JavaModelStatus(
 					IJavaModelStatusConstants.NAME_COLLISION, 
-					Util.bind("status.nameCollision", fDOMNode.getName())); //$NON-NLS-1$
+					Util.bind("status.nameCollision", getDOMNodeName())); //$NON-NLS-1$
 			}
 			break;
 		case IJavaElement.TYPE:
-			if (((IType) parent).getType(fDOMNode.getName()).exists()) {
+			if (((IType) parent).getType(getDOMNodeName()).exists()) {
 				return new JavaModelStatus(
 					IJavaModelStatusConstants.NAME_COLLISION, 
-					Util.bind("status.nameCollision", fDOMNode.getName())); //$NON-NLS-1$
+					Util.bind("status.nameCollision", getDOMNodeName())); //$NON-NLS-1$
 			}
 			break;
 		// Note: creating local/anonymous type is not supported 
 	}
 	return JavaModelStatus.VERIFIED_OK;
 }
+/**
+ * @deprecated marked deprecated to suppress JDOM-related deprecation warnings
+ */
+// TODO - JDOM - remove once model ported off of JDOM
+private String getDOMNodeName() {
+	return fDOMNode.getName();
+}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DefaultWorkingCopyOwner.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DefaultWorkingCopyOwner.java
index 02dbe0f..9897465 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DefaultWorkingCopyOwner.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DefaultWorkingCopyOwner.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -20,11 +20,7 @@
  */
 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();
 	
@@ -36,8 +32,8 @@
 	 * @deprecated Marked deprecated as it is using deprecated code
 	 */
 	public IBuffer createBuffer(ICompilationUnit workingCopy) {
-		if (this.factory == null) return super.createBuffer(workingCopy);
-		return this.factory.createBuffer(workingCopy); // TODO (jerome) change to use a org.eclipse.text buffer
+		if (this.primaryBufferProvider != null) return this.primaryBufferProvider.createBuffer(workingCopy);
+		return super.createBuffer(workingCopy);
 	}
 	public String toString() {
 		return "Primary owner"; //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeleteElementsOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeleteElementsOperation.java
index d33e759..3306502 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeleteElementsOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeleteElementsOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -21,9 +21,7 @@
 import org.eclipse.jdt.core.IRegion;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.core.jdom.DOMFactory;
-import org.eclipse.jdt.core.jdom.IDOMCompilationUnit;
-import org.eclipse.jdt.internal.core.jdom.DOMNode;
+import org.eclipse.jdt.core.jdom.*;
 import org.eclipse.jdt.internal.core.util.Util;
 
 /**
@@ -39,7 +37,7 @@
 public class DeleteElementsOperation extends MultiOperation {
 	/**
 	 * The elements this operation processes grouped by compilation unit
-	 * @see processElements(). Keys are compilation units,
+	 * @see #processElements() Keys are compilation units,
 	 * values are <code>IRegion</code>s of elements to be processed in each
 	 * compilation unit.
 	 */ 
@@ -47,7 +45,9 @@
 	/**
 	 * The <code>DOMFactory</code> used to manipulate the source code of
 	 * <code>ICompilationUnit</code>s.
+	 * @deprecated JDOM is obsolete 
 	 */
+    // TODO - JDOM - remove once model ported off of JDOM
 	protected DOMFactory factory;
 	/**
 	 * When executed, this operation will delete the given elements. The elements
@@ -56,10 +56,18 @@
 	 */
 	public DeleteElementsOperation(IJavaElement[] elementsToDelete, boolean force) {
 		super(elementsToDelete, force);
-		factory = new DOMFactory();
+		initDOMFactory();
 	}
 	
 	/**
+	 * @deprecated marked deprecated to suppress JDOM-related deprecation warnings
+	 */
+    // TODO - JDOM - remove once model ported off of JDOM
+	private void initDOMFactory() {
+		factory = new DOMFactory();
+	}
+
+	/**
 	 * @see MultiOperation
 	 */
 	protected String getMainTaskName() {
@@ -116,12 +124,8 @@
 			if (e.exists()) {
 				char[] contents = buffer.getCharacters();
 				if (contents == null) continue;
-				IDOMCompilationUnit cuDOM = factory.createCompilationUnit(contents, cu.getElementName());
-				DOMNode node = (DOMNode)((JavaElement) e).findNode(cuDOM);
-				if (node == null) Assert.isTrue(false, "Failed to locate " + e.getElementName() + " in " + cuDOM.getName()); //$NON-NLS-1$//$NON-NLS-2$
-
-				int startPosition = node.getStartPosition();
-				buffer.replace(startPosition, node.getEndPosition() - startPosition + 1, CharOperation.NO_CHAR);
+				String cuName = cu.getElementName();
+				replaceElementInBuffer(buffer, e, cuName);
 				delta.removed(e);
 				if (e.getElementType() == IJavaElement.IMPORT_DECLARATION) {
 					numberOfImports--;
@@ -140,6 +144,19 @@
 		}
 	}
 	/**
+	 * @deprecated marked deprecated to suppress JDOM-related deprecation warnings
+	 */
+    // TODO - JDOM - remove once model ported off of JDOM
+	private void replaceElementInBuffer(IBuffer buffer, IJavaElement elementToRemove, String cuName) {
+		IDOMCompilationUnit cuDOM = factory.createCompilationUnit(buffer.getCharacters(), cuName);
+		org.eclipse.jdt.internal.core.jdom.DOMNode node = (org.eclipse.jdt.internal.core.jdom.DOMNode)((JavaElement) elementToRemove).findNode(cuDOM);
+		if (node == null) Assert.isTrue(false, "Failed to locate " + elementToRemove.getElementName() + " in " + cuDOM.getName()); //$NON-NLS-1$//$NON-NLS-2$
+
+		int startPosition = node.getStartPosition();
+		buffer.replace(startPosition, node.getEndPosition() - startPosition + 1, CharOperation.NO_CHAR);
+	}
+
+	/**
 	 * @see MultiOperation
 	 * This method first group the elements by <code>ICompilationUnit</code>,
 	 * and then processes the <code>ICompilationUnit</code>.
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeletePackageFragmentRootOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeletePackageFragmentRootOperation.java
index fc68fc7..d4f2294 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeletePackageFragmentRootOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeletePackageFragmentRootOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeleteResourceElementsOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeleteResourceElementsOperation.java
index aae4d4d..b4b26cd 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeleteResourceElementsOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeleteResourceElementsOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -100,7 +100,7 @@
 	return Util.bind("operation.deleteResourceProgress"); //$NON-NLS-1$
 }
 /**
- * @see MultiOperation. This method delegate to <code>deleteResource</code> or
+ * @see MultiOperation This method delegate to <code>deleteResource</code> or
  * <code>deletePackageFragment</code> depending on the type of <code>element</code>.
  */
 protected void processElement(IJavaElement element) throws JavaModelException {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessingState.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessingState.java
index 00b080c..a367e3b 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessingState.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessingState.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -27,6 +27,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.Util;
 
 /**
  * Keep the global states used during Java element delta processing.
@@ -39,6 +40,12 @@
 	public IElementChangedListener[] elementChangedListeners = new IElementChangedListener[5];
 	public int[] elementChangedListenerMasks = new int[5];
 	public int elementChangedListenerCount = 0;
+	
+	/*
+	 * Collection of pre Java resource change listeners
+	 */
+	public IResourceChangeListener[] preResourceChangeListeners = new IResourceChangeListener[1];
+	public int preResourceChangeListenerCount = 0;
 
 	/*
 	 * The delta processor for the current thread.
@@ -71,13 +78,90 @@
 	private Set initializingThreads = Collections.synchronizedSet(new HashSet());	
 	
 	public Hashtable externalTimeStamps = new Hashtable();
+	
+	public HashMap projectUpdates = new HashMap();
 
+	public static class ProjectUpdateInfo {
+		JavaProject project;
+		IClasspathEntry[] oldResolvedPath;
+		IClasspathEntry[] newResolvedPath;
+		IClasspathEntry[] newRawPath;
+		
+		/**
+		 * Update projects references so that the build order is consistent with the classpath
+		 */
+		public void updateProjectReferencesIfNecessary() throws JavaModelException {
+			
+			String[] oldRequired = this.project.projectPrerequisites(this.oldResolvedPath);
+	
+			if (this.newResolvedPath == null) {
+				this.newResolvedPath = this.project.getResolvedClasspath(this.newRawPath, null, true, true, null/*no reverse map*/);
+			}
+			String[] newRequired = this.project.projectPrerequisites(this.newResolvedPath);
+			try {
+				IProject projectResource = this.project.getProject();
+				IProjectDescription description = projectResource.getDescription();
+				 
+				IProject[] projectReferences = description.getDynamicReferences();
+				
+				HashSet oldReferences = new HashSet(projectReferences.length);
+				for (int i = 0; i < projectReferences.length; i++){
+					String projectName = projectReferences[i].getName();
+					oldReferences.add(projectName);
+				}
+				HashSet newReferences = (HashSet)oldReferences.clone();
+		
+				for (int i = 0; i < oldRequired.length; i++){
+					String projectName = oldRequired[i];
+					newReferences.remove(projectName);
+				}
+				for (int i = 0; i < newRequired.length; i++){
+					String projectName = newRequired[i];
+					newReferences.add(projectName);
+				}
+		
+				Iterator iter;
+				int newSize = newReferences.size();
+				
+				checkIdentity: {
+					if (oldReferences.size() == newSize){
+						iter = newReferences.iterator();
+						while (iter.hasNext()){
+							if (!oldReferences.contains(iter.next())){
+								break checkIdentity;
+							}
+						}
+						return;
+					}
+				}
+				String[] requiredProjectNames = new String[newSize];
+				int index = 0;
+				iter = newReferences.iterator();
+				while (iter.hasNext()){
+					requiredProjectNames[index++] = (String)iter.next();
+				}
+				Util.sort(requiredProjectNames); // ensure that if changed, the order is consistent
+				
+				IProject[] requiredProjectArray = new IProject[newSize];
+				IWorkspaceRoot wksRoot = projectResource.getWorkspace().getRoot();
+				for (int i = 0; i < newSize; i++){
+					requiredProjectArray[i] = wksRoot.getProject(requiredProjectNames[i]);
+				}
+				description.setDynamicReferences(requiredProjectArray);
+				projectResource.setDescription(description, null);
+		
+			} catch(CoreException e){
+				throw new JavaModelException(e);
+			}
+		}
+	}
+	
 	/**
 	 * Workaround for bug 15168 circular errors not reported  
 	 * This is a cache of the projects before any project addition/deletion has started.
 	 */
 	public IJavaProject[] modelProjectsCache;
-		
+	
 	/*
 	 * Need to clone defensively the listener information, in case some listener is reacting to some notification iteration by adding/changing/removing
 	 * any of the other (for example, if it deregisters itself).
@@ -105,6 +189,21 @@
 		this.elementChangedListenerCount++;
 	}
 
+	public void addPreResourceChangedListener(IResourceChangeListener listener) {
+		for (int i = 0; i < this.preResourceChangeListenerCount; i++){
+			if (this.preResourceChangeListeners[i].equals(listener)) {
+				return;
+			}
+		}
+		// may need to grow, no need to clone, since iterators will have cached original arrays and max boundary and we only add to the end.
+		int length;
+		if ((length = this.preResourceChangeListeners.length) == this.preResourceChangeListenerCount){
+			System.arraycopy(this.preResourceChangeListeners, 0, this.preResourceChangeListeners = new IResourceChangeListener[length*2], 0, length);
+		}
+		this.preResourceChangeListeners[this.preResourceChangeListenerCount] = listener;
+		this.preResourceChangeListenerCount++;
+	}
+
 	public DeltaProcessor getDeltaProcessor() {
 		DeltaProcessor deltaProcessor = (DeltaProcessor)this.deltaProcessors.get();
 		if (deltaProcessor != null) return deltaProcessor;
@@ -113,6 +212,20 @@
 		return deltaProcessor;
 	}
 
+	public void performClasspathResourceChange(JavaProject project, IClasspathEntry[] oldResolvedPath, IClasspathEntry[] newResolvedPath, IClasspathEntry[] newRawPath, boolean canChangeResources) throws JavaModelException {
+	    ProjectUpdateInfo info = new ProjectUpdateInfo();
+	    info.project = project;
+	    info.oldResolvedPath = oldResolvedPath;
+	    info.newResolvedPath = newResolvedPath;
+	    info.newRawPath = newRawPath;
+	    if (canChangeResources) {
+            this.projectUpdates.remove(project); // remove possibly awaiting one
+	        info.updateProjectReferencesIfNecessary();
+	        return;
+	    }
+	    this.recordProjectUpdate(info);
+	}
+	
 	public void initializeRoots() {
 		
 		// recompute root infos only if necessary
@@ -141,10 +254,10 @@
 					return;
 				}
 				for (int i = 0, length = projects.length; i < length; i++) {
-					IJavaProject project = projects[i];
+					JavaProject project = (JavaProject) projects[i];
 					IClasspathEntry[] classpath;
 					try {
-						classpath = project.getResolvedClasspath(true);
+						classpath = project.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
 					} catch (JavaModelException e) {
 						// continue with next project
 						continue;
@@ -156,14 +269,14 @@
 						// root path
 						IPath path = entry.getPath();
 						if (newRoots.get(path) == null) {
-							newRoots.put(path, new DeltaProcessor.RootInfo(project, path, ((ClasspathEntry)entry).fullExclusionPatternChars(), entry.getEntryKind()));
+							newRoots.put(path, new DeltaProcessor.RootInfo(project, path, ((ClasspathEntry)entry).fullInclusionPatternChars(), ((ClasspathEntry)entry).fullExclusionPatternChars(), entry.getEntryKind()));
 						} else {
 							ArrayList rootList = (ArrayList)newOtherRoots.get(path);
 							if (rootList == null) {
 								rootList = new ArrayList();
 								newOtherRoots.put(path, rootList);
 							}
-							rootList.add(new DeltaProcessor.RootInfo(project, path, ((ClasspathEntry)entry).fullExclusionPatternChars(), entry.getEntryKind()));
+							rootList.add(new DeltaProcessor.RootInfo(project, path, ((ClasspathEntry)entry).fullInclusionPatternChars(), ((ClasspathEntry)entry).fullExclusionPatternChars(), entry.getEntryKind()));
 						}
 						
 						// source attachment path
@@ -205,6 +318,26 @@
 		}
 	}
 
+	public synchronized void recordProjectUpdate(ProjectUpdateInfo newInfo) {
+	    
+	    JavaProject project = newInfo.project;
+	    ProjectUpdateInfo oldInfo = (ProjectUpdateInfo) this.projectUpdates.get(project);
+	    if (oldInfo != null) { // refresh new classpath information
+	        oldInfo.newRawPath = newInfo.newRawPath;
+	        oldInfo.newResolvedPath = newInfo.newResolvedPath;
+	    } else {
+	        this.projectUpdates.put(project, newInfo);
+	    }
+	}
+	public synchronized ProjectUpdateInfo[] removeAllProjectUpdates() {
+	    int length = this.projectUpdates.size();
+	    if (length == 0) return null;
+	    ProjectUpdateInfo[]  updates = new ProjectUpdateInfo[length];
+	    this.projectUpdates.values().toArray(updates);
+	    this.projectUpdates.clear();
+	    return updates;
+	}
+	
 	public void removeElementChangedListener(IElementChangedListener listener) {
 		
 		for (int i = 0; i < this.elementChangedListenerCount; i++){
@@ -235,12 +368,53 @@
 		}
 	}
 
-	public void resourceChanged(IResourceChangeEvent event) {
+	public void removePreResourceChangedListener(IResourceChangeListener listener) {
+		
+		for (int i = 0; i < this.preResourceChangeListenerCount; i++){
+			
+			if (this.preResourceChangeListeners[i].equals(listener)){
+				
+				// need to clone defensively since we might be in the middle of listener notifications (#fire)
+				int length = this.preResourceChangeListeners.length;
+				IResourceChangeListener[] newListeners = new IResourceChangeListener[length];
+				System.arraycopy(this.preResourceChangeListeners, 0, newListeners, 0, i);
+				
+				// copy trailing listeners
+				int trailingLength = this.preResourceChangeListenerCount - i - 1;
+				if (trailingLength > 0){
+					System.arraycopy(this.preResourceChangeListeners, i+1, newListeners, i, trailingLength);
+				}
+				
+				// update manager listener state (#fire need to iterate over original listeners through a local variable to hold onto
+				// the original ones)
+				this.preResourceChangeListeners = newListeners;
+				this.preResourceChangeListenerCount--;
+				return;
+			}
+		}
+	}
+
+	public void resourceChanged(final IResourceChangeEvent event) {
+		boolean isPostChange = event.getType() == IResourceChangeEvent.POST_CHANGE;
+		if (isPostChange) {
+			for (int i = 0; i < this.preResourceChangeListenerCount; i++) {
+				// wrap callbacks with Safe runnable for subsequent listeners to be called when some are causing grief
+				final IResourceChangeListener listener = this.preResourceChangeListeners[i];
+				Platform.run(new ISafeRunnable() {
+					public void handleException(Throwable exception) {
+						Util.log(exception, "Exception occurred in listener of pre Java resource change notification"); //$NON-NLS-1$
+					}
+					public void run() throws Exception {
+						listener.resourceChanged(event);
+					}
+				});
+			}
+		}
 		try {
 			getDeltaProcessor().resourceChanged(event);
 		} finally {
 			// TODO (jerome) see 47631, may want to get rid of following so as to reuse delta processor ? 
-			if (event.getType() == IResourceChangeEvent.POST_CHANGE) {
+			if (isPostChange) {
 				this.deltaProcessors.set(null);
 			}
 		}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java
index 7bb54ad..6d22858 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -95,16 +95,34 @@
 	}
 	
 	static class RootInfo {
+		char[][] inclusionPatterns;
 		char[][] exclusionPatterns;
-		IJavaProject project;
+		JavaProject project;
 		IPath rootPath;
 		int entryKind;
-		RootInfo(IJavaProject project, IPath rootPath, char[][] exclusionPatterns, int entryKind) {
+		IPackageFragmentRoot root;
+		RootInfo(JavaProject project, IPath rootPath, char[][] inclusionPatterns, char[][] exclusionPatterns, int entryKind) {
 			this.project = project;
 			this.rootPath = rootPath;
+			this.inclusionPatterns = inclusionPatterns;
 			this.exclusionPatterns = exclusionPatterns;
 			this.entryKind = entryKind;
 		}
+		IPackageFragmentRoot getPackageFragmentRoot(IResource resource) {
+			if (this.root == null) {
+				if (resource != null) {
+					this.root = this.project.getPackageFragmentRoot(resource);
+				} else {
+					Object target = JavaModel.getTarget(ResourcesPlugin.getWorkspace().getRoot(), this.rootPath, false/*don't check existence*/);
+					if (target instanceof IResource) {
+						this.root = this.project.getPackageFragmentRoot((IResource)target);
+					} else {
+						this.root = this.project.getPackageFragmentRoot(this.rootPath.toOSString());
+					}
+				}
+			}
+			return this.root;
+		}
 		boolean isRootOfProject(IPath path) {
 			return this.rootPath.equals(path) && this.project.getProject().getFullPath().isPrefixOf(path);
 		}
@@ -121,6 +139,17 @@
 			} else {
 				buffer.append(this.rootPath.toString());
 			}
+			buffer.append("\nincluding="); //$NON-NLS-1$
+			if (this.inclusionPatterns == null) {
+				buffer.append("null"); //$NON-NLS-1$
+			} else {
+				for (int i = 0, length = this.inclusionPatterns.length; i < length; i++) {
+					buffer.append(new String(this.inclusionPatterns[i]));
+					if (i < length-1) {
+						buffer.append("|"); //$NON-NLS-1$
+					}
+				}
+			}
 			buffer.append("\nexcluding="); //$NON-NLS-1$
 			if (this.exclusionPatterns == null) {
 				buffer.append("null"); //$NON-NLS-1$
@@ -147,6 +176,7 @@
 	private final static String INTERNAL_JAR_IGNORE = "internal jar ignore"; //$NON-NLS-1$
 	
 	private final static int NON_JAVA_RESOURCE = -1;
+	public static boolean DEBUG = false;
 	public static boolean VERBOSE = false;
 
 	public static final int DEFAULT_CHANGE_EVENT = 0; // must not collide with ElementChangedEvent event masks
@@ -201,8 +231,8 @@
 	 */
 	private final ModelUpdater modelUpdater = new ModelUpdater();
 
-	/* A set of IJavaProject whose namelookup caches need to be refreshed */
-	private HashSet namelookupsToRefresh = new HashSet();  
+	/* A set of IJavaProject whose caches need to be reset */
+	private HashSet projectCachesToReset = new HashSet();  
 
 	/*
 	 * A list of IJavaElement used as a scope for external archives refresh during POST_CHANGE.
@@ -218,6 +248,11 @@
 	/* A set of IJavaProject whose package fragment roots need to be refreshed */
 	private HashSet rootsToRefresh = new HashSet();
 	
+	/*
+	 * Type of event that should be processed no matter what the real event type is.
+	 */
+	public int overridenEventType = -1;
+		
 	public DeltaProcessor(DeltaProcessingState state, JavaModelManager manager) {
 		this.state = state;
 		this.manager = manager;
@@ -300,9 +335,18 @@
 				IJavaElementDelta[] projectDeltas = this.currentDelta.getAffectedChildren();
 				for (int i = 0, length = projectDeltas.length; i < length; i++) {
 					IJavaElementDelta delta = projectDeltas[i];
-					((JavaProject)delta.getElement()).getResolvedClasspath(
-						true, // ignoreUnresolvedEntry
-						true); // generateMarkerOnError
+					JavaProject javaProject = (JavaProject)delta.getElement();
+					javaProject.getResolvedClasspath(
+						true/*ignoreUnresolvedEntry*/, 
+						true/*generateMarkerOnError*/, 
+						false/*don't returnResolutionInProgress*/);
+					
+					try {
+						// touch the project to force it to be recompiled
+						javaProject.getProject().touch(monitor);
+					} catch (CoreException e) {
+						throw new JavaModelException(e);
+					}
 				}		
 				if (this.currentDelta != null) { // if delta has not been fired while creating markers
 					this.fire(this.currentDelta, DEFAULT_CHANGE_EVENT);
@@ -340,12 +384,15 @@
 				// NB: No need to check project's nature as if the project is not a java project:
 				//     - if the project is added or changed this is a noop for projectsBeingDeleted
 				//     - if the project is closed, it has already lost its java nature
+				IProject project = (IProject)resource;
+				JavaProject javaProject = (JavaProject)JavaCore.create(project);
 				switch (delta.getKind()) {
 					case IResourceDelta.ADDED :
+						this.manager.batchContainerInitializations = true;
+					
 						// remember project and its dependents
-						IProject project = (IProject)resource;
-						JavaProject javaProject = (JavaProject)JavaCore.create(project);
 						this.addToRootsToRefreshWithDependents(javaProject);
+						
 						// workaround for bug 15168 circular errors not reported 
 						if (JavaProject.hasJavaNature(project)) {
 							this.addToParentInfo(javaProject);
@@ -354,10 +401,10 @@
 						break;
 						
 					case IResourceDelta.CHANGED : 
-							project = (IProject)resource;
 							if ((delta.getFlags() & IResourceDelta.OPEN) != 0) {
+								this.manager.batchContainerInitializations = true;
+		
 								// project opened or closed: remember  project and its dependents
-								javaProject = (JavaProject)JavaCore.create(project);
 								this.addToRootsToRefreshWithDependents(javaProject);
 								
 								// workaround for bug 15168 circular errors not reported 
@@ -374,12 +421,14 @@
 									this.removeFromParentInfo(javaProject);
 									this.manager.removePerProjectInfo(javaProject);
 								}
+								this.state.rootsAreStale = true;
 							} else if ((delta.getFlags() & IResourceDelta.DESCRIPTION) != 0) {
 								boolean wasJavaProject = this.manager.getJavaModel().findJavaProject(project) != null;
 								boolean isJavaProject = JavaProject.hasJavaNature(project);
 								if (wasJavaProject != isJavaProject) { 
+									this.manager.batchContainerInitializations = true;
+									
 									// java nature added or removed: remember  project and its dependents
-									javaProject = (JavaProject)JavaCore.create(project);
 									this.addToRootsToRefreshWithDependents(javaProject);
 		
 									// workaround for bug 15168 circular errors not reported 
@@ -400,7 +449,7 @@
 								} else {
 									// in case the project was removed then added then changed (see bug 19799)
 									if (isJavaProject) { // need nature check - 18698
-										this.addToParentInfo((JavaProject)JavaCore.create(project));
+										this.addToParentInfo(javaProject);
 										processChildren = true;
 									}
 								}
@@ -408,23 +457,30 @@
 								// workaround for bug 15168 circular errors not reported 
 								// in case the project was removed then added then changed
 								if (JavaProject.hasJavaNature(project)) { // need nature check - 18698
-									this.addToParentInfo((JavaProject)JavaCore.create(project));
+									this.addToParentInfo(javaProject);
 									processChildren = true;
 								}						
 							}		
 							break;
 
 					case IResourceDelta.REMOVED : 
-							// remove classpath cache so that initializeRoots() will not consider the project has a classpath
-							this.manager.removePerProjectInfo((JavaProject)JavaCore.create(resource));
-							this.state.rootsAreStale = true;
-							break;
+						this.manager.batchContainerInitializations = true;
+
+						// remove classpath cache so that initializeRoots() will not consider the project has a classpath
+						this.manager.removePerProjectInfo((JavaProject)JavaCore.create(resource));
+						this.state.rootsAreStale = true;
+						break;
 				}
+				
+				// in all cases, refresh the external jars for this project
+				addForRefresh(javaProject);
+				
 				break;
 			case IResource.FILE :
 				IFile file = (IFile) resource;
 				/* classpath file change */
 				if (file.getName().equals(JavaProject.CLASSPATH_FILENAME)) {
+					this.manager.batchContainerInitializations = true;
 					reconcileClasspathFileUpdate(delta, (JavaProject)JavaCore.create(file.getProject()));
 					this.state.rootsAreStale = true;
 				}
@@ -490,13 +546,26 @@
 	 */
 	private void contentChanged(Openable element) {
 
-		// filter out changes to primary compilation unit in working copy mode
-		if (!isPrimaryWorkingCopy(element, element.getElementType())) {
+		boolean isPrimary = false;
+		boolean isPrimaryWorkingCopy = false;
+		if (element.getElementType() == IJavaElement.COMPILATION_UNIT) {
+			CompilationUnit cu = (CompilationUnit)element;
+			isPrimary = cu.isPrimary();
+			isPrimaryWorkingCopy = isPrimary && cu.isWorkingCopy();
+		}
+		if (isPrimaryWorkingCopy) {
+			// filter out changes to primary compilation unit in working copy mode
+			// just report a change to the resource (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=59500)
+			currentDelta().changed(element, IJavaElementDelta.F_PRIMARY_RESOURCE);
+		} else {
 			close(element);
 			int flags = IJavaElementDelta.F_CONTENT;
 			if (element instanceof JarPackageFragmentRoot){
 				flags |= IJavaElementDelta.F_ARCHIVE_CONTENT_CHANGED;
 			}
+			if (isPrimary) {
+				flags |= IJavaElementDelta.F_PRIMARY_RESOURCE;
+			}
 			currentDelta().changed(element, flags);
 		}
 	}
@@ -525,7 +594,7 @@
 						return this.currentElement;
 					}
 					if  (rootInfo != null && rootInfo.project.getProject().equals(resource)){
-						element = (Openable)rootInfo.project;
+						element = rootInfo.project;
 						break;
 					}
 					IProject proj = (IProject)resource;
@@ -539,26 +608,37 @@
 				}
 				break;
 			case IJavaElement.PACKAGE_FRAGMENT_ROOT:
-				element = rootInfo == null ? JavaCore.create(resource) : rootInfo.project.getPackageFragmentRoot(resource);
+				element = rootInfo == null ? JavaCore.create(resource) : rootInfo.getPackageFragmentRoot(resource);
 				break;
 			case IJavaElement.PACKAGE_FRAGMENT:
-				// find the element that encloses the resource
-				this.popUntilPrefixOf(path);
-				
-				if (this.currentElement == null) {
-					element = rootInfo == null ? JavaCore.create(resource) : JavaModelManager.create(resource, rootInfo.project);
-				} else {
-					// find the root
-					IPackageFragmentRoot root = this.currentElement.getPackageFragmentRoot();
-					if (root == null) {
-						element =  rootInfo == null ? JavaCore.create(resource) : JavaModelManager.create(resource, rootInfo.project);
-					} else if (((JavaProject)root.getJavaProject()).contains(resource)) {
+				if (rootInfo != null) {
+					if (rootInfo.project.contains(resource)) {
+						IPackageFragmentRoot root = rootInfo.getPackageFragmentRoot(null);
 						// create package handle
-						IPath pkgPath = path.removeFirstSegments(root.getPath().segmentCount());
+						IPath pkgPath = path.removeFirstSegments(rootInfo.rootPath.segmentCount());
 						String pkg = Util.packageName(pkgPath);
 						if (pkg == null) return null;
 						element = root.getPackageFragment(pkg);
 					}
+				} else {
+					// find the element that encloses the resource
+					this.popUntilPrefixOf(path);
+				
+					if (this.currentElement == null) {
+						element = JavaCore.create(resource);
+					} else {
+						// find the root
+						IPackageFragmentRoot root = this.currentElement.getPackageFragmentRoot();
+						if (root == null) {
+							element =  JavaCore.create(resource);
+						} else if (((JavaProject)root.getJavaProject()).contains(resource)) {
+							// create package handle
+							IPath pkgPath = path.removeFirstSegments(root.getPath().segmentCount());
+							String pkg = Util.packageName(pkgPath);
+							if (pkg == null) return null;
+							element = root.getPackageFragment(pkg);
+						}
+					}
 				}
 				break;
 			case IJavaElement.COMPILATION_UNIT:
@@ -610,12 +690,9 @@
 				}
 				break;
 		}
-		if (element == null) {
-			return null;
-		} else {
-			this.currentElement = (Openable)element;
-			return this.currentElement;
-		}
+		if (element == null) return null;
+		this.currentElement = (Openable)element;
+		return this.currentElement;
 	}
 	/*
 	 * Check if external archives have changed and create the corresponding deltas.
@@ -630,63 +707,60 @@
 		
 		// find JARs to refresh
 		HashSet archivePathsToRefresh = new HashSet();
-		try {
-			Iterator iterator = this.refreshedElements.iterator();
-			while (iterator.hasNext()) {
-				IJavaElement element = (IJavaElement)iterator.next();
-				switch(element.getElementType()){
-					case IJavaElement.PACKAGE_FRAGMENT_ROOT :
-						archivePathsToRefresh.add(element.getPath());
+		Iterator iterator = this.refreshedElements.iterator();
+		this.refreshedElements = null; // null out early to avoid concurrent modification exception (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=63534)
+		while (iterator.hasNext()) {
+			IJavaElement element = (IJavaElement)iterator.next();
+			switch(element.getElementType()){
+				case IJavaElement.PACKAGE_FRAGMENT_ROOT :
+					archivePathsToRefresh.add(element.getPath());
+					break;
+				case IJavaElement.JAVA_PROJECT :
+					JavaProject project = (JavaProject) element;
+					if (!JavaProject.hasJavaNature(project.getProject())) {
+						// project is not accessible or has lost its Java nature
 						break;
-					case IJavaElement.JAVA_PROJECT :
-						IJavaProject project = (IJavaProject) element;
+					}
+					IClasspathEntry[] classpath;
+					try {
+						classpath = project.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
+						for (int j = 0, cpLength = classpath.length; j < cpLength; j++){
+							if (classpath[j].getEntryKind() == IClasspathEntry.CPE_LIBRARY){
+								archivePathsToRefresh.add(classpath[j].getPath());
+							}
+						}
+					} catch (JavaModelException e) {
+						// project doesn't exist -> ignore
+					}
+					break;
+				case IJavaElement.JAVA_MODEL :
+					IJavaProject[] projects;
+					try {
+						projects = this.manager.getJavaModel().getOldJavaProjectsList();
+					} catch (JavaModelException e1) {
+						// cannot retrieve old projects list -> ignore
+						continue;
+					}
+					for (int j = 0, projectsLength = projects.length; j < projectsLength; j++){
+						project = (JavaProject) projects[j];
 						if (!JavaProject.hasJavaNature(project.getProject())) {
 							// project is not accessible or has lost its Java nature
-							break;
-						}
-						IClasspathEntry[] classpath;
-						try {
-							classpath = project.getResolvedClasspath(true);
-							for (int j = 0, cpLength = classpath.length; j < cpLength; j++){
-								if (classpath[j].getEntryKind() == IClasspathEntry.CPE_LIBRARY){
-									archivePathsToRefresh.add(classpath[j].getPath());
-								}
-							}
-						} catch (JavaModelException e) {
-							// project doesn't exist -> ignore
-						}
-						break;
-					case IJavaElement.JAVA_MODEL :
-						IJavaProject[] projects;
-						try {
-							projects = this.manager.getJavaModel().getOldJavaProjectsList();
-						} catch (JavaModelException e1) {
-							// cannot retrieve old projects list -> ignore
 							continue;
 						}
-						for (int j = 0, projectsLength = projects.length; j < projectsLength; j++){
-							project = projects[j];
-							if (!JavaProject.hasJavaNature(project.getProject())) {
-								// project is not accessible or has lost its Java nature
-								continue;
-							}
-							try {
-								classpath = project.getResolvedClasspath(true);
-							} catch (JavaModelException e2) {
-								// project doesn't exist -> ignore
-								continue;
-							}
-							for (int k = 0, cpLength = classpath.length; k < cpLength; k++){
-								if (classpath[k].getEntryKind() == IClasspathEntry.CPE_LIBRARY){
-									archivePathsToRefresh.add(classpath[k].getPath());
-								}
+						try {
+							classpath = project.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
+						} catch (JavaModelException e2) {
+							// project doesn't exist -> ignore
+							continue;
+						}
+						for (int k = 0, cpLength = classpath.length; k < cpLength; k++){
+							if (classpath[k].getEntryKind() == IClasspathEntry.CPE_LIBRARY){
+								archivePathsToRefresh.add(classpath[k].getPath());
 							}
 						}
-						break;
-				}
+					}
+					break;
 			}
-		} finally {
-			this.refreshedElements = null;
 		}
 		
 		// perform refresh
@@ -702,14 +776,14 @@
 			
 			if (monitor != null && monitor.isCanceled()) break; 
 			
-			IJavaProject project = projects[i];
+			JavaProject project = (JavaProject) projects[i];
 			if (!JavaProject.hasJavaNature(project.getProject())) {
 				// project is not accessible or has lost its Java nature
 				continue;
 			}
 			IClasspathEntry[] entries;
 			try {
-				entries = project.getResolvedClasspath(true);
+				entries = project.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
 			} catch (JavaModelException e1) {
 				// project does not exist -> ignore
 				continue;
@@ -835,7 +909,7 @@
 				this.removedRoots.put(
 					javaProject, 
 					javaProject.computePackageFragmentRoots(
-						javaProject.getResolvedClasspath(true), 
+						javaProject.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/), 
 						false));
 			}
 			
@@ -877,14 +951,18 @@
 				}
 				this.state.updateRoots(element.getPath(), delta, this);
 				
-				// refresh pkg fragment roots and namelookup of the project (and its dependents)
+				// refresh pkg fragment roots and caches of the project (and its dependents)
 				this.rootsToRefresh.add(element);
-				this.namelookupsToRefresh.add(element);
+				this.projectCachesToReset.add(element);
 			}
 		} else {			
 			if (delta == null || (delta.getFlags() & IResourceDelta.MOVED_FROM) == 0) {
 				// regular element addition
-				if (!isPrimaryWorkingCopy(element, elementType)) { // filter out changes to primary compilation unit in working copy mode
+				if (isPrimaryWorkingCopy(element, elementType) ) {
+					// filter out changes to primary compilation unit in working copy mode
+					// just report a change to the resource (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=59500)
+					currentDelta().changed(element, IJavaElementDelta.F_PRIMARY_RESOURCE);
+				} else {
 					addToParentInfo(element);
 					
 					// Force the element to be closed as it might have been opened 
@@ -944,15 +1022,15 @@
 					// when a root is added, and is on the classpath, the project must be updated
 					JavaProject project = (JavaProject) element.getJavaProject();
 
-					// refresh pkg fragment roots and namelookup of the project (and its dependents)
+					// refresh pkg fragment roots and caches of the project (and its dependents)
 					this.rootsToRefresh.add(project);
-					this.namelookupsToRefresh.add(project);
+					this.projectCachesToReset.add(project);
 					
 					break;
 				case IJavaElement.PACKAGE_FRAGMENT :
-					//refresh namelookup since it holds onto obsolete cached info 
+					// reset project's package fragment cache 
 					project = (JavaProject) element.getJavaProject();
-					this.namelookupsToRefresh.add(project);						
+					this.projectCachesToReset.add(project);						
 
 					// add subpackages
 					if (delta != null){
@@ -993,7 +1071,11 @@
 		int elementType = element.getElementType();
 		if (delta == null || (delta.getFlags() & IResourceDelta.MOVED_TO) == 0) {
 			// regular element removal
-			if (!isPrimaryWorkingCopy(element, elementType)) { // filter out changes to primary compilation unit in working copy mode
+			if (isPrimaryWorkingCopy(element, elementType) ) {
+				// filter out changes to primary compilation unit in working copy mode
+				// just report a change to the resource (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=59500)
+				currentDelta().changed(element, IJavaElementDelta.F_PRIMARY_RESOURCE);
+			} else {
 				close(element);
 				removeFromParentInfo(element);
 				currentDelta().removed(element);
@@ -1051,23 +1133,23 @@
 			case IJavaElement.JAVA_PROJECT :
 				this.state.updateRoots(element.getPath(), delta, this);
 
-				// refresh pkg fragment roots and namelookup of the project (and its dependents)
+				// refresh pkg fragment roots and caches of the project (and its dependents)
 				this.rootsToRefresh.add(element);
-				this.namelookupsToRefresh.add(element);
+				this.projectCachesToReset.add(element);
 
 				break;
 			case IJavaElement.PACKAGE_FRAGMENT_ROOT :
 				JavaProject project = (JavaProject) element.getJavaProject();
 
-				// refresh pkg fragment roots and namelookup of the project (and its dependents)
+				// refresh pkg fragment roots and caches of the project (and its dependents)
 				this.rootsToRefresh.add(project);
-				this.namelookupsToRefresh.add(project);				
+				this.projectCachesToReset.add(project);				
 
 				break;
 			case IJavaElement.PACKAGE_FRAGMENT :
-				//refresh namelookup since it holds onto obsolete cached info 
+				// reset package fragment cache
 				project = (JavaProject) element.getJavaProject();
-				this.namelookupsToRefresh.add(project);
+				this.projectCachesToReset.add(project);
 
 				// remove subpackages
 				if (delta != null){
@@ -1103,6 +1185,7 @@
 			case IJavaElement.JAVA_MODEL:
 				// case of a movedTo or movedFrom project (other cases are handled in processResourceDelta(...)
 				return IJavaElement.JAVA_PROJECT;
+			
 			case NON_JAVA_RESOURCE:
 			case IJavaElement.JAVA_PROJECT:
 				if (rootInfo == null) {
@@ -1110,36 +1193,40 @@
 				}
 				if (rootInfo != null && rootInfo.isRootOfProject(res.getFullPath())) {
 					return IJavaElement.PACKAGE_FRAGMENT_ROOT;
-				} else {
-					return NON_JAVA_RESOURCE; // not yet in a package fragment root or root of another project
-				}
+				} 
+				// not yet in a package fragment root or root of another project
+				// or package fragment to be included (see below)
+				// -> let it go through
+
 			case IJavaElement.PACKAGE_FRAGMENT_ROOT:
 			case IJavaElement.PACKAGE_FRAGMENT:
 				if (rootInfo == null) {
 					rootInfo = this.enclosingRootInfo(res.getFullPath(), kind);
 				}
-				if (rootInfo == null || Util.isExcluded(res, rootInfo.exclusionPatterns)) {
+				if (rootInfo == null) {
 					return NON_JAVA_RESOURCE;
 				}
-				if (res instanceof IFolder) {
+				if (Util.isExcluded(res, rootInfo.inclusionPatterns, rootInfo.exclusionPatterns)) {
+					return NON_JAVA_RESOURCE;
+				}
+				if (res.getType() == IResource.FOLDER) {
 					if (Util.isValidFolderNameForPackage(res.getName())) {
 						return IJavaElement.PACKAGE_FRAGMENT;
-					} else {
-						return NON_JAVA_RESOURCE;
 					}
-				} else {
-					String fileName = res.getName();
-					if (Util.isValidCompilationUnitName(fileName)) {
-						return IJavaElement.COMPILATION_UNIT;
-					} else if (Util.isValidClassFileName(fileName)) {
-						return IJavaElement.CLASS_FILE;
-					} else if (this.rootInfo(res.getFullPath(), kind) != null) {
-						// case of proj=src=bin and resource is a jar file on the classpath
-						return IJavaElement.PACKAGE_FRAGMENT_ROOT;
-					} else {
-						return NON_JAVA_RESOURCE;
-					}
+					return NON_JAVA_RESOURCE;
 				}
+				String fileName = res.getName();
+				if (Util.isValidCompilationUnitName(fileName)) {
+					return IJavaElement.COMPILATION_UNIT;
+				} else if (Util.isValidClassFileName(fileName)) {
+					return IJavaElement.CLASS_FILE;
+				} else if (this.rootInfo(res.getFullPath(), kind) != null) {
+					// case of proj=src=bin and resource is a jar file on the classpath
+					return IJavaElement.PACKAGE_FRAGMENT_ROOT;
+				} else {
+					return NON_JAVA_RESOURCE;
+				}
+				
 			default:
 				return NON_JAVA_RESOURCE;
 		}
@@ -1169,7 +1256,7 @@
 	public void fire(IJavaElementDelta customDelta, int eventType) {
 		if (!this.isFiring) return;
 		
-		if (VERBOSE && eventType == DEFAULT_CHANGE_EVENT) {
+		if (DEBUG) {
 			System.out.println("-----------------------------------------------------------------------------------------------------------------------");//$NON-NLS-1$
 		}
 
@@ -1216,7 +1303,7 @@
 		int listenerCount) {
 			
 		// post change deltas
-		if (VERBOSE){
+		if (DEBUG){
 			System.out.println("FIRING POST_CHANGE Delta ["+Thread.currentThread()+"]:"); //$NON-NLS-1$//$NON-NLS-2$
 			System.out.println(deltaToNotify == null ? "<NONE>" : deltaToNotify.toString()); //$NON-NLS-1$
 		}
@@ -1234,7 +1321,7 @@
 
 
 		IJavaElementDelta deltaToNotify = mergeDeltas(this.reconcileDeltas.values());
-		if (VERBOSE){
+		if (DEBUG){
 			System.out.println("FIRING POST_RECONCILE Delta ["+Thread.currentThread()+"]:"); //$NON-NLS-1$//$NON-NLS-2$
 			System.out.println(deltaToNotify == null ? "<NONE>" : deltaToNotify.toString()); //$NON-NLS-1$
 		}
@@ -1306,14 +1393,13 @@
 						// case of bin=src
 						if (info.traverseModes[i] == SOURCE && elementType == IJavaElement.CLASS_FILE) {
 							return true;
-						} else {
-							// case of .class file under project and no source folder
-							// proj=bin
-							if (elementType == IJavaElement.JAVA_PROJECT 
-									&& res instanceof IFile 
-									&& Util.isValidClassFileName(res.getName())) {
-								return true;
-							}
+						}
+						// case of .class file under project and no source folder
+						// proj=bin
+						if (elementType == IJavaElement.JAVA_PROJECT 
+								&& res instanceof IFile 
+								&& Util.isValidClassFileName(res.getName())) {
+							return true;
 						}
 					} else {
 						return true;
@@ -1362,12 +1448,8 @@
 				insertedTree = true;
 			}
 		}
-		if (insertedTree) {
-			return rootDelta;
-		}
-		else {
-			return null;
-		}
+		if (insertedTree) return rootDelta;
+		return null;
 	}	
 	private void notifyListeners(IJavaElementDelta deltaToNotify, int eventType, IElementChangedListener[] listeners, int[] listenerMask, int listenerCount) {
 		final ElementChangedEvent extraEvent = new ElementChangedEvent(deltaToNotify, eventType);
@@ -1453,10 +1535,11 @@
 			}
 		}
 
-		JavaElementDelta elementDelta = currentDelta().find(element);
+		JavaElementDelta current = currentDelta();
+		JavaElementDelta elementDelta = current.find(element);
 		if (elementDelta == null) {
-			currentDelta().changed(element, IJavaElementDelta.F_CONTENT);
-			elementDelta = currentDelta().find(element);
+			// don't use find after creating the delta as it can be null (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=63434)
+			elementDelta = current.changed(element, IJavaElementDelta.F_CONTENT);
 		}
 		elementDelta.addResourceDelta(delta);
 	}
@@ -1466,49 +1549,48 @@
 	private ArrayList otherRootsInfo(IPath path, int kind) {
 		if (kind == IResourceDelta.REMOVED) {
 			return (ArrayList)this.state.oldOtherRoots.get(path);
-		} else {
-			return (ArrayList)this.state.otherRoots.get(path);
 		}
+		return (ArrayList)this.state.otherRoots.get(path);
 	}	
+	
 	private OutputsInfo outputsInfo(RootInfo rootInfo, IResource res) {
 		try {
-			IJavaProject proj =
+			JavaProject proj =
 				rootInfo == null ?
-					(IJavaProject)this.createElement(res.getProject(), IJavaElement.JAVA_PROJECT, null) :
+					(JavaProject)this.createElement(res.getProject(), IJavaElement.JAVA_PROJECT, null) :
 					rootInfo.project;
 			if (proj != null) {
 				IPath projectOutput = proj.getOutputLocation();
 				int traverseMode = IGNORE;
 				if (proj.getProject().getFullPath().equals(projectOutput)){ // case of proj==bin==src
 					return new OutputsInfo(new IPath[] {projectOutput}, new int[] {SOURCE}, 1);
-				} else {
-					IClasspathEntry[] classpath = proj.getResolvedClasspath(true);
-					IPath[] outputs = new IPath[classpath.length+1];
-					int[] traverseModes = new int[classpath.length+1];
-					int outputCount = 1;
-					outputs[0] = projectOutput;
-					traverseModes[0] = traverseMode;
-					for (int i = 0, length = classpath.length; i < length; i++) {
-						IClasspathEntry entry = classpath[i];
-						IPath entryPath = entry.getPath();
-						IPath output = entry.getOutputLocation();
-						if (output != null) {
-							outputs[outputCount] = output;
-							// check case of src==bin
-							if (entryPath.equals(output)) {
-								traverseModes[outputCount++] = (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) ? SOURCE : BINARY;
-							} else {
-								traverseModes[outputCount++] = IGNORE;
-							}
-						}
-						
+				} 
+				IClasspathEntry[] classpath = proj.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
+				IPath[] outputs = new IPath[classpath.length+1];
+				int[] traverseModes = new int[classpath.length+1];
+				int outputCount = 1;
+				outputs[0] = projectOutput;
+				traverseModes[0] = traverseMode;
+				for (int i = 0, length = classpath.length; i < length; i++) {
+					IClasspathEntry entry = classpath[i];
+					IPath entryPath = entry.getPath();
+					IPath output = entry.getOutputLocation();
+					if (output != null) {
+						outputs[outputCount] = output;
 						// check case of src==bin
-						if (entryPath.equals(projectOutput)) {
-							traverseModes[0] = (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) ? SOURCE : BINARY;
+						if (entryPath.equals(output)) {
+							traverseModes[outputCount++] = (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) ? SOURCE : BINARY;
+						} else {
+							traverseModes[outputCount++] = IGNORE;
 						}
 					}
-					return new OutputsInfo(outputs, traverseModes, outputCount);
+					
+					// check case of src==bin
+					if (entryPath.equals(projectOutput)) {
+						traverseModes[0] = (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) ? SOURCE : BINARY;
+					}
 				}
+				return new OutputsInfo(outputs, traverseModes, outputCount);
 			}
 		} catch (JavaModelException e) {
 			// java project doesn't exist: ignore
@@ -1601,13 +1683,13 @@
 
 			}
 			refreshPackageFragmentRoots();
-			refreshNamelookups();
+			resetProjectCaches();
 
 			return this.currentDelta;
 		} finally {
 			this.currentDelta = null;
 			this.rootsToRefresh.clear();
-			this.namelookupsToRefresh.clear();
+			this.projectCachesToReset.clear();
 		}
 	}
 	/*
@@ -1709,23 +1791,22 @@
 		}
 	}
 	/*
-	 * Traverse the set of projects which have changed namespace, and refresh their 
-	 * name lookups and their dependents
+	 * Traverse the set of projects which have changed namespace, and reset their 
+	 * caches and their dependents
 	 */
-	private void refreshNamelookups() {
-		Iterator iterator;
-		// update namelookup of dependent projects
-		iterator = this.namelookupsToRefresh.iterator();
+	private void resetProjectCaches() {
+		Iterator iterator = this.projectCachesToReset.iterator();
 		HashSet affectedDependents = new HashSet();
 		while (iterator.hasNext()) {
 			JavaProject project = (JavaProject)iterator.next();
-			project.resetNameLookup();
+			project.resetCaches();
 			addDependentProjects(project.getPath(), affectedDependents);
 		}
+		// reset caches of dependent projects
 		iterator = affectedDependents.iterator();
 		while (iterator.hasNext()) {
 			JavaProject project = (JavaProject) iterator.next();
-			project.resetNameLookup();
+			project.resetCaches();
 		}
 	}
 	/* 
@@ -1773,10 +1854,11 @@
 	public void resourceChanged(IResourceChangeEvent event) {
 	
 		if (event.getSource() instanceof IWorkspace) {
+			int eventType = this.overridenEventType == -1 ? event.getType() : this.overridenEventType;
 			IResource resource = event.getResource();
 			IResourceDelta delta = event.getDelta();
 			
-			switch(event.getType()){
+			switch(eventType){
 				case IResourceChangeEvent.PRE_DELETE :
 					try {
 						if(resource.getType() == IResource.PROJECT 
@@ -1789,19 +1871,6 @@
 					}
 					return;
 					
-				case IResourceChangeEvent.PRE_AUTO_BUILD :
-					// this.processPostChange = false;
-					if(isAffectedBy(delta)) { // avoid populating for SYNC or MARKER deltas
-						updateClasspathMarkers(delta);
-						JavaBuilder.buildStarting();
-					}
-					// does not fire any deltas
-					break;
-
-				case IResourceChangeEvent.POST_AUTO_BUILD :
-					JavaBuilder.buildFinished();
-					break;
-					
 				case IResourceChangeEvent.POST_CHANGE :
 					if (isAffectedBy(delta)) { // avoid populating for SYNC or MARKER deltas
 						try {
@@ -1826,6 +1895,30 @@
 							this.removedRoots = null;
 						}
 					}
+					return;
+					
+				case IResourceChangeEvent.PRE_BUILD :
+				    DeltaProcessingState.ProjectUpdateInfo[] updates = this.state.removeAllProjectUpdates();
+					if (updates != null) {
+					    for (int i = 0, length = updates.length; i < length; i++) {
+					        try {
+						        updates[i].updateProjectReferencesIfNecessary();
+					        } catch(JavaModelException e) {
+					            // do nothing
+					        }
+					    }
+					}
+					// this.processPostChange = false;
+					if(isAffectedBy(delta)) { // avoid populating for SYNC or MARKER deltas
+						updateClasspathMarkers(delta);
+						JavaBuilder.buildStarting();
+					}
+					// does not fire any deltas
+					return;
+
+				case IResourceChangeEvent.POST_BUILD :
+					JavaBuilder.buildFinished();
+					return;
 			}
 		}
 	}
@@ -1835,9 +1928,8 @@
 	private RootInfo rootInfo(IPath path, int kind) {
 		if (kind == IResourceDelta.REMOVED) {
 			return (RootInfo)this.state.oldRoots.get(path);
-		} else {
-			return (RootInfo)this.state.roots.get(path);
 		}
+		return (RootInfo)this.state.roots.get(path);
 	}
 	/*
 	 * Turns the firing mode to on. That is, deltas that are/have been
@@ -1867,7 +1959,7 @@
 	
 		// set stack of elements
 		if (this.currentElement == null && rootInfo != null) {
-			this.currentElement = (Openable)rootInfo.project;
+			this.currentElement = rootInfo.project;
 		}
 		
 		// process current delta
@@ -1940,13 +2032,13 @@
 								if (this.currentElement == null
 										|| !rootInfo.project.equals(this.currentElement.getJavaProject())) { // note if currentElement is the IJavaModel, getJavaProject() is null
 									// force the currentProject to be used
-									this.currentElement = (Openable)rootInfo.project;
+									this.currentElement = rootInfo.project;
 								}
 								if (elementType == IJavaElement.JAVA_PROJECT
 									|| (elementType == IJavaElement.PACKAGE_FRAGMENT_ROOT 
 										&& res instanceof IProject)) { 
 									// NB: attach non-java resource to project (not to its package fragment root)
-									parent = (Openable)rootInfo.project;
+									parent = rootInfo.project;
 								} else {
 									parent = this.createElement(res, elementType, rootInfo);
 								}
@@ -2022,7 +2114,7 @@
 	private void updateClasspathMarkers(IResourceDelta delta, HashSet affectedProjects, Map preferredClasspaths, Map preferredOutputs) {
 		IResource resource = delta.getResource();
 		boolean processChildren = false;
-		
+
 		switch (resource.getType()) {
 	
 			case IResource.ROOT :
@@ -2049,11 +2141,12 @@
 								javaProject.updateClasspathMarkers(preferredClasspaths, preferredOutputs); // in case .classpath got modified while closed
 							}
 						} else if ((delta.getFlags() & IResourceDelta.DESCRIPTION) != 0) {
-							if (!JavaProject.hasJavaNature(project)) {
+							boolean wasJavaProject = this.manager.getJavaModel().findJavaProject(project) != null;
+							if (wasJavaProject && !isJavaProject) {
 								// project no longer has Java nature, discard Java related obsolete markers
-								JavaProject javaProject = (JavaProject)JavaCore.create(project);
 								affectedProjects.add(project.getFullPath());
 								// flush classpath markers
+								JavaProject javaProject = (JavaProject)JavaCore.create(project);
 								javaProject.
 									flushClasspathProblemMarkers(
 										true, // flush cycle markers
@@ -2063,6 +2156,14 @@
 								// remove problems and tasks created  by the builder
 								JavaBuilder.removeProblemsAndTasksFor(project);
 							}
+						} else if (isJavaProject) {
+							// check if all entries exist
+							try {
+								JavaProject javaProject = (JavaProject)JavaCore.create(project);
+								javaProject.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, 	true/*generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
+							} catch (JavaModelException e) {
+								// project doesn't exist: ignore
+							}
 						}
 						break;
 					case IResourceDelta.REMOVED:
@@ -2095,7 +2196,7 @@
 	}
 
 	/*
-	 * Update the classpath markers and cycle markers for the projects to update.
+	 * Update the .classpath format, missing entries and cycle markers for the projects affected by the given delta.
 	 */
 	private void updateClasspathMarkers(IResourceDelta delta) {
 		
@@ -2103,46 +2204,48 @@
 		Map preferredOutputs = new HashMap(5);
 		HashSet affectedProjects = new HashSet(5);
 		
-		// read .classpath files that have changed, and create markers if format is wrong
+		// read .classpath files that have changed, and create markers if format is wrong or if an entry cannot be found
+		JavaModel.flushExternalFileCache();
 		updateClasspathMarkers(delta, affectedProjects, preferredClasspaths, preferredOutputs); 
 	
+		// update .classpath format markers for affected projects (dependent projects 
+		// or projects that reference a library in one of the projects that have changed)
 		if (!affectedProjects.isEmpty()) {
 			try {
-				if (!ResourcesPlugin.getWorkspace().isAutoBuilding()) {
-					IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
-					IProject[] projects = workspaceRoot.getProjects();
-					int length = projects.length;
-					for (int i = 0; i < length; i++){
-						IProject project = projects[i];
-						JavaProject javaProject = (JavaProject)JavaCore.create(project);
-						if (preferredClasspaths.get(javaProject) == null) { // not already updated
-							try {
-								IPath projectPath = project.getFullPath();
-								IClasspathEntry[] classpath = javaProject.getResolvedClasspath(true); // allowed to reuse model cache
-								for (int j = 0, cpLength = classpath.length; j < cpLength; j++) {
-									IClasspathEntry entry = classpath[j];
-									switch (entry.getEntryKind()) {
-										case IClasspathEntry.CPE_PROJECT:
-											if (affectedProjects.contains(entry.getPath())) {
-												javaProject.updateClasspathMarkers(null, null);
-											}
-											break;
-										case IClasspathEntry.CPE_LIBRARY:
-											IPath entryPath = entry.getPath();
-											IPath libProjectPath = entryPath.removeLastSegments(entryPath.segmentCount()-1);
-											if (!libProjectPath.equals(projectPath) // if library contained in another project
-													&& affectedProjects.contains(libProjectPath)) {
-												javaProject.updateClasspathMarkers(null, null);
-											}
-											break;
-									}
+				IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
+				IProject[] projects = workspaceRoot.getProjects();
+				int length = projects.length;
+				for (int i = 0; i < length; i++){
+					IProject project = projects[i];
+					JavaProject javaProject = (JavaProject)JavaCore.create(project);
+					if (preferredClasspaths.get(javaProject) == null) { // not already updated
+						try {
+							IPath projectPath = project.getFullPath();
+							IClasspathEntry[] classpath = javaProject.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/); // allowed to reuse model cache
+							for (int j = 0, cpLength = classpath.length; j < cpLength; j++) {
+								IClasspathEntry entry = classpath[j];
+								switch (entry.getEntryKind()) {
+									case IClasspathEntry.CPE_PROJECT:
+										if (affectedProjects.contains(entry.getPath())) {
+											javaProject.updateClasspathMarkers(null, null);
+										}
+										break;
+									case IClasspathEntry.CPE_LIBRARY:
+										IPath entryPath = entry.getPath();
+										IPath libProjectPath = entryPath.removeLastSegments(entryPath.segmentCount()-1);
+										if (!libProjectPath.equals(projectPath) // if library contained in another project
+												&& affectedProjects.contains(libProjectPath)) {
+											javaProject.updateClasspathMarkers(null, null);
+										}
+										break;
 								}
-							} catch(JavaModelException e) {
-									// project no longer exists
 							}
+						} catch(JavaModelException e) {
+								// project no longer exists
 						}
 					}
 				}
+
 				// update all cycle markers
 				JavaProject.updateAllCycleMarkers(preferredClasspaths);
 			} catch(JavaModelException e) {
@@ -2165,7 +2268,7 @@
 				if (element == null) {
 					// resource might be containing shared roots (see bug 19058)
 					this.state.updateRoots(deltaRes.getFullPath(), delta, this);
-					return false;
+					return rootInfo != null && rootInfo.inclusionPatterns != null;
 				}
 				updateIndex(element, delta);
 				elementAdded(element, delta, rootInfo);
@@ -2176,7 +2279,7 @@
 				if (element == null) {
 					// resource might be containing shared roots (see bug 19058)
 					this.state.updateRoots(deltaRes.getFullPath(), delta, this);
-					return false;
+					return rootInfo != null && rootInfo.inclusionPatterns != null;
 				}
 				updateIndex(element, delta);
 				elementRemoved(element, delta, rootInfo);
@@ -2290,13 +2393,12 @@
 							break;
 					}
 					break;
-				} else {
-					int kind = delta.getKind();
-					if (kind == IResourceDelta.ADDED || kind == IResourceDelta.REMOVED) {
-						IPackageFragmentRoot root = (IPackageFragmentRoot)element;
-						this.updateRootIndex(root, root.getPackageFragment(""), delta); //$NON-NLS-1$
-						break;
-					}
+				}
+				int kind = delta.getKind();
+				if (kind == IResourceDelta.ADDED || kind == IResourceDelta.REMOVED) {
+					IPackageFragmentRoot root = (IPackageFragmentRoot)element;
+					this.updateRootIndex(root, root.getPackageFragment(""), delta); //$NON-NLS-1$
+					break;
 				}
 				// don't break as packages of the package fragment root can be indexed below
 			case IJavaElement.PACKAGE_FRAGMENT :
@@ -2368,10 +2470,10 @@
 						if ((delta.getFlags() & IResourceDelta.CONTENT) == 0)
 							break;
 					case IResourceDelta.ADDED :
-						indexManager.addSource(file, file.getProject().getProject().getFullPath());
+						indexManager.addSource(file, file.getProject().getFullPath());
 						break;
 					case IResourceDelta.REMOVED :
-						indexManager.remove(file.getFullPath().toString(), file.getProject().getProject().getFullPath());
+						indexManager.remove(file.getFullPath().toString(), file.getProject().getFullPath());
 						break;
 				}
 		}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DiscardWorkingCopyOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DiscardWorkingCopyOperation.java
index e38a97d..37a2a9a 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DiscardWorkingCopyOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DiscardWorkingCopyOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ElementCache.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ElementCache.java
index 8e46fd8..55a8059 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ElementCache.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ElementCache.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IJavaElementRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IJavaElementRequestor.java
index 66c6717..f334805 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IJavaElementRequestor.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IJavaElementRequestor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/INamingRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/INamingRequestor.java
index d97b126..e7479e1 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/INamingRequestor.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/INamingRequestor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IPathRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IPathRequestor.java
index 1eaab30..ce90eed 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IPathRequestor.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/IPathRequestor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ImportContainer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ImportContainer.java
index 3560647..4f3c774 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ImportContainer.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ImportContainer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -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/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ImportDeclaration.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ImportDeclaration.java
index ac604dc..99a2bb0 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ImportDeclaration.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ImportDeclaration.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -13,7 +13,7 @@
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.IImportDeclaration;
 import org.eclipse.jdt.core.JavaModelException;
-import org.eclipse.jdt.core.jdom.IDOMNode;
+import org.eclipse.jdt.core.jdom.*;
 
 /**
  * Handle for an import declaration. Info object is a ImportDeclarationElementInfo.
@@ -36,7 +36,9 @@
 }
 /**
  * @see JavaElement#equalsDOMNode
+ * @deprecated JDOM is obsolete
  */
+// TODO - JDOM - remove once model ported off of JDOM
 protected boolean equalsDOMNode(IDOMNode node) {
 	return (node.getNodeType() == IDOMNode.IMPORT) && getElementName().equals(node.getName());
 }
@@ -46,7 +48,7 @@
 public int getElementType() {
 	return IMPORT_DECLARATION;
 }
-/* (non-Javadoc)
+/**
  * @see org.eclipse.jdt.core.IImportDeclaration#getFlags()
  */
 public int getFlags() throws JavaModelException {
@@ -59,7 +61,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);
@@ -100,7 +102,7 @@
 protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
 	buffer.append(this.tabString(tab));
 	buffer.append("import "); //$NON-NLS-1$
-	buffer.append(getElementName());
+	toStringName(buffer);
 	if (info == null) {
 		buffer.append(" (not open)"); //$NON-NLS-1$
 	}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ImportDeclarationElementInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ImportDeclarationElementInfo.java
index be3b883..8c48710 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ImportDeclarationElementInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ImportDeclarationElementInfo.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -14,7 +14,7 @@
 
 /**
  * Element info for IImportDeclaration elements.
- * @see IImportDeclaration
+ * @see org.eclipse.jdt.core.IImportDeclaration
  */
 public class ImportDeclarationElementInfo extends MemberElementInfo implements ISourceImport{
 	
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Initializer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Initializer.java
index 61aeee9..d8254ea 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Initializer.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Initializer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -18,7 +18,7 @@
 import org.eclipse.jdt.core.ISourceRange;
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.JavaModelException;
-import org.eclipse.jdt.core.jdom.IDOMNode;
+import org.eclipse.jdt.core.jdom.*;
 import org.eclipse.jdt.internal.core.util.Util;
 
 /**
@@ -40,7 +40,9 @@
 }
 /**
  * @see JavaElement#equalsDOMNode
+ * @deprecated JDOM is obsolete
  */
+// TODO - JDOM - remove once model ported off of JDOM
 protected boolean equalsDOMNode(IDOMNode node) {
 	if (node.getNodeType() == IDOMNode.INITIALIZER) {
 		try {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/InitializerElementInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/InitializerElementInfo.java
index bb05101..a9be5d6 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/InitializerElementInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/InitializerElementInfo.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/InternalNamingConventions.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/InternalNamingConventions.java
index 47c5a7b..79feb1f 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/InternalNamingConventions.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/InternalNamingConventions.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -33,7 +33,8 @@
 				false /*nls*/, 
 				compilerOptions.sourceLevel /*sourceLevel*/, 
 				null /*taskTags*/, 
-				null/*taskPriorities*/);
+				null/*taskPriorities*/,
+				true/*taskCaseSensitive*/);
 	}
 	public static void suggestArgumentNames(IJavaProject javaProject, char[] packageName, char[] qualifiedTypeName, int dim, char[][] excludedNames, INamingRequestor requestor) {
 		Map options = javaProject.getOptions(true);
@@ -150,9 +151,11 @@
 			if(dim > 0) {
 				int length = tempName.length;
 				if (tempName[length-1] == 's'){
-					System.arraycopy(tempName, 0, tempName = new char[length + 2], 0, length);
-					tempName[length] = 'e';
-					tempName[length+1] = 's';
+					if(tempName.length > 1 && tempName[length-2] == 's') {
+						System.arraycopy(tempName, 0, tempName = new char[length + 2], 0, length);
+						tempName[length] = 'e';
+						tempName[length+1] = 's';
+					}
 				} else if(tempName[length-1] == 'y') {
 					System.arraycopy(tempName, 0, tempName = new char[length + 2], 0, length);
 					tempName[length-1] = 'i';
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarEntryFile.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarEntryFile.java
index f345992..c1c124c 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarEntryFile.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarEntryFile.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragment.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragment.java
index 4054f55..207337e 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragment.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragment.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -26,7 +26,7 @@
 /**
  * A package fragment that represents a package fragment found in a JAR.
  *
- * @see IPackageFragment
+ * @see org.eclipse.jdt.core.IPackageFragment
  */
 class JarPackageFragment extends PackageFragment implements SuffixConstants {
 /**
@@ -39,11 +39,10 @@
  * Compute the children of this package fragment. Children of jar package fragments
  * can only be IClassFile (representing .class files).
  */
-protected boolean computeChildren(OpenableElementInfo info) {
-	JarPackageFragmentInfo jInfo= (JarPackageFragmentInfo)info;
-	if (jInfo.entryNames != null){
+protected boolean computeChildren(OpenableElementInfo info, ArrayList entryNames) {
+	if (entryNames != null && entryNames.size() > 0) {
 		ArrayList vChildren = new ArrayList();
-		for (Iterator iter = jInfo.entryNames.iterator(); iter.hasNext();) {
+		for (Iterator iter = entryNames.iterator(); iter.hasNext();) {
 			String child = (String) iter.next();
 			IClassFile classFile = getClassFile(child);
 			vChildren.add(classFile);
@@ -65,22 +64,26 @@
 		return;
 	}
 	int max = resNames.length;
-	Object[] res = new Object[max];
-	int index = 0;
-	for (int i = 0; i < max; i++) {
-		String resName = resNames[i];
-		// consider that a .java file is not a non-java resource (see bug 12246 Packages view shows .class and .java files when JAR has source)
-		if (!resName.toLowerCase().endsWith(SUFFIX_STRING_java)) {
-			if (!this.isDefaultPackage()) {
-				resName = this.getElementName().replace('.', '/') + "/" + resName;//$NON-NLS-1$
+	if (max == 0) {
+	    info.setNonJavaResources(JavaElementInfo.NO_NON_JAVA_RESOURCES);
+	} else {
+		Object[] res = new Object[max];
+		int index = 0;
+		for (int i = 0; i < max; i++) {
+			String resName = resNames[i];
+			// consider that a .java file is not a non-java resource (see bug 12246 Packages view shows .class and .java files when JAR has source)
+			if (!resName.toLowerCase().endsWith(SUFFIX_STRING_java)) {
+				if (!this.isDefaultPackage()) {
+					resName = this.getElementName().replace('.', '/') + "/" + resName;//$NON-NLS-1$
+				}
+				res[index++] = new JarEntryFile(resName, zipName);
 			}
-			res[index++] = new JarEntryFile(resName, zipName);
+		} 
+		if (index != max) {
+			System.arraycopy(res, 0, res = new Object[index], 0, index);
 		}
-	} 
-	if (index != max) {
-		System.arraycopy(res, 0, res = new Object[index], 0, index);
+		info.setNonJavaResources(res);
 	}
-	info.setNonJavaResources(res);
 }
 /**
  * Returns true if this fragment contains at least one java resource.
@@ -90,7 +93,7 @@
 	return ((JarPackageFragmentInfo) getElementInfo()).containsJavaResources();
 }
 /**
- * @see IPackageFragment
+ * @see org.eclipse.jdt.core.IPackageFragment
  */
 public ICompilationUnit createCompilationUnit(String cuName, String contents, boolean force, IProgressMonitor monitor) throws JavaModelException {
 	throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.READ_ONLY, this));
@@ -112,7 +115,7 @@
 	}
 }
 /**
- * @see IPackageFragment
+ * @see org.eclipse.jdt.core.IPackageFragment
  */
 public IClassFile[] getClassFiles() throws JavaModelException {
 	ArrayList list = getChildrenOfType(CLASS_FILE);
@@ -122,7 +125,7 @@
 }
 /**
  * A jar package fragment never contains compilation units.
- * @see IPackageFragment
+ * @see org.eclipse.jdt.core.IPackageFragment
  */
 public ICompilationUnit[] getCompilationUnits() {
 	return NO_COMPILATION_UNITS;
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentInfo.java
index 2a171ed..f8dba53 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentInfo.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -10,35 +10,14 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
-import java.util.ArrayList;
-
 /**
- * Element info for JarPackageFragments.  Caches the zip entry names
- * of the types (.class files) of the JarPackageFragment.  The entries
- * are used to compute the children of the JarPackageFragment.
+ * Element info for JarPackageFragments.
  */
 class JarPackageFragmentInfo extends PackageFragmentInfo {
-	/**
-	 * The names of the zip entries that are the class files associated
-	 * with this package fragment info in the JAR file of the JarPackageFragmentRootInfo.
-	 */
-	protected ArrayList entryNames;
-/**
- */
-boolean containsJavaResources() {
-	return this.entryNames != null && this.entryNames.size() != 0;
-}
 /**
  * Returns an array of non-java resources contained in the receiver.
  */
 Object[] getNonJavaResources() {
 	return this.nonJavaResources;
 }
-/**
- * Set the names of the zip entries that are the types associated
- * with this package fragment info in the JAR file of the JarPackageFragmentRootInfo.
- */
-protected void setEntryNames(ArrayList entries) {
-	this.entryNames = entries;
-}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRoot.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRoot.java
index 3ce52cb..e631714 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRoot.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRoot.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -145,9 +145,6 @@
 				ArrayList[] entries= (ArrayList[]) packageFragToTypes.get(packName);
 				JarPackageFragment packFrag= (JarPackageFragment) getPackageFragment(packName);
 				JarPackageFragmentInfo fragInfo= new JarPackageFragmentInfo();
-				if (entries[0].size() > 0){
-					fragInfo.setEntryNames(entries[JAVA]);
-				}
 				int resLength= entries[NON_JAVA].size();
 				if (resLength == 0) {
 					packFrag.computeNonJavaResources(NO_STRINGS, fragInfo, jar.getName());
@@ -156,7 +153,7 @@
 					entries[NON_JAVA].toArray(resNames);
 					packFrag.computeNonJavaResources(resNames, fragInfo, jar.getName());
 				}
-				packFrag.computeChildren(fragInfo);
+				packFrag.computeChildren(fragInfo, entries[JAVA]);
 				newElements.put(packFrag, fragInfo);
 				vChildren.add(packFrag);
 			}
@@ -263,18 +260,6 @@
 			return super.getUnderlyingResource();
 		}
 	}
-	/**
-	 * If I am not open, return true to avoid parsing.
-	 *
-	 * @see IParent 
-	 */
-	public boolean hasChildren() throws JavaModelException {
-		if (isOpen()) {
-			return getChildren().length > 0;
-		} else {
-			return true;
-		}
-	}
 	public int hashCode() {
 		return this.jarPath.hashCode();
 	}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRootInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRootInfo.java
index 03ee082..5dd52ea 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRootInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRootInfo.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElement.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElement.java
index 9e1a8a0..821f298 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElement.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElement.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -10,17 +10,15 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
-import java.util.*;
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.Iterator;
 
-import org.eclipse.core.resources.IResourceStatus;
-import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.*;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
 import org.eclipse.jdt.core.*;
-import org.eclipse.jdt.core.jdom.IDOMCompilationUnit;
-import org.eclipse.jdt.core.jdom.IDOMNode;
+import org.eclipse.jdt.core.jdom.*;
+import org.eclipse.jdt.internal.core.util.MementoTokenizer;
 import org.eclipse.jdt.internal.core.util.Util;
 
 /**
@@ -30,8 +28,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 = '~';
@@ -73,7 +72,8 @@
 	 * Constructs a handle for a java element with
 	 * the given parent element and name.
 	 *
-	 * @param type - one of the constants defined in IJavaLanguageElement
+	 * @param parent The parent of java element
+	 * @param name The name of java element
 	 *
 	 * @exception IllegalArgumentException if the type is not one of the valid
 	 *		Java element type constants
@@ -124,10 +124,35 @@
 	/**
 	 * Returns true if this <code>JavaElement</code> is equivalent to the given
 	 * <code>IDOMNode</code>.
+	 * @deprecated JDOM is obsolete
 	 */
+    // TODO - JDOM - remove once model ported off of JDOM
 	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
 	 */
@@ -145,7 +170,9 @@
 	/**
 	 * Returns the <code>IDOMNode</code> that corresponds to this <code>JavaElement</code>
 	 * or <code>null</code> if there is no corresponding node.
+	 * @deprecated JDOM is obsolete
 	 */
+    // TODO - JDOM - remove once model ported off of JDOM
 	public IDOMNode findNode(IDOMCompilationUnit dom) {
 		int type = getElementType();
 		if (type == IJavaElement.COMPILATION_UNIT || 
@@ -177,7 +204,9 @@
 		}
 	}
 	/**
+	 * @deprecated JDOM is obsolete
 	 */
+    // TODO - JDOM - remove once model ported off of JDOM
 	protected IDOMNode followPath(ArrayList path, int position, IDOMNode node) {
 	
 		if (equalsDOMNode(node)) {
@@ -229,7 +258,7 @@
 	 * Returns a collection of (immediate) children of this node of the
 	 * specified type.
 	 *
-	 * @param type - one of constants defined by IJavaLanguageElementTypes
+	 * @param type - one of the JEM_* constants defined by JavaElement
 	 */
 	public ArrayList getChildrenOfType(int type) throws JavaModelException {
 		IJavaElement[] children = getChildren();
@@ -290,12 +319,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 +333,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 +351,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);
@@ -399,14 +428,31 @@
 	protected IJavaElement getSourceElementAt(int position) throws JavaModelException {
 		if (this instanceof ISourceReference) {
 			IJavaElement[] children = getChildren();
-			int i;
-			for (i = 0; i < children.length; i++) {
+			for (int i = children.length-1; i >= 0; i--) {
 				IJavaElement aChild = children[i];
 				if (aChild instanceof SourceRefElement) {
 					SourceRefElement child = (SourceRefElement) children[i];
 					ISourceRange range = child.getSourceRange();
-					if (position < range.getOffset() + range.getLength() && position >= range.getOffset()) {
-						if (child instanceof IParent) {
+					int start = range.getOffset();
+					int end = start + range.getLength();
+					if (start <= position && position <= end) {
+						if (child instanceof IField) {
+							// check muti-declaration case (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=39943)
+							int declarationStart = start;
+							SourceRefElement candidate = null;
+							do {
+								// check name range
+								range = ((IField)child).getNameRange();
+								if (position <= range.getOffset() + range.getLength()) {
+									candidate = child;
+								} else {
+									return candidate == null ? child.getSourceElementAt(position) : candidate.getSourceElementAt(position);
+								}
+								child = --i>=0 ? (SourceRefElement) children[i] : null;
+							} while (child != null && child.getSourceRange().getOffset() == declarationStart);
+							// position in field's type: use first field
+							return candidate.getSourceElementAt(position);
+						} else if (child instanceof IParent) {
 							return child.getSourceElementAt(position);
 						} else {
 							return child;
@@ -428,12 +474,50 @@
 	public SourceMapper getSourceMapper() {
 		return ((JavaElement)getParent()).getSourceMapper();
 	}
-
+	/* (non-Javadoc)
+	 * @see org.eclipse.jdt.core.IJavaElement#getSchedulingRule()
+	 */
+	public ISchedulingRule getSchedulingRule() {
+		IResource resource = getResource();
+		if (resource == null) {
+			class NoResourceSchedulingRule implements ISchedulingRule {
+				public IPath path;
+				public NoResourceSchedulingRule(IPath path) {
+					this.path = path;
+				}
+				public boolean contains(ISchedulingRule rule) {
+					if (rule instanceof NoResourceSchedulingRule) {
+						return this.path.isPrefixOf(((NoResourceSchedulingRule)rule).path);
+					} else {
+						return false;
+					}
+				}
+				public boolean isConflicting(ISchedulingRule rule) {
+					if (rule instanceof NoResourceSchedulingRule) {
+						IPath otherPath = ((NoResourceSchedulingRule)rule).path;
+						return this.path.isPrefixOf(otherPath) || otherPath.isPrefixOf(this.path);
+					} else {
+						return false;
+					}
+				}
+			}
+			return new NoResourceSchedulingRule(getPath());
+		} else {
+			return resource;
+		}
+	}
 	/**
 	 * @see IParent 
 	 */
 	public boolean hasChildren() throws JavaModelException {
-		return getChildren().length > 0;
+		// if I am not open, return true to avoid opening (case of a Java project, a compilation unit or a class file).
+		// also see https://bugs.eclipse.org/bugs/show_bug.cgi?id=52474
+		Object elementInfo = JavaModelManager.getJavaModelManager().getInfo(this);
+		if (elementInfo instanceof JavaElementInfo) {
+			return ((JavaElementInfo)elementInfo).getChildren().length > 0;
+		} else {
+			return true;
+		}
 	}
 
 	/**
@@ -490,14 +574,12 @@
 				info = newElements.get(this);
 			}
 			if (info == null) { // a source ref element could not be opened
-				// close any buffer that was opened for the openable parent
-				Iterator iterator = newElements.keySet().iterator();
-				while (iterator.hasNext()) {
-					IJavaElement element = (IJavaElement)iterator.next();
-					if (element instanceof Openable) {
-						((Openable)element).closeBuffer();
-					}
-				}
+				// close the buffer that was opened for the openable parent
+			    // close only the openable's buffer (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=62854)
+			    Openable openable = (Openable) getOpenable();
+			    if (newElements.containsKey(openable)) {
+			        openable.closeBuffer();
+			    }
 				throw newNotPresentException();
 			}
 			if (!hadTemporaryCache) {
@@ -515,33 +597,6 @@
 	public String readableName() {
 		return this.getElementName();
 	}
-	/**
-	 * Runs a Java Model Operation
-	 */
-	public static void runOperation(JavaModelOperation operation, IProgressMonitor monitor) throws JavaModelException {
-		try {
-			if (operation.isReadOnly()) {
-				operation.run(monitor);
-			} else {
-				// Use IWorkspace.run(...) to ensure that a build will be done in autobuild mode.
-				// Note that if the tree is locked, this will throw a CoreException, but this is ok
-				// as this operation is modifying the tree (not read-only) and a CoreException will be thrown anyway.
-				ResourcesPlugin.getWorkspace().run(operation, monitor);
-			}
-		} catch (CoreException ce) {
-			if (ce instanceof JavaModelException) {
-				throw (JavaModelException)ce;
-			} else {
-				if (ce.getStatus().getCode() == IResourceStatus.OPERATION_FAILED) {
-					Throwable e= ce.getStatus().getException();
-					if (e instanceof JavaModelException) {
-						throw (JavaModelException) e;
-					}
-				}
-				throw new JavaModelException(ce);
-			}
-		}
-	}
 	protected String tabString(int tab) {
 		StringBuffer buffer = new StringBuffer();
 		for (int i = tab; i > 0; i--)
@@ -619,9 +674,19 @@
 	 */
 	protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
 		buffer.append(this.tabString(tab));
-		buffer.append(getElementName());
+		toStringName(buffer);
 		if (info == null) {
 			buffer.append(" (not open)"); //$NON-NLS-1$
 		}
 	}
+	/**
+	 *  Debugging purposes
+	 */
+	protected void toStringName(StringBuffer buffer) {
+		buffer.append(getElementName());
+		if (this.occurrenceCount > 1) {
+			buffer.append("#"); //$NON-NLS-1$
+			buffer.append(this.occurrenceCount);
+		}
+	}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementDelta.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementDelta.java
index 92d1b3d..76dc45c 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementDelta.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementDelta.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -40,11 +40,11 @@
 	 */
 	protected int resourceDeltasCounter;
 	/**
-	 * @see #getMovedFromHandle()
+	 * @see #getMovedFromElement()
 	 */
 	protected IJavaElement fMovedFromHandle = null;
 	/**
-	 * @see #getMovedToHandle()
+	 * @see #getMovedToElement()
 	 */
 	protected IJavaElement fMovedToHandle = null;
 	/**
@@ -224,10 +224,11 @@
  * The constructor should be used to create the root delta 
  * and then a change operation should call this method.
  */
-public void changed(IJavaElement element, int changeFlag) {
+public JavaElementDelta changed(IJavaElement element, int changeFlag) {
 	JavaElementDelta changedDelta = new JavaElementDelta(element);
 	changedDelta.changed(changeFlag);
 	insertDeltaTree(element, changedDelta);
+	return changedDelta;
 }
 /**
  * Mark this delta as a content changed delta.
@@ -662,6 +663,30 @@
 		buffer.append("PRIMARY WORKING COPY"); //$NON-NLS-1$
 		prev = true;
 	}
+	if ((flags & IJavaElementDelta.F_CLASSPATH_CHANGED) != 0) {
+		if (prev)
+			buffer.append(" | "); //$NON-NLS-1$
+		buffer.append("CLASSPATH CHANGED"); //$NON-NLS-1$
+		prev = true;
+	}
+	if ((flags & IJavaElementDelta.F_PRIMARY_RESOURCE) != 0) {
+		if (prev)
+			buffer.append(" | "); //$NON-NLS-1$
+		buffer.append("PRIMARY RESOURCE"); //$NON-NLS-1$
+		prev = true;
+	}
+	if ((flags & IJavaElementDelta.F_OPENED) != 0) {
+		if (prev)
+			buffer.append(" | "); //$NON-NLS-1$
+		buffer.append("OPENED"); //$NON-NLS-1$
+		prev = true;
+	}
+	if ((flags & IJavaElementDelta.F_CLOSED) != 0) {
+		if (prev)
+			buffer.append(" | "); //$NON-NLS-1$
+		buffer.append("CLOSED"); //$NON-NLS-1$
+		prev = true;
+	}
 	return prev;
 }
 /** 
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementDeltaBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementDeltaBuilder.java
index dd1926e..f2a9e32 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementDeltaBuilder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementDeltaBuilder.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementInfo.java
index 2a15394..ed0dc11 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementInfo.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementRequestor.java
index f9941a1..e316b45 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementRequestor.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementRequestor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModel.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModel.java
index f3d3fd1..193a5b4 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModel.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModel.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -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;
 
 /**
@@ -122,9 +122,9 @@
  */
 public void delete(IJavaElement[] elements, boolean force, IProgressMonitor monitor) throws JavaModelException {
 	if (elements != null && elements.length > 0 && elements[0] != null && elements[0].getElementType() < IJavaElement.TYPE) {
-		runOperation(new DeleteResourceElementsOperation(elements, force), monitor);
+		new DeleteResourceElementsOperation(elements, force).runOperation(monitor);
 	} else {
-		runOperation(new DeleteElementsOperation(elements, force), monitor);
+		new DeleteElementsOperation(elements, force).runOperation(monitor);
 	}
 }
 public boolean equals(Object o) {
@@ -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);
@@ -301,7 +301,7 @@
 		op = new RenameElementsOperation(elements, destinations, renamings, force);
 	}
 	
-	runOperation(op, monitor);
+	op.runOperation(monitor);
 }
 /**
  * Configures and runs the <code>MultiOperation</code>.
@@ -313,7 +313,7 @@
 			op.setInsertBefore(elements[i], siblings[i]);
 		}
 	}
-	runOperation(op, monitor);
+	op.runOperation(monitor);
 }
 /**
  * @private Debugging purposes
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelCache.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelCache.java
index 9572170..c7699bc 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelCache.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelCache.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelInfo.java
index 49154de..ba479f4 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelInfo.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -17,7 +17,7 @@
  * Implementation of IJavaModel. A Java Model is specific to a
  * workspace.
  *
- * @see IJavaModel
+ * @see org.eclipse.jdt.core.IJavaModel
  */
 public class JavaModelInfo extends OpenableElementInfo {
 
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java
index 320e8c7..5b7f53f 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -57,18 +57,26 @@
 	/**
 	 * Classpath variables pool
 	 */
-	public static HashMap Variables = new HashMap(5);
-	public static HashMap PreviousSessionVariables = new HashMap(5);
-	public static HashSet OptionNames = new HashSet(20);
-	public final static String CP_VARIABLE_PREFERENCES_PREFIX = JavaCore.PLUGIN_ID+".classpathVariable."; //$NON-NLS-1$
-	public final static String CP_CONTAINER_PREFERENCES_PREFIX = JavaCore.PLUGIN_ID+".classpathContainer."; //$NON-NLS-1$
-	public final static String CP_ENTRY_IGNORE = "##<cp entry ignore>##"; //$NON-NLS-1$
+	public HashMap variables = new HashMap(5);
+	public HashMap previousSessionVariables = new HashMap(5);
+	private ThreadLocal variableInitializationInProgress = new ThreadLocal();
 		
 	/**
 	 * Classpath containers pool
 	 */
-	public static HashMap Containers = new HashMap(5);
-	public static HashMap PreviousSessionContainers = new HashMap(5);
+	public HashMap containers = new HashMap(5);
+	public HashMap previousSessionContainers = new HashMap(5);
+	private ThreadLocal containerInitializationInProgress = new ThreadLocal();
+	public boolean batchContainerInitializations = true;
+	
+	/*
+	 * A HashSet that contains the IJavaProject whose classpath is being resolved.
+	 */
+	private ThreadLocal classpathsBeingResolved = new ThreadLocal();
+
+	public final static String CP_VARIABLE_PREFERENCES_PREFIX = JavaCore.PLUGIN_ID+".classpathVariable."; //$NON-NLS-1$
+	public final static String CP_CONTAINER_PREFERENCES_PREFIX = JavaCore.PLUGIN_ID+".classpathContainer."; //$NON-NLS-1$
+	public final static String CP_ENTRY_IGNORE = "##<cp entry ignore>##"; //$NON-NLS-1$
 
 	/**
 	 * Name of the extension point for contributing classpath variable initializers
@@ -86,15 +94,10 @@
 	public static final String FORMATTER_EXTPOINT_ID = "codeFormatter" ; //$NON-NLS-1$
 	
 	/**
-	 * Name of the extension point for contributing a search participant
-	 * TODO search participant
-	 */
-	public static final String SEARCH_PARTICIPANT_EXTPOINT_ID = "searchParticipant" ; //$NON-NLS-1$
-	/**
 	 * Special value used for recognizing ongoing initialization and breaking initialization cycles
 	 */
-	public final static IPath VariableInitializationInProgress = new Path("Variable Initialization In Progress"); //$NON-NLS-1$
-	public final static IClasspathContainer ContainerInitializationInProgress = new IClasspathContainer() {
+	public final static IPath VARIABLE_INITIALIZATION_IN_PROGRESS = new Path("Variable Initialization In Progress"); //$NON-NLS-1$
+	public final static IClasspathContainer CONTAINER_INITIALIZATION_IN_PROGRESS = new IClasspathContainer() {
 		public IClasspathEntry[] getClasspathEntries() { return null; }
 		public String getDescription() { return "Container Initialization In Progress"; } //$NON-NLS-1$
 		public int getKind() { return 0; }
@@ -109,6 +112,7 @@
 	private static final String CP_RESOLVE_DEBUG = JavaCore.PLUGIN_ID + "/debug/cpresolution" ; //$NON-NLS-1$
 	private static final String ZIP_ACCESS_DEBUG = JavaCore.PLUGIN_ID + "/debug/zipaccess" ; //$NON-NLS-1$
 	private static final String DELTA_DEBUG =JavaCore.PLUGIN_ID + "/debug/javadelta" ; //$NON-NLS-1$
+	private static final String DELTA_DEBUG_VERBOSE =JavaCore.PLUGIN_ID + "/debug/javadelta/verbose" ; //$NON-NLS-1$
 	private static final String HIERARCHY_DEBUG = JavaCore.PLUGIN_ID + "/debug/hierarchy" ; //$NON-NLS-1$
 	private static final String POST_ACTION_DEBUG = JavaCore.PLUGIN_ID + "/debug/postaction" ; //$NON-NLS-1$
 	private static final String BUILDER_DEBUG = JavaCore.PLUGIN_ID + "/debug/builder" ; //$NON-NLS-1$
@@ -116,8 +120,10 @@
 	private static final String SELECTION_DEBUG = JavaCore.PLUGIN_ID + "/debug/selection" ; //$NON-NLS-1$
 	private static final String SEARCH_DEBUG = JavaCore.PLUGIN_ID + "/debug/search" ; //$NON-NLS-1$
 
-	public final static ICompilationUnit[] NoWorkingCopy = new ICompilationUnit[0];
+	public final static ICompilationUnit[] NO_WORKING_COPY = new ICompilationUnit[0];
 	
+	public HashSet optionNames = new HashSet(20);
+
 	/**
 	 * Returns whether the given full path (for a package) conflicts with the output location
 	 * of the given project.
@@ -132,7 +138,7 @@
 			if (outputLocation.isPrefixOf(folderPath)) {
 				// only allow nesting in project's output if there is a corresponding source folder
 				// or if the project's output is not used (in other words, if all source folders have their custom output)
-				IClasspathEntry[] classpath = project.getResolvedClasspath(true);
+				IClasspathEntry[] classpath = project.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
 				boolean isOutputUsed = false;
 				for (int i = 0, length = classpath.length; i < length; i++) {
 					IClasspathEntry entry = classpath[i];
@@ -154,50 +160,100 @@
 		}
 	}
 
-	public static IClasspathContainer containerGet(IJavaProject project, IPath containerPath) {	
-		Map projectContainers = (Map)Containers.get(project);
+	public synchronized IClasspathContainer containerGet(IJavaProject project, IPath containerPath) {	
+		// check initialization in progress first
+		HashSet projectInitializations = containerInitializationInProgress(project);
+		if (projectInitializations.contains(containerPath)) {
+			return CONTAINER_INITIALIZATION_IN_PROGRESS;
+		}
+		
+		Map projectContainers = (Map)this.containers.get(project);
 		if (projectContainers == null){
 			return null;
 		}
 		IClasspathContainer container = (IClasspathContainer)projectContainers.get(containerPath);
 		return container;
 	}
-
-	public static void containerPut(IJavaProject project, IPath containerPath, IClasspathContainer container){
-
-		Map projectContainers = (Map)Containers.get(project);
-		if (projectContainers == null){
-			projectContainers = new HashMap(1);
-			Containers.put(project, projectContainers);
+	
+	private synchronized Map containerClone(IJavaProject project) {
+		Map originalProjectContainers = (Map)this.containers.get(project);
+		if (originalProjectContainers == null) return null;
+		Map projectContainers = new HashMap(originalProjectContainers.size());
+		projectContainers.putAll(originalProjectContainers);
+		return projectContainers;
+	}
+	
+	/*
+	 * Returns the set of container paths for the given project that are being initialized in the current thread.
+	 */
+	private HashSet containerInitializationInProgress(IJavaProject project) {
+		Map initializations = (Map)this.containerInitializationInProgress.get();
+		if (initializations == null) {
+			initializations = new HashMap();
+			this.containerInitializationInProgress.set(initializations);
 		}
+		HashSet projectInitializations = (HashSet)initializations.get(project);
+		if (projectInitializations == null) {
+			projectInitializations = new HashSet();
+			initializations.put(project, projectInitializations);
+		}
+		return projectInitializations;
+	}
 
-		if (container == null) {
-			projectContainers.remove(containerPath);
-			Map previousContainers = (Map)PreviousSessionContainers.get(project);
+	public synchronized void containerPut(IJavaProject project, IPath containerPath, IClasspathContainer container){
+
+		// set/unset the initialization in progress
+		HashSet projectInitializations = containerInitializationInProgress(project);
+		if (container == CONTAINER_INITIALIZATION_IN_PROGRESS) {
+			projectInitializations.add(containerPath);
+			
+			// do not write out intermediate initialization value
+			return;
+		} else {
+			projectInitializations.remove(containerPath);
+			if (projectInitializations.size() == 0) {
+				Map initializations = (Map)this.containerInitializationInProgress.get();
+				initializations.remove(project);
+			}
+
+			Map projectContainers = (Map)this.containers.get(project);
+			if (projectContainers == null){
+				projectContainers = new HashMap(1);
+				this.containers.put(project, projectContainers);
+			}
+	
+			if (container == null) {
+				projectContainers.remove(containerPath);
+			} else {
+   				projectContainers.put(containerPath, container);
+			}
+			// discard obsoleted information about previous session
+			Map previousContainers = (Map)this.previousSessionContainers.get(project);
 			if (previousContainers != null){
 				previousContainers.remove(containerPath);
 			}
-		} else {
-			projectContainers.put(containerPath, container);
 		}
-
-		// do not write out intermediate initialization value
-		if (container == JavaModelManager.ContainerInitializationInProgress) {
-			return;
-		}
-		Preferences preferences = JavaCore.getPlugin().getPluginPreferences();
-		String containerKey = CP_CONTAINER_PREFERENCES_PREFIX+project.getElementName() +"|"+containerPath;//$NON-NLS-1$
-		String containerString = CP_ENTRY_IGNORE;
-		try {
-			if (container != null) {
-				containerString = ((JavaProject)project).encodeClasspath(container.getClasspathEntries(), null, false);
+		// container values are persisted in preferences during save operations, see #saving(ISaveContext)
+	}
+	
+	private synchronized void containersReset(String[] containerIDs) {
+		for (int i = 0; i < containerIDs.length; i++) {
+			String containerID = containerIDs[i];
+			Iterator projectIterator = this.containers.keySet().iterator();
+			while (projectIterator.hasNext()){
+				IJavaProject project = (IJavaProject)projectIterator.next();
+				Map projectContainers = (Map)this.containers.get(project);
+				if (projectContainers != null){
+					Iterator containerIterator = projectContainers.keySet().iterator();
+					while (containerIterator.hasNext()){
+						IPath containerPath = (IPath)containerIterator.next();
+						if (containerPath.segment(0).equals(containerID)) { // registered container
+							projectContainers.put(containerPath, null); // reset container value, but leave entry in Map
+						}
+					}
+				}
 			}
-		} catch(JavaModelException e){
-			// could not encode entry: leave it as CP_ENTRY_IGNORE
 		}
-		preferences.setDefault(containerKey, CP_ENTRY_IGNORE); // use this default to get rid of removed ones
-		preferences.setValue(containerKey, containerString);
-		JavaCore.getPlugin().savePluginPreferences();
 	}
 
 	/**
@@ -364,7 +420,7 @@
 		// Create a jar package fragment root only if on the classpath
 		IPath resourcePath = file.getFullPath();
 		try {
-			IClasspathEntry[] entries = ((JavaProject)project).getResolvedClasspath(true);
+			IClasspathEntry[] entries = ((JavaProject)project).getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
 			for (int i = 0, length = entries.length; i < length; i++) {
 				IClasspathEntry entry = entries[i];
 				IPath rootPath = entry.getPath();
@@ -392,7 +448,7 @@
 			IClasspathEntry[] entries = 
 				org.eclipse.jdt.internal.compiler.util.Util.isJavaFileName(resourcePath.lastSegment())
 					? project.getRawClasspath() // JAVA file can only live inside SRC folder (on the raw path)
-					: ((JavaProject)project).getResolvedClasspath(true);
+					: ((JavaProject)project).getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
 				
 			for (int i = 0; i < entries.length; i++) {
 				IClasspathEntry entry = entries[i];
@@ -400,22 +456,25 @@
 				IPath rootPath = entry.getPath();
 				if (rootPath.equals(resourcePath)) {
 					return project.getPackageFragmentRoot(resource);
-				} else if (rootPath.isPrefixOf(resourcePath) && !Util.isExcluded(resource, ((ClasspathEntry)entry).fullExclusionPatternChars())) {
-					// given we have a resource child of the root, it cannot be a JAR pkg root
-					IPackageFragmentRoot root = ((JavaProject) project).getFolderPackageFragmentRoot(rootPath);
-					if (root == null) return null;
-					IPath pkgPath = resourcePath.removeFirstSegments(rootPath.segmentCount());
-
-					if (resource.getType() == IResource.FILE) {
-						// if the resource is a file, then remove the last segment which
-						// is the file name in the package
-						pkgPath = pkgPath.removeLastSegments(1);
+				} else if (rootPath.isPrefixOf(resourcePath)) {
+					// allow creation of package fragment if it contains a .java file that is included
+					if (!Util.isExcluded(resource, ((ClasspathEntry)entry).fullInclusionPatternChars(), ((ClasspathEntry)entry).fullExclusionPatternChars())) {
+						// given we have a resource child of the root, it cannot be a JAR pkg root
+						IPackageFragmentRoot root = ((JavaProject) project).getFolderPackageFragmentRoot(rootPath);
+						if (root == null) return null;
+						IPath pkgPath = resourcePath.removeFirstSegments(rootPath.segmentCount());
+	
+						if (resource.getType() == IResource.FILE) {
+							// if the resource is a file, then remove the last segment which
+							// is the file name in the package
+							pkgPath = pkgPath.removeLastSegments(1);
+						}
+						String pkgName = Util.packageName(pkgPath);
+						if (pkgName == null || JavaConventions.validatePackageName(pkgName).getSeverity() == IStatus.ERROR) {
+							return null;
+						}
+						return root.getPackageFragment(pkgName);
 					}
-					String pkgName = Util.packageName(pkgPath);
-					if (pkgName == null || JavaConventions.validatePackageName(pkgName).getSeverity() == IStatus.ERROR) {
-						return null;
-					}
-					return root.getPackageFragment(pkgName);
 				}
 			}
 		} catch (JavaModelException npe) {
@@ -427,7 +486,7 @@
 	/**
 	 * The singleton manager
 	 */
-	private final static JavaModelManager Manager= new JavaModelManager();
+	private final static JavaModelManager MANAGER= new JavaModelManager();
 
 	/**
 	 * Infos cache.
@@ -458,7 +517,7 @@
 	protected Map perProjectInfos = new HashMap(5);
 	
 	/**
-	 * Table from WorkingCopyOwner to a table of IPath (working copy's path) to PerWorkingCopyInfo.
+	 * Table from WorkingCopyOwner to a table of ICompilationUnit (working copy handle) to PerWorkingCopyInfo.
 	 * NOTE: this object itself is used as a lock to synchronize creation/removal of per working copy infos
 	 */
 	protected Map perWorkingCopyInfos = new HashMap(5);
@@ -493,6 +552,39 @@
 			this.resolvedClasspath = null;
 			this.resolvedPathToRawEntries = null;
 		}
+		public String toString() {
+			StringBuffer buffer = new StringBuffer();
+			buffer.append("Info for "); //$NON-NLS-1$
+			buffer.append(this.project.getFullPath());
+			buffer.append("\nRaw classpath:\n"); //$NON-NLS-1$
+			if (this.rawClasspath == null) {
+				buffer.append("  <null>\n"); //$NON-NLS-1$
+			} else {
+				for (int i = 0, length = this.rawClasspath.length; i < length; i++) {
+					buffer.append("  "); //$NON-NLS-1$
+					buffer.append(this.rawClasspath[i]);
+					buffer.append('\n');
+				}
+			}
+			buffer.append("Resolved classpath:\n"); //$NON-NLS-1$
+			IClasspathEntry[] resolvedCP = this.resolvedClasspath;
+			if (resolvedCP == null) {
+				buffer.append("  <null>\n"); //$NON-NLS-1$
+			} else {
+				for (int i = 0, length = resolvedCP.length; i < length; i++) {
+					buffer.append("  "); //$NON-NLS-1$
+					buffer.append(resolvedCP[i]);
+					buffer.append('\n');
+				}
+			}
+			buffer.append("Output location:\n  "); //$NON-NLS-1$
+			if (this.outputLocation == null) {
+				buffer.append("<null>"); //$NON-NLS-1$
+			} else {
+				buffer.append(this.outputLocation);
+			}
+			return buffer.toString();
+		}
 	}
 	
 	public static class PerWorkingCopyInfo implements IProblemRequestor {
@@ -521,6 +613,16 @@
 		public boolean isActive() {
 			return this.problemRequestor != null && this.problemRequestor.isActive();
 		}
+		public String toString() {
+			StringBuffer buffer = new StringBuffer();
+			buffer.append("Info for "); //$NON-NLS-1$
+			buffer.append(((JavaElement)workingCopy).toStringWithAncestors());
+			buffer.append("\nUse count = "); //$NON-NLS-1$
+			buffer.append(this.useCount);
+			buffer.append("\nProblem requestor:\n  "); //$NON-NLS-1$
+			buffer.append(this.problemRequestor);
+			return buffer.toString();
+		}
 	}
 	
 	public static boolean VERBOSE = false;
@@ -539,7 +641,7 @@
 	 */
 	public static class PluginPreferencesListener implements Preferences.IPropertyChangeListener {
 		/**
-		 * @see org.eclipse.core.runtime.Preferences.IPropertyChangeListener#propertyChange(PropertyChangeEvent)
+		 * @see org.eclipse.core.runtime.Preferences.IPropertyChangeListener#propertyChange(Preferences.PropertyChangeEvent)
 		 */
 		public void propertyChange(Preferences.PropertyChangeEvent event) {
 
@@ -548,9 +650,9 @@
 				String varName = propertyName.substring(CP_VARIABLE_PREFERENCES_PREFIX.length());
 				String newValue = (String)event.getNewValue();
 				if (newValue != null && !(newValue = newValue.trim()).equals(CP_ENTRY_IGNORE)) {
-					Variables.put(varName, new Path(newValue));
+					getJavaModelManager().variables.put(varName, new Path(newValue));
 				} else {
-					Variables.remove(varName);
+					getJavaModelManager().variables.remove(varName);
 				}
 			}
 			if (propertyName.startsWith(CP_CONTAINER_PREFERENCES_PREFIX)) {
@@ -610,6 +712,9 @@
 			if(option != null) JavaModelManager.CP_RESOLVE_VERBOSE = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
 
 			option = Platform.getDebugOption(DELTA_DEBUG);
+			if(option != null) DeltaProcessor.DEBUG = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
+
+			option = Platform.getDebugOption(DELTA_DEBUG_VERBOSE);
 			if(option != null) DeltaProcessor.VERBOSE = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
 
 			option = Platform.getDebugOption(HIERARCHY_DEBUG);
@@ -642,46 +747,49 @@
 	 * and register it.
 	 * Close the working copy, its buffer and remove it from the shared working copy table.
 	 * Ignore if no per-working copy info existed.
+	 * NOTE: it must NOT be synchronized as it may interact with the element info cache (if useCount is decremented to 0), see bug 50667.
 	 * Returns the new use count (or -1 if it didn't exist).
 	 */
 	public int discardPerWorkingCopyInfo(CompilationUnit workingCopy) throws JavaModelException {
+		
+		// create the delta builder (this remembers the current content of the working copy)
+		// outside the perWorkingCopyInfos lock (see bug 50667)
+		JavaElementDeltaBuilder deltaBuilder = null;
+		if (workingCopy.isPrimary()) {
+			deltaBuilder = new JavaElementDeltaBuilder(workingCopy);
+		}
+		PerWorkingCopyInfo info = null;
 		synchronized(perWorkingCopyInfos) {
 			WorkingCopyOwner owner = workingCopy.owner;
-			Map pathToPerWorkingCopyInfos = (Map)this.perWorkingCopyInfos.get(owner);
-			if (pathToPerWorkingCopyInfos == null) return -1;
+			Map workingCopyToInfos = (Map)this.perWorkingCopyInfos.get(owner);
+			if (workingCopyToInfos == null) return -1;
 			
-			IPath path = workingCopy.getPath();
-			PerWorkingCopyInfo info = (PerWorkingCopyInfo)pathToPerWorkingCopyInfos.get(path);
+			info = (PerWorkingCopyInfo)workingCopyToInfos.get(workingCopy);
 			if (info == null) return -1;
 			
 			if (--info.useCount == 0) {
-				// create the delta builder (this remembers the current content of the working copy)
-				JavaElementDeltaBuilder deltaBuilder = null;
-				if (workingCopy.isPrimary()) {
-					deltaBuilder = new JavaElementDeltaBuilder(workingCopy);
-				}
-
 				// remove per working copy info
-				pathToPerWorkingCopyInfos.remove(path);
-				if (pathToPerWorkingCopyInfos.isEmpty()) {
+				workingCopyToInfos.remove(workingCopy);
+				if (workingCopyToInfos.isEmpty()) {
 					this.perWorkingCopyInfos.remove(owner);
 				}
-
-				// remove infos + close buffer (since no longer working copy)
-				removeInfoAndChildren(workingCopy);
-				workingCopy.closeBuffer();
-
-				// compute the delta if needed and register it if there are changes
-				if (deltaBuilder != null) {
-					deltaBuilder.buildDeltas();
-					if ((deltaBuilder.delta != null) && (deltaBuilder.delta.getAffectedChildren().length > 0)) {
-						getDeltaProcessor().registerJavaModelDelta(deltaBuilder.delta);
-					}
-				}
-				
 			}
-			return info.useCount;
 		}
+		if (info.useCount == 0) { // info cannot be null here (check was done above)
+			// remove infos + close buffer (since no longer working copy)
+			// outside the perWorkingCopyInfos lock (see bug 50667)
+			removeInfoAndChildren(workingCopy);
+			workingCopy.closeBuffer();
+
+			// compute the delta if needed and register it if there are changes
+			if (deltaBuilder != null) {
+				deltaBuilder.buildDeltas();
+				if ((deltaBuilder.delta != null) && (deltaBuilder.delta.getAffectedChildren().length > 0)) {
+					getDeltaProcessor().registerJavaModelDelta(deltaBuilder.delta);
+				}
+			}
+		}
+		return info.useCount;
 	}
 	
 	/**
@@ -713,6 +821,22 @@
 		}
 	}
 	
+	public IClasspathContainer getClasspathContainer(IPath containerPath, IJavaProject project) throws JavaModelException {
+
+		IClasspathContainer container = containerGet(project, containerPath);
+
+		if (container == null) {
+			if (this.batchContainerInitializations) {
+				// avoid deep recursion while initializaing container on workspace restart
+				// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=60437)
+				this.batchContainerInitializations = false;
+				return initializeAllContainers(project, containerPath);
+			}
+			return initializeContainer(project, containerPath);
+		}
+		return container;			
+	}
+
 	public DeltaProcessor getDeltaProcessor() {
 		return this.deltaState.getDeltaProcessor();
 	}
@@ -753,7 +877,7 @@
 	 * Returns the singleton JavaModelManager
 	 */
 	public final static JavaModelManager getJavaModelManager() {
-		return Manager;
+		return MANAGER;
 	}
 
 	/**
@@ -814,26 +938,80 @@
 	 * If recordUsage, increment the per-working copy info's use count.
 	 * Returns null if it doesn't exist and not create.
 	 */
-	public PerWorkingCopyInfo getPerWorkingCopyInfo(CompilationUnit workingCopy, IPath path, boolean create, boolean recordUsage, IProblemRequestor problemRequestor) {
+	public PerWorkingCopyInfo getPerWorkingCopyInfo(CompilationUnit workingCopy,boolean create, boolean recordUsage, IProblemRequestor problemRequestor) {
 		synchronized(perWorkingCopyInfos) { // use the perWorkingCopyInfo collection as its own lock
 			WorkingCopyOwner owner = workingCopy.owner;
-			Map pathToPerWorkingCopyInfos = (Map)this.perWorkingCopyInfos.get(owner);
-			if (pathToPerWorkingCopyInfos == null && create) {
-				pathToPerWorkingCopyInfos = new HashMap();
-				this.perWorkingCopyInfos.put(owner, pathToPerWorkingCopyInfos);
+			Map workingCopyToInfos = (Map)this.perWorkingCopyInfos.get(owner);
+			if (workingCopyToInfos == null && create) {
+				workingCopyToInfos = new HashMap();
+				this.perWorkingCopyInfos.put(owner, workingCopyToInfos);
 			}
 
-			PerWorkingCopyInfo info = pathToPerWorkingCopyInfos == null ? null : (PerWorkingCopyInfo) pathToPerWorkingCopyInfos.get(path);
+			PerWorkingCopyInfo info = workingCopyToInfos == null ? null : (PerWorkingCopyInfo) workingCopyToInfos.get(workingCopy);
 			if (info == null && create) {
 				info= new PerWorkingCopyInfo(workingCopy, problemRequestor);
-				pathToPerWorkingCopyInfos.put(path, info);
+				workingCopyToInfos.put(workingCopy, info);
 			}
 			if (info != null && recordUsage) info.useCount++;
 			return info;
 		}
 	}	
+
+	/**
+	 * Returns a persisted container from previous session if any. Note that it is not the original container from previous
+	 * session (i.e. it did not get serialized) but rather a summary of its entries recreated for CP initialization purpose.
+	 * As such it should not be stored into container caches.
+	 */
+	public IClasspathContainer getPreviousSessionContainer(IPath containerPath, IJavaProject project) {
+			Map previousContainerValues = (Map)this.previousSessionContainers.get(project);
+			if (previousContainerValues != null){
+			    IClasspathContainer previousContainer = (IClasspathContainer)previousContainerValues.get(containerPath);
+			    if (previousContainer != null) {
+					if (JavaModelManager.CP_RESOLVE_VERBOSE){
+						StringBuffer buffer = new StringBuffer();
+						buffer.append("CPContainer INIT - reentering access to project container during its initialization, will see previous value\n"); //$NON-NLS-1$ 
+						buffer.append("	project: " + project.getElementName() + '\n'); //$NON-NLS-1$
+						buffer.append("	container path: " + containerPath + '\n'); //$NON-NLS-1$
+						buffer.append("	previous value: "); //$NON-NLS-1$
+						buffer.append(previousContainer.getDescription());
+						buffer.append(" {\n"); //$NON-NLS-1$
+						IClasspathEntry[] entries = previousContainer.getClasspathEntries();
+						if (entries != null){
+							for (int j = 0; j < entries.length; j++){
+								buffer.append(" 		"); //$NON-NLS-1$
+								buffer.append(entries[j]); 
+								buffer.append('\n'); 
+							}
+						}
+						buffer.append(" 	}"); //$NON-NLS-1$
+						Util.verbose(buffer.toString());
+						new Exception("<Fake exception>").printStackTrace(System.out); //$NON-NLS-1$
+					}			    
+					return previousContainer;
+			    }
+			}
+		    return null; // break cycle if none found
+	}
 	
-	/*
+	/**
+	 * Returns a persisted container from previous session if any
+	 */
+	public IPath getPreviousSessionVariable(String variableName) {
+		IPath previousPath = (IPath)this.previousSessionVariables.get(variableName);
+		if (previousPath != null){
+			if (CP_RESOLVE_VERBOSE){
+				Util.verbose(
+					"CPVariable INIT - reentering access to variable during its initialization, will see previous value\n" + //$NON-NLS-1$
+					"	variable: "+ variableName + '\n' + //$NON-NLS-1$
+					"	previous value: " + previousPath); //$NON-NLS-1$
+				new Exception("<Fake exception>").printStackTrace(System.out); //$NON-NLS-1$
+			}
+			return previousPath;
+		}
+	    return null; // break cycle
+	}
+	
+	/**
 	 * Returns the temporary cache for newly opened elements for the current thread.
 	 * Creates it if not already created.
 	 */
@@ -855,7 +1033,7 @@
 		if (jdtCorePlugin == null) return null;
 
 		ArrayList variableList = new ArrayList(5);
-		IExtensionPoint extension = jdtCorePlugin.getDescriptor().getExtensionPoint(JavaModelManager.CPVARIABLE_INITIALIZER_EXTPOINT_ID);
+		IExtensionPoint extension = Platform.getExtensionRegistry().getExtensionPoint(JavaCore.PLUGIN_ID, JavaModelManager.CPVARIABLE_INITIALIZER_EXTPOINT_ID);
 		if (extension != null) {
 			IExtension[] extensions =  extension.getExtensions();
 			for(int i = 0; i < extensions.length; i++){
@@ -880,7 +1058,7 @@
 		if (jdtCorePlugin == null) return null;
 
 		ArrayList containerIDList = new ArrayList(5);
-		IExtensionPoint extension = jdtCorePlugin.getDescriptor().getExtensionPoint(JavaModelManager.CPCONTAINER_INITIALIZER_EXTPOINT_ID);
+		IExtensionPoint extension = Platform.getExtensionRegistry().getExtensionPoint(JavaCore.PLUGIN_ID, JavaModelManager.CPCONTAINER_INITIALIZER_EXTPOINT_ID);
 		if (extension != null) {
 			IExtension[] extensions =  extension.getExtensions();
 			for(int i = 0; i < extensions.length; i++){
@@ -901,8 +1079,7 @@
 	 */
 	private File getSerializationFile(IProject project) {
 		if (!project.exists()) return null;
-		IPluginDescriptor descr= JavaCore.getJavaCore().getDescriptor();
-		IPath workingLocation= project.getPluginWorkingLocation(descr);
+		IPath workingLocation = project.getWorkingLocation(JavaCore.PLUGIN_ID);
 		return workingLocation.append("state.dat").toFile(); //$NON-NLS-1$
 	}
 	
@@ -916,15 +1093,15 @@
 			ICompilationUnit[] primaryWCs = addPrimary && owner != DefaultWorkingCopyOwner.PRIMARY 
 				? getWorkingCopies(DefaultWorkingCopyOwner.PRIMARY, false) 
 				: null;
-			Map pathToPerWorkingCopyInfos = (Map)perWorkingCopyInfos.get(owner);
-			if (pathToPerWorkingCopyInfos == null) return primaryWCs;
+			Map workingCopyToInfos = (Map)perWorkingCopyInfos.get(owner);
+			if (workingCopyToInfos == null) return primaryWCs;
 			int primaryLength = primaryWCs == null ? 0 : primaryWCs.length;
-			int size = pathToPerWorkingCopyInfos.size(); // note size is > 0 otherwise pathToPerWorkingCopyInfos would be null
+			int size = workingCopyToInfos.size(); // note size is > 0 otherwise pathToPerWorkingCopyInfos would be null
 			ICompilationUnit[] result = new ICompilationUnit[primaryLength + size];
 			if (primaryWCs != null) {
 				System.arraycopy(primaryWCs, 0, result, 0, primaryLength);
 			}
-			Iterator iterator = pathToPerWorkingCopyInfos.values().iterator();
+			Iterator iterator = workingCopyToInfos.values().iterator();
 			int index = primaryLength;
 			while(iterator.hasNext()) {
 				result[index++] = ((JavaModelManager.PerWorkingCopyInfo)iterator.next()).getWorkingCopy();
@@ -984,6 +1161,196 @@
 	public boolean hasTemporaryCache() {
 		return this.temporaryCache.get() != null;
 	}
+	
+	/*
+	 * Initialize all container at the same time as the given container.
+	 * Return the container for the given path and project.
+	 */
+	private IClasspathContainer initializeAllContainers(IJavaProject javaProjectToInit, IPath containerToInit) throws JavaModelException {
+		if (CP_RESOLVE_VERBOSE) {
+			Util.verbose(
+				"CPContainer INIT - batching containers initialization\n" + //$NON-NLS-1$
+				"	project to init: " + javaProjectToInit.getElementName() + '\n' + //$NON-NLS-1$
+				"	container path to init: " + containerToInit); //$NON-NLS-1$
+		}
+
+		// collect all container paths
+		HashMap allContainerPaths = new HashMap();
+		IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
+		for (int i = 0, length = projects.length; i < length; i++) {
+			IProject project = projects[i];
+			if (!JavaProject.hasJavaNature(project)) continue;
+			IJavaProject javaProject = new JavaProject(project, getJavaModel());
+			HashSet paths = null;
+			IClasspathEntry[] rawClasspath = javaProject.getRawClasspath();
+			for (int j = 0, length2 = rawClasspath.length; j < length2; j++) {
+				IClasspathEntry entry = rawClasspath[j];
+				IPath path = entry.getPath();
+				if (entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER
+						&& containerGet(javaProject, path) == null) {
+					if (paths == null) {
+						paths = new HashSet();
+						allContainerPaths.put(javaProject, paths);
+					}
+					paths.add(path);
+				}
+			}
+			if (javaProject.equals(javaProjectToInit)) {
+				if (paths == null) {
+					paths = new HashSet();
+					allContainerPaths.put(javaProject, paths);
+				}
+				paths.add(containerToInit);
+			}
+		}
+		
+		// mark all containers as being initialized
+		this.containerInitializationInProgress.set(allContainerPaths);
+		
+		// initialize all containers
+		boolean ok = false;
+		try {
+			Set keys = allContainerPaths.keySet();
+			int length = keys.size();
+			IJavaProject[] javaProjects = new IJavaProject[length]; // clone as the following will have a side effect
+			keys.toArray(javaProjects);
+			for (int i = 0; i < length; i++) {
+				IJavaProject javaProject = javaProjects[i];
+				HashSet pathSet = (HashSet) allContainerPaths.get(javaProject);
+				if (pathSet == null) continue;
+				int length2 = pathSet.size();
+				IPath[] paths = new IPath[length2];
+				pathSet.toArray(paths); // clone as the following will have a side effect
+				for (int j = 0; j < length2; j++) {
+					IPath path = paths[j];
+					initializeContainer(javaProject, path);
+				}
+			}
+			ok = true;
+		} finally {
+			if (!ok) { 
+				// if we're being traversed by an exception, ensure that that containers are 
+				// no longer marked as initialization in progress
+				// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=66437)
+				this.containerInitializationInProgress.set(null);
+			}
+		}
+		
+		return containerGet(javaProjectToInit, containerToInit);
+	}
+
+	private IClasspathContainer initializeContainer(IJavaProject project, IPath containerPath) throws JavaModelException {
+
+		IClasspathContainer container = null;
+		final ClasspathContainerInitializer initializer = JavaCore.getClasspathContainerInitializer(containerPath.segment(0));
+		if (initializer != null){
+			if (CP_RESOLVE_VERBOSE){
+				Util.verbose(
+					"CPContainer INIT - triggering initialization\n" + //$NON-NLS-1$
+					"	project: " + project.getElementName() + '\n' + //$NON-NLS-1$
+					"	container path: " + containerPath + '\n' + //$NON-NLS-1$
+					"	initializer: " + initializer + '\n' + //$NON-NLS-1$
+					"	invocation stack trace:"); //$NON-NLS-1$
+				new Exception("<Fake exception>").printStackTrace(System.out); //$NON-NLS-1$
+			}
+			containerPut(project, containerPath, CONTAINER_INITIALIZATION_IN_PROGRESS); // avoid initialization cycles
+			boolean ok = false;
+			try {
+				// let OperationCanceledException go through
+				// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=59363)
+				initializer.initialize(containerPath, project);
+				
+				// retrieve value (if initialization was successful)
+				container = containerGet(project, containerPath);
+				if (container == CONTAINER_INITIALIZATION_IN_PROGRESS) return null; // break cycle
+				ok = true;
+			} catch (CoreException e) {
+				if (e instanceof JavaModelException) {
+					throw (JavaModelException) e;
+				} else {
+					throw new JavaModelException(e);
+				}
+			} catch (RuntimeException e) {
+				if (JavaModelManager.CP_RESOLVE_VERBOSE) {
+					e.printStackTrace();
+				}
+				throw e;
+			} catch (Error e) {
+				if (JavaModelManager.CP_RESOLVE_VERBOSE) {
+					e.printStackTrace();
+				}
+				throw e;
+			} finally {
+				if (!ok) {
+					containerPut(project, containerPath, null); // flush cache
+					if (CP_RESOLVE_VERBOSE) {
+						if (container == CONTAINER_INITIALIZATION_IN_PROGRESS) {
+							Util.verbose(
+								"CPContainer INIT - FAILED (initializer did not initialize container)\n" + //$NON-NLS-1$
+								"	project: " + project.getElementName() + '\n' + //$NON-NLS-1$
+								"	container path: " + containerPath + '\n' + //$NON-NLS-1$
+								"	initializer: " + initializer); //$NON-NLS-1$
+							
+						} else {
+							Util.verbose(
+								"CPContainer INIT - FAILED (see exception above)\n" + //$NON-NLS-1$
+								"	project: " + project.getElementName() + '\n' + //$NON-NLS-1$
+								"	container path: " + containerPath + '\n' + //$NON-NLS-1$
+								"	initializer: " + initializer); //$NON-NLS-1$
+						}
+					}
+				}
+			}
+			if (CP_RESOLVE_VERBOSE){
+				StringBuffer buffer = new StringBuffer();
+				buffer.append("CPContainer INIT - after resolution\n"); //$NON-NLS-1$
+				buffer.append("	project: " + project.getElementName() + '\n'); //$NON-NLS-1$
+				buffer.append("	container path: " + containerPath + '\n'); //$NON-NLS-1$
+				if (container != null){
+					buffer.append("	container: "+container.getDescription()+" {\n"); //$NON-NLS-2$//$NON-NLS-1$
+					IClasspathEntry[] entries = container.getClasspathEntries();
+					if (entries != null){
+						for (int i = 0; i < entries.length; i++){
+							buffer.append("		" + entries[i] + '\n'); //$NON-NLS-1$
+						}
+					}
+					buffer.append("	}");//$NON-NLS-1$
+				} else {
+					buffer.append("	container: {unbound}");//$NON-NLS-1$
+				}
+				Util.verbose(buffer.toString());
+			}
+		} else {
+			if (CP_RESOLVE_VERBOSE){
+				Util.verbose(
+					"CPContainer INIT - no initializer found\n" + //$NON-NLS-1$
+					"	project: " + project.getElementName() + '\n' + //$NON-NLS-1$
+					"	container path: " + containerPath); //$NON-NLS-1$
+			}
+		}
+		return container;
+	}
+	
+	private HashSet getClasspathBeingResolved() {
+	    HashSet result = (HashSet) this.classpathsBeingResolved.get();
+	    if (result == null) {
+	        result = new HashSet();
+	        this.classpathsBeingResolved.set(result);
+	    }
+	    return result;
+	}
+	
+	public boolean isClasspathBeingResolved(IJavaProject project) {
+	    return getClasspathBeingResolved().contains(project);
+	}
+	
+	public void setClasspathBeingResolved(IJavaProject project, boolean classpathIsResolved) {
+	    if (classpathIsResolved) {
+	        getClasspathBeingResolved().add(project);
+	    } else {
+	        getClasspathBeingResolved().remove(project);
+	    }
+	}
 
 	public void loadVariablesAndContainers() throws CoreException {
 
@@ -1046,8 +1413,8 @@
 				String varName = propertyName.substring(variablePrefixLength);
 				IPath varPath = new Path(preferences.getString(propertyName).trim());
 				
-				Variables.put(varName, varPath); 
-				PreviousSessionVariables.put(varName, varPath);
+				this.variables.put(varName, varPath); 
+				this.previousSessionVariables.put(varName, varPath);
 			}
 			if (propertyName.startsWith(CP_CONTAINER_PREFERENCES_PREFIX)){
 				recreatePersistedContainer(propertyName, preferences.getString(propertyName), true/*add to container values*/);
@@ -1057,27 +1424,10 @@
 		String[] registeredVariables = getRegisteredVariableNames();
 		for (int i = 0; i < registeredVariables.length; i++) {
 			String varName = registeredVariables[i];
-			Variables.put(varName, null); // reset variable, but leave its entry in the Map, so it will be part of variable names.
+			this.variables.put(varName, null); // reset variable, but leave its entry in the Map, so it will be part of variable names.
 		}
 		// override persisted values for containers which have a registered initializer
-		String[] registeredContainerIDs = getRegisteredContainerIDs();
-		for (int i = 0; i < registeredContainerIDs.length; i++) {
-			String containerID = registeredContainerIDs[i];
-			Iterator projectIterator = Containers.keySet().iterator();
-			while (projectIterator.hasNext()){
-				IJavaProject project = (IJavaProject)projectIterator.next();
-				Map projectContainers = (Map)Containers.get(project);
-				if (projectContainers != null){
-					Iterator containerIterator = projectContainers.keySet().iterator();
-					while (containerIterator.hasNext()){
-						IPath containerPath = (IPath)containerIterator.next();
-						if (containerPath.segment(0).equals(containerID)) { // registered container
-							projectContainers.put(containerPath, null); // reset container value, but leave entry in Map
-						}
-					}
-				}
-			}
-		}
+		containersReset(getRegisteredContainerIDs());
 	}
 
 	/**
@@ -1109,16 +1459,20 @@
 	 * its ancestors). So returns without updating the cache.
 	 */
 	protected synchronized void putInfos(IJavaElement openedElement, Map newElements) {
-		while (openedElement != null) {
-			if (!newElements.containsKey(openedElement)) {
-				break;
+		// remove children
+		Object existingInfo = this.cache.peekAtInfo(openedElement);
+		if (openedElement instanceof IParent && existingInfo instanceof JavaElementInfo) {
+			IJavaElement[] children = ((JavaElementInfo)existingInfo).getChildren();
+			for (int i = 0, size = children.length; i < size; ++i) {
+				JavaElement child = (JavaElement) children[i];
+				try {
+					child.close();
+				} catch (JavaModelException e) {
+					// ignore
+				}
 			}
-			if (this.cache.peekAtInfo(openedElement) != null) {
-				return;
-			}
-			openedElement = openedElement.getParent();
 		}
-		
+	
 		Iterator iterator = newElements.keySet().iterator();
 		while (iterator.hasNext()) {
 			IJavaElement element = (IJavaElement)iterator.next();
@@ -1167,7 +1521,7 @@
 			final IPath containerPath = new Path(propertyName.substring(index+1).trim());
 			
 			if (containerString == null || containerString.equals(CP_ENTRY_IGNORE)) {
-				containerPut(project, containerPath, null);
+				getJavaModelManager().containerPut(project, containerPath, null);
 			} else {
 				final IClasspathEntry[] containerEntries = project.decodeClasspath(containerString, false, false);
 				if (containerEntries != null && containerEntries != JavaProject.INVALID_CLASSPATH) {
@@ -1190,12 +1544,12 @@
 
 					};
 					if (addToContainerValues) {
-						containerPut(project, containerPath, container);
+						getJavaModelManager().containerPut(project, containerPath, container);
 					}
-					Map projectContainers = (Map)PreviousSessionContainers.get(project);
+					Map projectContainers = (Map)getJavaModelManager().previousSessionContainers.get(project);
 					if (projectContainers == null){
 						projectContainers = new HashMap(1);
-						PreviousSessionContainers.put(project, projectContainers);
+						getJavaModelManager().previousSessionContainers.put(project, projectContainers);
 					}
 					projectContainers.put(containerPath, container);
 				}
@@ -1218,7 +1572,7 @@
 	 * Returns the info for the given element, or null if it was closed.
 	 */
 	public synchronized Object removeInfoAndChildren(JavaElement element) throws JavaModelException {
-		Object info = peekAtInfo(element);
+		Object info = this.cache.peekAtInfo(element);
 		if (info != null) {
 			boolean wasVerbose = false;
 			try {
@@ -1333,6 +1687,44 @@
 	 * @see ISaveParticipant
 	 */
 	public void saving(ISaveContext context) throws CoreException {
+		
+	    // save container values on snapshot/full save
+		Preferences preferences = JavaCore.getPlugin().getPluginPreferences();
+		IJavaProject[] projects = getJavaModel().getJavaProjects();
+		for (int i = 0, length = projects.length; i < length; i++) {
+		    IJavaProject project = projects[i];
+			// clone while iterating (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=59638)
+			Map projectContainers = containerClone(project);
+			if (projectContainers == null) continue;
+			for (Iterator keys = projectContainers.keySet().iterator(); keys.hasNext();) {
+			    IPath containerPath = (IPath) keys.next();
+			    IClasspathContainer container = (IClasspathContainer) projectContainers.get(containerPath);
+				String containerKey = CP_CONTAINER_PREFERENCES_PREFIX+project.getElementName() +"|"+containerPath;//$NON-NLS-1$
+				String containerString = CP_ENTRY_IGNORE;
+				try {
+					if (container != null) {
+						containerString = ((JavaProject)project).encodeClasspath(container.getClasspathEntries(), null, false);
+					}
+				} catch(JavaModelException e){
+					// could not encode entry: leave it as CP_ENTRY_IGNORE
+				}
+				preferences.setDefault(containerKey, CP_ENTRY_IGNORE); // use this default to get rid of removed ones
+				preferences.setValue(containerKey, containerString);
+			}
+		}
+		JavaCore.getPlugin().savePluginPreferences();
+		
+		if (context.getKind() == ISaveContext.FULL_SAVE) {
+			// will need delta since this save (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=38658)
+			context.needDelta();
+			
+			// clean up indexes on workspace full save
+			// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=52347)
+			IndexManager manager = this.indexManager;
+			if (manager != null) {
+				manager.cleanUpIndexes();
+			}
+		}
 	
 		IProject savedProject = context.getProject();
 		if (savedProject != null) {
@@ -1443,14 +1835,186 @@
 		// Note: no need to close the Java model as this just removes Java element infos from the Java model cache
 	}
 		
-	public static IPath variableGet(String variableName){
-		return (IPath)Variables.get(variableName);
+	public synchronized IPath variableGet(String variableName){
+		// check initialization in progress first
+		HashSet initializations = variableInitializationInProgress();
+		if (initializations.contains(variableName)) {
+			return VARIABLE_INITIALIZATION_IN_PROGRESS;
+		}
+		return (IPath)this.variables.get(variableName);
 	}
 
-	public static String[] variableNames(){
-		int length = Variables.size();
+	/*
+	 * Internal updating of a variable values (null path meaning removal), allowing to change multiple variable values at once.
+	 */
+	public void updateVariableValues(
+		String[] variableNames,
+		IPath[] variablePaths,
+		IProgressMonitor monitor) throws JavaModelException {
+	
+		if (monitor != null && monitor.isCanceled()) return;
+		
+		if (CP_RESOLVE_VERBOSE){
+			Util.verbose(
+				"CPVariable SET  - setting variables\n" + //$NON-NLS-1$
+				"	variables: " + org.eclipse.jdt.internal.compiler.util.Util.toString(variableNames) + '\n' +//$NON-NLS-1$
+				"	values: " + org.eclipse.jdt.internal.compiler.util.Util.toString(variablePaths)); //$NON-NLS-1$
+		}
+
+		int varLength = variableNames.length;
+		
+		// gather classpath information for updating
+		final HashMap affectedProjectClasspaths = new HashMap(5);
+		IJavaModel model = getJavaModel();
+	
+		// filter out unmodified variables
+		int discardCount = 0;
+		for (int i = 0; i < varLength; i++){
+			String variableName = variableNames[i];
+			IPath oldPath = this.variableGet(variableName); // if reentering will provide previous session value 
+			if (oldPath == VARIABLE_INITIALIZATION_IN_PROGRESS){
+//				IPath previousPath = (IPath)this.previousSessionVariables.get(variableName);
+//				if (previousPath != null){
+//					if (CP_RESOLVE_VERBOSE){
+//						Util.verbose(
+//							"CPVariable INIT - reentering access to variable during its initialization, will see previous value\n" + //$NON-NLS-1$
+//							"	variable: "+ variableName + '\n' + //$NON-NLS-1$
+//							"	previous value: " + previousPath); //$NON-NLS-1$
+//					}
+//					this.variablePut(variableName, previousPath); // replace value so reentering calls are seeing old value
+//				}
+				oldPath = null;  //33695 - cannot filter out restored variable, must update affected project to reset cached CP
+			}
+			if (oldPath != null && oldPath.equals(variablePaths[i])){
+				variableNames[i] = null;
+				discardCount++;
+			}
+		}
+		if (discardCount > 0){
+			if (discardCount == varLength) return;
+			int changedLength = varLength - discardCount;
+			String[] changedVariableNames = new String[changedLength];
+			IPath[] changedVariablePaths = new IPath[changedLength];
+			for (int i = 0, index = 0; i < varLength; i++){
+				if (variableNames[i] != null){
+					changedVariableNames[index] = variableNames[i];
+					changedVariablePaths[index] = variablePaths[i];
+					index++;
+				}
+			}
+			variableNames = changedVariableNames;
+			variablePaths = changedVariablePaths;
+			varLength = changedLength;
+		}
+		
+		if (monitor != null && monitor.isCanceled()) return;
+
+		if (model != null) {
+			IJavaProject[] projects = model.getJavaProjects();
+			nextProject : for (int i = 0, projectLength = projects.length; i < projectLength; i++){
+				JavaProject project = (JavaProject) projects[i];
+						
+				// check to see if any of the modified variables is present on the classpath
+				IClasspathEntry[] classpath = project.getRawClasspath();
+				for (int j = 0, cpLength = classpath.length; j < cpLength; j++){
+					
+					IClasspathEntry entry = classpath[j];
+					for (int k = 0; k < varLength; k++){
+	
+						String variableName = variableNames[k];						
+						if (entry.getEntryKind() ==  IClasspathEntry.CPE_VARIABLE){
+	
+							if (variableName.equals(entry.getPath().segment(0))){
+								affectedProjectClasspaths.put(project, project.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/));
+								continue nextProject;
+							}
+							IPath sourcePath, sourceRootPath;
+							if (((sourcePath = entry.getSourceAttachmentPath()) != null	&& variableName.equals(sourcePath.segment(0)))
+								|| ((sourceRootPath = entry.getSourceAttachmentRootPath()) != null	&& variableName.equals(sourceRootPath.segment(0)))) {
+	
+								affectedProjectClasspaths.put(project, project.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/));
+								continue nextProject;
+							}
+						}												
+					}
+				}
+			}
+		}
+		// update variables
+		for (int i = 0; i < varLength; i++){
+			this.variablePut(variableNames[i], variablePaths[i]);
+		}
+		final String[] dbgVariableNames = variableNames;
+				
+		// update affected project classpaths
+		if (!affectedProjectClasspaths.isEmpty()) {
+			try {
+				final boolean canChangeResources = !ResourcesPlugin.getWorkspace().isTreeLocked();
+				JavaCore.run(
+					new IWorkspaceRunnable() {
+						public void run(IProgressMonitor progressMonitor) throws CoreException {
+							// propagate classpath change
+							Iterator projectsToUpdate = affectedProjectClasspaths.keySet().iterator();
+							while (projectsToUpdate.hasNext()) {
+			
+								if (progressMonitor != null && progressMonitor.isCanceled()) return;
+			
+								JavaProject affectedProject = (JavaProject) projectsToUpdate.next();
+
+								if (CP_RESOLVE_VERBOSE){
+									Util.verbose(
+										"CPVariable SET  - updating affected project due to setting variables\n" + //$NON-NLS-1$
+										"	project: " + affectedProject.getElementName() + '\n' + //$NON-NLS-1$
+										"	variables: " + org.eclipse.jdt.internal.compiler.util.Util.toString(dbgVariableNames)); //$NON-NLS-1$
+								}
+
+								affectedProject
+									.setRawClasspath(
+										affectedProject.getRawClasspath(),
+										SetClasspathOperation.ReuseOutputLocation,
+										null, // don't call beginTask on the monitor (see http://bugs.eclipse.org/bugs/show_bug.cgi?id=3717)
+										canChangeResources, 
+										(IClasspathEntry[]) affectedProjectClasspaths.get(affectedProject),
+										false, // updating - no need for early validation
+										false); // updating - no need to save
+							}
+						}
+					},
+					null/*no need to lock anything*/,
+					monitor);
+			} catch (CoreException e) {
+				if (CP_RESOLVE_VERBOSE){
+					Util.verbose(
+						"CPVariable SET  - FAILED DUE TO EXCEPTION\n" + //$NON-NLS-1$
+						"	variables: " + org.eclipse.jdt.internal.compiler.util.Util.toString(dbgVariableNames), //$NON-NLS-1$
+						System.err); 
+					e.printStackTrace();
+				}
+				if (e instanceof JavaModelException) {
+					throw (JavaModelException)e;
+				} else {
+					throw new JavaModelException(e);
+				}
+			}
+		}
+	}
+	
+	/*
+	 * Returns the set of variable names that are being initialized in the current thread.
+	 */
+	private HashSet variableInitializationInProgress() {
+		HashSet initializations = (HashSet)this.variableInitializationInProgress.get();
+		if (initializations == null) {
+			initializations = new HashSet();
+			this.variableInitializationInProgress.set(initializations);
+		}
+		return initializations;
+	}
+
+	public synchronized String[] variableNames(){
+		int length = this.variables.size();
 		String[] result = new String[length];
-		Iterator vars = Variables.keySet().iterator();
+		Iterator vars = this.variables.keySet().iterator();
 		int index = 0;
 		while (vars.hasNext()) {
 			result[index++] = (String) vars.next();
@@ -1458,20 +2022,28 @@
 		return result;
 	}
 	
-	public static void variablePut(String variableName, IPath variablePath){		
+	public synchronized void variablePut(String variableName, IPath variablePath){		
 
-		// update cache - do not only rely on listener refresh		
-		if (variablePath == null) {
-			Variables.remove(variableName);
-			PreviousSessionVariables.remove(variableName);
+		// set/unset the initialization in progress
+		HashSet initializations = variableInitializationInProgress();
+		if (variablePath == VARIABLE_INITIALIZATION_IN_PROGRESS) {
+			initializations.add(variableName);
+			
+			// do not write out intermediate initialization value
+			return;
 		} else {
-			Variables.put(variableName, variablePath);
+			initializations.remove(variableName);
+
+			// update cache - do not only rely on listener refresh		
+			if (variablePath == null) {
+				this.variables.remove(variableName);
+			} else {
+				this.variables.put(variableName, variablePath);
+			}
+			// discard obsoleted information about previous session
+			this.previousSessionVariables.remove(variableName);
 		}
 
-		// do not write out intermediate initialization value
-		if (variablePath == JavaModelManager.VariableInitializationInProgress){
-			return;
-		} 
 		Preferences preferences = JavaCore.getPlugin().getPluginPreferences();
 		String variableKey = CP_VARIABLE_PREFERENCES_PREFIX+variableName;
 		String variableString = variablePath == null ? CP_ENTRY_IGNORE : variablePath.toString();
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelOperation.java
index 16a6eb8..5ff5392 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -16,6 +16,7 @@
 
 import org.eclipse.core.resources.*;
 import org.eclipse.core.runtime.*;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.internal.core.util.Util;
 
@@ -348,28 +349,13 @@
 		return false;
 	}
 	/**
-	 * Verifies the operation can proceed and executes the operation.
-	 * Subclasses should override <code>#verify</code> and
-	 * <code>executeOperation</code> to implement the specific operation behavior.
-	 *
-	 * @exception JavaModelException The operation has failed.
-	 */
-	protected void execute() throws JavaModelException {
-		IJavaModelStatus status= verify();
-		if (status.isOK()) {
-			// computes the root infos before executing the operation
-			// noop if aready initialized
-			JavaModelManager.getJavaModelManager().deltaState.initializeRoots();
-
-			executeOperation();
-		} else {
-			throw new JavaModelException(status);
-		}
-	}
-	/**
 	 * Convenience method to run an operation within this operation
 	 */
 	public void executeNestedOperation(JavaModelOperation operation, int subWorkAmount) throws JavaModelException {
+		IJavaModelStatus status= operation.verify();
+		if (!status.isOK()) {
+			throw new JavaModelException(status);
+		}
 		IProgressMonitor subProgressMonitor = getSubProgressMonitor(subWorkAmount);
 		// fix for 1FW7IKC, part (1)
 		try {
@@ -496,6 +482,14 @@
 	public IJavaElement[] getResultElements() {
 		return resultElements;
 	}
+	/*
+	 * Returns the scheduling rule for this operation (i.e. the resource that needs to be locked 
+	 * while this operation is running.
+	 * Subclasses can override.
+	 */
+	protected ISchedulingRule getSchedulingRule() {
+		return ResourcesPlugin.getWorkspace().getRoot();
+	}
 	/**
 	 * Creates and returns a subprogress monitor if appropriate.
 	 */
@@ -686,8 +680,7 @@
 	}
 	
 	/**
-	 * Main entry point for Java Model operations.  Executes this operation
-	 * and registers any deltas created.
+	 * Runs this operation and registers any deltas created.
 	 *
 	 * @see IWorkspaceRunnable
 	 * @exception CoreException if the operation fails
@@ -700,7 +693,11 @@
 			progressMonitor = monitor;
 			pushOperation(this);
 			try {
-				this.execute();
+				// computes the root infos before executing the operation
+				// noop if aready initialized
+				JavaModelManager.getJavaModelManager().deltaState.initializeRoots();
+				
+				executeOperation();
 			} finally {
 				if (this.isTopLevelOperation()) {
 					this.runPostActions();
@@ -728,6 +725,38 @@
 			}
 		}
 	}
+	/**
+	 * Main entry point for Java Model operations. Runs a Java Model Operation as an IWorkspaceRunnable
+	 * if not read-only.
+	 */
+	public void runOperation(IProgressMonitor monitor) throws JavaModelException {
+		IJavaModelStatus status= verify();
+		if (!status.isOK()) {
+			throw new JavaModelException(status);
+		}
+		try {
+			if (isReadOnly()) {
+				run(monitor);
+			} else {
+				// Use IWorkspace.run(...) to ensure that a build will be done in autobuild mode.
+				// Note that if the tree is locked, this will throw a CoreException, but this is ok
+				// as this operation is modifying the tree (not read-only) and a CoreException will be thrown anyway.
+				ResourcesPlugin.getWorkspace().run(this, getSchedulingRule(), IWorkspace.AVOID_UPDATE, monitor);
+			}
+		} catch (CoreException ce) {
+			if (ce instanceof JavaModelException) {
+				throw (JavaModelException)ce;
+			} else {
+				if (ce.getStatus().getCode() == IResourceStatus.OPERATION_FAILED) {
+					Throwable e= ce.getStatus().getException();
+					if (e instanceof JavaModelException) {
+						throw (JavaModelException) e;
+					}
+				}
+				throw new JavaModelException(ce);
+			}
+		}
+	}
 	protected void runPostActions() throws JavaModelException {
 		while (this.actionsStart <= this.actionsEnd) {
 			IPostAction postAction = this.actions[this.actionsStart++];
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelStatus.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelStatus.java
index d116030..8ccf7cb 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelStatus.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelStatus.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -336,7 +336,7 @@
 				if (path.segment(0).toString().equals(projectName)) {
 					newPath = path.removeFirstSegments(1);
 				}
-				return Util.bind("classpath.disabledExclusionPatterns", newPath.makeRelative().toString(), projectName); //$NON-NLS-1$
+				return Util.bind("classpath.disabledInclusionExclusionPatterns", newPath.makeRelative().toString(), projectName); //$NON-NLS-1$
 
 			case DISABLED_CP_MULTIPLE_OUTPUT_LOCATIONS:
 				javaProject = (IJavaProject)elements[0];
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java
index 5e59741..8cd77f4 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -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;
@@ -69,10 +68,10 @@
 import org.eclipse.jdt.core.WorkingCopyOwner;
 import org.eclipse.jdt.core.eval.IEvaluationContext;
 import org.eclipse.jdt.internal.codeassist.ISearchableNameEnvironment;
-import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 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;
@@ -135,6 +134,11 @@
 
 	private static final String CUSTOM_DEFAULT_OPTION_VALUE = "#\r\n\r#custom-non-empty-default-value#\r\n\r#"; //$NON-NLS-1$
 	
+	/*
+	 * Value of project's resolved classpath while it is being resolved
+	 */
+	private static final IClasspathEntry[] RESOLUTION_IN_PROGRESS = new IClasspathEntry[0];
+	
 	/**
 	 * Returns a canonicalized path from the given external path.
 	 * Note that the return path contains the same number of segments
@@ -235,9 +239,9 @@
 	protected void addToBuildSpec(String builderID) throws CoreException {
 
 		IProjectDescription description = this.project.getDescription();
-		ICommand javaCommand = getJavaCommand(description);
+		int javaCommandIndex = getJavaCommandIndex(description.getBuildSpec());
 
-		if (javaCommand == null) {
+		if (javaCommandIndex == -1) {
 
 			// Add a Java command to the build spec
 			ICommand command = description.newCommand();
@@ -259,11 +263,11 @@
 		IWorkspace workspace = ResourcesPlugin.getWorkspace();
 		IWorkspaceRoot wRoot = workspace.getRoot();
 		// cannot refresh cp markers on opening (emulate cp check on startup) since can create deadlocks (see bug 37274)
-		IClasspathEntry[] resolvedClasspath = getResolvedClasspath(true/*ignore unresolved variable*/);
+		IClasspathEntry[] resolvedClasspath = getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
 
 		// compute the pkg fragment roots
-		computeChildren((JavaProjectElementInfo)info);				
-
+		info.setChildren(computePackageFragmentRoots(resolvedClasspath, false));	
+		
 		// remember the timestamps of external libraries the first time they are looked up
 		for (int i = 0, length = resolvedClasspath.length; i < length; i++) {
 			IClasspathEntry entry = resolvedClasspath[i];
@@ -302,10 +306,9 @@
 	 * @throws JavaModelException
 	 */
 	public void computeChildren(JavaProjectElementInfo info) throws JavaModelException {
-		IClasspathEntry[] classpath = getResolvedClasspath(true);
-		NameLookup lookup = info.getNameLookup();
-		if (lookup != null){
-			IPackageFragmentRoot[] oldRoots = lookup.fPackageFragmentRoots;
+		IClasspathEntry[] classpath = getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
+		IPackageFragmentRoot[] oldRoots = info.allPkgFragmentRootsCache;
+		if (oldRoots != null) {
 			IPackageFragmentRoot[] newRoots = computePackageFragmentRoots(classpath, true);
 			checkIdentical: { // compare all pkg fragment root lists
 				if (oldRoots.length == newRoots.length){
@@ -317,8 +320,8 @@
 					return; // no need to update
 				}	
 			}
-			info.setNameLookup(null); // discard name lookup (hold onto roots)
-		}				
+		}
+		info.resetCaches(); // discard caches (hold onto roots and pkg fragments)
 		info.setNonJavaResources(null);
 		info.setChildren(
 			computePackageFragmentRoots(classpath, false));		
@@ -334,28 +337,33 @@
 		JavaProject initialProject, 
 		boolean ignoreUnresolvedVariable,
 		boolean generateMarkerOnError,
-		HashSet visitedProjects, 
+		HashSet rootIDs,
 		ObjectVector accumulatedEntries,
 		Map preferredClasspaths,
 		Map preferredOutputs) throws JavaModelException {
 		
-		if (visitedProjects.contains(this)){
+		String projectRootId = this.rootID();
+		if (rootIDs.contains(projectRootId)){
 			return; // break cycles if any
 		}
-		visitedProjects.add(this);
+		rootIDs.add(projectRootId);
 
 		IClasspathEntry[] preferredClasspath = preferredClasspaths != null ? (IClasspathEntry[])preferredClasspaths.get(this) : null;
 		IPath preferredOutput = preferredOutputs != null ? (IPath)preferredOutputs.get(this) : null;
 		IClasspathEntry[] immediateClasspath = 
 			preferredClasspath != null 
 				? getResolvedClasspath(preferredClasspath, preferredOutput, ignoreUnresolvedVariable, generateMarkerOnError, null)
-				: getResolvedClasspath(ignoreUnresolvedVariable, generateMarkerOnError);
+				: getResolvedClasspath(ignoreUnresolvedVariable, generateMarkerOnError, false/*don't returnResolutionInProgress*/);
 			
 		IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
 		boolean isInitialProject = this.equals(initialProject);
 		for (int i = 0, length = immediateClasspath.length; i < length; i++){
-			IClasspathEntry entry = immediateClasspath[i];
+			ClasspathEntry entry = (ClasspathEntry) immediateClasspath[i];
 			if (isInitialProject || entry.isExported()){
+				String rootID = entry.rootID();
+				if (rootIDs.contains(rootID)) {
+					continue;
+				}
 				
 				accumulatedEntries.add(entry);
 				
@@ -370,12 +378,14 @@
 								initialProject, 
 								ignoreUnresolvedVariable, 
 								false /* no marker when recursing in prereq*/,
-								visitedProjects, 
+								rootIDs,
 								accumulatedEntries,
 								preferredClasspaths,
 								preferredOutputs);
 						}
 					}
+				} else {
+					rootIDs.add(rootID);
 				}
 			}			
 		}
@@ -523,7 +533,7 @@
 						rootIDs.add(rootID);
 						JavaProject requiredProject = (JavaProject)JavaCore.create(requiredProjectRsc);
 						requiredProject.computePackageFragmentRoots(
-							requiredProject.getResolvedClasspath(true), 
+							requiredProject.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/), 
 							accumulatedRoots, 
 							rootIDs, 
 							false, 
@@ -598,7 +608,7 @@
 		IClasspathEntry[] classpath;
 		IPath output;
 		try {
-			classpath = getResolvedClasspath(true);
+			classpath = getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
 			output = getOutputLocation();
 		} catch (JavaModelException e) {
 			return false;
@@ -716,8 +726,9 @@
 			);
 		} catch (CoreException e) {
 			// could not create marker: cannot do much
-			// TODO (jerome) print stack trace in VERBOSE mode only
-			e.printStackTrace();
+			if (JavaModelManager.VERBOSE) {
+				e.printStackTrace();
+			}
 		}
 	}
 	
@@ -891,8 +902,7 @@
 	}
 
 	public boolean exists() {
-		if (!hasJavaNature(this.project)) return false;
-		return super.exists();
+		return hasJavaNature(this.project);
 	}	
 
 	/**
@@ -917,8 +927,8 @@
 			if (extension == null) {
 				String packageName = path.toString().replace(IPath.SEPARATOR, '.');
 
-				IPackageFragment[] pkgFragments =
-					getNameLookup().findPackageFragments(packageName, false);
+				NameLookup lookup = newNameLookup((WorkingCopyOwner)null/*no need to look at working copies for pkgs*/);
+				IPackageFragment[] pkgFragments = lookup.findPackageFragments(packageName, false);
 				if (pkgFragments == null) {
 					return null;
 
@@ -947,25 +957,14 @@
 				} else {
 					qualifiedName = typeName;
 				}
-				IType type = null;
-				NameLookup lookup = null;
-				try {
-					// set units to look inside
-					lookup = getNameLookup();
-					JavaModelManager manager = JavaModelManager.getJavaModelManager();
-					ICompilationUnit[] workingCopies = manager.getWorkingCopies(owner, true/*add primary WCs*/);
-					lookup.setUnitsToLookInside(workingCopies);
-					
-					// lookup type
-					type = lookup.findType(
-						qualifiedName,
-						false,
-						NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES);
-				} finally {
-					if (lookup != null) {
-						lookup.setUnitsToLookInside(null);
-					}
-				}
+
+				// lookup type
+				NameLookup lookup = newNameLookup(owner);
+				IType type = lookup.findType(
+					qualifiedName,
+					false,
+					NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES);
+
 				if (type != null) {
 					return type.getParent();
 				} else {
@@ -997,10 +996,11 @@
 	/*
 	 * non path canonicalizing version
 	 */
-	public IPackageFragment findPackageFragment0(IPath path) 
+	private IPackageFragment findPackageFragment0(IPath path) 
 		throws JavaModelException {
 
-		return getNameLookup().findPackageFragment(path);
+		NameLookup lookup = newNameLookup((WorkingCopyOwner)null/*no need to look at working copies for pkgs*/);
+		return lookup.findPackageFragment(path);
 	}
 
 	/**
@@ -1062,25 +1062,11 @@
 	 */
 	public IType findType(String fullyQualifiedName, WorkingCopyOwner owner) throws JavaModelException {
 		
-		IType type = null;
-		NameLookup lookup = null;
-		try {
-			// set units to look inside
-			lookup = getNameLookup();
-			JavaModelManager manager = JavaModelManager.getJavaModelManager();
-			ICompilationUnit[] workingCopies = manager.getWorkingCopies(owner, true/*add primary WCs*/);
-			lookup.setUnitsToLookInside(workingCopies);
-			
-			// lookup type
-			type = lookup.findType(
-				fullyQualifiedName,
-				false,
-				NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES);
-		} finally {
-			if (lookup != null) {
-				lookup.setUnitsToLookInside(null);
-			}
-		}
+		NameLookup lookup = newNameLookup(owner);
+		IType type = lookup.findType(
+			fullyQualifiedName,
+			false,
+			NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES);
 		if (type == null) {
 			// try to find enclosing type
 			int lastDot = fullyQualifiedName.lastIndexOf('.');
@@ -1107,25 +1093,12 @@
 	 * @see IJavaProject#findType(String, String, WorkingCopyOwner)
 	 */
 	public IType findType(String packageName, String typeQualifiedName, WorkingCopyOwner owner) throws JavaModelException {
-		NameLookup lookup = null;
-		try {
-			// set units to look inside
-			lookup = getNameLookup();
-			JavaModelManager manager = JavaModelManager.getJavaModelManager();
-			ICompilationUnit[] workingCopies = manager.getWorkingCopies(owner, true/*add primary WCs*/);
-			lookup.setUnitsToLookInside(workingCopies);
-			
-			// lookup type
-			return lookup.findType(
-				typeQualifiedName, 
-				packageName,
-				false,
-				NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES);
-		} finally {
-			if (lookup != null) {
-				lookup.setUnitsToLookInside(null);
-			}
-		}
+		NameLookup lookup = newNameLookup(owner);
+		return lookup.findType(
+			typeQualifiedName, 
+			packageName,
+			false,
+			NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES);
 	}	
 	
 	/**
@@ -1151,8 +1124,9 @@
 			}
 		} catch (CoreException e) {
 			// could not flush markers: not much we can do
-			// TODO (jerome) print stack trace in VERBOSE mode only
-			e.printStackTrace();
+			if (JavaModelManager.VERBOSE) {
+				e.printStackTrace();
+			}
 		}
 	}
 
@@ -1222,7 +1196,7 @@
 				outputLocation, 
 				monitor, 
 				!ResourcesPlugin.getWorkspace().isTreeLocked(), // canChangeResource
-				oldResolvedClasspath != null ? oldResolvedClasspath : getResolvedClasspath(true), // ignoreUnresolvedVariable
+				oldResolvedClasspath != null ? oldResolvedClasspath : getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/),
 				true, // needValidation
 				false); // no need to save
 			
@@ -1268,7 +1242,7 @@
 	public IPackageFragmentRoot[] getAllPackageFragmentRoots()
 		throws JavaModelException {
 
-		return computePackageFragmentRoots(getResolvedClasspath(true), true);
+		return computePackageFragmentRoots(getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/), true/*retrieveExportedRoots*/);
 	}
 
 	/**
@@ -1360,7 +1334,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);
@@ -1396,17 +1370,17 @@
 	}
 
 	/**
-	 * Find the specific Java command amongst the build spec of a given description
+	 * Find the specific Java command amongst the given build spec
+	 * and return its index or -1 if not found.
 	 */
-	private ICommand getJavaCommand(IProjectDescription description) {
+	private int getJavaCommandIndex(ICommand[] buildSpec) {
 
-		ICommand[] commands = description.getBuildSpec();
-		for (int i = 0; i < commands.length; ++i) {
-			if (commands[i].getBuilderName().equals(JavaCore.BUILDER_ID)) {
-				return commands[i];
+		for (int i = 0; i < buildSpec.length; ++i) {
+			if (buildSpec[i].getBuilderName().equals(JavaCore.BUILDER_ID)) {
+				return i;
 			}
 		}
-		return null;
+		return -1;
 	}
 
 	/**
@@ -1419,23 +1393,6 @@
 	}
 
 	/**
-	 * @return NameLookup
-	 * @throws JavaModelException
-	 */
-	public NameLookup getNameLookup() throws JavaModelException {
-
-		JavaProjectElementInfo info = getJavaProjectElementInfo();
-		// lock on the project info to avoid race condition
-		synchronized(info){
-			NameLookup nameLookup;
-			if ((nameLookup = info.getNameLookup()) == null){
-				info.setNameLookup(nameLookup = new NameLookup(this));
-			}
-			return nameLookup;
-		}
-	}
-
-	/**
 	 * Returns an array of non-java resources contained in the receiver.
 	 */
 	public Object[] getNonJavaResources() throws JavaModelException {
@@ -1449,7 +1406,7 @@
 	public String getOption(String optionName, boolean inheritJavaCoreOptions) {
 		
 		String propertyName = optionName;
-		if (JavaModelManager.OptionNames.contains(propertyName)){
+		if (JavaModelManager.getJavaModelManager().optionNames.contains(propertyName)){
 			Preferences preferences = getPreferences();
 			if (preferences == null || preferences.isDefault(propertyName)) {
 				return inheritJavaCoreOptions ? JavaCore.getOption(propertyName) : null;
@@ -1469,18 +1426,10 @@
 
 		Preferences preferences = getPreferences();
 		if (preferences == null) return options; // cannot do better (non-Java project)
-		HashSet optionNames = JavaModelManager.OptionNames;
+		HashSet optionNames = JavaModelManager.getJavaModelManager().optionNames;
 		
-		// get preferences set to their default
-		if (inheritJavaCoreOptions){
-			String[] defaultPropertyNames = preferences.defaultPropertyNames();
-			for (int i = 0; i < defaultPropertyNames.length; i++){
-				String propertyName = defaultPropertyNames[i];
-				if (optionNames.contains(propertyName)){
-					options.put(propertyName, preferences.getDefaultString(propertyName).trim());
-				}
-			}		
-		}
+		// project cannot hold custom preferences set to their default, as it uses CUSTOM_DEFAULT_OPTION_VALUE
+
 		// get custom preferences not set to their default
 		String[] propertyNames = preferences.propertyNames();
 		for (int i = 0; i < propertyNames.length; i++){
@@ -1488,37 +1437,12 @@
 			String value = preferences.getString(propertyName).trim();
 			if (optionNames.contains(propertyName)){
 				options.put(propertyName, value);
-			}		
-			// bug 45112 backward compatibility.
-			// TODO (frederic) remove after 3.0 M6
-			else if (CompilerOptions.OPTION_ReportInvalidAnnotation.equals(propertyName)) {
-				options.put(JavaCore.COMPILER_PB_INVALID_JAVADOC, value);
 			}
-			else if (CompilerOptions.OPTION_ReportMissingAnnotation.equals(propertyName)) {
-				if (JavaCore.ENABLED.equals(value)) {
-					value = preferences.getString(JavaCore.COMPILER_PB_INVALID_JAVADOC);
-				} else {
-					value = JavaCore.IGNORE;
-				}
-				options.put(JavaCore.COMPILER_PB_MISSING_JAVADOC_COMMENTS, value);
-			}
-			// end bug 45112
-			// bug 46854 backward compatibility
-			// TODO (frederic) remove after 3.0 M7
-			else if (CompilerOptions.OPTION_ReportMissingJavadoc.equals(propertyName)) {
-				if (JavaCore.ENABLED.equals(value)) {
-					value = preferences.getString(JavaCore.COMPILER_PB_INVALID_JAVADOC);
-				} else {
-					value = JavaCore.IGNORE;
-				}
-				options.put(JavaCore.COMPILER_PB_MISSING_JAVADOC_COMMENTS, value);
-			}
-			// end bug 46854
 		}		
 
 		return options;
 	}
-	
+
 	/**
 	 * @see IJavaProject
 	 */
@@ -1802,7 +1726,7 @@
 	 */
 	public String[] getRequiredProjectNames() throws JavaModelException {
 
-		return this.projectPrerequisites(getResolvedClasspath(true));
+		return this.projectPrerequisites(getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/));
 	}
 
 	/**
@@ -1812,40 +1736,74 @@
 		throws JavaModelException {
 
 		return 
-			this.getResolvedClasspath(
+			getResolvedClasspath(
 				ignoreUnresolvedEntry, 
-				false); // generateMarkerOnError
+				false, // don't generateMarkerOnError
+				true // returnResolutionInProgress
+			);
 	}
 
 	/**
+	 * @see IJavaProject
+	 */
+	public IClasspathEntry[] getResolvedClasspath(boolean ignoreUnresolvedEntry, boolean generateMarkerOnError)
+		throws JavaModelException {
+
+		return 
+			getResolvedClasspath(
+				ignoreUnresolvedEntry, 
+				generateMarkerOnError,
+				true // returnResolutionInProgress
+			);
+	}
+
+	/*
 	 * Internal variant which can create marker on project for invalid entries
-	 * and caches the resolved classpath on perProjectInfo
-	 * @param ignoreUnresolvedEntry boolean
-	 * @param generateMarkerOnError boolean
-	 * @return IClasspathEntry[]
-	 * @throws JavaModelException
+	 * and caches the resolved classpath on perProjectInfo.
+	 * If requested, return a special classpath (RESOLUTION_IN_PROGRESS) if the classpath is being resolved.
 	 */
 	public IClasspathEntry[] getResolvedClasspath(
 		boolean ignoreUnresolvedEntry,
-		boolean generateMarkerOnError)
+		boolean generateMarkerOnError,
+		boolean returnResolutionInProgress)
 		throws JavaModelException {
 
+	    JavaModelManager manager = JavaModelManager.getJavaModelManager();
 		JavaModelManager.PerProjectInfo perProjectInfo = null;
 		if (ignoreUnresolvedEntry && !generateMarkerOnError) {
 			perProjectInfo = getPerProjectInfo();
 			if (perProjectInfo != null) {
 				// resolved path is cached on its info
 				IClasspathEntry[] infoPath = perProjectInfo.resolvedClasspath;
-				if (infoPath != null) return infoPath;
+				if (infoPath != null) {
+					return infoPath;
+				} else if  (returnResolutionInProgress && manager.isClasspathBeingResolved(this)) {
+					if (JavaModelManager.CP_RESOLVE_VERBOSE) {
+						Util.verbose(
+							"CPResolution: reentering raw classpath resolution, will use empty classpath instead" + //$NON-NLS-1$
+							"	project: " + getElementName() + '\n' + //$NON-NLS-1$
+							"	invocation stack trace:"); //$NON-NLS-1$
+						new Exception("<Fake exception>").printStackTrace(System.out); //$NON-NLS-1$
+					}						
+				    return RESOLUTION_IN_PROGRESS;
+				}
 			}
 		}
 		Map reverseMap = perProjectInfo == null ? null : new HashMap(5);
-		IClasspathEntry[] resolvedPath = getResolvedClasspath(
-			getRawClasspath(generateMarkerOnError, !generateMarkerOnError), 
-			generateMarkerOnError ? getOutputLocation() : null, 
-			ignoreUnresolvedEntry, 
-			generateMarkerOnError,
-			reverseMap);
+		IClasspathEntry[] resolvedPath = null;
+		boolean nullOldResolvedCP = perProjectInfo != null && perProjectInfo.resolvedClasspath == null;
+		try {
+			// protect against misbehaving clients (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=61040)
+			if (nullOldResolvedCP) manager.setClasspathBeingResolved(this, true);
+			resolvedPath = getResolvedClasspath(
+				getRawClasspath(generateMarkerOnError, !generateMarkerOnError), 
+				generateMarkerOnError ? getOutputLocation() : null, 
+				ignoreUnresolvedEntry, 
+				generateMarkerOnError,
+				reverseMap);
+		} finally {
+			if (nullOldResolvedCP) perProjectInfo.resolvedClasspath = null;
+		}
 
 		if (perProjectInfo != null){
 			if (perProjectInfo.rawClasspath == null // .classpath file could not be read
@@ -1856,10 +1814,11 @@
 					this.createClasspathProblemMarker(new JavaModelStatus(
 						IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
 						Util.bind("classpath.cannotReadClasspathFile", this.getElementName()))); //$NON-NLS-1$
-				}
+			}
 
 			perProjectInfo.resolvedClasspath = resolvedPath;
 			perProjectInfo.resolvedPathToRawEntries = reverseMap;
+			manager.setClasspathBeingResolved(this, false);
 		}
 		return resolvedPath;
 	}
@@ -1906,7 +1865,16 @@
 				
 				case IClasspathEntry.CPE_VARIABLE :
 				
-					IClasspathEntry resolvedEntry = JavaCore.getResolvedClasspathEntry(rawEntry);
+					IClasspathEntry resolvedEntry = null;
+					try {
+						resolvedEntry = JavaCore.getResolvedClasspathEntry(rawEntry);
+					} catch (Assert.AssertionFailedException e) {
+						// Catch the assertion failure and throw java model exception instead
+						// see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=55992
+						// if ignoredUnresolvedEntry is false, status is set by by ClasspathEntry.validateClasspathEntry
+						// called above as validation was needed
+						if (!ignoreUnresolvedEntry) throw new JavaModelException(status);
+					}
 					if (resolvedEntry == null) {
 						if (!ignoreUnresolvedEntry) throw new JavaModelException(status);
 					} else {
@@ -1937,9 +1905,9 @@
 						if (rawEntry.isExported()){
 							cEntry = new ClasspathEntry(cEntry.getContentKind(),
 								cEntry.getEntryKind(), cEntry.getPath(),
-								cEntry.getExclusionPatterns(), cEntry.getSourceAttachmentPath(),
-								cEntry.getSourceAttachmentRootPath(), cEntry.getOutputLocation(), 
-								true); // duplicate container entry for tagging it as exported
+								cEntry.getInclusionPatterns(), cEntry.getExclusionPatterns(), 
+								cEntry.getSourceAttachmentPath(), cEntry.getSourceAttachmentRootPath(), 
+								cEntry.getOutputLocation(), true); // duplicate container entry for tagging it as exported
 						}
 						if (reverseMap != null && reverseMap.get(resolvedPath = cEntry.getPath()) == null) reverseMap.put(resolvedPath, rawEntry);
 						resolvedEntries.add(cEntry);
@@ -1972,20 +1940,6 @@
 	}
 
 	/**
-	 * @return ISearchableNameEnvironment
-	 * @throws JavaModelException
-	 */
-	public ISearchableNameEnvironment getSearchableNameEnvironment()
-		throws JavaModelException {
-
-		JavaProjectElementInfo info = getJavaProjectElementInfo();
-		if (info.getSearchableEnvironment() == null) {
-			info.setSearchableEnvironment(new SearchableEnvironment(this));
-		}
-		return info.getSearchableEnvironment();
-	}
-
-	/**
 	 * Retrieve a shared property on a project. If the property is not defined, answers null.
 	 * Note that it is orthogonal to IResource persistent properties, and client code has to decide
 	 * which form of storage to use appropriately. Shared properties produce real resource files which
@@ -2124,52 +2078,76 @@
 	 */
 	public boolean isOnClasspath(IJavaElement element) {
 		IPath path = element.getPath();
-		switch (element.getElementType()) {
-			case IJavaElement.PACKAGE_FRAGMENT_ROOT:
-				if (!((IPackageFragmentRoot)element).isArchive()) {
-					// ensure that folders are only excluded if all of their children are excluded
-					path = path.append("*"); //$NON-NLS-1$
-				}
-				break;
-			case IJavaElement.PACKAGE_FRAGMENT:
-				if (!((IPackageFragmentRoot)element.getParent()).isArchive()) {
-					// ensure that folders are only excluded if all of their children are excluded
-					path = path.append("*"); //$NON-NLS-1$
-				}
-				break;
-		}
-		return this.isOnClasspath(path);
-	}
-	private boolean isOnClasspath(IPath path) {
 		IClasspathEntry[] classpath;
 		try {
-			classpath = this.getResolvedClasspath(true/*ignore unresolved variable*/);
+			classpath = getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
 		} catch(JavaModelException e){
 			return false; // not a Java project
 		}
+		boolean isFolderPath = false;
+		switch (element.getElementType()) {
+			case IJavaElement.PACKAGE_FRAGMENT_ROOT:
+				// package fragment roots must match exactly entry pathes (no exclusion there)
+				for (int i = 0; i < classpath.length; i++) {
+					IClasspathEntry entry = classpath[i];
+					IPath entryPath = entry.getPath();
+					if (entryPath.equals(path)) {
+						return true;
+					}
+				}
+				return false;
+				
+			case IJavaElement.PACKAGE_FRAGMENT:
+				if (!((IPackageFragmentRoot)element.getParent()).isArchive()) {
+					// ensure that folders are only excluded if all of their children are excluded
+					isFolderPath = true;
+				}
+				break;
+		}
 		for (int i = 0; i < classpath.length; i++) {
 			IClasspathEntry entry = classpath[i];
-			if (entry.getPath().isPrefixOf(path) 
-					&& !Util.isExcluded(path, ((ClasspathEntry)entry).fullExclusionPatternChars())) {
+			IPath entryPath = entry.getPath();
+			if (entryPath.isPrefixOf(path) 
+					&& !Util.isExcluded(path, ((ClasspathEntry)entry).fullInclusionPatternChars(), ((ClasspathEntry)entry).fullExclusionPatternChars(), isFolderPath)) {
 				return true;
 			}
 		}
 		return false;
 	}
+
 	/*
 	 * @see IJavaProject
 	 */
 	public boolean isOnClasspath(IResource resource) {
-		IPath path = resource.getFullPath();
+		IPath exactPath = resource.getFullPath();
+		IPath path = exactPath;
 		
 		// ensure that folders are only excluded if all of their children are excluded
-		if (resource.getType() == IResource.FOLDER) {
-			path = path.append("*"); //$NON-NLS-1$
-		}
+		boolean isFolderPath = resource.getType() == IResource.FOLDER;
 		
-		return this.isOnClasspath(path);
+		IClasspathEntry[] classpath;
+		try {
+			classpath = this.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
+		} catch(JavaModelException e){
+			return false; // not a Java project
+		}
+		for (int i = 0; i < classpath.length; i++) {
+			IClasspathEntry entry = classpath[i];
+			IPath entryPath = entry.getPath();
+			if (entryPath.equals(exactPath)) { // package fragment roots must match exactly entry pathes (no exclusion there)
+				return true;
+			}
+			if (entryPath.isPrefixOf(path) 
+					&& !Util.isExcluded(path, ((ClasspathEntry)entry).fullInclusionPatternChars(), ((ClasspathEntry)entry).fullExclusionPatternChars(), isFolderPath)) {
+				return true;
+			}
+		}
+		return false;
 	}
 
+	private IPath getPluginWorkingLocation() {
+		return this.project.getWorkingLocation(JavaCore.PLUGIN_ID);
+	}	
 
 	/*
 	 * load preferences from a shareable format (VCM-wise)
@@ -2179,7 +2157,7 @@
 	 	Preferences preferences = new Preferences();
 	 	
 //		File prefFile = this.project.getLocation().append(PREF_FILENAME).toFile();
-		IPath projectMetaLocation = this.project.getPluginWorkingLocation(JavaCore.getPlugin().getDescriptor());
+		IPath projectMetaLocation = getPluginWorkingLocation();
 		if (projectMetaLocation != null) {
 			File prefFile = projectMetaLocation.append(PREF_FILENAME).toFile();
 			if (prefFile.exists()) { // load preferences from file
@@ -2210,6 +2188,43 @@
 		return new EvaluationContextWrapper(new EvaluationContext(), this);
 	}
 
+	/*
+	 * Returns a new name lookup. This name lookup first looks in the given working copies.
+	 */
+	public NameLookup newNameLookup(ICompilationUnit[] workingCopies) throws JavaModelException {
+
+		JavaProjectElementInfo info = getJavaProjectElementInfo();
+		// lock on the project info to avoid race condition while computing the pkg fragment roots and package fragment caches
+		synchronized(info){
+			return new NameLookup(info.getAllPackageFragmentRoots(this), info.getAllPackageFragments(this), workingCopies);
+		}
+	}
+
+	/*
+	 * Returns a new name lookup. This name lookup first looks in the working copies of the given owner.
+	 */
+	public NameLookup newNameLookup(WorkingCopyOwner owner) throws JavaModelException {
+		
+		JavaModelManager manager = JavaModelManager.getJavaModelManager();
+		ICompilationUnit[] workingCopies = owner == null ? null : manager.getWorkingCopies(owner, true/*add primary WCs*/);
+		return newNameLookup(workingCopies);
+	}
+
+	/*
+	 * Returns a new search name environment for this project. This name environment first looks in the given working copies.
+	 */
+	public ISearchableNameEnvironment newSearchableNameEnvironment(ICompilationUnit[] workingCopies) throws JavaModelException {
+		return new SearchableEnvironment(this, workingCopies);
+	}
+
+	/*
+	 * Returns a new search name environment for this project. This name environment first looks in the working copies
+	 * of the given owner.
+	 */
+	public ISearchableNameEnvironment newSearchableNameEnvironment(WorkingCopyOwner owner) throws JavaModelException {
+		return new SearchableEnvironment(this, owner);
+	}
+
 	/**
 	 * @see IJavaProject
 	 */
@@ -2236,7 +2251,7 @@
 		ICompilationUnit[] workingCopies = JavaModelManager.getJavaModelManager().getWorkingCopies(owner, true/*add primary working copies*/);
 		CreateTypeHierarchyOperation op =
 			new CreateTypeHierarchyOperation(region, this, workingCopies, null, true);
-		runOperation(op, monitor);
+		op.runOperation(monitor);
 		return op.getResult();
 	}
 
@@ -2271,7 +2286,7 @@
 		ICompilationUnit[] workingCopies = JavaModelManager.getJavaModelManager().getWorkingCopies(owner, true/*add primary working copies*/);
 		CreateTypeHierarchyOperation op =
 			new CreateTypeHierarchyOperation(region, this, workingCopies, type, true);
-		runOperation(op, monitor);
+		op.runOperation(monitor);
 		return op.getResult();
 	}
 	public String[] projectPrerequisites(IClasspathEntry[] entries)
@@ -2388,15 +2403,12 @@
 	}
 	
 	/*
-	 * Resets this project's name lookup
+	 * Resets this project's caches
 	 */
-	public void resetNameLookup() {
-		if (isOpen()){
-			try {
-				((JavaProjectElementInfo)getElementInfo()).setNameLookup(null);
-			} catch (JavaModelException e) {
-				// project was closed and deleted by another thread: ignore
-			}
+	public void resetCaches() {
+		JavaProjectElementInfo info = (JavaProjectElementInfo) JavaModelManager.getJavaModelManager().peekAtInfo(this);
+		if (info != null){
+			info.resetCaches();
 		}
 	}
 
@@ -2452,7 +2464,7 @@
 		// the preferences file is located in the plug-in's state area
 		// at a well-known name (.jprefs)
 //		File prefFile = this.project.getLocation().append(PREF_FILENAME).toFile();
-		File prefFile = this.project.getPluginWorkingLocation(JavaCore.getPlugin().getDescriptor()).append(PREF_FILENAME).toFile();
+		File prefFile = getPluginWorkingLocation().append(PREF_FILENAME).toFile();
 		if (preferences.propertyNames().length == 0) {
 			// there are no preference settings
 			// rather than write an empty file, just delete any existing file
@@ -2489,23 +2501,18 @@
 		ICommand newCommand)
 		throws CoreException {
 
-		ICommand[] oldCommands = description.getBuildSpec();
-		ICommand oldJavaCommand = getJavaCommand(description);
+		ICommand[] oldBuildSpec = description.getBuildSpec();
+		int oldJavaCommandIndex = getJavaCommandIndex(oldBuildSpec);
 		ICommand[] newCommands;
 
-		if (oldJavaCommand == null) {
+		if (oldJavaCommandIndex == -1) {
 			// Add a Java build spec before other builders (1FWJK7I)
-			newCommands = new ICommand[oldCommands.length + 1];
-			System.arraycopy(oldCommands, 0, newCommands, 1, oldCommands.length);
+			newCommands = new ICommand[oldBuildSpec.length + 1];
+			System.arraycopy(oldBuildSpec, 0, newCommands, 1, oldBuildSpec.length);
 			newCommands[0] = newCommand;
 		} else {
-			for (int i = 0, max = oldCommands.length; i < max; i++) {
-				if (oldCommands[i] == oldJavaCommand) {
-					oldCommands[i] = newCommand;
-					break;
-				}
-			}
-			newCommands = oldCommands;
+		    oldBuildSpec[oldJavaCommandIndex] = newCommand;
+			newCommands = oldBuildSpec;
 		}
 
 		// Commit the spec change into the project
@@ -2517,7 +2524,7 @@
 	 * @see org.eclipse.jdt.core.IJavaProject#setOption(java.lang.String, java.lang.String)
 	 */
 	public void setOption(String optionName, String optionValue) {
-		if (!JavaModelManager.OptionNames.contains(optionName)) return; // unrecognized option
+		if (!JavaModelManager.getJavaModelManager().optionNames.contains(optionName)) return; // unrecognized option
 		Preferences preferences = getPreferences();
 		preferences.setDefault(optionName, CUSTOM_DEFAULT_OPTION_VALUE); // empty string isn't the default (26251)
 		preferences.setValue(optionName, optionValue);
@@ -2529,37 +2536,29 @@
 	 */
 	public void setOptions(Map newOptions) {
 
-		Preferences preferences;
-		setPreferences(preferences = new Preferences()); // always reset (26255)
+		Preferences preferences = getPreferences();
 		if (newOptions != null){
 			Iterator keys = newOptions.keySet().iterator();
 			while (keys.hasNext()){
 				String key = (String)keys.next();
-				if (!JavaModelManager.OptionNames.contains(key)) continue; // unrecognized option
+				if (!JavaModelManager.getJavaModelManager().optionNames.contains(key)) continue; // unrecognized option
 				// no filtering for encoding (custom encoding for project is allowed)
 				String value = (String)newOptions.get(key);
 				preferences.setDefault(key, CUSTOM_DEFAULT_OPTION_VALUE); // empty string isn't the default (26251)
 				preferences.setValue(key, value);
 			}
 		}
-
-		// Backward compatibility
-		String[] propertyNames = preferences.propertyNames();
-		for (int i = 0; i < propertyNames.length; i++){
-			String propertyName = propertyNames[i];
-			// bug 45112
-			if (CompilerOptions.OPTION_ReportInvalidAnnotation.equals(propertyName)) {
-				preferences.setToDefault(JavaCore.OLD_COMPILER_PB_INVALID_ANNOTATION);
+			
+		// reset to default all options not in new map
+		// @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=26255
+		// @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=49691
+		String[] pNames = preferences.propertyNames();
+		int ln = pNames.length;
+		for (int i=0; i<ln; i++) {
+			String key = pNames[i];
+			if (newOptions == null || !newOptions.containsKey(key)) {
+				preferences.setToDefault(key); // set default => remove from preferences table
 			}
-			else if (CompilerOptions.OPTION_ReportMissingAnnotation.equals(propertyName)) {
-				preferences.setToDefault(JavaCore.OLD_COMPILER_PB_MISSING_ANNOTATION);
-			}
-			// end bug 45112
-			// bug 46854
-			else if (CompilerOptions.OPTION_ReportMissingJavadoc.equals(propertyName)) {
-				preferences.setToDefault(JavaCore.OLD_COMPILER_PB_MISSING_JAVADOC);
-			}
-			// end bug 46854
 		}
 
 		// persist options
@@ -2618,7 +2617,7 @@
 			outputLocation, 
 			monitor, 
 			true, // canChangeResource (as per API contract)
-			getResolvedClasspath(true), // ignoreUnresolvedVariable
+			getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/),
 			true, // needValidation
 			true); // need to save
 	}
@@ -2648,7 +2647,7 @@
 					canChangeResource, 
 					needValidation,
 					needSave);
-			runOperation(op, monitor);
+			op.runOperation(monitor);
 			
 		} catch (JavaModelException e) {
 			manager.getDeltaProcessor().flush();
@@ -2669,7 +2668,7 @@
 			SetClasspathOperation.ReuseOutputLocation, 
 			monitor, 
 			true, // canChangeResource (as per API contract)
-			getResolvedClasspath(true), // ignoreUnresolvedVariable
+			getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/),
 			true, // needValidation
 			true); // need to save
 	}
@@ -2785,7 +2784,7 @@
 		try {
 			IClasspathEntry[] classpath = null;
 			if (preferredClasspaths != null) classpath = (IClasspathEntry[])preferredClasspaths.get(this);
-			if (classpath == null) classpath = getResolvedClasspath(true);
+			if (classpath == null) classpath = getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
 			for (int i = 0, length = classpath.length; i < length; i++) {
 				IClasspathEntry entry = classpath[i];
 				
@@ -2812,7 +2811,10 @@
 		}
 		prereqChain.remove(path);
 	}
-		
+	
+	/*
+	 * Update .classpath format markers.
+	 */
 	public void updateClasspathMarkers(Map preferredClasspaths, Map preferredOutputs) {
 		
 		this.flushClasspathProblemMarkers(false/*cycle*/, true/*format*/);
@@ -2867,4 +2869,4 @@
 				}
 			}
 	}
-}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProjectElementInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProjectElementInfo.java
index d487621..2710ef5 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProjectElementInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProjectElementInfo.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -10,11 +10,16 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
+import java.util.ArrayList;
+import java.util.HashMap;
+
 import org.eclipse.core.resources.IContainer;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPath;
+import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.internal.core.util.Util;
 
@@ -32,26 +37,26 @@
 class JavaProjectElementInfo extends OpenableElementInfo {
 
 	/**
-	 * The name lookup facility to use with this project.
-	 */
-	protected NameLookup fNameLookup = null;
-
-	/**
-	 * The searchable builder environment facility used
-	 * with this project (doubles as the builder environment). 
-	 */
-	protected SearchableEnvironment fSearchableEnvironment = null;
-
-	/**
 	 * A array with all the non-java resources contained by this PackageFragment
 	 */
-	private Object[] fNonJavaResources;
+	private Object[] nonJavaResources;
+	
+	/*
+	 * A cache of all package fragment roots of this project.
+	 */
+	public IPackageFragmentRoot[] allPkgFragmentRootsCache;
+	
+	/*
+	 * A cache of all package fragments in this project.
+	 * (a map from String (the package name) to IPackageFragment[] (the package fragments with this name)
+	 */
+	private HashMap allPkgFragmentsCache;
 
 	/**
 	 * Create and initialize a new instance of the receiver
 	 */
 	public JavaProjectElementInfo() {
-		fNonJavaResources = null;
+		this.nonJavaResources = null;
 	}
 	
 	/**
@@ -63,15 +68,17 @@
 		IPath projectPath = project.getProject().getFullPath();
 		boolean srcIsProject = false;
 		boolean binIsProject = false;
+		char[][] inclusionPatterns = null;
 		char[][] exclusionPatterns = null;
 		IClasspathEntry[] classpath = null;
 		IPath projectOutput = null;
 		try {
-			classpath = project.getResolvedClasspath(true/*ignore unresolved variable*/);
+			classpath = project.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
 			for (int i = 0; i < classpath.length; i++) {
 				IClasspathEntry entry = classpath[i];
 				if (projectPath.equals(entry.getPath())) {
 					srcIsProject = true;
+					inclusionPatterns = ((ClasspathEntry)entry).fullInclusionPatternChars();
 					exclusionPatterns = ((ClasspathEntry)entry).fullExclusionPatternChars();
 					break;
 				}
@@ -82,8 +89,8 @@
 			// ignore
 		}
 
-		Object[] nonJavaResources = new IResource[5];
-		int nonJavaResourcesCounter = 0;
+		Object[] resources = new IResource[5];
+		int resourcesCounter = 0;
 		try {
 			IResource[] members = ((IContainer) project.getResource()).members();
 			for (int i = 0, max = members.length; i < max; i++) {
@@ -100,7 +107,7 @@
 						// ignore .java file if src == project
 						if (srcIsProject 
 							&& Util.isValidCompilationUnitName(resName)
-							&& !Util.isExcluded(res, exclusionPatterns)) {
+							&& !Util.isExcluded(res, inclusionPatterns, exclusionPatterns)) {
 							break;
 						}
 						// ignore .class file if bin == project
@@ -108,59 +115,86 @@
 							break;
 						}
 						// else add non java resource
-						if (nonJavaResources.length == nonJavaResourcesCounter) {
+						if (resources.length == resourcesCounter) {
 							// resize
 							System.arraycopy(
-								nonJavaResources,
+								resources,
 								0,
-								(nonJavaResources = new IResource[nonJavaResourcesCounter * 2]),
+								(resources = new IResource[resourcesCounter * 2]),
 								0,
-								nonJavaResourcesCounter);
+								resourcesCounter);
 						}
-						nonJavaResources[nonJavaResourcesCounter++] = res;
+						resources[resourcesCounter++] = res;
 						break;
 					case IResource.FOLDER :
 						resFullPath = res.getFullPath();
 						
 						// ignore non-excluded folders on the classpath or that correspond to an output location
-						if ((srcIsProject && !Util.isExcluded(res, exclusionPatterns) && Util.isValidFolderNameForPackage(res.getName()))
+						if ((srcIsProject && !Util.isExcluded(res, inclusionPatterns, exclusionPatterns) && Util.isValidFolderNameForPackage(res.getName()))
 								|| this.isClasspathEntryOrOutputLocation(resFullPath, classpath, projectOutput)) {
 							break;
 						}
 						// else add non java resource
-						if (nonJavaResources.length == nonJavaResourcesCounter) {
+						if (resources.length == resourcesCounter) {
 							// resize
 							System.arraycopy(
-								nonJavaResources,
+								resources,
 								0,
-								(nonJavaResources = new IResource[nonJavaResourcesCounter * 2]),
+								(resources = new IResource[resourcesCounter * 2]),
 								0,
-								nonJavaResourcesCounter);
+								resourcesCounter);
 						}
-						nonJavaResources[nonJavaResourcesCounter++] = res;
+						resources[resourcesCounter++] = res;
 				}
 			}
-			if (nonJavaResources.length != nonJavaResourcesCounter) {
+			if (resources.length != resourcesCounter) {
 				System.arraycopy(
-					nonJavaResources,
+					resources,
 					0,
-					(nonJavaResources = new IResource[nonJavaResourcesCounter]),
+					(resources = new IResource[resourcesCounter]),
 					0,
-					nonJavaResourcesCounter);
+					resourcesCounter);
 			}
 		} catch (CoreException e) {
-			nonJavaResources = NO_NON_JAVA_RESOURCES;
-			nonJavaResourcesCounter = 0;
+			resources = NO_NON_JAVA_RESOURCES;
+			resourcesCounter = 0;
 		}
-		return nonJavaResources;
+		return resources;
+	}
+
+	IPackageFragmentRoot[] getAllPackageFragmentRoots(JavaProject project) {
+		if (this.allPkgFragmentRootsCache == null) {
+			try {
+				this.allPkgFragmentRootsCache = project.getAllPackageFragmentRoots();
+			} catch (JavaModelException e) {
+				// project does not exist: cannot happend since this is the info of the project
+			}
+		}
+		return this.allPkgFragmentRootsCache;
 	}
 	
-	/**
-	 * @see IJavaProject
-	 */
-	protected NameLookup getNameLookup() {
-
-		return fNameLookup;
+	HashMap getAllPackageFragments(JavaProject project) {
+		if (this.allPkgFragmentsCache == null) {
+			HashMap cache = new HashMap();
+			IPackageFragmentRoot[] roots = getAllPackageFragmentRoots(project);
+			IPackageFragment[] frags = this.getPackageFragmentsInRoots(roots, project);
+			for (int i= 0; i < frags.length; i++) {
+				IPackageFragment fragment= frags[i];
+				IPackageFragment[] entry= (IPackageFragment[]) cache.get(fragment.getElementName());
+				if (entry == null) {
+					entry= new IPackageFragment[1];
+					entry[0]= fragment;
+					cache.put(fragment.getElementName(), entry);
+				} else {
+					IPackageFragment[] copy= new IPackageFragment[entry.length + 1];
+					System.arraycopy(entry, 0, copy, 0, entry.length);
+					copy[entry.length]= fragment;
+					cache.put(fragment.getElementName(), copy);
+				}
+			}
+			this.allPkgFragmentsCache = cache;
+		}
+		return this.allPkgFragmentsCache;
 	}
 	
 	/**
@@ -168,21 +202,56 @@
 	 */
 	Object[] getNonJavaResources(JavaProject project) {
 
-		Object[] nonJavaResources = fNonJavaResources;
-		if (nonJavaResources == null) {
-			nonJavaResources = computeNonJavaResources(project);
-			fNonJavaResources = nonJavaResources;
+		if (this.nonJavaResources == null) {
+			this.nonJavaResources = computeNonJavaResources(project);
 		}
-		return nonJavaResources;
+		return this.nonJavaResources;
 	}
 	
 	/**
-	 * @see IJavaProject 
+	 * Returns all the package fragments found in the specified
+	 * package fragment roots. Make sure the returned fragments have the given
+	 * project as great parent. This ensures the name lookup will not refer to another
+	 * project (through jar package fragment roots)
 	 */
-	protected SearchableEnvironment getSearchableEnvironment() {
+	private IPackageFragment[] getPackageFragmentsInRoots(IPackageFragmentRoot[] roots, IJavaProject project) {
 
-		return fSearchableEnvironment;
+		// The following code assumes that all the roots have the given project as their parent
+		ArrayList frags = new ArrayList();
+		for (int i = 0; i < roots.length; i++) {
+			IPackageFragmentRoot root = roots[i];
+			try {
+				IJavaElement[] pkgs = root.getChildren();
+
+				/* 2 jar package fragment roots can be equals but not belonging 
+				   to the same project. As a result, they share the same element info.
+				   So this jar package fragment root could get the children of
+				   another jar package fragment root.
+				   The following code ensures that the children of this jar package
+				   fragment root have the given project as a great parent.
+				 */
+				int length = pkgs.length;
+				if (length == 0) continue;
+				if (pkgs[0].getParent().getParent().equals(project)) {
+					// the children have the right parent, simply add them to the list
+					for (int j = 0; j < length; j++) {
+						frags.add(pkgs[j]);
+					}
+				} else {
+					// create a new handle with the root as the parent
+					for (int j = 0; j < length; j++) {
+						frags.add(root.getPackageFragment(pkgs[j].getElementName()));
+					}
+				}
+			} catch (JavaModelException e) {
+				// do nothing
+			}
+		}
+		IPackageFragment[] fragments = new IPackageFragment[frags.size()];
+		frags.toArray(fragments);
+		return fragments;
 	}
+
 	/*
 	 * Returns whether the given path is a classpath entry or an output location.
 	 */
@@ -201,13 +270,12 @@
 		return false;
 	}
 	
-	protected void setNameLookup(NameLookup newNameLookup) {
-
-		fNameLookup = newNameLookup;
-
-		// Reinitialize the searchable name environment since it caches
-		// the name lookup.
-		fSearchableEnvironment = null;
+	/*
+	 * Reset the package fragment roots and package fragment caches
+	 */
+	void resetCaches() {
+		this.allPkgFragmentRootsCache = null;
+		this.allPkgFragmentsCache = null;
 	}
 	
 	/**
@@ -215,11 +283,7 @@
 	 */
 	void setNonJavaResources(Object[] resources) {
 
-		fNonJavaResources = resources;
+		this.nonJavaResources = resources;
 	}
 	
-	protected void setSearchableEnvironment(SearchableEnvironment newSearchableEnvironment) {
-
-		fSearchableEnvironment = newSearchableEnvironment;
-	}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LRUCacheEnumerator.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LRUCacheEnumerator.java
index 4a21e0f..bddecbb 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LRUCacheEnumerator.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LRUCacheEnumerator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LocalVariable.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LocalVariable.java
index 4551114..22d77c0 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LocalVariable.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LocalVariable.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -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);
@@ -181,6 +181,6 @@
 			buffer.append(Signature.toString(this.getTypeSignature()));
 			buffer.append(" "); //$NON-NLS-1$
 		}
-		buffer.append(this.getElementName());
+		toStringName(buffer);
 	}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Member.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Member.java
index f30f42d..388336f 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Member.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Member.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -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;
@@ -23,9 +22,10 @@
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.Signature;
-import org.eclipse.jdt.core.jdom.IDOMNode;
+import org.eclipse.jdt.core.jdom.*;
 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
@@ -93,7 +93,9 @@
 }
 /**
  * @see JavaElement#equalsDOMNode
+ * @deprecated JDOM is obsolete
  */
+// TODO - JDOM - remove once model ported off of JDOM
 protected boolean equalsDOMNode(IDOMNode node) {
 	return getElementName().equals(node.getName());
 }
@@ -155,7 +157,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);
@@ -240,14 +242,13 @@
  * @see IMember
  */
 public IType getType(String typeName, int count) {
-	// TODO (jerome) disable after M6
-//	if (isBinary()) {
-//		throw new IllegalArgumentException("Not a source member " + toStringWithAncestors()); //$NON-NLS-1$
-//	} else {
+	if (isBinary()) {
+		throw new IllegalArgumentException("Not a source member " + toStringWithAncestors()); //$NON-NLS-1$
+	} else {
 		SourceType type = new SourceType(this, typeName);
 		type.occurrenceCount = count;
 		return type;
-//	}
+	}
 }
 /**
  * @see IMember
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MemberElementInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MemberElementInfo.java
index 75cc7d8..379bfe5 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MemberElementInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MemberElementInfo.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -17,7 +17,7 @@
 	/**
 	 * The modifiers associated with this member.
 	 *
-	 * @see IConstants
+	 * @see org.eclipse.jdt.internal.compiler.env.IConstants
 	 */
 	protected int flags;
 
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ModelUpdater.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ModelUpdater.java
index eb3e7b6..e52e7a3 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ModelUpdater.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ModelUpdater.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -90,9 +90,9 @@
 				this.projectsToUpdate.add(element.getJavaProject());
 				break;
 			case IJavaElement.PACKAGE_FRAGMENT :
-				// get rid of namelookup since it holds onto obsolete cached info 
+				// get rid of package fragment cache
 				JavaProject project = (JavaProject) element.getJavaProject();
-				project.resetNameLookup();
+				project.resetCaches();
 				break;
 		}
 	}
@@ -135,9 +135,9 @@
 				this.projectsToUpdate.add(element.getJavaProject());
 				break;
 			case IJavaElement.PACKAGE_FRAGMENT :
-				//1G1TW2T - get rid of namelookup since it holds onto obsolete cached info 
+				// get rid of package fragment cache
 				JavaProject project = (JavaProject) element.getJavaProject();
-				project.resetNameLookup();
+				project.resetCaches();
 				break;
 		}
 	}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MoveElementsOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MoveElementsOperation.java
index bce98b6..d6f28bd 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MoveElementsOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MoveElementsOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MovePackageFragmentRootOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MovePackageFragmentRootOperation.java
index adbed48..26338c0 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MovePackageFragmentRootOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MovePackageFragmentRootOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MoveResourceElementsOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MoveResourceElementsOperation.java
index 55dc1c2..73c8f71 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MoveResourceElementsOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MoveResourceElementsOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MultiOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MultiOperation.java
index 97e6315..212db65 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MultiOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MultiOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -30,7 +30,7 @@
 	 * Table specifying insertion positions for elements being 
 	 * copied/moved/renamed. Keyed by elements being processed, and
 	 * values are the corresponding insertion point.
-	 * @see processElements(IProgressMonitor)
+	 * @see #processElements()
 	 */
 	protected Map insertBeforeElements = new HashMap(1);
 	/**
@@ -114,11 +114,11 @@
 	 * values are the new name.
 	 */
 	private void initializeRenamings() {
-		if (this.renamingsList != null && this.renamingsList.length == elementsToProcess.length) {
+		if (this.renamingsList != null && this.renamingsList.length == this.elementsToProcess.length) {
 			this.renamings = new HashMap(this.renamingsList.length);
 			for (int i = 0; i < this.renamingsList.length; i++) {
 				if (this.renamingsList[i] != null) {
-					this.renamings.put(elementsToProcess[i], this.renamingsList[i]);
+					this.renamings.put(this.elementsToProcess[i], this.renamingsList[i]);
 				}
 			}
 		}
@@ -151,13 +151,13 @@
 	 * be completed.
 	 */
 	protected void processElements() throws JavaModelException {
-		beginTask(getMainTaskName(), elementsToProcess.length);
+		beginTask(getMainTaskName(), this.elementsToProcess.length);
 		IJavaModelStatus[] errors = new IJavaModelStatus[3];
 		int errorsCounter = 0;
-		for (int i = 0; i < elementsToProcess.length; i++) {
+		for (int i = 0; i < this.elementsToProcess.length; i++) {
 			try {
-				verify(elementsToProcess[i]);
-				processElement(elementsToProcess[i]);
+				verify(this.elementsToProcess[i]);
+				processElement(this.elementsToProcess[i]);
 			} catch (JavaModelException jme) {
 				if (errorsCounter == errors.length) {
 					// resize
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/NameLookup.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/NameLookup.java
index e02fc53..dc0234a 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/NameLookup.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/NameLookup.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -16,10 +16,10 @@
 import java.util.HashMap;
 import java.util.Map;
 
+import org.eclipse.core.resources.*;
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.resources.IWorkspace;
-import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.Path;
 import org.eclipse.core.runtime.OperationCanceledException;
@@ -27,12 +27,12 @@
 import org.eclipse.jdt.core.IClasspathEntry;
 import org.eclipse.jdt.core.ICompilationUnit;
 import org.eclipse.jdt.core.IJavaElement;
-import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.IPackageFragment;
 import org.eclipse.jdt.core.IPackageFragmentRoot;
 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;
@@ -71,7 +71,7 @@
 	 * with the classpath of this NameLookup facility's
 	 * project.
 	 */
-	protected IPackageFragmentRoot[] fPackageFragmentRoots= null;
+	protected IPackageFragmentRoot[] packageFragmentRoots;
 
 	/**
 	 * Table that maps package names to lists of package fragments for
@@ -80,24 +80,26 @@
 	 * with the same name, values are arrays of package fragments
 	 * ordered as they appear on the classpath.
 	 */
-	protected Map fPackageFragments;
+	protected Map packageFragments;
 
 	/**
-	 * The <code>IWorkspace</code> that this NameLookup
-	 * is configure within.
-	 */
-	protected IWorkspace workspace;
-	
-	/**
 	 * A map from compilation unit handles to units to look inside (compilation
 	 * units or working copies).
 	 * Allows working copies to take precedence over compilation units.
-	 * The cache is a 2-level cache, first keyed by thread.
 	 */
-	protected ThreadLocal unitsToLookInside = new ThreadLocal();
+	protected HashMap unitsToLookInside;
 
-	public NameLookup(IJavaProject project) throws JavaModelException {
-		configureFromProject(project);
+	public NameLookup(IPackageFragmentRoot[] packageFragmentRoots, HashMap packageFragments, ICompilationUnit[] workingCopies) {
+		this.packageFragmentRoots = packageFragmentRoots;
+		this.packageFragments = packageFragments;
+		if (workingCopies != null) {
+			this.unitsToLookInside = new HashMap();
+			for (int i = 0, length = workingCopies.length; i < length; i++) {
+				ICompilationUnit unitToLookInside = workingCopies[i];
+				ICompilationUnit original = unitToLookInside.getPrimary();
+				this.unitsToLookInside.put(original, unitToLookInside);
+			}
+		}
 	}
 
 	/**
@@ -126,33 +128,6 @@
 	}
 
 	/**
-	 * Configures this <code>NameLookup</code> based on the
-	 * info of the given <code>IJavaProject</code>.
-	 *
-	 * @throws JavaModelException if the <code>IJavaProject</code> has no classpath.
-	 */
-	private void configureFromProject(IJavaProject project) throws JavaModelException {
-		workspace= ResourcesPlugin.getWorkspace();
-		fPackageFragmentRoots= ((JavaProject) project).getAllPackageFragmentRoots();
-		fPackageFragments= new HashMap();
-		IPackageFragment[] frags = this.getPackageFragmentsInRoots(fPackageFragmentRoots, project);
-		for (int i= 0; i < frags.length; i++) {
-			IPackageFragment fragment= frags[i];
-			IPackageFragment[] entry= (IPackageFragment[]) fPackageFragments.get(fragment.getElementName());
-			if (entry == null) {
-				entry= new IPackageFragment[1];
-				entry[0]= fragment;
-				fPackageFragments.put(fragment.getElementName(), entry);
-			} else {
-				IPackageFragment[] copy= new IPackageFragment[entry.length + 1];
-				System.arraycopy(entry, 0, copy, 0, entry.length);
-				copy[entry.length]= fragment;
-				fPackageFragments.put(fragment.getElementName(), copy);
-			}
-		}
-	}
-
-	/**
 	 * Finds every type in the project whose simple name matches
 	 * the prefix, informing the requestor of each hit. The requestor
 	 * is polled for cancellation at regular intervals.
@@ -161,11 +136,11 @@
 	 * should be considered.
 	 */
 	private void findAllTypes(String prefix, boolean partialMatch, int acceptFlags, IJavaElementRequestor requestor) {
-		int count= fPackageFragmentRoots.length;
+		int count= this.packageFragmentRoots.length;
 		for (int i= 0; i < count; i++) {
 			if (requestor.isCanceled())
 				return;
-			IPackageFragmentRoot root= fPackageFragmentRoots[i];
+			IPackageFragmentRoot root= this.packageFragmentRoots[i];
 			IJavaElement[] packages= null;
 			try {
 				packages= root.getChildren();
@@ -205,7 +180,7 @@
 			cuName= cuName.substring(0, index);
 		}
 		cuName += SUFFIX_STRING_java;
-		IPackageFragment[] frags= (IPackageFragment[]) fPackageFragments.get(pkgName);
+		IPackageFragment[] frags= (IPackageFragment[]) this.packageFragments.get(pkgName);
 		if (frags != null) {
 			for (int i= 0; i < frags.length; i++) {
 				IPackageFragment frag= frags[i];
@@ -237,11 +212,11 @@
  * this code should rather use the package fragment map to find the candidate package, then
  * check if the respective enclosing root maps to the one on this given IPath.
  */		
-		IResource possibleFragment = workspace.getRoot().findMember(path);
+		IResource possibleFragment = ResourcesPlugin.getWorkspace().getRoot().findMember(path);
 		if (possibleFragment == null) {
 			//external jar
-			for (int i = 0; i < fPackageFragmentRoots.length; i++) {
-				IPackageFragmentRoot root = fPackageFragmentRoots[i];
+			for (int i = 0; i < this.packageFragmentRoots.length; i++) {
+				IPackageFragmentRoot root = this.packageFragmentRoots[i];
 				if (!root.isExternal()) {
 					continue;
 				}
@@ -272,10 +247,10 @@
 			if (fromFactory == null) {
 				return null;
 			}
-			if (fromFactory instanceof IPackageFragment) {
-				return (IPackageFragment) fromFactory;
-			} else
-				if (fromFactory instanceof IJavaProject) {
+			switch (fromFactory.getElementType()) {
+				case IJavaElement.PACKAGE_FRAGMENT:
+					return (IPackageFragment) fromFactory;
+				case IJavaElement.JAVA_PROJECT:
 					// default package in a default root
 					JavaProject project = (JavaProject) fromFactory;
 					try {
@@ -283,7 +258,7 @@
 						if (entry != null) {
 							IPackageFragmentRoot root =
 								project.getPackageFragmentRoot(project.getResource());
-							IPackageFragment[] pkgs = (IPackageFragment[]) fPackageFragments.get(IPackageFragment.DEFAULT_PACKAGE_NAME);
+							IPackageFragment[] pkgs = (IPackageFragment[]) this.packageFragments.get(IPackageFragment.DEFAULT_PACKAGE_NAME);
 							if (pkgs == null) {
 								return null;
 							}
@@ -296,7 +271,10 @@
 					} catch (JavaModelException e) {
 						return null;
 					}
-				}
+					return null;
+				case IJavaElement.PACKAGE_FRAGMENT_ROOT:
+					return ((IPackageFragmentRoot)fromFactory).getPackageFragment(IPackageFragment.DEFAULT_PACKAGE_NAME);
+			}
 		}
 		return null;
 	}
@@ -312,11 +290,11 @@
 	 *	only exact name matches qualify when <code>false</code>
 	 */
 	public IPackageFragment[] findPackageFragments(String name, boolean partialMatch) {
-		int count= fPackageFragmentRoots.length;
+		int count= this.packageFragmentRoots.length;
 		if (partialMatch) {
 			name= name.toLowerCase();
 			for (int i= 0; i < count; i++) {
-				IPackageFragmentRoot root= fPackageFragmentRoots[i];
+				IPackageFragmentRoot root= this.packageFragmentRoots[i];
 				IJavaElement[] list= null;
 				try {
 					list= root.getChildren();
@@ -340,7 +318,7 @@
 				}
 			}
 		} else {
-			IPackageFragment[] fragments= (IPackageFragment[]) fPackageFragments.get(name);
+			IPackageFragment[] fragments= (IPackageFragment[]) this.packageFragments.get(name);
 			if (fragments != null) {
 				IPackageFragment[] result = new IPackageFragment[fragments.length];
 				int resultLength = 0; 
@@ -380,49 +358,6 @@
 		}
 		return null;
 	}
-	/**
-	 * Returns all the package fragments found in the specified
-	 * package fragment roots. Make sure the returned fragments have the given
-	 * project as great parent. This ensures the name lookup will not refer to another
-	 * project (through jar package fragment roots)
-	 */
-	private IPackageFragment[] getPackageFragmentsInRoots(IPackageFragmentRoot[] roots, IJavaProject project) {
-
-		// The following code assumes that all the roots have the given project as their parent
-		ArrayList frags = new ArrayList();
-		for (int i = 0; i < roots.length; i++) {
-			IPackageFragmentRoot root = roots[i];
-			try {
-				IJavaElement[] children = root.getChildren();
-
-				/* 2 jar package fragment roots can be equals but not belonging 
-				   to the same project. As a result, they share the same element info.
-				   So this jar package fragment root could get the children of
-				   another jar package fragment root.
-				   The following code ensures that the children of this jar package
-				   fragment root have the given project as a great parent.
-				 */
-				int length = children.length;
-				if (length == 0) continue;
-				if (children[0].getParent().getParent().equals(project)) {
-					// the children have the right parent, simply add them to the list
-					for (int j = 0; j < length; j++) {
-						frags.add(children[j]);
-					}
-				} else {
-					// create a new handle with the root as the parent
-					for (int j = 0; j < length; j++) {
-						frags.add(root.getPackageFragment(children[j].getElementName()));
-					}
-				}
-			} catch (JavaModelException e) {
-				// do nothing
-			}
-		}
-		IPackageFragment[] fragments = new IPackageFragment[frags.size()];
-		frags.toArray(fragments);
-		return fragments;
-	}
 
 	/**
 	 * Returns the first type in the given package whose name
@@ -470,12 +405,12 @@
 				}
 			};
 
+			int matchMode = partialMatch ? SearchPattern.R_PREFIX_MATCH : SearchPattern.R_EXACT_MATCH;
+			int matchRule = !partialMatch ? matchMode | SearchPattern.R_CASE_SENSITIVE : matchMode;
 			new SearchEngine().searchAllTypeNames(
-				workspace,
 				pkg.getElementName().toCharArray(),
 				typeName.toCharArray(),
-				partialMatch ? IJavaSearchConstants.PREFIX_MATCH : IJavaSearchConstants.EXACT_MATCH,
-				partialMatch ? IJavaSearchConstants.CASE_INSENSITIVE : IJavaSearchConstants.CASE_SENSITIVE,
+				matchRule,
 				IJavaSearchConstants.TYPE,
 				SearchEngine.createJavaSearchScope(new IJavaElement[] {pkg}, false),
 				nameRequestor,
@@ -483,6 +418,7 @@
 				null);
 
 			if (!paths.isEmpty()) {
+				IWorkspace workspace = ResourcesPlugin.getWorkspace();
 				for (int i = 0, l = paths.size(); i < l; i++) {
 					String pathname = (String) paths.get(i);
 					if (org.eclipse.jdt.internal.compiler.util.Util.isJavaFileName(pathname)) {
@@ -556,12 +492,12 @@
 	 *	only exact name matches qualify when <code>false</code>
 	 */
 	public void seekPackageFragments(String name, boolean partialMatch, IJavaElementRequestor requestor) {
-		int count= fPackageFragmentRoots.length;
+		int count= this.packageFragmentRoots.length;
 		String matchName= partialMatch ? name.toLowerCase() : name;
 		for (int i= 0; i < count; i++) {
 			if (requestor.isCanceled())
 				return;
-			IPackageFragmentRoot root= fPackageFragmentRoots[i];
+			IPackageFragmentRoot root= this.packageFragmentRoots[i];
 			IJavaElement[] list= null;
 			try {
 				list= root.getChildren();
@@ -690,11 +626,10 @@
 		// replace with working copies to look inside
 		int length= compilationUnits.length;
 		boolean[] isWorkingCopy = new boolean[length];
-		Map workingCopies = (Map) this.unitsToLookInside.get();
 		int workingCopiesSize;
-		if (workingCopies != null && (workingCopiesSize = workingCopies.size()) > 0) {
+		if (this.unitsToLookInside != null && (workingCopiesSize = this.unitsToLookInside.size()) > 0) {
 			Map temp = new HashMap(workingCopiesSize);
-			temp.putAll(workingCopies);
+			temp.putAll(this.unitsToLookInside);
 			for (int i = 0; i < length; i++) {
 				ICompilationUnit unit = compilationUnits[i];
 				ICompilationUnit workingCopy = (ICompilationUnit)temp.remove(unit);
@@ -792,26 +727,6 @@
 
 		}
 	}
-/**
- * Remembers a set of compilation units that will be looked inside
- * when looking up a type. If they are working copies, they take
- * precedence over their compilation units.
- * <code>null</code> means that no special compilation units should be used.
- */
-public void setUnitsToLookInside(ICompilationUnit[] unitsToLookInside) {
-	
-	if (unitsToLookInside == null) {
-		this.unitsToLookInside.set(null); 
-	} else {
-		HashMap workingCopies = new HashMap();
-		this.unitsToLookInside.set(workingCopies);
-		for (int i = 0, length = unitsToLookInside.length; i < length; i++) {
-			ICompilationUnit unitToLookInside = unitsToLookInside[i];
-			ICompilationUnit original = unitToLookInside.getPrimary();
-			workingCopies.put(original, unitToLookInside);
-		}
-	}
-}
 
 	/**
 	 * Notifies the given requestor of all types (classes and interfaces) in the
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Openable.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Openable.java
index ef25cbe..92f7a4c 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Openable.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Openable.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -26,7 +26,6 @@
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.compiler.IProblem;
 import org.eclipse.jdt.internal.codeassist.CompletionEngine;
-import org.eclipse.jdt.internal.codeassist.ISearchableNameEnvironment;
 import org.eclipse.jdt.internal.codeassist.SelectionEngine;
 
 
@@ -110,69 +109,39 @@
 		return;
 	}
 	if (position < -1 || position > buffer.getLength()) {
-		throw new IllegalArgumentException("Completion position "+position+" is not located in supplied source range (0, "+buffer.getLength()+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.INDEX_OUT_OF_BOUNDS));
 	}
 	JavaProject project = (JavaProject) getJavaProject();
-	SearchableEnvironment environment = null;
-	NameLookup nameLookup = null;
-	try {
-		// set unit to skip
-		environment = (SearchableEnvironment) project.getSearchableNameEnvironment();
-		environment.unitToSkip = unitToSkip;
-	
-		// set the units to look inside
-		nameLookup = project.getNameLookup();
-		JavaModelManager manager = JavaModelManager.getJavaModelManager();
-		ICompilationUnit[] workingCopies = manager.getWorkingCopies(owner, true/*add primary WCs*/);
-		nameLookup.setUnitsToLookInside(workingCopies);
+	SearchableEnvironment environment = (SearchableEnvironment) project.newSearchableNameEnvironment(owner);
 
-		// code complete
-		CompletionRequestorWrapper requestorWrapper = new CompletionRequestorWrapper(requestor,nameLookup);
-		CompletionEngine engine = new CompletionEngine(environment, requestorWrapper, project.getOptions(true), project);
-		requestorWrapper.completionEngine = engine;
-		engine.complete(cu, position, 0);
-	} finally {
-		if (environment != null) {
-			environment.unitToSkip = null;
-		}
-		if (nameLookup != null) {
-			nameLookup.setUnitsToLookInside(null);
-		}
-	}
+	// set unit to skip
+	environment.unitToSkip = unitToSkip;
+
+	// code complete
+	CompletionRequestorWrapper requestorWrapper = new CompletionRequestorWrapper(requestor, environment.nameLookup);
+	CompletionEngine engine = new CompletionEngine(environment, requestorWrapper, project.getOptions(true), project);
+	requestorWrapper.completionEngine = engine;
+	engine.complete(cu, position, 0);
 }
 protected IJavaElement[] codeSelect(org.eclipse.jdt.internal.compiler.env.ICompilationUnit cu, int offset, int length, WorkingCopyOwner owner) throws JavaModelException {
-	NameLookup nameLookup = null;
-	try {
-		// set the units to look inside
-		nameLookup = ((JavaProject)getJavaProject()).getNameLookup();
-		JavaModelManager manager = JavaModelManager.getJavaModelManager();
-		ICompilationUnit[] workingCopies = manager.getWorkingCopies(owner, true/*add primary WCs*/);
-		nameLookup.setUnitsToLookInside(workingCopies);
 
-		// code select
-		SelectionRequestor requestor= new SelectionRequestor(nameLookup, this);
-		IBuffer buffer = getBuffer();
-		if (buffer == null) {
-			return requestor.getElements();
-		}
-		int end= buffer.getLength();
-		if (offset < 0 || length < 0 || offset + length > end ) {
-			throw new IllegalArgumentException("Selected range ("+offset+ ", " + (offset+length)+") is not located in supplied source range (0, "+end+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
-		}
+	JavaProject project = (JavaProject)getJavaProject();
+	SearchableEnvironment environment = (SearchableEnvironment) project.newSearchableNameEnvironment(owner);
 	
-		// fix for 1FVGGKF
-		JavaProject project = (JavaProject)getJavaProject();
-		ISearchableNameEnvironment environment = project.getSearchableNameEnvironment();
-		
-		// fix for 1FVXGDK
-		SelectionEngine engine = new SelectionEngine(environment, requestor, project.getOptions(true));
-		engine.select(cu, offset, offset + length - 1);
+	SelectionRequestor requestor= new SelectionRequestor(environment.nameLookup, this);
+	IBuffer buffer = getBuffer();
+	if (buffer == null) {
 		return requestor.getElements();
-	} finally {
-		if (nameLookup != null) {
-			nameLookup.setUnitsToLookInside(null);
-		}
 	}
+	int end= buffer.getLength();
+	if (offset < 0 || length < 0 || offset + length > end ) {
+		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.INDEX_OUT_OF_BOUNDS));
+	}
+
+	// fix for 1FVXGDK
+	SelectionEngine engine = new SelectionEngine(environment, requestor, project.getOptions(true));
+	engine.select(cu, offset, offset + length - 1);
+	return requestor.getElements();
 }
 /*
  * Returns a new element info for this element.
@@ -180,6 +149,20 @@
 protected Object createElementInfo() {
 	return new OpenableElementInfo();
 }
+/**
+ * @see IJavaElement
+ */
+public boolean exists() {
+	JavaModelManager manager = JavaModelManager.getJavaModelManager();
+	if (manager.getInfo(this) != null) return true;
+	if (!parentExists()) return false;
+	PackageFragmentRoot root = getPackageFragmentRoot();
+	if (root != null
+			&& (root == this || !root.isArchive())) {
+		return resourceExists();
+	}
+	return super.exists();
+}
 protected void generateInfos(Object info, HashMap newElements, IProgressMonitor monitor) throws JavaModelException {
 
 	if (JavaModelManager.VERBOSE){
@@ -297,12 +280,6 @@
 	return false;
 }
 /**
- * @see IParent 
- */
-public boolean hasChildren() throws JavaModelException {
-	return getChildren().length > 0;
-}
-/**
  * @see IOpenable
  */
 public boolean hasUnsavedChanges() throws JavaModelException{
@@ -364,10 +341,9 @@
 public void makeConsistent(IProgressMonitor monitor) throws JavaModelException {
 	if (isConsistent()) return;
 	
-	// close
+	// create a new info and make it the current info
+	// (this will remove the info and its children just before storing the new infos)
 	JavaModelManager manager = JavaModelManager.getJavaModelManager();
-	manager.removeInfoAndChildren(this);
-	
 	boolean hadTemporaryCache = manager.hasTemporaryCache();
 	try {
 		HashMap newElements = manager.getTemporaryCache();
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/OpenableElementInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/OpenableElementInfo.java
index f402e24..ddf8505 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/OpenableElementInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/OpenableElementInfo.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/OverflowingLRUCache.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/OverflowingLRUCache.java
index 7c784c4..135d3ad 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/OverflowingLRUCache.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/OverflowingLRUCache.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageDeclaration.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageDeclaration.java
index 9b1b439..b3e9c22 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageDeclaration.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageDeclaration.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -12,7 +12,7 @@
 
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.IPackageDeclaration;
-import org.eclipse.jdt.core.jdom.IDOMNode;
+import org.eclipse.jdt.core.jdom.*;
 
 /**
  * @see IPackageDeclaration
@@ -28,7 +28,9 @@
 }
 /**
  * @see JavaElement#equalsDOMNode
+ * @deprecated JDOM is obsolete
  */
+// TODO - JDOM - remove once model ported off of JDOM
 protected boolean equalsDOMNode(IDOMNode node) {
 	return (node.getNodeType() == IDOMNode.PACKAGE) && getElementName().equals(node.getName());
 }
@@ -58,7 +60,7 @@
 protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
 	buffer.append(this.tabString(tab));
 	buffer.append("package "); //$NON-NLS-1$
-	buffer.append(getElementName());
+	toStringName(buffer);
 	if (info == null) {
 		buffer.append(" (not open)"); //$NON-NLS-1$
 	}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragment.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragment.java
index b77aa49..b3f9d1f 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragment.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragment.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -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;
 
 /**
@@ -72,12 +72,14 @@
 	// add compilation units/class files from resources
 	HashSet vChildren = new HashSet();
 	try {
-		char[][] exclusionPatterns = getPackageFragmentRoot().fullExclusionPatternChars();
+	    PackageFragmentRoot root = getPackageFragmentRoot();
+		char[][] inclusionPatterns = root.fullInclusionPatternChars();
+		char[][] exclusionPatterns = root.fullExclusionPatternChars();
 		IResource[] members = ((IContainer) underlyingResource).members();
 		for (int i = 0, max = members.length; i < max; i++) {
 			IResource child = members[i];
 			if (child.getType() != IResource.FOLDER
-					&& !Util.isExcluded(child, exclusionPatterns)) {
+					&& !Util.isExcluded(child, inclusionPatterns, exclusionPatterns)) {
 				String extension = child.getProjectRelativePath().getFileExtension();
 				if (extension != null) {
 					if (extension.equalsIgnoreCase(extType)) {
@@ -142,7 +144,7 @@
  */
 public ICompilationUnit createCompilationUnit(String cuName, String contents, boolean force, IProgressMonitor monitor) throws JavaModelException {
 	CreateCompilationUnitOperation op= new CreateCompilationUnitOperation(this, cuName, contents, force);
-	runOperation(op, monitor);
+	op.runOperation(monitor);
 	return new CompilationUnit(this, cuName, DefaultWorkingCopyOwner.PRIMARY);
 }
 /**
@@ -164,7 +166,7 @@
 }
 /**
  * @see IPackageFragment#getClassFile(String)
- * @exception IllegalArgumentExcpetion if the name does not end with ".class"
+ * @exception IllegalArgumentException if the name does not end with ".class"
  */
 public IClassFile getClassFile(String classFileName) {
 	if (!org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(classFileName)) {
@@ -191,7 +193,7 @@
 }
 /**
  * @see IPackageFragment#getCompilationUnit(String)
- * @exception IllegalArgumentExcpetion if the name does not end with ".java"
+ * @exception IllegalArgumentException if the name does not end with ".java"
  */
 public ICompilationUnit getCompilationUnit(String cuName) {
 	if (!org.eclipse.jdt.internal.compiler.util.Util.isJavaFileName(cuName)) {
@@ -217,13 +219,13 @@
  */
 public ICompilationUnit[] getCompilationUnits(WorkingCopyOwner owner) {
 	ICompilationUnit[] workingCopies = JavaModelManager.getJavaModelManager().getWorkingCopies(owner, false/*don't add primary*/);
-	if (workingCopies == null) return JavaModelManager.NoWorkingCopy;
+	if (workingCopies == null) return JavaModelManager.NO_WORKING_COPY;
 	int length = workingCopies.length;
 	ICompilationUnit[] result = new ICompilationUnit[length];
 	int index = 0;
 	for (int i = 0; i < length; i++) {
 		ICompilationUnit wc = workingCopies[i];
-		if (equals(wc.getParent())) {
+		if (equals(wc.getParent()) && !Util.isExcluded(wc)) { // 59933 - excluded wc shouldn't be answered back
 			result[index++] = wc;
 		}
 	}
@@ -241,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);
@@ -333,6 +335,12 @@
 	}
 }
 /**
+ * @see IParent 
+ */
+public boolean hasChildren() throws JavaModelException {
+	return getChildren().length > 0;
+}
+/**
  * @see IPackageFragment#hasSubpackages()
  */
 public boolean hasSubpackages() throws JavaModelException {
@@ -401,7 +409,7 @@
 	if (getElementName().length() == 0) {
 		buffer.append("<default>"); //$NON-NLS-1$
 	} else {
-		buffer.append(getElementName());
+		toStringName(buffer);
 	}
 	if (info == null) {
 		buffer.append(" (not open)"); //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentInfo.java
index b3fd72e..0858cde 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentInfo.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -45,6 +45,7 @@
 				PackageFragmentRootInfo.computeFolderNonJavaResources(
 					(JavaProject)rootHandle.getJavaProject(), 
 					(IContainer)underlyingResource, 
+					rootHandle.fullInclusionPatternChars(),
 					rootHandle.fullExclusionPatternChars());
 		} catch (JavaModelException e) {
 			// root doesn't exist: consider package has no nonJavaResources
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java
index d5c2c53..f68bcd0 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -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;
 
 /**
@@ -190,7 +190,7 @@
 	throws JavaModelException {
 
 	DeletePackageFragmentRootOperation op = new DeletePackageFragmentRootOperation(this, updateResourceFlags, updateModelFlags);
-	runOperation(op, monitor);
+	op.runOperation(monitor);
 }
 
 /**
@@ -207,8 +207,10 @@
 		IResource underlyingResource = getResource();
 		if (underlyingResource.getType() == IResource.FOLDER || underlyingResource.getType() == IResource.PROJECT) {
 			ArrayList vChildren = new ArrayList(5);
+			IContainer rootFolder = (IContainer) underlyingResource;
+			char[][] inclusionPatterns = fullInclusionPatternChars();
 			char[][] exclusionPatterns = fullExclusionPatternChars();
-			computeFolderChildren((IContainer) underlyingResource, "", vChildren, exclusionPatterns); //$NON-NLS-1$
+			computeFolderChildren(rootFolder, !Util.isExcluded(rootFolder, inclusionPatterns, exclusionPatterns), "", vChildren, inclusionPatterns, exclusionPatterns); //$NON-NLS-1$
 			IJavaElement[] children = new IJavaElement[vChildren.size()];
 			vChildren.toArray(children);
 			info.setChildren(children);
@@ -227,29 +229,50 @@
  * 
  * @exception JavaModelException  The resource associated with this package fragment does not exist
  */
-protected void computeFolderChildren(IContainer folder, String prefix, ArrayList vChildren, char[][] exclusionPatterns) throws JavaModelException {
-	IPackageFragment pkg = getPackageFragment(prefix);
-	vChildren.add(pkg);
+protected void computeFolderChildren(IContainer folder, boolean isIncluded, String prefix, ArrayList vChildren, char[][] inclusionPatterns, char[][] exclusionPatterns) throws JavaModelException {
+
+	if (isIncluded) {
+	    IPackageFragment pkg = getPackageFragment(prefix);
+		vChildren.add(pkg);
+	}
 	try {
 		JavaProject javaProject = (JavaProject)getJavaProject();
 		IResource[] members = folder.members();
+		boolean hasIncluded = isIncluded;
 		for (int i = 0, max = members.length; i < max; i++) {
 			IResource member = members[i];
 			String memberName = member.getName();
-			if (member.getType() == IResource.FOLDER 
-				&& Util.isValidFolderNameForPackage(memberName)
-				&& !Util.isExcluded(member, exclusionPatterns)) {
-					
-				// eliminate binary output only if nested inside direct subfolders
-				if (javaProject.contains(member)) {
-					String newPrefix;
-					if (prefix.length() == 0) {
-						newPrefix = memberName;
-					} else {
-						newPrefix = prefix + "." + memberName; //$NON-NLS-1$
+			
+			switch(member.getType()) {
+			    
+			    case IResource.FOLDER:
+					if (Util.isValidFolderNameForPackage(memberName)) {
+					    boolean isMemberIncluded = !Util.isExcluded(member, inclusionPatterns, exclusionPatterns);
+						// keep looking inside as long as included already, or may have child included due to inclusion patterns
+					    if (isMemberIncluded || inclusionPatterns != null) { 
+							// eliminate binary output only if nested inside direct subfolders
+							if (javaProject.contains(member)) {
+								String newPrefix;
+								if (prefix.length() == 0) {
+									newPrefix = memberName;
+								} else {
+									newPrefix = prefix + "." + memberName; //$NON-NLS-1$
+								}
+								computeFolderChildren((IFolder) member, isMemberIncluded, newPrefix, vChildren, inclusionPatterns, exclusionPatterns);
+							}
+						}
 					}
-					computeFolderChildren((IFolder) member, newPrefix, vChildren, exclusionPatterns);
-				}
+			    	break;
+			    case IResource.FILE:
+			        // inclusion filter may only include files, in which case we still want to include the immediate parent package (lazily)
+					if (!hasIncluded
+								&& Util.isValidCompilationUnitName(memberName)
+								&& !Util.isExcluded(member, inclusionPatterns, exclusionPatterns)) {
+						hasIncluded = true;
+					    IPackageFragment pkg = getPackageFragment(prefix);
+					    vChildren.add(pkg); 
+					}
+			        break;
 			}
 		}
 	} catch(IllegalArgumentException e){
@@ -272,7 +295,7 @@
 		
 	CopyPackageFragmentRootOperation op = 
 		new CopyPackageFragmentRootOperation(this, destination, updateResourceFlags, updateModelFlags, sibling);
-	runOperation(op, monitor);
+	op.runOperation(monitor);
 }
 
 /**
@@ -287,7 +310,7 @@
  */
 public IPackageFragment createPackageFragment(String pkgName, boolean force, IProgressMonitor monitor) throws JavaModelException {
 	CreatePackageFragmentOperation op = new CreatePackageFragmentOperation(this, pkgName, force);
-	runOperation(op, monitor);
+	op.runOperation(monitor);
 	return getPackageFragment(pkgName);
 }
 
@@ -295,7 +318,7 @@
  * Returns the root's kind - K_SOURCE or K_BINARY, defaults
  * to K_SOURCE if it is not on the classpath.
  *
- * @exception NotPresentException if the project and root do
+ * @exception JavaModelException if the project and root do
  * 		not exist.
  */
 protected int determineKind(IResource underlyingResource) throws JavaModelException {
@@ -312,7 +335,7 @@
 /**
  * Compares two objects for equality;
  * for <code>PackageFragmentRoot</code>s, equality is having the
- * same <code>JavaModel</code>, same resources, and occurrence count.
+ * same parent, same resources, and occurrence count.
  *
  */
 public boolean equals(Object o) {
@@ -322,17 +345,15 @@
 		return false;
 	PackageFragmentRoot other = (PackageFragmentRoot) o;
 	return this.resource.equals(other.resource) &&
-			this.occurrenceCount == other.occurrenceCount;
+			this.occurrenceCount == other.occurrenceCount && 
+			this.parent.equals(other.parent);
 }
 
 /**
  * @see IJavaElement
  */
 public boolean exists() {
-	return 
-		parentExists() 
-			&& resourceExists() 
-			&& isOnClasspath();
+	return super.exists() && isOnClasspath();
 }
 
 public IClasspathEntry findSourceAttachmentRecommendation() {
@@ -347,15 +368,16 @@
 			entry = parentProject.getClasspathEntryFor(rootPath);
 			if (entry != null){
 				Object target = JavaModel.getTarget(workspaceRoot, entry.getSourceAttachmentPath(), true);
-				if (target instanceof IFile){
-					IFile file = (IFile) target;
-					if (org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(file.getName())){
+				if (target instanceof IResource) {
+					if (target instanceof IFile) {
+						IFile file = (IFile) target;
+						if (org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(file.getName())){
+							return entry;
+						}
+					} else if (target instanceof IContainer) {
 						return entry;
 					}
-				} else if (target instanceof IFolder) {
-					return entry;
-				}
-				if (target instanceof java.io.File){
+				} else if (target instanceof java.io.File){
 					java.io.File file = (java.io.File) target;
 					if (file.isFile()) {
 						if (org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(file.getName())){
@@ -381,15 +403,16 @@
 				entry = jProject.getClasspathEntryFor(rootPath);
 				if (entry != null){
 					Object target = JavaModel.getTarget(workspaceRoot, entry.getSourceAttachmentPath(), true);
-					if (target instanceof IFile){
-						IFile file = (IFile) target;
-						if (org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(file.getName())){
+					if (target instanceof IResource) {
+						if (target instanceof IFile){
+							IFile file = (IFile) target;
+							if (org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(file.getName())){
+								return entry;
+							}
+						} else if (target instanceof IContainer) {
 							return entry;
 						}
-					} else if (target instanceof IFolder) {
-						return entry;
-					}
-					if (target instanceof java.io.File){
+					} else if (target instanceof java.io.File){
 						java.io.File file = (java.io.File) target;
 						if (file.isFile()) {
 							if (org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(file.getName())){
@@ -428,6 +451,24 @@
 		return null;
 	}
 }		
+
+/*
+ * Returns the inclusion patterns from the classpath entry associated with this root.
+ */
+public char[][] fullInclusionPatternChars() {
+	try {
+		if (this.isOpen() && this.getKind() != IPackageFragmentRoot.K_SOURCE) return null;
+		ClasspathEntry entry = (ClasspathEntry)getRawClasspathEntry();
+		if (entry == null) {
+			return null;
+		} else {
+			return entry.fullInclusionPatternChars();
+		}
+	} catch (JavaModelException e) { 
+		return null;
+	}
+}		
+
 /**
  * @see IJavaElement
  */
@@ -443,7 +484,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);
@@ -490,7 +531,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);
@@ -562,7 +603,7 @@
 
 	IClasspathEntry rawEntry = null;
 	JavaProject project = (JavaProject)this.getJavaProject();
-	project.getResolvedClasspath(true); // force the reverse rawEntry cache to be populated
+	project.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/); // force the reverse rawEntry cache to be populated
 	JavaModelManager.PerProjectInfo perProjectInfo = project.getPerProjectInfo();
 	if (perProjectInfo != null && perProjectInfo.resolvedPathToRawEntries != null) {
 		rawEntry = (IClasspathEntry) perProjectInfo.resolvedPathToRawEntries.get(this.getPath());
@@ -726,6 +767,14 @@
 	return getResource();
 }
 
+/**
+ * @see IParent 
+ */
+public boolean hasChildren() throws JavaModelException {
+	// a package fragment root always has the default package as a child
+	return true;
+}
+
 public int hashCode() {
 	return this.resource.hashCode();
 }
@@ -752,8 +801,8 @@
 	IPath path = this.getPath();
 	try {
 		// check package fragment root on classpath of its project
-		IJavaProject project = this.getJavaProject();
-		IClasspathEntry[] classpath = project.getResolvedClasspath(true);	
+		JavaProject project = (JavaProject) getJavaProject();
+		IClasspathEntry[] classpath = project.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);	
 		for (int i = 0, length = classpath.length; i < length; i++) {
 			IClasspathEntry entry = classpath[i];
 			if (entry.getPath().equals(path)) {
@@ -778,7 +827,7 @@
 
 	MovePackageFragmentRootOperation op = 
 		new MovePackageFragmentRootOperation(this, destination, updateResourceFlags, updateModelFlags, sibling);
-	runOperation(op, monitor);
+	op.runOperation(monitor);
 }
 
 /**
@@ -786,15 +835,19 @@
  */
 protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
 	buffer.append(this.tabString(tab));
-	if (getElementName().length() == 0) {
-		buffer.append("<project root>"); //$NON-NLS-1$
-	} else {
-		IPath path = getPath();
-		if (getJavaProject().getElementName().equals(path.segment(0))) {
+	IPath path = getPath();
+	if (getJavaProject().getElementName().equals(path.segment(0))) {
+	    if (path.segmentCount() == 1) {
+	buffer.append("<project root>"); //$NON-NLS-1$
+	    } else {
 			buffer.append(path.removeFirstSegments(1).makeRelative());
-		} else {
+	    }
+	} else {
+	    if (isExternal()) {
+			buffer.append(path.toOSString());
+	    } else {
 			buffer.append(path);
-		}
+	    }
 	}
 	if (info == null) {
 		buffer.append(" (not open)"); //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRootInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRootInfo.java
index d45bd43..f110a9d 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRootInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRootInfo.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -48,7 +48,7 @@
  * Create and initialize a new instance of the receiver
  */
 public PackageFragmentRootInfo() {
-	fNonJavaResources = null;
+	this.fNonJavaResources = null;
 }
 /**
  * Starting at this folder, create non-java resources for this package fragment root 
@@ -56,11 +56,11 @@
  * 
  * @exception JavaModelException  The resource associated with this package fragment does not exist
  */
-static Object[] computeFolderNonJavaResources(JavaProject project, IContainer folder, char[][] exclusionPatterns) throws JavaModelException {
+static Object[] computeFolderNonJavaResources(JavaProject project, IContainer folder, char[][] inclusionPatterns, char[][] exclusionPatterns) throws JavaModelException {
 	Object[] nonJavaResources = new IResource[5];
 	int nonJavaResourcesCounter = 0;
 	try {
-		IClasspathEntry[] classpath = project.getResolvedClasspath(true/*ignore unresolved variable*/);
+		IClasspathEntry[] classpath = project.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
 		IResource[] members = folder.members();
 		nextResource: for (int i = 0, max = members.length; i < max; i++) {
 			IResource member = members[i];
@@ -69,7 +69,7 @@
 					String fileName = member.getName();
 					
 					// ignore .java files that are not excluded
-					if (Util.isValidCompilationUnitName(fileName) && !Util.isExcluded(member, exclusionPatterns)) 
+					if (Util.isValidCompilationUnitName(fileName) && !Util.isExcluded(member, inclusionPatterns, exclusionPatterns)) 
 						continue nextResource;
 					// ignore .class files
 					if (Util.isValidClassFileName(fileName)) 
@@ -82,7 +82,7 @@
 				case IResource.FOLDER :
 					// ignore valid packages or excluded folders that correspond to a nested pkg fragment root
 					if (Util.isValidFolderNameForPackage(member.getName())
-							&& (!Util.isExcluded(member, exclusionPatterns) 
+							&& (!Util.isExcluded(member, inclusionPatterns, exclusionPatterns) 
 								|| isClasspathEntry(member.getFullPath(), classpath)))
 						continue nextResource;
 					break;
@@ -104,8 +104,6 @@
 }
 /**
  * Compute the non-package resources of this package fragment root.
- * 
- * @exception JavaModelException  The resource associated with this package fragment root does not exist
  */
 private Object[] computeNonJavaResources(IJavaProject project, IResource underlyingResource, PackageFragmentRoot handle) {
 	Object[] nonJavaResources = NO_NON_JAVA_RESOURCES;
@@ -117,6 +115,7 @@
 				computeFolderNonJavaResources(
 					(JavaProject)project, 
 					(IContainer) underlyingResource,  
+					handle.fullInclusionPatternChars(),
 					handle.fullExclusionPatternChars());
 		}
 	} catch (JavaModelException e) {
@@ -128,10 +127,10 @@
  * Returns an array of non-java resources contained in the receiver.
  */
 synchronized Object[] getNonJavaResources(IJavaProject project, IResource underlyingResource, PackageFragmentRoot handle) {
-	Object[] nonJavaResources = fNonJavaResources;
+	Object[] nonJavaResources = this.fNonJavaResources;
 	if (nonJavaResources == null) {
 		nonJavaResources = this.computeNonJavaResources(project, underlyingResource, handle);
-		fNonJavaResources = nonJavaResources;
+		this.fNonJavaResources = nonJavaResources;
 	}
 	return nonJavaResources;
 }
@@ -139,7 +138,7 @@
  * Returns the kind of this root.
  */
 public int getRootKind() {
-	return fRootKind;
+	return this.fRootKind;
 }
 /**
  * Retuns the SourceMapper for this root, or <code>null</code>
@@ -161,13 +160,13 @@
  * Set the fNonJavaResources to res value
  */
 void setNonJavaResources(Object[] resources) {
-	fNonJavaResources = resources;
+	this.fNonJavaResources = resources;
 }
 /**
  * Sets the kind of this root.
  */
 protected void setRootKind(int newRootKind) {
-	fRootKind = newRootKind;
+	this.fRootKind = newRootKind;
 }
 /**
  * Sets the SourceMapper for this root.
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ReconcileWorkingCopyOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ReconcileWorkingCopyOperation.java
index 9dad92f..0def8a5 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ReconcileWorkingCopyOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ReconcileWorkingCopyOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -10,9 +10,13 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
+import java.util.Map;
+
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.dom.AST;
+import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
 import org.eclipse.jdt.internal.core.util.Util;
 
 /**
@@ -20,56 +24,70 @@
  */
 public class ReconcileWorkingCopyOperation extends JavaModelOperation {
 		
+	boolean createAST;
+	int astLevel;
 	boolean forceProblemDetection;
+	WorkingCopyOwner workingCopyOwner;
+	org.eclipse.jdt.core.dom.CompilationUnit ast;
 	
-	public ReconcileWorkingCopyOperation(IJavaElement workingCopy, boolean forceProblemDetection) {
+	public ReconcileWorkingCopyOperation(IJavaElement workingCopy, boolean creatAST, int astLevel, boolean forceProblemDetection, WorkingCopyOwner workingCopyOwner) {
 		super(new IJavaElement[] {workingCopy});
+		this.createAST = creatAST;
+		this.astLevel = astLevel;
 		this.forceProblemDetection = forceProblemDetection;
+		this.workingCopyOwner = workingCopyOwner;
 	}
 	/**
 	 * @exception JavaModelException if setting the source
 	 * 	of the original compilation unit fails
 	 */
 	protected void executeOperation() throws JavaModelException {
-		if (progressMonitor != null){
-			if (progressMonitor.isCanceled()) return;
-			progressMonitor.beginTask(Util.bind("element.reconciling"), 10); //$NON-NLS-1$
+		if (this.progressMonitor != null){
+			if (this.progressMonitor.isCanceled()) return;
+			this.progressMonitor.beginTask(Util.bind("element.reconciling"), 2); //$NON-NLS-1$
 		}
 	
 		CompilationUnit workingCopy = getWorkingCopy();
 		boolean wasConsistent = workingCopy.isConsistent();
-		JavaElementDeltaBuilder deltaBuilder = null;
-	
 		try {
-			// create the delta builder (this remembers the current content of the cu)
-			if (!wasConsistent){
-				deltaBuilder = new JavaElementDeltaBuilder(workingCopy);
+			if (!wasConsistent) {
+				// create the delta builder (this remembers the current content of the cu)
+				JavaElementDeltaBuilder deltaBuilder = new JavaElementDeltaBuilder(workingCopy);
 				
 				// update the element infos with the content of the working copy
-				workingCopy.makeConsistent(progressMonitor);
+				this.ast = workingCopy.makeConsistent(this.createAST, this.astLevel, this.progressMonitor);
 				deltaBuilder.buildDeltas();
-		
-			}
-	
-			if (progressMonitor != null) progressMonitor.worked(2);
+
+				if (progressMonitor != null) progressMonitor.worked(2);
 			
-			// force problem detection? - if structure was consistent
-			if (forceProblemDetection && wasConsistent){
-				if (progressMonitor != null && progressMonitor.isCanceled()) return;
-		
-				IProblemRequestor problemRequestor = workingCopy.getPerWorkingCopyInfo();
-				if (problemRequestor != null && problemRequestor.isActive()){
-					problemRequestor.beginReporting();
-					CompilationUnitProblemFinder.process(workingCopy, problemRequestor, progressMonitor);
-					problemRequestor.endReporting();
-				}
-			}
-			
-			// register the deltas
-			if (deltaBuilder != null){
+				// register the deltas
 				if (deltaBuilder.delta != null) {
 					addReconcileDelta(workingCopy, deltaBuilder.delta);
 				}
+			} else {
+				// force problem detection? - if structure was consistent
+				if (forceProblemDetection) {
+					IProblemRequestor problemRequestor = workingCopy.getPerWorkingCopyInfo();
+					if (problemRequestor != null && problemRequestor.isActive()) {
+					    CompilationUnitDeclaration unit = null;
+					    try {
+							problemRequestor.beginReporting();
+							char[] contents = workingCopy.getContents();
+							unit = CompilationUnitProblemFinder.process(workingCopy, contents, this.workingCopyOwner, problemRequestor, false/*don't cleanup cu*/, this.progressMonitor);
+							problemRequestor.endReporting();
+							if (progressMonitor != null) progressMonitor.worked(1);
+							if (this.createAST && unit != null) {
+								Map options = workingCopy.getJavaProject().getOptions(true);
+								this.ast = AST.convertCompilationUnit(this.astLevel, unit, contents, options, true/*isResolved*/, this.progressMonitor);
+								if (progressMonitor != null) progressMonitor.worked(1);
+							}
+					    } finally {
+					        if (unit != null) {
+					            unit.cleanUp();
+					        }
+					    }
+					}
+				}
 			}
 		} finally {
 			if (progressMonitor != null) progressMonitor.done();
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Region.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Region.java
index c9fa056..fde2ce0 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Region.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Region.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/RenameElementsOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/RenameElementsOperation.java
index eca7f3d..feef114 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/RenameElementsOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/RenameElementsOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/RenameResourceElementsOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/RenameResourceElementsOperation.java
index e8eab23..2715054 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/RenameResourceElementsOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/RenameResourceElementsOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SearchableEnvironment.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SearchableEnvironment.java
index 10001e3..fb09e05 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SearchableEnvironment.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SearchableEnvironment.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -12,12 +12,14 @@
 
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.IPackageFragment;
 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;
@@ -36,7 +38,8 @@
  */
 public class SearchableEnvironment
 	implements ISearchableNameEnvironment, IJavaSearchConstants {
-	protected NameLookup nameLookup;
+	
+	public NameLookup nameLookup;
 	protected ICompilationUnit unitToSkip;
 
 	protected IJavaProject project;
@@ -45,9 +48,20 @@
 	/**
 	 * Creates a SearchableEnvironment on the given project
 	 */
-	public SearchableEnvironment(IJavaProject project) throws JavaModelException {
+	public SearchableEnvironment(JavaProject project, org.eclipse.jdt.core.ICompilationUnit[] workingCopies) throws JavaModelException {
 		this.project = project;
-		this.nameLookup = ((JavaProject) project).getNameLookup();
+		this.nameLookup = project.newNameLookup(workingCopies);
+
+		// Create search scope with visible entry on the project's classpath
+		this.searchScope = SearchEngine.createJavaSearchScope(this.project.getAllPackageFragmentRoots());
+	}
+
+	/**
+	 * Creates a SearchableEnvironment on the given project
+	 */
+	public SearchableEnvironment(JavaProject project, WorkingCopyOwner owner) throws JavaModelException {
+		this.project = project;
+		this.nameLookup = project.newNameLookup(owner);
 
 		// Create search scope with visible entry on the project's classpath
 		this.searchScope = SearchEngine.createJavaSearchScope(this.project.getAllPackageFragmentRoots());
@@ -88,10 +102,11 @@
 
 					// in the resulting collection, ensure the requested type is the first one
 					sourceTypes[0] = sourceType;
-					for (int i = 0, index = 1; i < types.length; i++) {
+					int length = types.length;
+					for (int i = 0, index = 1; i < length; i++) {
 						ISourceType otherType =
 							(ISourceType) ((JavaElement) types[i]).getElementInfo();
-						if (!otherType.equals(topLevelType))
+						if (!otherType.equals(topLevelType) && index < length) // check that the index is in bounds (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=62861)
 							sourceTypes[index++] = otherType;
 					}
 					return new NameEnvironmentAnswer(sourceTypes);
@@ -114,7 +129,7 @@
 	}
 
 	/**
-	 * @see INameEnvironment#findType(char[][])
+	 * @see org.eclipse.jdt.internal.compiler.env.INameEnvironment#findType(char[][])
 	 */
 	public NameEnvironmentAnswer findType(char[][] compoundTypeName) {
 		if (compoundTypeName == null) return null;
@@ -135,7 +150,7 @@
 	}
 
 	/**
-	 * @see INameEnvironment#findType(char[], char[][])
+	 * @see org.eclipse.jdt.internal.compiler.env.INameEnvironment#findType(char[], char[][])
 	 */
 	public NameEnvironmentAnswer findType(char[] name, char[][] packageName) {
 		if (name == null) return null;
@@ -236,11 +251,9 @@
 			};
 			try {
 				new SearchEngine().searchAllTypeNames(
-					this.project.getProject().getWorkspace(),
 					qualification,
 					simpleName,
-					PREFIX_MATCH,
-					CASE_INSENSITIVE,
+					SearchPattern.R_PREFIX_MATCH, // not case sensitive
 					IJavaSearchConstants.TYPE,
 					this.searchScope,
 					nameRequestor,
@@ -287,7 +300,7 @@
 	}
 
 	/**
-	 * @see INameEnvironment#isPackage(char[][], char[])
+	 * @see org.eclipse.jdt.internal.compiler.env.INameEnvironment#isPackage(char[][], char[])
 	 */
 	public boolean isPackage(char[][] parentPackageName, char[] subPackageName) {
 		if (subPackageName == null || CharOperation.contains('.', subPackageName))
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SearchableEnvironmentRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SearchableEnvironmentRequestor.java
index 67ec4fa..d06e21d 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SearchableEnvironmentRequestor.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SearchableEnvironmentRequestor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SelectionRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SelectionRequestor.java
index ecfe7b9..93a3d5f 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SelectionRequestor.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SelectionRequestor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -17,6 +17,7 @@
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.IMethod;
 import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.jdt.core.ISourceRange;
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.Signature;
@@ -98,8 +99,8 @@
 /**
  * Resolve the class.
  */
-public void acceptClass(char[] packageName, char[] className, boolean needQualification) {
-	acceptType(packageName, className, NameLookup.ACCEPT_CLASSES, needQualification);
+public void acceptClass(char[] packageName, char[] className, boolean needQualification, boolean isDeclaration, int start, int end) {
+	acceptType(packageName, className, NameLookup.ACCEPT_CLASSES, needQualification, isDeclaration, start, end);
 }
 /**
  * @see ISelectionRequestor#acceptError
@@ -110,17 +111,45 @@
 /**
  * Resolve the field.
  */
-public void acceptField(char[] declaringTypePackageName, char[] declaringTypeName, char[] name) {
-	IType type= resolveType(declaringTypePackageName, declaringTypeName,
-		NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES);
-	if (type != null) {
-		IField field= type.getField(new String(name));
-		if (field.exists()) {
-			addElement(field);
-			if(SelectionEngine.DEBUG){
-				System.out.print("SELECTION - accept field("); //$NON-NLS-1$
-				System.out.print(field.toString());
-				System.out.println(")"); //$NON-NLS-1$
+public void acceptField(char[] declaringTypePackageName, char[] declaringTypeName, char[] name, boolean isDeclaration, int start, int end) {
+	if(isDeclaration) {
+		IType type= resolveTypeByLocation(declaringTypePackageName, declaringTypeName,
+				NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES,
+				start, end);
+		if(type != null) {
+			try {
+				IField[] fields = type.getFields();
+				for (int i = 0; i < fields.length; i++) {
+					IField field = fields[i];
+					ISourceRange range = field.getNameRange();
+					if(range.getOffset() <= start
+							&& range.getOffset() + range.getLength() >= end
+							&& field.getElementName().equals(new String(name))) {
+						addElement(fields[i]);
+						if(SelectionEngine.DEBUG){
+							System.out.print("SELECTION - accept field("); //$NON-NLS-1$
+							System.out.print(field.toString());
+							System.out.println(")"); //$NON-NLS-1$
+						}
+						return; // only one method is possible
+					}
+				}
+			} catch (JavaModelException e) {
+				return; 
+			}
+		}
+	} else {
+		IType type= resolveType(declaringTypePackageName, declaringTypeName,
+				NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES);
+		if (type != null) {
+			IField field= type.getField(new String(name));
+			if (field.exists()) {
+				addElement(field);
+				if(SelectionEngine.DEBUG){
+					System.out.print("SELECTION - accept field("); //$NON-NLS-1$
+					System.out.print(field.toString());
+					System.out.println(")"); //$NON-NLS-1$
+				}
 			}
 		}
 	}
@@ -128,8 +157,8 @@
 /**
  * Resolve the interface
  */
-public void acceptInterface(char[] packageName, char[] interfaceName, boolean needQualification) {
-	acceptType(packageName, interfaceName, NameLookup.ACCEPT_INTERFACES, needQualification);
+public void acceptInterface(char[] packageName, char[] interfaceName, boolean needQualification, boolean isDeclaration, int start, int end) {
+	acceptType(packageName, interfaceName, NameLookup.ACCEPT_INTERFACES, needQualification, isDeclaration, start, end);
 }
 public void acceptLocalField(SourceTypeBinding typeBinding, char[] name, CompilationUnitDeclaration parsedUnit) {
 	IType type = (IType)this.handleFactory.createElement(typeBinding.scope.referenceContext, parsedUnit, this.openable);
@@ -145,7 +174,7 @@
 		}
 	}
 }
-public void acceptLocalMethod(SourceTypeBinding typeBinding, char[] selector, char[][] parameterPackageNames, char[][] parameterTypeNames, boolean isConstructor, CompilationUnitDeclaration parsedUnit) {
+public void acceptLocalMethod(SourceTypeBinding typeBinding, char[] selector, char[][] parameterPackageNames, char[][] parameterTypeNames, boolean isConstructor, CompilationUnitDeclaration parsedUnit, boolean isDeclaration, int start, int end) {
 	IType type = (IType)this.handleFactory.createElement(typeBinding.scope.referenceContext, parsedUnit, this.openable);
 	// fix for 1FWFT6Q
 	if (type != null) {
@@ -201,35 +230,45 @@
 /**
  * Resolve the method
  */
-public void acceptMethod(char[] declaringTypePackageName, char[] declaringTypeName, char[] selector, char[][] parameterPackageNames, char[][] parameterTypeNames, boolean isConstructor) {
-	IType type= resolveType(declaringTypePackageName, declaringTypeName,
-		NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES);
-	// fix for 1FWFT6Q
-	if (type != null) {
-		if (type.isBinary()) {
-			
-			// need to add a paramater for constructor in binary type
-			IType declaringDeclaringType = type.getDeclaringType();
-			
-			boolean isStatic = false;
-			try {
-				isStatic = Flags.isStatic(type.getFlags());
-			} catch (JavaModelException e) {
-				// isStatic == false
-			}
-			
-			if(declaringDeclaringType != null && isConstructor	&& !isStatic) {
-				int length = parameterPackageNames.length;
-				System.arraycopy(parameterPackageNames, 0, parameterPackageNames = new char[length+1][], 1, length);
-				System.arraycopy(parameterTypeNames, 0, parameterTypeNames = new char[length+1][], 1, length);
+public void acceptMethod(char[] declaringTypePackageName, char[] declaringTypeName, char[] selector, char[][] parameterPackageNames, char[][] parameterTypeNames, boolean isConstructor, boolean isDeclaration, int start, int end) {
+	if(isDeclaration) {
+		IType type = resolveTypeByLocation(declaringTypePackageName, declaringTypeName,
+				NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES,
+				start, end);
+		
+		if(type != null) {
+			this.acceptMethodDeclaration(type, selector, start, end);
+		}
+	} else {
+		IType type = resolveType(declaringTypePackageName, declaringTypeName,
+			NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES);
+		// fix for 1FWFT6Q
+		if (type != null) {
+			if (type.isBinary()) {
 				
-				parameterPackageNames[0] = declaringDeclaringType.getPackageFragment().getElementName().toCharArray();
-				parameterTypeNames[0] = declaringDeclaringType.getTypeQualifiedName().toCharArray();
+				// need to add a paramater for constructor in binary type
+				IType declaringDeclaringType = type.getDeclaringType();
+				
+				boolean isStatic = false;
+				try {
+					isStatic = Flags.isStatic(type.getFlags());
+				} catch (JavaModelException e) {
+					// isStatic == false
+				}
+				
+				if(declaringDeclaringType != null && isConstructor	&& !isStatic) {
+					int length = parameterPackageNames.length;
+					System.arraycopy(parameterPackageNames, 0, parameterPackageNames = new char[length+1][], 1, length);
+					System.arraycopy(parameterTypeNames, 0, parameterTypeNames = new char[length+1][], 1, length);
+					
+					parameterPackageNames[0] = declaringDeclaringType.getPackageFragment().getElementName().toCharArray();
+					parameterTypeNames[0] = declaringDeclaringType.getTypeQualifiedName().toCharArray();
+				}
+				
+				acceptBinaryMethod(type, selector, parameterPackageNames, parameterTypeNames);
+			} else {
+				acceptSourceMethod(type, selector, parameterPackageNames, parameterTypeNames);
 			}
-			
-			acceptBinaryMethod(type, selector, parameterPackageNames, parameterTypeNames);
-		} else {
-			acceptSourceMethod(type, selector, parameterPackageNames, parameterTypeNames);
 		}
 	}
 }
@@ -260,7 +299,8 @@
 	try {
 		methods = type.getMethods();
 		for (int i = 0; i < methods.length; i++) {
-			if (methods[i].getElementName().equals(name) && methods[i].getParameterTypes().length == parameterTypeNames.length) {
+			if (methods[i].getElementName().equals(name)
+					&& methods[i].getParameterTypes().length == parameterTypeNames.length) {
 				addElement(methods[i]);
 			}
 		}
@@ -318,11 +358,49 @@
 	}
 	
 }
+protected void acceptMethodDeclaration(IType type, char[] selector, int start, int end) {
+	String name = new String(selector);
+	IMethod[] methods = null;
+	try {
+		methods = type.getMethods();
+		for (int i = 0; i < methods.length; i++) {
+			ISourceRange range = methods[i].getNameRange();
+			if(range.getOffset() <= start
+					&& range.getOffset() + range.getLength() >= end
+					&& methods[i].getElementName().equals(name)) {
+				addElement(methods[i]);
+				if(SelectionEngine.DEBUG){
+					System.out.print("SELECTION - accept method("); //$NON-NLS-1$
+					System.out.print(this.elements[0].toString());
+					System.out.println(")"); //$NON-NLS-1$
+				}
+				return; // only one method is possible
+			}
+		}
+	} catch (JavaModelException e) {
+		return; 
+	}
+
+	// no match was actually found
+	addElement(type);
+	if(SelectionEngine.DEBUG){
+		System.out.print("SELECTION - accept type("); //$NON-NLS-1$
+		System.out.print(type.toString());
+		System.out.println(")"); //$NON-NLS-1$
+	}
+	return;
+}
 /**
  * Resolve the type, adding to the resolved elements.
  */
-protected void acceptType(char[] packageName, char[] typeName, int acceptFlags, boolean needQualification) {
-	IType type= resolveType(packageName, typeName, acceptFlags);
+protected void acceptType(char[] packageName, char[] typeName, int acceptFlags, boolean needQualification, boolean isDeclaration, int start, int end) {
+	IType type = null;
+	if(isDeclaration) {
+		type = resolveTypeByLocation(packageName, typeName, acceptFlags, start, end);
+	} else {
+		type = resolveType(packageName, typeName, acceptFlags);
+	}
+	
 	if (type != null) {
 		addElement(type);
 		if(SelectionEngine.DEBUG){
@@ -331,7 +409,6 @@
 			System.out.println(")"); //$NON-NLS-1$
 		}
 	} 
-	
 }
 /*
  * Adds the given element to the list of resolved elements.
@@ -419,4 +496,84 @@
 	}
 	return type;
 }
+protected IType resolveTypeByLocation(char[] packageName, char[] typeName, int acceptFlags, int start, int end) {
+
+	IType type= null;
+	
+	// TODO (david) post 3.0 should remove isOpen check, and investigate reusing ICompilationUnit#getElementAt. may need to optimize #getElementAt to remove recursions
+	if (this.openable instanceof CompilationUnit && ((CompilationUnit)this.openable).isOpen()) {
+		CompilationUnit wc = (CompilationUnit) this.openable;
+		try {
+			if(((packageName == null || packageName.length == 0) && wc.getPackageDeclarations().length == 0) ||
+				(!(packageName == null || packageName.length == 0) && wc.getPackageDeclaration(new String(packageName)).exists())) {
+					
+				char[][] compoundName = CharOperation.splitOn('.', typeName);
+				if(compoundName.length > 0) {
+					
+					IType[] tTypes = wc.getTypes();
+					int i = 0;
+					int depth = 0;
+					done : while(i < tTypes.length) {
+						ISourceRange range = tTypes[i].getSourceRange();
+						if(range.getOffset() <= start
+								&& range.getOffset() + range.getLength() >= end
+								&& tTypes[i].getElementName().equals(new String(compoundName[depth]))) {
+							if(depth == compoundName.length - 1) {
+								type = tTypes[i];
+								break done;
+							}
+							tTypes = tTypes[i].getTypes();
+							i = 0;
+							depth++;
+							continue done;
+						}
+						i++;
+					}
+				}
+				
+				if(type != null && !type.exists()) {
+					type = null;
+				}
+			}
+		}catch (JavaModelException e) {
+			type = null;
+		}
+	}
+
+	if(type == null) {
+		IPackageFragment[] pkgs = this.nameLookup.findPackageFragments(
+			(packageName == null || packageName.length == 0) ? IPackageFragment.DEFAULT_PACKAGE_NAME : new String(packageName), 
+			false);
+		// iterate type lookup in each package fragment
+		for (int i = 0, length = pkgs == null ? 0 : pkgs.length; i < length; i++) {
+			type= this.nameLookup.findType(new String(typeName), pkgs[i], false, acceptFlags);
+			if (type != null) break;	
+		}
+		if (type == null) {
+			String pName= IPackageFragment.DEFAULT_PACKAGE_NAME;
+			if (packageName != null) {
+				pName = new String(packageName);
+			}
+			if (this.openable != null && this.openable.getParent().getElementName().equals(pName)) {
+				// look inside the type in which we are resolving in
+				String tName= new String(typeName);
+				tName = tName.replace('.','$');
+				IType[] allTypes= null;
+				try {
+					ArrayList list = this.openable.getChildrenOfType(IJavaElement.TYPE);
+					allTypes = new IType[list.size()];
+					list.toArray(allTypes);
+				} catch (JavaModelException e) {
+					return null;
+				}
+				for (int i= 0; i < allTypes.length; i++) {
+					if (allTypes[i].getTypeQualifiedName().equals(tName)) {
+						return allTypes[i];
+					}
+				}
+			}
+		}
+	}
+	return type;
+}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SetClasspathOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SetClasspathOperation.java
index b3845ec..1bb8d83 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SetClasspathOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SetClasspathOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -17,11 +17,8 @@
 import java.util.Iterator;
 
 import org.eclipse.core.resources.IFolder;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.IProjectDescription;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.resources.IWorkspace;
-import org.eclipse.core.resources.IWorkspaceRoot;
 import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPath;
@@ -50,6 +47,7 @@
 	IClasspathEntry[] oldResolvedPath, newResolvedPath;
 	IClasspathEntry[] newRawPath;
 	boolean canChangeResources;
+	boolean classpathWasSaved;
 	boolean needCycleCheck;
 	boolean needValidation;
 	boolean needSave;
@@ -122,6 +120,7 @@
 		IClasspathEntry entry) {
 
 		IPath[] exclusionPatterns = entry.getExclusionPatterns();
+		IPath[] inclusionPatterns = entry.getInclusionPatterns();
 		nextEntry: for (int i = 0; i < list.length; i++) {
 			IClasspathEntry other = list[i];
 			if (other.getContentKind() == entry.getContentKind()
@@ -139,11 +138,26 @@
 							continue;
 					}
 					
+					// check inclusion patterns
+					IPath[] otherIncludes = other.getInclusionPatterns();
+					if (inclusionPatterns != otherIncludes) {
+					    if (inclusionPatterns == null) continue;
+						int includeLength = inclusionPatterns.length;
+						if (otherIncludes == null || otherIncludes.length != includeLength)
+							continue;
+						for (int j = 0; j < includeLength; j++) {
+							// compare toStrings instead of IPaths 
+							// since IPath.equals is specified to ignore trailing separators
+							if (!inclusionPatterns[j].toString().equals(otherIncludes[j].toString()))
+								continue nextEntry;
+						}
+					}
 					// check exclusion patterns
 					IPath[] otherExcludes = other.getExclusionPatterns();
 					if (exclusionPatterns != otherExcludes) {
+					    if (exclusionPatterns == null) continue;
 						int excludeLength = exclusionPatterns.length;
-						if (otherExcludes.length != excludeLength)
+						if (otherExcludes == null || otherExcludes.length != excludeLength)
 							continue;
 						for (int j = 0; j < excludeLength; j++) {
 							// compare toStrings instead of IPaths 
@@ -266,7 +280,7 @@
 						this.project.getProject().touch(this.progressMonitor);
 					} catch (CoreException e) {
 						if (JavaModelManager.CP_RESOLVE_VERBOSE){
-							System.out.println("CPInit - FAILED to touch project: "+ this.project.getElementName()); //$NON-NLS-1$
+							Util.verbose("CPContainer INIT - FAILED to touch project: "+ this.project.getElementName(), System.err); //$NON-NLS-1$
 							e.printStackTrace();
 						}
 					}
@@ -287,6 +301,10 @@
 		boolean needToUpdateDependents = false;
 		JavaElementDelta delta = new JavaElementDelta(getJavaModel());
 		boolean hasDelta = false;
+		if (this.classpathWasSaved) {
+			delta.changed(this.project, IJavaElementDelta.F_CLASSPATH_CHANGED);
+			hasDelta = true;
+		}
 		int oldLength = oldResolvedPath.length;
 		int newLength = newResolvedPath.length;
 			
@@ -360,13 +378,14 @@
 					final IPath path = oldEntry.getPath();
 					switch (changeKind) {
 						case IClasspathEntry.CPE_SOURCE:
+							final char[][] inclusionPatterns = ((ClasspathEntry)oldEntry).fullInclusionPatternChars();
 							final char[][] exclusionPatterns = ((ClasspathEntry)oldEntry).fullExclusionPatternChars();
 							postAction(new IPostAction() {
 								public String getID() {
 									return path.toString();
 								}
 								public void run() /* throws JavaModelException */ {
-									indexManager.removeSourceFolderFromIndex(project, path, exclusionPatterns);
+									indexManager.removeSourceFolderFromIndex(project, path, inclusionPatterns, exclusionPatterns);
 								}
 							}, 
 							REMOVEALL_APPEND);
@@ -486,13 +505,14 @@
 						case IClasspathEntry.CPE_SOURCE:
 							IClasspathEntry entry = newResolvedPath[i];
 							final IPath path = entry.getPath();
+							final char[][] inclusionPatterns = ((ClasspathEntry)entry).fullInclusionPatternChars();
 							final char[][] exclusionPatterns = ((ClasspathEntry)entry).fullExclusionPatternChars();
 							postAction(new IPostAction() {
 								public String getID() {
 									return path.toString();
 								}
 								public void run() /* throws JavaModelException */ {
-									indexManager.indexSourceFolder(project, path, exclusionPatterns);
+									indexManager.indexSourceFolder(project, path, inclusionPatterns, exclusionPatterns);
 								}
 							}, 
 							APPEND); // append so that a removeSourceFolder action is not removed
@@ -515,7 +535,6 @@
 			updateAffectedProjects(project.getProject().getFullPath());
 		}
 	}
-
 	/*
 	 * Returns the source attachment flag for the delta between the 2 give source paths.
 	 * Returns either F_SOURCEATTACHED, F_SOURCEDETACHED, F_SOURCEATTACHED | F_SOURCEDETACHED
@@ -563,6 +582,7 @@
 		}
 		// if read-only .classpath, then the classpath setting will never been performed completely
 		if (project.saveClasspath(classpathForSave, outputLocationForSave)) {
+			this.classpathWasSaved = true;
 			this.setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); 
 		}
 	}
@@ -599,7 +619,7 @@
 
 		// resolve new path (asking for marker creation if problems)
 		if (this.newResolvedPath == null) {
-			this.newResolvedPath = project.getResolvedClasspath(true, this.canChangeResources);
+			this.newResolvedPath = project.getResolvedClasspath(true, this.canChangeResources, false/*don't returnResolutionInProgress*/);
 		}
 		
 		if (this.oldResolvedPath != null) {
@@ -649,7 +669,7 @@
 											SetClasspathOperation.ReuseOutputLocation, 
 											SetClasspathOperation.this.progressMonitor, 
 											SetClasspathOperation.this.canChangeResources,  
-											affectedProject.getResolvedClasspath(true), 
+											affectedProject.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/), 
 											false, // updating only - no validation
 											false); // updating only - no need to save
 									}
@@ -746,72 +766,14 @@
 	 */
 	protected void updateProjectReferencesIfNecessary() throws JavaModelException {
 		
-		if (!this.canChangeResources) return;
 		if (this.newRawPath == ReuseClasspath || this.newRawPath == UpdateClasspath) return;
-	
-		String[] oldRequired = this.project.projectPrerequisites(this.oldResolvedPath);
-
-		if (this.newResolvedPath == null) {
-			this.newResolvedPath = this.project.getResolvedClasspath(this.newRawPath, null, true, true, null/*no reverse map*/);
-		}
-		String[] newRequired = this.project.projectPrerequisites(this.newResolvedPath);
-	
-		try {		
-			IProject projectResource = this.project.getProject();
-			IProjectDescription description = projectResource.getDescription();
-			 
-			IProject[] projectReferences = description.getReferencedProjects();
-			
-			HashSet oldReferences = new HashSet(projectReferences.length);
-			for (int i = 0; i < projectReferences.length; i++){
-				String projectName = projectReferences[i].getName();
-				oldReferences.add(projectName);
-			}
-			HashSet newReferences = (HashSet)oldReferences.clone();
-	
-			for (int i = 0; i < oldRequired.length; i++){
-				String projectName = oldRequired[i];
-				newReferences.remove(projectName);
-			}
-			for (int i = 0; i < newRequired.length; i++){
-				String projectName = newRequired[i];
-				newReferences.add(projectName);
-			}
-	
-			Iterator iter;
-			int newSize = newReferences.size();
-			
-			checkIdentity: {
-				if (oldReferences.size() == newSize){
-					iter = newReferences.iterator();
-					while (iter.hasNext()){
-						if (!oldReferences.contains(iter.next())){
-							break checkIdentity;
-						}
-					}
-					return;
-				}
-			}
-			String[] requiredProjectNames = new String[newSize];
-			int index = 0;
-			iter = newReferences.iterator();
-			while (iter.hasNext()){
-				requiredProjectNames[index++] = (String)iter.next();
-			}
-			Util.sort(requiredProjectNames); // ensure that if changed, the order is consistent
-			
-			IProject[] requiredProjectArray = new IProject[newSize];
-			IWorkspaceRoot wksRoot = projectResource.getWorkspace().getRoot();
-			for (int i = 0; i < newSize; i++){
-				requiredProjectArray[i] = wksRoot.getProject(requiredProjectNames[i]);
-			}
-	
-			description.setReferencedProjects(requiredProjectArray);
-			projectResource.setDescription(description, this.progressMonitor);
-	
-		} catch(CoreException e){
-			throw new JavaModelException(e);
-		}
+		// will run now, or be deferred until next pre-auto-build notification if resource tree is locked
+		JavaModelManager.getJavaModelManager().deltaState.performClasspathResourceChange(
+		        project, 
+		        oldResolvedPath, 
+		        newResolvedPath, 
+		        newRawPath, 
+		        canChangeResources);
 	}
 
 	public IJavaModelStatus verify() {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SimpleDelta.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SimpleDelta.java
index 522589c..1eed95e 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SimpleDelta.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SimpleDelta.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SingleTypeRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SingleTypeRequestor.java
index 1908d03..577b051 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SingleTypeRequestor.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SingleTypeRequestor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SortElementBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SortElementBuilder.java
index 92f17b3..ae7c5cc 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SortElementBuilder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SortElementBuilder.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -931,8 +931,8 @@
 		this.source = source;
 		this.comparator = comparator;
 		this.positionsToMap = positionsToMap;
-		this.scanner = new Scanner(false, false, false, ClassFileConstants.JDK1_3/*sourceLevel*/, null, null);
-		this.ast = new AST();
+		this.scanner = new Scanner(false, false, false, ClassFileConstants.JDK1_3/*sourceLevel*/, null, null, true/*taskCaseSensitive*/);
+		this.ast = AST.newAST(AST.JLS2);
 	}
 	
 	/*
@@ -982,7 +982,7 @@
 	}
 	
 	void sort() {
-		compilationUnit.sort();
+		this.compilationUnit.sort();
 	}
 
 	void mapNextPosition(SortJavaElement node, int start, int end) {
@@ -999,7 +999,7 @@
 		this.positionsToMapIndex = i;
 	}
 	/**
-	 * @see org.eclipse.jdt.internal.compiler.ISourceElementRequestor#enterClass(int, int, char, int, int, char, char)
+	 * @see org.eclipse.jdt.internal.compiler.ISourceElementRequestor#enterClass(int, int, char[], int, int, char[], char[][])
 	 */
 	public void enterClass(
 		int declarationStart,
@@ -1019,11 +1019,11 @@
 	 */
 	public void enterCompilationUnit() {
 		this.stack = new Stack();
-		push(compilationUnit = new SortCompilationUnit(0));
+		push(this.compilationUnit = new SortCompilationUnit(0));
 	}
 
 	/**
-	 * @see org.eclipse.jdt.internal.compiler.ISourceElementRequestor#enterConstructor(int, int, char, int, int, char, char, char)
+	 * @see org.eclipse.jdt.internal.compiler.ISourceElementRequestor#enterConstructor(int, int, char[], int, int, char[][], char[][], char[][])
 	 */
 	public void enterConstructor(
 		int declarationStart,
@@ -1042,7 +1042,7 @@
 	}
 
 	/**
-	 * @see org.eclipse.jdt.internal.compiler.ISourceElementRequestor#enterField(int, int, char, char, int, int)
+	 * @see org.eclipse.jdt.internal.compiler.ISourceElementRequestor#enterField(int, int, char[], char[], int, int)
 	 */
 	public void enterField(
 		int declarationStart,
@@ -1084,7 +1084,7 @@
 	}
 
 	/**
-	 * @see org.eclipse.jdt.internal.compiler.ISourceElementRequestor#enterInterface(int, int, char, int, int, char)
+	 * @see org.eclipse.jdt.internal.compiler.ISourceElementRequestor#enterInterface(int, int, char[], int, int, char[][])
 	 */
 	public void enterInterface(
 		int declarationStart,
@@ -1099,7 +1099,7 @@
 	}
 
 	/**
-	 * @see org.eclipse.jdt.internal.compiler.ISourceElementRequestor#enterMethod(int, int, char, char, int, int, char, char, char)
+	 * @see org.eclipse.jdt.internal.compiler.ISourceElementRequestor#enterMethod(int, int, char[], char[], int, int, char[][], char[][], char[][])
 	 */
 	public void enterMethod(
 		int declarationStart,
@@ -1141,7 +1141,7 @@
 	}
 
 	/**
-	 * @see org.eclipse.jdt.internal.compiler.ISourceElementRequestor#exitField(int, int)
+	 * @see org.eclipse.jdt.internal.compiler.ISourceElementRequestor#exitField(int, int, int)
 	 */
 	public void exitField(int initializationStart, int declarationEnd, int declarationSourceEnd) {
 		int normalizedDeclarationSourceEnd = this.normalizeSourceEnd(declarationSourceEnd);
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SortElementsOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SortElementsOperation.java
index a5996d2..9e11710 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SortElementsOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SortElementsOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -41,6 +41,8 @@
 	/**
 	 * Constructor for SortElementsOperation.
 	 * @param elements
+	 * @param positions
+	 * @param comparator
 	 */
 	public SortElementsOperation(IJavaElement[] elements, int[] positions, Comparator comparator) {
 		super(elements);
@@ -53,7 +55,7 @@
 	 * progress reporting.
 	 */
 	protected int getMainAmountOfWork(){
-		return elementsToProcess.length;
+		return this.elementsToProcess.length;
 	}
 	
 	/**
@@ -62,14 +64,14 @@
 	protected void executeOperation() throws JavaModelException {
 		try {
 			beginTask(Util.bind("operation.sortelements"), getMainAmountOfWork()); //$NON-NLS-1$
-			CompilationUnit copy = (CompilationUnit) elementsToProcess[0];
+			CompilationUnit copy = (CompilationUnit) this.elementsToProcess[0];
 			ICompilationUnit unit = copy.getPrimary();
 			IBuffer buffer = copy.getBuffer();
 			if (buffer  == null) { 
 				return;
 			}
 			char[] bufferContents = buffer.getCharacters();
-			String result = processElement(unit, positions, bufferContents);
+			String result = processElement(unit, this.positions, bufferContents);
 			if (!CharOperation.equals(result.toCharArray(), bufferContents)) {
 				copy.getBuffer().setContents(result);
 			}
@@ -82,10 +84,11 @@
 	/**
 	 * Method processElement.
 	 * @param unit
-	 * @param bufferContents
+	 * @param positionsToMap
+	 * @param source
 	 */
 	private String processElement(ICompilationUnit unit, int[] positionsToMap, char[] source) {
-		SortElementBuilder builder = new SortElementBuilder(source, positionsToMap, comparator);
+		SortElementBuilder builder = new SortElementBuilder(source, positionsToMap, this.comparator);
 		SourceElementParser parser = new SourceElementParser(builder,
 			ProblemFactory.getProblemFactory(Locale.getDefault()), new CompilerOptions(JavaCore.getOptions()), true);
 		
@@ -100,7 +103,7 @@
 					source,
 					expectedPackageName,
 					unit.getElementName(),
-					null),
+					unit),
 				false/*diet parse*/);
 		} else {
 			parser.parseCompilationUnit(
@@ -108,7 +111,7 @@
 					source,
 					null,
 					"",//$NON-NLS-1$
-					null),
+					unit.getJavaProject()),//$NON-NLS-1$
 				false/*diet parse*/);
 		}
 		return builder.getSource();
@@ -120,18 +123,17 @@
 	 *  <li>NO_ELEMENTS_TO_PROCESS - the compilation unit supplied to the operation is <code>null</code></li>.
 	 *  <li>INVALID_ELEMENT_TYPES - the supplied elements are not an instance of IWorkingCopy</li>.
 	 * </ul>
-	 * @see IJavaModelStatus
-	 * @see JavaConventions
+	 * @return IJavaModelStatus
 	 */
 	public IJavaModelStatus verify() {
-		if (elementsToProcess.length != 1) {
+		if (this.elementsToProcess.length != 1) {
 			return new JavaModelStatus(IJavaModelStatusConstants.NO_ELEMENTS_TO_PROCESS);
 		}
-		if (elementsToProcess[0] == null) {
+		if (this.elementsToProcess[0] == null) {
 			return new JavaModelStatus(IJavaModelStatusConstants.NO_ELEMENTS_TO_PROCESS);
 		}
-		if (!(elementsToProcess[0] instanceof ICompilationUnit) || !((ICompilationUnit) elementsToProcess[0]).isWorkingCopy()) {
-			return new JavaModelStatus(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, elementsToProcess[0]);
+		if (!(this.elementsToProcess[0] instanceof ICompilationUnit) || !((ICompilationUnit) this.elementsToProcess[0]).isWorkingCopy()) {
+			return new JavaModelStatus(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, this.elementsToProcess[0]);
 		}
 		return JavaModelStatus.VERIFIED_OK;
 	}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SortJavaElement.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SortJavaElement.java
index e7dc5f4..d8aae70 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SortJavaElement.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SortJavaElement.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceField.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceField.java
index d04ee34..5974b74 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceField.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceField.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -15,7 +15,7 @@
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.Signature;
-import org.eclipse.jdt.core.jdom.IDOMNode;
+import org.eclipse.jdt.core.jdom.*;
 
 /**
  * @see IField
@@ -35,7 +35,9 @@
 }
 /**
  * @see JavaElement#equalsDOMNode
+ * @deprecated JDOM is obsolete
  */
+// TODO - JDOM - remove once model ported off of JDOM
 protected boolean equalsDOMNode(IDOMNode node) {
 	return (node.getNodeType() == IDOMNode.FIELD) && super.equalsDOMNode(node);
 }
@@ -117,15 +119,15 @@
 protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
 	buffer.append(this.tabString(tab));
 	if (info == null) {
-		buffer.append(getElementName());
+		toStringName(buffer);
 		buffer.append(" (not open)"); //$NON-NLS-1$
 	} else if (info == NO_INFO) {
-		buffer.append(getElementName());
+		toStringName(buffer);
 	} else {
 		try {
 			buffer.append(Signature.toString(this.getTypeSignature()));
 			buffer.append(" "); //$NON-NLS-1$
-			buffer.append(this.getElementName());
+			toStringName(buffer);
 		} catch (JavaModelException e) {
 			buffer.append("<JavaModelException in toString of " + getElementName()); //$NON-NLS-1$
 		}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceFieldElementInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceFieldElementInfo.java
index 4d9dd85..df249da 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceFieldElementInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceFieldElementInfo.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMapper.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMapper.java
index a53a21c..d969ade 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMapper.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMapper.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -21,7 +21,8 @@
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
-import org.eclipse.core.resources.*;
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IFolder;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.resources.ResourcesPlugin;
@@ -29,8 +30,17 @@
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Path;
-import org.eclipse.jdt.core.*;
-import org.eclipse.jdt.core.compiler.*;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IMember;
+import org.eclipse.jdt.core.IMethod;
+import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
+import org.eclipse.jdt.core.ISourceRange;
+import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.JavaConventions;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.Signature;
+import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.compiler.IProblem;
 import org.eclipse.jdt.internal.compiler.IProblemFactory;
 import org.eclipse.jdt.internal.compiler.ISourceElementRequestor;
@@ -110,7 +120,7 @@
 	/**
 	 * The unknown source range {-1, 0}
 	 */
-	protected static SourceRange fgUnknownRange = new SourceRange(-1, 0);
+	public static SourceRange fgUnknownRange = new SourceRange(-1, 0);
 
 	/**
 	 * The position within the source of the start of the
@@ -184,7 +194,11 @@
 	public SourceMapper(IPath sourcePath, String rootPath, Map options) {
 		this.areRootPathsComputed = false;
 		this.options = options;
-		this.encoding = (String)options.get(JavaCore.CORE_ENCODING);
+		try {
+			this.encoding = ResourcesPlugin.getWorkspace().getRoot().getDefaultCharset();
+		} catch (CoreException e) {
+			// use no encoding
+		}
 		if (rootPath != null) {
 			this.rootPaths = new HashSet();
 			this.rootPaths.add(rootPath);
@@ -269,7 +283,7 @@
 	 * Converts these type names to unqualified signatures. This needs to be done in order to be consistent
 	 * with the way the source range is retrieved.
 	 * @see SourceMapper#getUnqualifiedMethodHandle
-	 * @see Signature.
+	 * @see Signature
 	 */
 	private String[] convertTypeNamesToSigs(char[][] typeNames) {
 		if (typeNames == null)
@@ -292,8 +306,7 @@
 		return typeSigs;
 	}
 	
-	private void computeAllRootPaths(IType type) {
-		IPackageFragmentRoot root = (IPackageFragmentRoot) type.getPackageFragment().getParent();
+	private void computeAllRootPaths(IPackageFragmentRoot root) {
 		if (this.rootPaths == null) {
 			this.rootPaths = new HashSet();
 		}
@@ -334,11 +347,11 @@
 			}
 		} else {
 			Object target = JavaModel.getTarget(ResourcesPlugin.getWorkspace().getRoot(), root.getPath(), true);
-			if (target instanceof IFolder) {
-				IResource resource = root.getResource();
-				if (resource.getType() == IResource.FOLDER) {
+			if (target instanceof IResource) {
+				IResource resource = (IResource) target;
+				if (resource instanceof IContainer) {
 					try {
-						IResource[] members = ((IFolder) resource).members();
+						IResource[] members = ((IContainer) resource).members();
 						for (int i = 0, max = members.length; i < max; i++) {
 							IResource member = members[i];
 							if (member.getType() == IResource.FOLDER) {
@@ -399,8 +412,10 @@
 			}
 		} else {
 			Object target = JavaModel.getTarget(ResourcesPlugin.getWorkspace().getRoot(), this.sourcePath, true);
-			if (target instanceof IFolder) {
-				computeRootPath((IFolder)target, firstLevelPackageNames, containsADefaultPackage);
+			if (target instanceof IResource) {
+				if (target instanceof IContainer) {
+					computeRootPath((IContainer)target, firstLevelPackageNames, containsADefaultPackage);
+				}
 			} else if (target instanceof File) {
 				File file = (File)target;
 				if (file.isDirectory()) {
@@ -441,16 +456,16 @@
 		}
 	}	
 
-	private void computeRootPath(IFolder directory, HashSet firstLevelPackageNames, boolean hasDefaultPackage) {
+	private void computeRootPath(IContainer container, HashSet firstLevelPackageNames, boolean hasDefaultPackage) {
 		try {
-			IResource[] resources = directory.members();
+			IResource[] resources = container.members();
 			boolean hasSubDirectories = false;
 			loop: for (int i = 0, max = resources.length; i < max; i++) {
 				IResource resource = resources[i];
 				if (resource.getType() == IResource.FOLDER) {
 					hasSubDirectories = true;
 					if (firstLevelPackageNames.contains(resource.getName())) {
-						IPath fullPath = resource.getParent().getFullPath();
+						IPath fullPath = container.getFullPath();
 						IPath rootPathEntry = fullPath.removeFirstSegments(this.sourcePath.segmentCount()).setDevice(null);
 						this.rootPaths.add(rootPathEntry.toString());
 						break loop;
@@ -459,12 +474,10 @@
 					}
 				}
 				if (i == max - 1 && !hasSubDirectories && hasDefaultPackage) {
-					IContainer container = resource.getParent();
 					// check if one member is a .java file
-					IResource[] members = container.members();
 					boolean hasJavaSourceFile = false;
-					for (int j = 0, max2 = members.length; j < max2; j++) {
-						if (Util.isJavaFileName(members[i].getName())) {
+					for (int j = 0; j < max; j++) {
+						if (Util.isJavaFileName(resources[i].getName())) {
 							hasJavaSourceFile = true;
 							break;
 						}
@@ -792,7 +805,7 @@
 		char[] source = null;
 		
 		if (!areRootPathsComputed) {
-			computeAllRootPaths(type);
+			computeAllRootPaths((IPackageFragmentRoot) type.getPackageFragment().getParent());
 		}
 		
 		if (this.rootPath != null) {
@@ -836,27 +849,27 @@
 			 * For example, A.class comes from A.java and p.A.class comes from a file A.java
 			 * in the folder p.
 			 */
-			try {
-				if (type.isMember()) {
-					IType enclosingType = type.getDeclaringType();
-					if (enclosingType == null) return null; // play it safe
-					while (enclosingType.getDeclaringType() != null) {
-						enclosingType = enclosingType.getDeclaringType();
-					}
-					return enclosingType.getElementName() + SUFFIX_STRING_java;
-				} else if (type.isLocal() || type.isAnonymous()){
-					String typeQualifiedName = type.getTypeQualifiedName();
-					return typeQualifiedName.substring(0, typeQualifiedName.indexOf('$')) + SUFFIX_STRING_java;
-				} else {
+			if (info.isMember()) {
+				IType enclosingType = type.getDeclaringType();
+				if (enclosingType == null) return null; // play it safe
+				while (enclosingType.getDeclaringType() != null) {
+					enclosingType = enclosingType.getDeclaringType();
+				}
+				return enclosingType.getElementName() + SUFFIX_STRING_java;
+			} else if (info.isLocal() || info.isAnonymous()){
+				String typeQualifiedName = type.getTypeQualifiedName();
+				int dollar = typeQualifiedName.indexOf('$');
+				if (dollar == -1) {
+					// malformed inner type: name doesn't contain a dollar
 					return type.getElementName() + SUFFIX_STRING_java;
 				}
-			} catch (JavaModelException e) {
-				// ignore
+				return typeQualifiedName.substring(0, dollar) + SUFFIX_STRING_java;
+			} else {
+				return type.getElementName() + SUFFIX_STRING_java;
 			}
 		} else {
 			return  new String(sourceFileName);
 		}
-		return null;
 	}
 
 	private char[] getSourceForRootPath(String currentRootPath, String name) {
@@ -894,24 +907,27 @@
 			}
 		} else {
 			Object target = JavaModel.getTarget(ResourcesPlugin.getWorkspace().getRoot(), this.sourcePath, true);
-			if (target instanceof IFolder) {
-				IFolder folder = (IFolder)target;
-				IResource res = folder.findMember(fullName);
-				if (res instanceof IFile) {
-					try {
-						source = org.eclipse.jdt.internal.core.util.Util.getResourceContentsAsCharArray((IFile)res, this.encoding);
-					} catch (JavaModelException e) {
-						// ignore
+			if (target instanceof IResource) {
+				if (target instanceof IContainer) {
+					IResource res = ((IContainer)target).findMember(fullName);
+					if (res instanceof IFile) {
+						try {
+							source = org.eclipse.jdt.internal.core.util.Util.getResourceContentsAsCharArray((IFile)res);
+						} catch (JavaModelException e) {
+							// ignore
+						}
 					}
 				}
 			} else if (target instanceof File) {
 				File file = (File)target;
 				if (file.isDirectory()) {
 					File sourceFile = new File(file, fullName);
-					try {
-						source = Util.getFileCharContent(sourceFile, this.encoding);
-					} catch (IOException e) {
-						// ignore
+					if (sourceFile.isFile()) {
+						try {
+							source = Util.getFileCharContent(sourceFile, this.encoding);
+						} catch (IOException e) {
+							// ignore
+						}
 					}
 				}
 			}
@@ -1101,8 +1117,10 @@
 			}
 			boolean doFullParse = hasToRetrieveSourceRangesForLocalClass(fullName);
 			parser = new SourceElementParser(this, factory, new CompilerOptions(this.options), doFullParse);
+			IJavaElement javaElement = this.fType.getCompilationUnit();
+			if (javaElement == null) javaElement = this.fType.getParent();
 			parser.parseCompilationUnit(
-				new BasicCompilationUnit(contents, null, type.getElementName() + SUFFIX_STRING_java, encoding),
+				new BasicCompilationUnit(contents, null, type.getElementName() + SUFFIX_STRING_java, javaElement),
 				doFullParse);
 			if (elementToFind != null) {
 				ISourceRange range = this.getNameRange(elementToFind);
@@ -1137,7 +1155,7 @@
 	/** 
 	 * Sets the mapping for this method to its parameter names.
 	 *
-	 * @see fParameterNames
+	 * @see #fParameterNames
 	 */
 	protected void setMethodParameterNames(
 		IMethod method,
@@ -1152,7 +1170,7 @@
 	 * Sets the mapping for this element to its source ranges for its source range
 	 * and name range.
 	 *
-	 * @see fSourceRanges
+	 * @see #fSourceRanges
 	 */
 	protected void setSourceRange(
 		IJavaElement element,
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMethod.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMethod.java
index 40eadd1..811d3c4 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMethod.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMethod.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -16,8 +16,7 @@
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.Signature;
-import org.eclipse.jdt.core.jdom.IDOMMethod;
-import org.eclipse.jdt.core.jdom.IDOMNode;
+import org.eclipse.jdt.core.jdom.*;
 import org.eclipse.jdt.internal.core.util.Util;
 
 /**
@@ -52,7 +51,9 @@
 }
 /**
  * @see JavaElement#equalsDOMNode
+ * @deprecated JDOM is obsolete
  */
+// TODO - JDOM - remove once model ported off of JDOM
 protected boolean equalsDOMNode(IDOMNode node) {
 	if (node.getNodeType() == IDOMNode.METHOD) {
 		try {
@@ -91,10 +92,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) {
@@ -136,6 +138,16 @@
 public String[] getParameterTypes() {
 	return fParameterTypes;
 }
+
+/**
+ * @see IMethod#getTypeParameterSignatures()
+ * @since 3.0
+ */
+public String[] getTypeParameterSignatures() throws JavaModelException {
+	// TODO (jerome) - missing implementation
+	return new String[0];
+}
+
 /*
  * @see JavaElement#getPrimaryElement(boolean)
  */
@@ -162,6 +174,16 @@
 	return info.getSignature();
 }
 /**
+ * @see org.eclipse.jdt.internal.core.JavaElement#hashCode()
+ */
+public int hashCode() {
+   int hash = super.hashCode();
+	for (int i = 0, length = fParameterTypes.length; i < length; i++) {
+	    hash = Util.combineHashCodes(hash, fParameterTypes[i].hashCode());
+	}
+	return hash;
+}
+/**
  * @see IMethod
  */
 public boolean isConstructor() throws JavaModelException {
@@ -208,7 +230,9 @@
 /**
  * Returns <code>true</code> if the signature of this <code>SourceMethod</code> matches that of the given
  * <code>IDOMMethod</code>, otherwise <code>false</code>. 
+ * @deprecated JDOM is obsolete
  */
+// TODO - JDOM - remove once model ported off of JDOM
 protected boolean signatureEquals(IDOMMethod method) {
 	String[] otherTypes= method.getParameterTypes();
 	String[] types= getParameterTypes();
@@ -245,12 +269,10 @@
 protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
 	buffer.append(this.tabString(tab));
 	if (info == null) {
-		buffer.append(getElementName());
-			toStringParameters(buffer);
+		toStringName(buffer);
 		buffer.append(" (not open)"); //$NON-NLS-1$
 	} else if (info == NO_INFO) {
-		buffer.append(getElementName());
-			toStringParameters(buffer);
+		toStringName(buffer);
 	} else {
 		try {
 			if (Flags.isStatic(this.getFlags())) {
@@ -260,25 +282,29 @@
 				buffer.append(Signature.toString(this.getReturnType()));
 				buffer.append(' ');
 			}
-			buffer.append(this.getElementName());
-			toStringParameters(buffer);
+			toStringName(buffer);
 		} catch (JavaModelException e) {
 			buffer.append("<JavaModelException in toString of " + getElementName()); //$NON-NLS-1$
 		}
 	}
 }
-private void toStringParameters(StringBuffer buffer) {
+protected void toStringName(StringBuffer buffer) {
+	buffer.append(getElementName());
 	buffer.append('(');
-	String[] parameterTypes = this.getParameterTypes();
+	String[] parameters = this.getParameterTypes();
 	int length;
-	if (parameterTypes != null && (length = parameterTypes.length) > 0) {
+	if (parameters != null && (length = parameters.length) > 0) {
 		for (int i = 0; i < length; i++) {
-			buffer.append(Signature.toString(parameterTypes[i]));
+			buffer.append(Signature.toString(parameters[i]));
 			if (i < length - 1) {
 				buffer.append(", "); //$NON-NLS-1$
 			}
 		}
 	}
 	buffer.append(')');
+	if (this.occurrenceCount > 1) {
+		buffer.append("#"); //$NON-NLS-1$
+		buffer.append(this.occurrenceCount);
+	}
 }
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMethodElementInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMethodElementInfo.java
index a76fa2b..f2fdf3f 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMethodElementInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMethodElementInfo.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceRange.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceRange.java
index 6d2513e..24cb1b9 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceRange.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceRange.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceRefElement.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceRefElement.java
index 775e6f7..64e6a7b 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceRefElement.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceRefElement.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -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);
@@ -171,6 +171,12 @@
 	return getParent().getUnderlyingResource();
 }
 /**
+ * @see IParent 
+ */
+public boolean hasChildren() throws JavaModelException {
+	return getChildren().length > 0;
+}
+/**
  * @see ISourceManipulation
  */
 public void move(IJavaElement container, IJavaElement sibling, String rename, boolean force, IProgressMonitor monitor) throws JavaModelException {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceRefElementInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceRefElementInfo.java
index 79f1fc9..29c2b6d 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceRefElementInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceRefElementInfo.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceType.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceType.java
index 5e3e11e..b5d443f 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceType.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceType.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -12,13 +12,12 @@
 
 import java.io.InputStream;
 import java.util.ArrayList;
-import java.util.StringTokenizer;
 
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.compiler.*;
 import org.eclipse.jdt.core.compiler.IProblem;
-import org.eclipse.jdt.core.jdom.IDOMNode;
+import org.eclipse.jdt.core.jdom.*;
 import org.eclipse.jdt.core.search.SearchEngine;
 import org.eclipse.jdt.internal.codeassist.CompletionEngine;
 import org.eclipse.jdt.internal.codeassist.ISearchableNameEnvironment;
@@ -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;
 
 /**
@@ -60,40 +60,26 @@
 	}
 	
 	JavaProject project = (JavaProject) getJavaProject();
-	SearchableEnvironment environment = (SearchableEnvironment) project.getSearchableNameEnvironment();
-	NameLookup nameLookup = project.getNameLookup();
-	CompletionRequestorWrapper requestorWrapper = new CompletionRequestorWrapper(requestor,nameLookup);
+	SearchableEnvironment environment = (SearchableEnvironment) project.newSearchableNameEnvironment(owner);
+	CompletionRequestorWrapper requestorWrapper = new CompletionRequestorWrapper(requestor, environment.nameLookup);
 	CompletionEngine engine = new CompletionEngine(environment, requestorWrapper, project.getOptions(true), project);
 	requestorWrapper.completionEngine = engine;
 	
 	String source = getCompilationUnit().getSource();
 	if (source != null && insertion > -1 && insertion < source.length()) {
-		try {
-			// set the units to look inside
-			JavaModelManager manager = JavaModelManager.getJavaModelManager();
-			ICompilationUnit[] workingCopies = manager.getWorkingCopies(owner, true/*add primary WCs*/);
-			nameLookup.setUnitsToLookInside(workingCopies);
-	
-			// code complete
-			String encoding = project.getOption(JavaCore.CORE_ENCODING, true);
-			
-			char[] prefix = CharOperation.concat(source.substring(0, insertion).toCharArray(), new char[]{'{'});
-			char[] suffix = CharOperation.concat(new char[]{'}'}, source.substring(insertion).toCharArray());
-			char[] fakeSource = CharOperation.concat(prefix, snippet, suffix);
-			
-			BasicCompilationUnit cu = 
-				new BasicCompilationUnit(
-					fakeSource, 
-					null,
-					getElementName(),
-					encoding); 
-	
-			engine.complete(cu, prefix.length + position, prefix.length);
-		} finally {
-			if (nameLookup != null) {
-				nameLookup.setUnitsToLookInside(null);
-			}
-		}
+		
+		char[] prefix = CharOperation.concat(source.substring(0, insertion).toCharArray(), new char[]{'{'});
+		char[] suffix = CharOperation.concat(new char[]{'}'}, source.substring(insertion).toCharArray());
+		char[] fakeSource = CharOperation.concat(prefix, snippet, suffix);
+		
+		BasicCompilationUnit cu = 
+			new BasicCompilationUnit(
+				fakeSource, 
+				null,
+				getElementName(),
+				getParent());
+
+		engine.complete(cu, prefix.length + position, prefix.length);
 	} else {
 		engine.complete(this, snippet, position, localVariableTypeNames, localVariableNames, localVariableModifiers, isStatic);
 	}
@@ -106,7 +92,7 @@
 	if (sibling != null) {
 		op.createBefore(sibling);
 	}
-	runOperation(op, monitor);
+	op.runOperation(monitor);
 	return (IField) op.getResultElements()[0];
 }
 /**
@@ -117,7 +103,7 @@
 	if (sibling != null) {
 		op.createBefore(sibling);
 	}
-	runOperation(op, monitor);
+	op.runOperation(monitor);
 	return (IInitializer) op.getResultElements()[0];
 }
 /**
@@ -128,7 +114,7 @@
 	if (sibling != null) {
 		op.createBefore(sibling);
 	}
-	runOperation(op, monitor);
+	op.runOperation(monitor);
 	return (IMethod) op.getResultElements()[0];
 }
 /**
@@ -139,7 +125,7 @@
 	if (sibling != null) {
 		op.createBefore(sibling);
 	}
-	runOperation(op, monitor);
+	op.runOperation(monitor);
 	return (IType) op.getResultElements()[0];
 }
 public boolean equals(Object o) {
@@ -148,7 +134,9 @@
 }
 /**
  * @see JavaElement#equalsDOMNode
+ * @deprecated JDOM is obsolete
  */
+// TODO - JDOM - remove once model ported off of JDOM
 protected boolean equalsDOMNode(IDOMNode node) {
 	return (node.getNodeType() == IDOMNode.TYPE) && super.equalsDOMNode(node);
 }
@@ -202,7 +190,7 @@
 	return array;
 }
 /**
- * @see IType#getFullyQualifiedName
+ * @see IType#getFullyQualifiedName()
  */
 public String getFullyQualifiedName() {
 	return this.getFullyQualifiedName('$');
@@ -220,7 +208,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);
@@ -369,6 +357,20 @@
 	}
 	return new String(superclassName);
 }
+
+/**
+ * @see IType#getSuperclassTypeSignature()
+ * @since 3.0
+ */
+public String getSuperclassTypeSignature() throws JavaModelException {
+	SourceTypeElementInfo info = (SourceTypeElementInfo) getElementInfo();
+	char[] superclassName= info.getSuperclassName();
+	if (superclassName == null) {
+		return null;
+	}
+	return new String(Signature.createTypeSignature(superclassName, false));
+}
+
 /**
  * @see IType
  */
@@ -384,6 +386,33 @@
 	}
 	return strings;
 }
+
+/**
+ * @see IType#getSuperInterfaceTypeSignatures()
+ * @since 3.0
+ */
+public String[] getSuperInterfaceTypeSignatures() throws JavaModelException {
+	SourceTypeElementInfo info = (SourceTypeElementInfo) getElementInfo();
+	char[][] names= info.getInterfaceNames();
+	if (names == null) {
+		return fgEmptyList;
+	}
+	String[] strings= new String[names.length];
+	for (int i= 0; i < names.length; i++) {
+		strings[i]= new String(Signature.createTypeSignature(names[i], false));
+	}
+	return strings;
+}
+
+/**
+ * @see IType#getTypeParameterSignatures()
+ * @since 3.0
+ */
+public String[] getTypeParameterSignatures() throws JavaModelException {
+	// TODO (jerome) - missing implementation
+	return new String[0];
+}
+
 /**
  * @see IType
  */
@@ -391,7 +420,7 @@
 	return new SourceType(this, typeName);
 }
 /**
- * @see IType#getTypeQualifiedName
+ * @see IType#getTypeQualifiedName()
  */
 public String getTypeQualifiedName() {
 	return this.getTypeQualifiedName('$');
@@ -404,13 +433,15 @@
 		case IJavaElement.COMPILATION_UNIT:
 			return this.name;
 		case IJavaElement.TYPE:
-			return ((IType) this.parent).getTypeQualifiedName(enclosingTypeSeparator) + enclosingTypeSeparator + this.name;
+			String simpleName = this.name.length() == 0 ? Integer.toString(this.occurrenceCount) : this.name;
+			return ((IType) this.parent).getTypeQualifiedName(enclosingTypeSeparator) + enclosingTypeSeparator + simpleName;
 		case IJavaElement.FIELD:
 		case IJavaElement.INITIALIZER:
 		case IJavaElement.METHOD:
+			simpleName = this.name.length() == 0 ? Integer.toString(this.occurrenceCount) : this.name;
 			return 
 				((IMember) this.parent).getDeclaringType().getTypeQualifiedName(enclosingTypeSeparator) 
-				+ enclosingTypeSeparator + this.name;
+				+ enclosingTypeSeparator + simpleName;
 	}
 	return null;
 }
@@ -430,19 +461,42 @@
 public boolean isAnonymous() {
 	return this.name.length() == 0;
 }
+
 /**
  * @see IType
  */
 public boolean isClass() throws JavaModelException {
+	// TODO (jerome) - isClass should only return true for classes other than enum classes
 	return !isInterface();
 }
+
+/**
+ * @see IType#isEnum()
+ * @since 3.0
+ */
+public boolean isEnum() throws JavaModelException {
+	// TODO (jerome) - missing implementation - should only return true for enum classes
+	return false;
+}
+
 /**
  * @see IType
  */
 public boolean isInterface() throws JavaModelException {
 	SourceTypeElementInfo info = (SourceTypeElementInfo) getElementInfo();
+	// TODO (jerome) - isInterface should not return true for annotation types
 	return info.isInterface();
 }
+
+/**
+ * @see IType#isAnnotation()
+ * @since 3.0
+ */
+public boolean isAnnotation() throws JavaModelException {
+	// TODO (jerome) - missing implementation - should only return true for annotation types
+	return false;
+}
+
 /**
  * @see IType#isLocal()
  */
@@ -488,7 +542,7 @@
  * @exception JavaModelException if the hierarchy could not be restored, reasons include:
  *      - type is not the focus of the hierarchy or 
  *		- unable to read the input stream (wrong format, IOException during reading, ...)
- * @see ITypeHierarchy#store(OutputStream, IProgressMonitor)
+ * @see ITypeHierarchy#store(java.io.OutputStream, IProgressMonitor)
  * @since 3.0
  */
 public ITypeHierarchy loadTypeHierachy(InputStream input, WorkingCopyOwner owner, IProgressMonitor monitor) throws JavaModelException {
@@ -510,7 +564,7 @@
 	throws JavaModelException {
 
 	CreateTypeHierarchyOperation op= new CreateTypeHierarchyOperation(this, workingCopies, SearchEngine.createWorkspaceScope(), false);
-	runOperation(op, monitor);
+	op.runOperation(monitor);
 	return op.getResult();
 }
 /**
@@ -547,7 +601,7 @@
 
 	ICompilationUnit[] workingCopies = JavaModelManager.getJavaModelManager().getWorkingCopies(owner, true/*add primary working copies*/);
 	CreateTypeHierarchyOperation op= new CreateTypeHierarchyOperation(this, workingCopies, SearchEngine.createWorkspaceScope(), false);
-	runOperation(op, monitor);
+	op.runOperation(monitor);
 	return op.getResult();
 }
 /**
@@ -584,7 +638,7 @@
 		projectWCs,
 		project, 
 		true);
-	runOperation(op, monitor);
+	op.runOperation(monitor);
 	return op.getResult();
 }
 /**
@@ -592,7 +646,7 @@
  */
 public ITypeHierarchy newTypeHierarchy(IProgressMonitor monitor) throws JavaModelException {
 	CreateTypeHierarchyOperation op= new CreateTypeHierarchyOperation(this, null, SearchEngine.createWorkspaceScope(), true);
-	runOperation(op, monitor);
+	op.runOperation(monitor);
 	return op.getResult();
 }
 /*
@@ -604,7 +658,7 @@
 	throws JavaModelException {
 		
 	CreateTypeHierarchyOperation op= new CreateTypeHierarchyOperation(this, workingCopies, SearchEngine.createWorkspaceScope(), true);
-	runOperation(op, monitor);
+	op.runOperation(monitor);
 	return op.getResult();
 }
 /**
@@ -635,7 +689,7 @@
 		
 	ICompilationUnit[] workingCopies = JavaModelManager.getJavaModelManager().getWorkingCopies(owner, true/*add primary working copies*/);
 	CreateTypeHierarchyOperation op= new CreateTypeHierarchyOperation(this, workingCopies, SearchEngine.createWorkspaceScope(), true);
-	runOperation(op, monitor);
+	op.runOperation(monitor);
 	return op.getResult();	
 }
 /**
@@ -648,95 +702,81 @@
  * @see IType#resolveType(String, WorkingCopyOwner)
  */
 public String[][] resolveType(String typeName, WorkingCopyOwner owner) throws JavaModelException {
-	JavaProject project = (JavaProject)getJavaProject();
-	NameLookup lookup = null;
-	try {
-		// set the units to look inside
-		lookup = project.getNameLookup();
-		JavaModelManager manager = JavaModelManager.getJavaModelManager();
-		ICompilationUnit[] workingCopies = manager.getWorkingCopies(owner, true/*add primary WCs*/);
-		lookup.setUnitsToLookInside(workingCopies);
-			
-		// resolve
-		ISourceType info = (ISourceType) this.getElementInfo();
-		ISearchableNameEnvironment environment = project.getSearchableNameEnvironment();
-	
-		class TypeResolveRequestor implements ISelectionRequestor {
-			String[][] answers = null;
-			void acceptType(String[] answer){
-				if (answers == null) {
-					answers = new String[][]{ answer };
-				} else {
-					// grow
-					int length = answers.length;
-					System.arraycopy(answers, 0, answers = new String[length+1][], 0, length);
-					answers[length] = answer;
-				}
+	ISourceType info = (ISourceType) getElementInfo();
+	JavaProject project = (JavaProject) getJavaProject();
+	ISearchableNameEnvironment environment = project.newSearchableNameEnvironment(owner);
+
+	class TypeResolveRequestor implements ISelectionRequestor {
+		String[][] answers = null;
+		void acceptType(String[] answer){
+			if (this.answers == null) {
+				this.answers = new String[][]{ answer };
+			} else {
+				// grow
+				int length = this.answers.length;
+				System.arraycopy(this.answers, 0, this.answers = new String[length+1][], 0, length);
+				this.answers[length] = answer;
 			}
-			public void acceptClass(char[] packageName, char[] className, boolean needQualification) {
-				acceptType(new String[]  { new String(packageName), new String(className) });
-			}
-			
-			public void acceptInterface(char[] packageName, char[] interfaceName, boolean needQualification) {
-				acceptType(new String[]  { new String(packageName), new String(interfaceName) });
-			}
-	
-			public void acceptError(IProblem error) {
-				// ignore
-			}
-			public void acceptField(char[] declaringTypePackageName, char[] declaringTypeName, char[] fieldName) {
-				// ignore
-			}
-			public void acceptMethod(char[] declaringTypePackageName, char[] declaringTypeName, char[] selector, char[][] parameterPackageNames, char[][] parameterTypeNames, boolean isConstructor) {
-				// ignore
-			}
-			public void acceptPackage(char[] packageName){
-				// ignore
-			}
-	
 		}
-		TypeResolveRequestor requestor = new TypeResolveRequestor();
-		SelectionEngine engine = 
-			new SelectionEngine(environment, requestor, this.getJavaProject().getOptions(true));
-			
-	 	IType[] topLevelTypes = this.getCompilationUnit().getTypes();
-	 	int length = topLevelTypes.length;
-	 	ISourceType[] topLevelInfos = new ISourceType[length];
-	 	for (int i = 0; i < length; i++) {
-			topLevelInfos[i] = (ISourceType)((SourceType)topLevelTypes[i]).getElementInfo();
+		public void acceptClass(char[] packageName, char[] className, boolean needQualification, boolean isDeclaration, int start, int end) {
+			acceptType(new String[]  { new String(packageName), new String(className) });
 		}
-			
-		engine.selectType(info, typeName.toCharArray(), topLevelInfos, false);
-		return requestor.answers;
-	} finally {
-		if (lookup != null) {
-			lookup.setUnitsToLookInside(null);
+		
+		public void acceptInterface(char[] packageName, char[] interfaceName, boolean needQualification, boolean isDeclaration, int start, int end) {
+			acceptType(new String[]  { new String(packageName), new String(interfaceName) });
 		}
+
+		public void acceptError(IProblem error) {
+			// ignore
+		}
+		public void acceptField(char[] declaringTypePackageName, char[] declaringTypeName, char[] fieldName, boolean isDeclaration, int start, int end) {
+			// ignore
+		}
+		public void acceptMethod(char[] declaringTypePackageName, char[] declaringTypeName, char[] selector, char[][] parameterPackageNames, char[][] parameterTypeNames, boolean isConstructor, boolean isDeclaration, int start, int end) {
+			// ignore
+		}
+		public void acceptPackage(char[] packageName){
+			// ignore
+		}
+
 	}
+	TypeResolveRequestor requestor = new TypeResolveRequestor();
+	SelectionEngine engine = 
+		new SelectionEngine(environment, requestor, project.getOptions(true));
+		
+ 	IType[] topLevelTypes = getCompilationUnit().getTypes();
+ 	int length = topLevelTypes.length;
+ 	SourceTypeElementInfo[] topLevelInfos = new SourceTypeElementInfo[length];
+ 	for (int i = 0; i < length; i++) {
+		topLevelInfos[i] = (SourceTypeElementInfo) ((SourceType)topLevelTypes[i]).getElementInfo();
+	}
+		
+	engine.selectType(info, typeName.toCharArray(), topLevelInfos, false);
+	return requestor.answers;
 }
 /**
  * @private Debugging purposes
  */
 protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
-	buffer.append(this.tabString(tab));
+	buffer.append(tabString(tab));
 	if (info == null) {
-		String elementName = this.getElementName();
+		String elementName = getElementName();
 		if (elementName.length() == 0) {
 			buffer.append("<anonymous #"); //$NON-NLS-1$
 			buffer.append(this.occurrenceCount);
 			buffer.append(">"); //$NON-NLS-1$
 		} else {
-			buffer.append(elementName);
+			toStringName(buffer);
 		}
 		buffer.append(" (not open)"); //$NON-NLS-1$
 	} else if (info == NO_INFO) {
-		String elementName = this.getElementName();
+		String elementName = getElementName();
 		if (elementName.length() == 0) {
 			buffer.append("<anonymous #"); //$NON-NLS-1$
 			buffer.append(this.occurrenceCount);
 			buffer.append(">"); //$NON-NLS-1$
 		} else {
-			buffer.append(elementName);
+			toStringName(buffer);
 		}
 	} else {
 		try {
@@ -745,13 +785,13 @@
 			} else {
 				buffer.append("class "); //$NON-NLS-1$
 			}
-			String elementName = this.getElementName();
+			String elementName = getElementName();
 			if (elementName.length() == 0) {
 				buffer.append("<anonymous #"); //$NON-NLS-1$
 				buffer.append(this.occurrenceCount);
 				buffer.append(">"); //$NON-NLS-1$
 			} else {
-				buffer.append(elementName);
+				toStringName(buffer);
 			}
 		} catch (JavaModelException e) {
 			buffer.append("<JavaModelException in toString of " + getElementName()); //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceTypeElementInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceTypeElementInfo.java
index cb44dbb..428f07f 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceTypeElementInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceTypeElementInfo.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/TypeConverter.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/TypeConverter.java
index 79abc76..b6b2344 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/TypeConverter.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/TypeConverter.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -179,8 +179,9 @@
 			}
 		}
 		boolean isInterface = type.isInterface();
+		neededCount = isInterface ? 0 : neededCount;
 		typeDeclaration.methods = new AbstractMethodDeclaration[methodCount + neededCount];
-		if (neededCount != 0 && !isInterface) { // add default constructor in first position
+		if (neededCount != 0) { // add default constructor in first position
 			typeDeclaration.methods[0] = typeDeclaration.createsInternalConstructor(false, false);
 		}
 		for (int i = 0; i < methodCount; i++) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/TypeVector.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/TypeVector.java
index a32bb8e..011b6e2 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/TypeVector.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/TypeVector.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/UserLibrary.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/UserLibrary.java
new file mode 100644
index 0000000..c958abe
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/UserLibrary.java
@@ -0,0 +1,180 @@
+/*******************************************************************************
+ * 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);
+	}
+	
+	public String toString() {
+		if (this.entries == null)
+			return "null"; //$NON-NLS-1$
+		StringBuffer buffer = new StringBuffer();
+		int length = this.entries.length;
+		for (int i=0; i<length; i++) {
+			buffer.append(this.entries[i].toString()+'\n');
+		}
+		return buffer.toString();
+	}
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/UserLibraryClasspathContainer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/UserLibraryClasspathContainer.java
new file mode 100644
index 0000000..4069ac9
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/UserLibraryClasspathContainer.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * 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;
+	}
+	
+	private UserLibrary getUserLibrary() {
+		return UserLibraryManager.getUserLibrary(this.name);
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.jdt.core.IClasspathContainer#getClasspathEntries()
+	 */
+	public IClasspathEntry[] getClasspathEntries() {
+		UserLibrary library= getUserLibrary();
+		if (library != null) {
+			return library.getEntries();
+		}
+		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() {
+		UserLibrary library= getUserLibrary();
+		if (library != null && library.isSystemLibrary()) {
+			return K_SYSTEM;
+		}
+		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/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/UserLibraryClasspathContainerInitializer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/UserLibraryClasspathContainerInitializer.java
new file mode 100644
index 0000000..2920dcb
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/UserLibraryClasspathContainerInitializer.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;
+
+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);
+						
+			UserLibrary entries= UserLibraryManager.getUserLibrary(userLibName);
+			if (entries != null) {
+				UserLibraryClasspathContainer container= new UserLibraryClasspathContainer(userLibName);
+				JavaCore.setClasspathContainer(containerPath, new IJavaProject[] { project }, 	new IClasspathContainer[] { container }, 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/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/UserLibraryManager.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/UserLibraryManager.java
new file mode 100644
index 0000000..6c22a3a
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/UserLibraryManager.java
@@ -0,0 +1,253 @@
+/*******************************************************************************
+ * 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 UserLibrary getUserLibrary(String name) {
+		return (UserLibrary) 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, library==null, monitor);
+			}
+			
+		} finally {
+			preferences.addPropertyChangeListener(listener);
+		}
+	}
+
+	private static void rebindClasspathEntries(String name, boolean remove, 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];
+			if (!remove) {
+				// Previously, containers array only contained a null value. Then, user library classpath entry was first removed
+				// and then added a while after when post change delta event on .classpath file was fired...
+				// Unfortunately, in some cases, this event was fired a little bit too late and missed the refresh of Package Explorer
+				// (see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=61872)
+				// So now, instanciate a new user library classpath container instead which allow to refresh its content immediately
+				// as there's no classpath entry removal...
+				// Note that it works because equals(Object) method is not overridden for UserLibraryClasspathContainer.
+				// If it was, the update wouldn't happen while setting classpath container
+				// @see javaCore.setClasspathContainer(IPath, IJavaProject[], IClasspathContainer[], IProgressMonitor)
+				UserLibraryClasspathContainer container= new UserLibraryClasspathContainer(name);
+				containers[0] = container;
+			}
+			JavaCore.setClasspathContainer(containerPath, affected, containers, monitor);
+		} else {
+			if (monitor != null) {
+				monitor.done();
+			}
+		}
+	}
+
+
+	
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/XMLWriter.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/XMLWriter.java
index 92390c7..94e4a3f 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/XMLWriter.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/XMLWriter.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -72,9 +72,9 @@
 		sb.append("<"); //$NON-NLS-1$
 		sb.append(name);
 		if (parameters != null) {
-			for (Enumeration enum= Collections.enumeration(parameters.keySet()); enum.hasMoreElements();) {
+			for (Enumeration en = Collections.enumeration(parameters.keySet()); en.hasMoreElements();) {
 				sb.append(" "); //$NON-NLS-1$
-				String key= (String) enum.nextElement();
+				String key= (String) en.nextElement();
 				sb.append(key);
 				sb.append("=\""); //$NON-NLS-1$
 				sb.append(getEscaped(String.valueOf(parameters.get(key))));
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/AbortIncrementalBuildException.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/AbortIncrementalBuildException.java
index 377f20e..f6a11f6 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/AbortIncrementalBuildException.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/AbortIncrementalBuildException.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/AbstractImageBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/AbstractImageBuilder.java
index 4c2d3d3..1f08553 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/AbstractImageBuilder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/AbstractImageBuilder.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -41,7 +41,6 @@
 protected ClasspathMultiDirectory[] sourceLocations;
 protected BuildNotifier notifier;
 
-protected String encoding;
 protected Compiler compiler;
 protected WorkQueue workQueue;
 protected ArrayList problemSourceFiles;
@@ -60,7 +59,6 @@
 	this.sourceLocations = this.nameEnvironment.sourceLocations;
 	this.notifier = javaBuilder.notifier;
 
-	this.encoding = javaBuilder.javaProject.getOption(JavaCore.CORE_ENCODING, true);
 	this.compiler = newCompiler();
 	this.workQueue = new WorkQueue();
 	this.problemSourceFiles = new ArrayList(3);
@@ -95,7 +93,7 @@
 			ClassFile classFile = classFiles[i];
 			char[][] compoundName = classFile.getCompoundName();
 			char[] typeName = compoundName[compoundName.length - 1];
-			boolean isNestedType = CharOperation.contains('$', typeName);
+			boolean isNestedType = classFile.enclosingClassFile != null;
 
 			// Look for a possible collision, if one exists, report an error but do not write the class file
 			if (isNestedType) {
@@ -269,12 +267,24 @@
 
 protected Compiler newCompiler() {
 	// called once when the builder is initialized... can override if needed
-	return new Compiler(
+	Compiler newCompiler = new Compiler(
 		nameEnvironment,
 		DefaultErrorHandlingPolicies.proceedWithAllProblems(),
 		javaBuilder.javaProject.getOptions(true),
 		this,
 		ProblemFactory.getProblemFactory(Locale.getDefault()));
+	// enable the compiler reference info support
+	newCompiler.options.produceReferenceInfo = true;
+
+	org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment env = newCompiler.lookupEnvironment;
+	synchronized (env) {
+		// enable shared byte[]'s used by ClassFile to avoid allocating MBs during a build
+		env.sharedArraysUsed = false;
+		env.sharedClassFileHeader = new byte[30000];
+		env.sharedClassFileContents = new byte[30000];
+	}
+
+	return newCompiler;
 }
 
 protected boolean isExcludedFromProject(IPath childPath) throws JavaModelException {
@@ -443,6 +453,13 @@
 
 	IFile file = container.getFile(filePath.addFileExtension(SuffixConstants.EXTENSION_class));
 	writeClassFileBytes(classFile.getBytes(), file, fileName, isSecondaryType, compilationUnit.updateClassFile);
+	if (classFile.ownSharedArrays) {
+		org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment env = this.compiler.lookupEnvironment;
+		synchronized (env) {
+			env.sharedArraysUsed = false;
+		}
+	}
+
 	// answer the name of the class file as in Y or Y$M
 	return filePath.lastSegment().toCharArray();
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/AdditionalTypeCollection.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/AdditionalTypeCollection.java
index 4b63c77..6ac6116 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/AdditionalTypeCollection.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/AdditionalTypeCollection.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/BatchImageBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/BatchImageBuilder.java
index c055344..5aa5cb4 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/BatchImageBuilder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/BatchImageBuilder.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -14,7 +14,6 @@
 import org.eclipse.core.runtime.*;
 
 import org.eclipse.jdt.core.JavaCore;
-import org.eclipse.jdt.internal.core.JavaModelManager;
 import org.eclipse.jdt.internal.core.util.Util;
 
 import java.util.*;
@@ -32,9 +31,8 @@
 
 	try {
 		notifier.subTask(Util.bind("build.cleaningOutput")); //$NON-NLS-1$
-		JavaModelManager.getJavaModelManager().getDeltaProcessor().addForRefresh(javaBuilder.javaProject);
 		JavaBuilder.removeProblemsAndTasksFor(javaBuilder.currentProject);
-		cleanOutputFolders();
+		cleanOutputFolders(true);
 		notifier.updateProgressDelta(0.1f);
 
 		notifier.subTask(Util.bind("build.analyzingSources")); //$NON-NLS-1$
@@ -64,24 +62,30 @@
 	for (int i = 0, l = sourceLocations.length; i < l; i++) {
 		final ClasspathMultiDirectory sourceLocation = sourceLocations[i];
 		final char[][] exclusionPatterns = sourceLocation.exclusionPatterns;
+		final char[][] inclusionPatterns = sourceLocation.inclusionPatterns;
 		final boolean isAlsoProject = sourceLocation.sourceFolder.equals(javaBuilder.currentProject);
 		sourceLocation.sourceFolder.accept(
 			new IResourceProxyVisitor() {
 				public boolean visit(IResourceProxy proxy) throws CoreException {
 					IResource resource = null;
-					if (exclusionPatterns != null) {
-						resource = proxy.requestResource();
-						if (Util.isExcluded(resource, exclusionPatterns)) return false;
-					}
 					switch(proxy.getType()) {
 						case IResource.FILE :
+							if (exclusionPatterns != null || inclusionPatterns != null) {
+								resource = proxy.requestResource();
+								if (Util.isExcluded(resource, inclusionPatterns, exclusionPatterns)) return false;
+							}
 							if (org.eclipse.jdt.internal.compiler.util.Util.isJavaFileName(proxy.getName())) {
 								if (resource == null)
 									resource = proxy.requestResource();
-								sourceFiles.add(new SourceFile((IFile) resource, sourceLocation, encoding));
+								sourceFiles.add(new SourceFile((IFile) resource, sourceLocation));
 							}
 							return false;
 						case IResource.FOLDER :
+							if (exclusionPatterns != null && inclusionPatterns == null) {
+								// if there are inclusion patterns then we must walk the children
+								resource = proxy.requestResource();
+								if (Util.isExcluded(resource, inclusionPatterns, exclusionPatterns)) return false;
+							}
 							if (isAlsoProject && isExcludedFromProject(proxy.requestFullPath())) return false;
 					}
 					return true;
@@ -93,7 +97,7 @@
 	}
 }
 
-protected void cleanOutputFolders() throws CoreException {
+protected void cleanOutputFolders(boolean copyBack) throws CoreException {
 	boolean deleteAll = JavaCore.CLEAN.equals(
 		javaBuilder.javaProject.getOption(JavaCore.CORE_JAVA_BUILD_CLEAN_OUTPUT_FOLDER, true));
 	if (deleteAll) {
@@ -122,22 +126,27 @@
 					}
 				}
 				notifier.checkCancel();
-				copyExtraResourcesBack(sourceLocation, true);
+				if (copyBack)
+					copyExtraResourcesBack(sourceLocation, true);
 			} else {
 				boolean isOutputFolder = sourceLocation.sourceFolder.equals(sourceLocation.binaryFolder);
 				final char[][] exclusionPatterns =
 					isOutputFolder
 						? sourceLocation.exclusionPatterns
 						: null; // ignore exclusionPatterns if output folder == another source folder... not this one
+				final char[][] inclusionPatterns =
+					isOutputFolder
+						? sourceLocation.inclusionPatterns
+						: null; // ignore inclusionPatterns if output folder == another source folder... not this one
 				sourceLocation.binaryFolder.accept(
 					new IResourceProxyVisitor() {
 						public boolean visit(IResourceProxy proxy) throws CoreException {
 							IResource resource = null;
-							if (exclusionPatterns != null) {
-								resource = proxy.requestResource();
-								if (Util.isExcluded(resource, exclusionPatterns)) return false;
-							}
 							if (proxy.getType() == IResource.FILE) {
+								if (exclusionPatterns != null || inclusionPatterns != null) {
+									resource = proxy.requestResource();
+									if (Util.isExcluded(resource, inclusionPatterns, exclusionPatterns)) return false;
+								}
 								if (org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(proxy.getName())) {
 									if (resource == null)
 										resource = proxy.requestResource();
@@ -145,20 +154,25 @@
 								}
 								return false;
 							}
+							if (exclusionPatterns != null && inclusionPatterns == null) {
+								// if there are inclusion patterns then we must walk the children
+								resource = proxy.requestResource();
+								if (Util.isExcluded(resource, inclusionPatterns, exclusionPatterns)) return false;
+							}
 							notifier.checkCancel();
 							return true;
 						}
 					},
 					IResource.NONE
 				);
-				if (!isOutputFolder) {
+				if (!isOutputFolder && copyBack) {
 					notifier.checkCancel();
 					copyPackages(sourceLocation);
 				}
 			}
 			notifier.checkCancel();
 		}
-	} else {
+	} else if (copyBack) {
 		for (int i = 0, l = sourceLocations.length; i < l; i++) {
 			ClasspathMultiDirectory sourceLocation = sourceLocations[i];
 			if (sourceLocation.hasIndependentOutputFolder)
@@ -177,6 +191,7 @@
 	notifier.subTask(Util.bind("build.copyingResources")); //$NON-NLS-1$
 	final int segmentCount = sourceLocation.sourceFolder.getFullPath().segmentCount();
 	final char[][] exclusionPatterns = sourceLocation.exclusionPatterns;
+	final char[][] inclusionPatterns = sourceLocation.inclusionPatterns;
 	final IContainer outputFolder = sourceLocation.binaryFolder;
 	final boolean isAlsoProject = sourceLocation.sourceFolder.equals(javaBuilder.currentProject);
 	sourceLocation.sourceFolder.accept(
@@ -190,8 +205,9 @@
 
 						resource = proxy.requestResource();
 						if (javaBuilder.filterExtraResource(resource)) return false;
-						if (exclusionPatterns != null && Util.isExcluded(resource, exclusionPatterns))
-							return false;
+						if (exclusionPatterns != null || inclusionPatterns != null)
+							if (Util.isExcluded(resource, inclusionPatterns, exclusionPatterns))
+								return false;
 
 						IPath partialPath = resource.getFullPath().removeFirstSegments(segmentCount);
 						IResource copiedResource = outputFolder.getFile(partialPath);
@@ -209,15 +225,15 @@
 						}
 						resource.copy(copiedResource.getFullPath(), IResource.FORCE, null);
 						copiedResource.setDerived(true);
+						copiedResource.setReadOnly(false); // just in case the original was read only
 						return false;
 					case IResource.FOLDER :
 						resource = proxy.requestResource();
 						if (javaBuilder.filterExtraResource(resource)) return false;
-						if (exclusionPatterns != null && Util.isExcluded(resource, exclusionPatterns))
-							return false;
-
 						IPath folderPath = resource.getFullPath();
 						if (isAlsoProject && isExcludedFromProject(folderPath)) return false; // the sourceFolder == project
+						if (exclusionPatterns != null && Util.isExcluded(resource, inclusionPatterns, exclusionPatterns))
+					        return inclusionPatterns != null; // need to go further only if inclusionPatterns are set
 						createFolder(folderPath.removeFirstSegments(segmentCount), outputFolder);
 				}
 				return true;
@@ -230,6 +246,7 @@
 protected void copyPackages(ClasspathMultiDirectory sourceLocation) throws CoreException {
 	final int segmentCount = sourceLocation.sourceFolder.getFullPath().segmentCount();
 	final char[][] exclusionPatterns = sourceLocation.exclusionPatterns;
+	final char[][] inclusionPatterns = sourceLocation.inclusionPatterns;
 	final IContainer outputFolder = sourceLocation.binaryFolder;
 	final boolean isAlsoProject = sourceLocation.sourceFolder.equals(javaBuilder.currentProject);
 	sourceLocation.sourceFolder.accept(
@@ -241,11 +258,10 @@
 					case IResource.FOLDER :
 						IResource resource = proxy.requestResource();
 						if (javaBuilder.filterExtraResource(resource)) return false;
-						if (exclusionPatterns != null && Util.isExcluded(resource, exclusionPatterns))
-							return false;
-
 						IPath folderPath = resource.getFullPath();
 						if (isAlsoProject && isExcludedFromProject(folderPath)) return false; // the sourceFolder == project
+						if (exclusionPatterns != null && Util.isExcluded(resource, inclusionPatterns, exclusionPatterns))
+					        return inclusionPatterns != null; // need to go further only if inclusionPatterns are set
 						createFolder(folderPath.removeFirstSegments(segmentCount), outputFolder);
 				}
 				return true;
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/BuildNotifier.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/BuildNotifier.java
index 62ebb34..60662bb 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/BuildNotifier.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/BuildNotifier.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathDirectory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathDirectory.java
index 155e977..8cab8e2 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathDirectory.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathDirectory.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJar.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJar.java
index 1ceba9f..47ce39b 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJar.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJar.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -103,9 +103,9 @@
 }
 
 public void cleanup() {
-	if (zipFile != null && this.closeZipFileAtEnd) {
+	if (this.zipFile != null && this.closeZipFileAtEnd) {
 		try {
-			zipFile.close();
+			this.zipFile.close();
 		} catch(IOException e) { // ignore it
 		}
 		this.zipFile = null;
@@ -124,7 +124,7 @@
 	if (!isPackage(qualifiedPackageName)) return null; // most common case
 
 	try {
-		ClassFileReader reader = ClassFileReader.read(zipFile, qualifiedBinaryFileName);
+		ClassFileReader reader = ClassFileReader.read(this.zipFile, qualifiedBinaryFileName);
 		if (reader != null) return new NameEnvironmentAnswer(reader);
 	} catch (Exception e) { // treat as if class file is missing
 	}
@@ -132,24 +132,27 @@
 }
 
 public IPath getProjectRelativePath() {
-	if (resource == null) return null;
-	return	resource.getProjectRelativePath();
+	if (this.resource == null) return null;
+	return	this.resource.getProjectRelativePath();
 }
 
 public boolean isPackage(String qualifiedPackageName) {
-	if (knownPackageNames != null)
-		return knownPackageNames.includes(qualifiedPackageName);
+	if (this.knownPackageNames != null)
+		return this.knownPackageNames.includes(qualifiedPackageName);
 
 	try {
 		if (this.zipFile == null) {
+			if (org.eclipse.jdt.internal.core.JavaModelManager.ZIP_ACCESS_VERBOSE) {
+				System.out.println("(" + Thread.currentThread() + ") [ClasspathJar.isPackage(String)] Creating ZipFile on " + zipFilename); //$NON-NLS-1$	//$NON-NLS-2$
+			}
 			this.zipFile = new ZipFile(zipFilename);
 			this.closeZipFileAtEnd = true;
 		}
-		this.knownPackageNames = findPackageSet(zipFile);
+		this.knownPackageNames = findPackageSet(this.zipFile);
 	} catch(Exception e) {
 		this.knownPackageNames = new SimpleSet(); // assume for this build the zipFile is empty
 	}
-	return knownPackageNames.includes(qualifiedPackageName);
+	return this.knownPackageNames.includes(qualifiedPackageName);
 }
 
 public String toString() {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathLocation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathLocation.java
index cb7cc27..291b775 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathLocation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathLocation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -17,8 +17,8 @@
 
 public abstract class ClasspathLocation {
 
-static ClasspathLocation forSourceFolder(IContainer sourceFolder, IContainer outputFolder, char[][] exclusionPatterns) {
-	return new ClasspathMultiDirectory(sourceFolder, outputFolder, exclusionPatterns);
+static ClasspathLocation forSourceFolder(IContainer sourceFolder, IContainer outputFolder, char[][] inclusionPatterns, char[][] exclusionPatterns) {
+	return new ClasspathMultiDirectory(sourceFolder, outputFolder, inclusionPatterns, exclusionPatterns);
 }
 
 public static ClasspathLocation forBinaryFolder(IContainer binaryFolder, boolean isOutputFolder) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathMultiDirectory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathMultiDirectory.java
index ca87205..ba22e37 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathMultiDirectory.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathMultiDirectory.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -18,17 +18,21 @@
 class ClasspathMultiDirectory extends ClasspathDirectory {
 
 IContainer sourceFolder;
+char[][] inclusionPatterns; // used by builders when walking source folders
 char[][] exclusionPatterns; // used by builders when walking source folders
 boolean hasIndependentOutputFolder; // if output folder is not equal to any of the source folders
 
-ClasspathMultiDirectory(IContainer sourceFolder, IContainer binaryFolder, char[][] exclusionPatterns) {
+ClasspathMultiDirectory(IContainer sourceFolder, IContainer binaryFolder, char[][] inclusionPatterns, char[][] exclusionPatterns) {
 	super(binaryFolder, true);
 
 	this.sourceFolder = sourceFolder;
+	this.inclusionPatterns = inclusionPatterns;
 	this.exclusionPatterns = exclusionPatterns;
 	this.hasIndependentOutputFolder = false;
 
 	// handle the case when a state rebuilds a source folder
+	if (this.inclusionPatterns != null && this.inclusionPatterns.length == 0)
+		this.inclusionPatterns = null;
 	if (this.exclusionPatterns != null && this.exclusionPatterns.length == 0)
 		this.exclusionPatterns = null;
 }
@@ -39,12 +43,14 @@
 
 	ClasspathMultiDirectory md = (ClasspathMultiDirectory) o;
 	return sourceFolder.equals(md.sourceFolder) && binaryFolder.equals(md.binaryFolder)
+		&& CharOperation.equals(inclusionPatterns, md.inclusionPatterns)
 		&& CharOperation.equals(exclusionPatterns, md.exclusionPatterns);
 } 
 
 protected boolean isExcluded(IResource resource) {
-	if (this.exclusionPatterns != null && this.sourceFolder.equals(this.binaryFolder))
-		return Util.isExcluded(resource, this.exclusionPatterns);
+	if (this.exclusionPatterns != null || this.inclusionPatterns != null)
+		if (this.sourceFolder.equals(this.binaryFolder))
+			return Util.isExcluded(resource, this.inclusionPatterns, this.exclusionPatterns);
 	return false;
 }
 
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ImageBuilderInternalException.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ImageBuilderInternalException.java
index fa2a40e..5e5ab23 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ImageBuilderInternalException.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ImageBuilderInternalException.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -10,7 +10,7 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.builder;
 
-import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.*;
 
 /**
  * Exception thrown when there is an internal error in the image builder.
@@ -24,6 +24,16 @@
 	this.coreException = e;
 }
 
+public String getLocalizedMessage() {
+	IStatus status = this.coreException.getStatus();
+	if (status.isMultiStatus()) {
+		IStatus[] children = status.getChildren();
+		if (children != null && children.length > 0)
+		    return children[0].getMessage();
+	}
+    return this.coreException.getLocalizedMessage();
+}
+
 public CoreException getThrowable() {
 	return coreException;
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IncrementalImageBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IncrementalImageBuilder.java
index 3b87aee..3efff69 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IncrementalImageBuilder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IncrementalImageBuilder.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -157,12 +157,14 @@
 					for (int j = 0, m = sourceLocations.length; j < m; j++) {
 						if (sourceLocations[j].sourceFolder.getFullPath().isPrefixOf(sourceFileFullPath)) {
 							md = sourceLocations[j];
-							if (md.exclusionPatterns == null || !Util.isExcluded(file, md.exclusionPatterns))
+							if (md.exclusionPatterns == null && md.inclusionPatterns == null)
+								break;
+							if (!Util.isExcluded(file, md.inclusionPatterns, md.exclusionPatterns))
 								break;
 						}
 					}
 				}
-				SourceFile sourceFile = new SourceFile(file, md, encoding);
+				SourceFile sourceFile = new SourceFile(file, md);
 				if (sourceFiles.contains(sourceFile)) continue next;
 				if (compiledAllAtOnce && previousSourceFiles != null && previousSourceFiles.contains(sourceFile))
 					continue next; // can skip previously compiled files since already saw hierarchy related problems
@@ -345,17 +347,24 @@
 	// When a package becomes a type or vice versa, expect 2 deltas,
 	// one on the folder & one on the source file
 	IResource resource = sourceDelta.getResource();
-	if (md.exclusionPatterns != null && Util.isExcluded(resource, md.exclusionPatterns)) return;
+	// remember that if inclusion & exclusion patterns change then a full build is done
+	boolean isExcluded = (md.exclusionPatterns != null || md.inclusionPatterns != null)
+		&& Util.isExcluded(resource, md.inclusionPatterns, md.exclusionPatterns);
 	switch(resource.getType()) {
 		case IResource.FOLDER :
+			if (isExcluded && md.inclusionPatterns == null)
+		        return; // no need to go further with this delta since its children cannot be included
+
 			switch (sourceDelta.getKind()) {
 				case IResourceDelta.ADDED :
-					IPath addedPackagePath = resource.getFullPath().removeFirstSegments(segmentCount);
-					createFolder(addedPackagePath, md.binaryFolder); // ensure package exists in the output folder
-					// add dependents even when the package thinks it exists to be on the safe side
-					if (JavaBuilder.DEBUG)
-						System.out.println("Found added package " + addedPackagePath); //$NON-NLS-1$
-					addDependentsOf(addedPackagePath, true);
+				    if (!isExcluded) {
+						IPath addedPackagePath = resource.getFullPath().removeFirstSegments(segmentCount);
+						createFolder(addedPackagePath, md.binaryFolder); // ensure package exists in the output folder
+						// add dependents even when the package thinks it exists to be on the safe side
+						if (JavaBuilder.DEBUG)
+							System.out.println("Found added package " + addedPackagePath); //$NON-NLS-1$
+						addDependentsOf(addedPackagePath, true);
+				    }
 					// fall thru & collect all the source files
 				case IResourceDelta.CHANGED :
 					IResourceDelta[] children = sourceDelta.getAffectedChildren();
@@ -363,6 +372,13 @@
 						findSourceFiles(children[i], md, segmentCount);
 					return;
 				case IResourceDelta.REMOVED :
+				    if (isExcluded) {
+				    	// since this folder is excluded then there is nothing to delete (from this md), but must walk any included subfolders
+						children = sourceDelta.getAffectedChildren();
+						for (int i = 0, l = children.length; i < l; i++)
+							findSourceFiles(children[i], md, segmentCount);
+						return;
+				    }
 					IPath removedPackagePath = resource.getFullPath().removeFirstSegments(segmentCount);
 					if (sourceLocations.length > 1) {
 						for (int i = 0, l = sourceLocations.length; i < l; i++) {
@@ -387,6 +403,8 @@
 			}
 			return;
 		case IResource.FILE :
+			if (isExcluded) return;
+
 			String resourceName = resource.getName();
 			if (org.eclipse.jdt.internal.compiler.util.Util.isJavaFileName(resourceName)) {
 				IPath typePath = resource.getFullPath().removeFirstSegments(segmentCount).removeFileExtension();
@@ -395,7 +413,7 @@
 					case IResourceDelta.ADDED :
 						if (JavaBuilder.DEBUG)
 							System.out.println("Compile this added source file " + typeLocator); //$NON-NLS-1$
-						sourceFiles.add(new SourceFile((IFile) resource, md, encoding, true));
+						sourceFiles.add(new SourceFile((IFile) resource, md, true));
 						String typeName = typePath.toString();
 						if (!newState.isDuplicateLocator(typeName, typeLocator)) { // adding dependents results in 2 duplicate errors
 							if (JavaBuilder.DEBUG)
@@ -432,7 +450,7 @@
 							return; // skip it since it really isn't changed
 						if (JavaBuilder.DEBUG)
 							System.out.println("Compile this changed source file " + typeLocator); //$NON-NLS-1$
-						sourceFiles.add(new SourceFile((IFile) resource, md, encoding, true));
+						sourceFiles.add(new SourceFile((IFile) resource, md, true));
 				}
 				return;
 			} else if (org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(resourceName)) {
@@ -455,6 +473,7 @@
 						createFolder(resourcePath.removeLastSegments(1), md.binaryFolder); // ensure package exists in the output folder
 						resource.copy(outputFile.getFullPath(), IResource.FORCE, null);
 						outputFile.setDerived(true);
+						outputFile.setReadOnly(false); // just in case the original was read only
 						return;
 					case IResourceDelta.REMOVED :
 						if (outputFile.exists()) {
@@ -476,6 +495,7 @@
 						createFolder(resourcePath.removeLastSegments(1), md.binaryFolder); // ensure package exists in the output folder
 						resource.copy(outputFile.getFullPath(), IResource.FORCE, null);
 						outputFile.setDerived(true);
+						outputFile.setReadOnly(false); // just in case the original was read only
 				}
 				return;
 			}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java
index 247ab90..faede61 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -165,14 +165,14 @@
 			ok = true;
 		}
 	} catch (CoreException e) {
-		Util.log(e, "JavaBuilder handling CoreException"); //$NON-NLS-1$
+		Util.log(e, "JavaBuilder handling CoreException while building: " + currentProject.getName()); //$NON-NLS-1$
 		IMarker marker = currentProject.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
 		marker.setAttribute(IMarker.MESSAGE, Util.bind("build.inconsistentProject", e.getLocalizedMessage())); //$NON-NLS-1$
 		marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
 	} catch (ImageBuilderInternalException e) {
-		Util.log(e.getThrowable(), "JavaBuilder handling ImageBuilderInternalException"); //$NON-NLS-1$
+		Util.log(e.getThrowable(), "JavaBuilder handling ImageBuilderInternalException while building: " + currentProject.getName()); //$NON-NLS-1$
 		IMarker marker = currentProject.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
-		marker.setAttribute(IMarker.MESSAGE, Util.bind("build.inconsistentProject", e.coreException.getLocalizedMessage())); //$NON-NLS-1$
+		marker.setAttribute(IMarker.MESSAGE, Util.bind("build.inconsistentProject", e.getLocalizedMessage())); //$NON-NLS-1$
 		marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
 	} catch (MissingClassFileException e) {
 		// do not log this exception since its thrown to handle aborted compiles because of missing class files
@@ -227,6 +227,38 @@
 		buildAll();
 }
 
+protected void clean(IProgressMonitor monitor) throws CoreException {
+	this.currentProject = getProject();
+	if (currentProject == null || !currentProject.isAccessible()) return;
+
+	if (DEBUG)
+		System.out.println("\nCleaning " + currentProject.getName() //$NON-NLS-1$
+			+ " @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$
+	this.notifier = new BuildNotifier(monitor, currentProject);
+	notifier.begin();
+	try {
+		notifier.checkCancel();
+
+		initializeBuilder();
+		if (DEBUG)
+			System.out.println("Clearing last state as part of clean : " + lastState); //$NON-NLS-1$
+		clearLastState();
+		removeProblemsAndTasksFor(currentProject);
+		new BatchImageBuilder(this).cleanOutputFolders(false);
+	} catch (CoreException e) {
+		Util.log(e, "JavaBuilder handling CoreException while cleaning: " + currentProject.getName()); //$NON-NLS-1$
+		IMarker marker = currentProject.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
+		marker.setAttribute(IMarker.MESSAGE, Util.bind("build.inconsistentProject", e.getLocalizedMessage())); //$NON-NLS-1$
+		marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
+	} finally {
+		notifier.done();
+		cleanup();
+	}
+	if (DEBUG)
+		System.out.println("Finished cleaning " + currentProject.getName() //$NON-NLS-1$
+			+ " @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$
+}
+
 private void cleanup() {
 	this.nameEnvironment = null;
 	this.binaryLocationsPerProject = null;
@@ -501,8 +533,6 @@
 		if (DEBUG)
 			System.out.println("Aborted build because project has classpath errors (incomplete or involved in cycle)"); //$NON-NLS-1$
 
-		JavaModelManager.getJavaModelManager().getDeltaProcessor().addForRefresh(javaProject);
-
 		removeProblemsAndTasksFor(currentProject); // remove all compilation problems
 
 		IMarker marker = currentProject.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/MissingClassFileException.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/MissingClassFileException.java
index 69ec46c..2096e8b 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/MissingClassFileException.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/MissingClassFileException.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/MissingSourceFileException.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/MissingSourceFileException.java
index 3aeb2ee..379c058 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/MissingSourceFileException.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/MissingSourceFileException.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/NameEnvironment.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/NameEnvironment.java
index 7d18d77..ab912f6 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/NameEnvironment.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/NameEnvironment.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -77,9 +77,6 @@
 	JavaProject javaProject,
 	SimpleLookupTable binaryLocationsPerProject) throws CoreException {
 
-	/* Update incomplete classpath marker */
-	IClasspathEntry[] classpathEntries = javaProject.getExpandedClasspath(true/*ignore unresolved variable*/, true/*create markers*/, null/*preferred cp*/, null/*preferred output*/);
-
 	/* Update cycle marker */
 	IMarker cycleMarker = javaProject.getCycleMarker();
 	if (cycleMarker != null) {
@@ -90,6 +87,7 @@
 			cycleMarker.setAttribute(IMarker.SEVERITY, severity);
 	}
 
+	IClasspathEntry[] classpathEntries = javaProject.getExpandedClasspath(true/*ignore unresolved variable*/, false/*don't create markers*/, null/*preferred cp*/, null/*preferred output*/);
 	ArrayList sLocations = new ArrayList(classpathEntries.length);
 	ArrayList bLocations = new ArrayList(classpathEntries.length);
 	nextEntry : for (int i = 0, l = classpathEntries.length; i < l; i++) {
@@ -113,7 +111,7 @@
 						createFolder(outputFolder);
 				}
 				sLocations.add(
-					ClasspathLocation.forSourceFolder((IContainer) target, outputFolder, entry.fullExclusionPatternChars()));
+					ClasspathLocation.forSourceFolder((IContainer) target, outputFolder, entry.fullInclusionPatternChars(), entry.fullExclusionPatternChars()));
 				continue nextEntry;
 
 			case IClasspathEntry.CPE_PROJECT :
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/NameSet.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/NameSet.java
index 82a9eba..144d38a 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/NameSet.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/NameSet.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -12,7 +12,7 @@
 
 import org.eclipse.jdt.core.compiler.CharOperation;
 
-public class NameSet {
+public final class NameSet {
 
 // to avoid using Enumerations, walk the individual values skipping nulls
 public char[][] names;
@@ -20,10 +20,12 @@
 public int threshold;
 
 public NameSet(int size) {
-	if (size < 3) size = 3;
 	this.elementSize = 0;
-	this.threshold = size + 1; // size is the expected number of elements
-	this.names = new char[2 * size + 1][];
+	this.threshold = size; // size represents the expected number of elements
+	int extraRoom = (int) (size * 1.5f);
+	if (this.threshold == extraRoom)
+		extraRoom++;
+	this.names = new char[extraRoom][];
 }
 
 public char[] add(char[] name) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ProblemFactory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ProblemFactory.java
index 6e2d2d0..ce6c6a3 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ProblemFactory.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ProblemFactory.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/QualifiedNameSet.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/QualifiedNameSet.java
index fef6e8a..91036b2 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/QualifiedNameSet.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/QualifiedNameSet.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -20,10 +20,12 @@
 public int threshold;
 
 public QualifiedNameSet(int size) {
-	if (size < 3) size = 3;
 	this.elementSize = 0;
-	this.threshold = size + 1; // size is the expected number of elements
-	this.qualifiedNames = new char[2 * size + 1][][];
+	this.threshold = size; // size represents the expected number of elements
+	int extraRoom = (int) (size * 1.5f);
+	if (this.threshold == extraRoom)
+		extraRoom++;
+	this.qualifiedNames = new char[extraRoom][][];
 }
 
 public char[][] add(char[][] qualifiedName) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ReferenceCollection.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ReferenceCollection.java
index f5de9b5..9c8a57b 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ReferenceCollection.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ReferenceCollection.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/SourceFile.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/SourceFile.java
index 9f2ad0a..6fea880 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/SourceFile.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/SourceFile.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -24,19 +24,17 @@
 IFile resource;
 ClasspathMultiDirectory sourceLocation;
 String initialTypeName;
-String encoding;
 boolean updateClassFile;
 
-public SourceFile(IFile resource, ClasspathMultiDirectory sourceLocation, String encoding) {
+public SourceFile(IFile resource, ClasspathMultiDirectory sourceLocation) {
 	this.resource = resource;
 	this.sourceLocation = sourceLocation;
 	this.initialTypeName = extractTypeName();
-	this.encoding = encoding;
 	this.updateClassFile = false;
 }
 
-public SourceFile(IFile resource, ClasspathMultiDirectory sourceLocation, String encoding, boolean updateClassFile) {
-	this(resource, sourceLocation, encoding);
+public SourceFile(IFile resource, ClasspathMultiDirectory sourceLocation, boolean updateClassFile) {
+	this(resource, sourceLocation);
 
 	this.updateClassFile = updateClassFile;
 }
@@ -46,14 +44,14 @@
 	if (!(o instanceof SourceFile)) return false;
 
 	SourceFile f = (SourceFile) o;
-	return sourceLocation == f.sourceLocation && resource.getFullPath().equals(f.resource.getFullPath());
+	return this.sourceLocation == f.sourceLocation && this.resource.getFullPath().equals(f.resource.getFullPath());
 } 
 
 String extractTypeName() {
 	// answer a String with the qualified type name for the source file in the form: 'p1/p2/A'
-	IPath fullPath = resource.getFullPath();
+	IPath fullPath = this.resource.getFullPath();
 	int resourceSegmentCount = fullPath.segmentCount();
-	int sourceFolderSegmentCount = sourceLocation.sourceFolder.getFullPath().segmentCount();
+	int sourceFolderSegmentCount = this.sourceLocation.sourceFolder.getFullPath().segmentCount();
 	int charCount = (resourceSegmentCount - sourceFolderSegmentCount - 1) - 5; // length of ".java"
 	for (int i = sourceFolderSegmentCount; i < resourceSegmentCount; i++)
 		charCount += fullPath.segment(i).length();
@@ -77,34 +75,34 @@
 public char[] getContents() {
 
 	try {	
-		return Util.getResourceContentsAsCharArray(resource, this.encoding);
+		return Util.getResourceContentsAsCharArray(this.resource);
 	} catch (CoreException e) {
-		throw new AbortCompilation(true, new MissingSourceFileException(resource.getFullPath().toString()));
+		throw new AbortCompilation(true, new MissingSourceFileException(this.resource.getFullPath().toString()));
 	}
 }
 
 public char[] getFileName() {
-	return resource.getFullPath().toString().toCharArray(); // do not know what you want to return here
+	return this.resource.getFullPath().toString().toCharArray(); // do not know what you want to return here
 }
 
 public char[] getMainTypeName() {
-	char[] typeName = initialTypeName.toCharArray();
+	char[] typeName = this.initialTypeName.toCharArray();
 	int lastIndex = CharOperation.lastIndexOf('/', typeName);
 	return CharOperation.subarray(typeName, lastIndex + 1, -1);
 }
 
 public char[][] getPackageName() {
-	char[] typeName = initialTypeName.toCharArray();
+	char[] typeName = this.initialTypeName.toCharArray();
 	int lastIndex = CharOperation.lastIndexOf('/', typeName);
 	return CharOperation.splitOn('/', typeName, 0, lastIndex);
 }
 
 String typeLocator() {
-	return resource.getProjectRelativePath().toString();
+	return this.resource.getProjectRelativePath().toString();
 }
 
 public String toString() {
 	return "SourceFile[" //$NON-NLS-1$
-		+ resource.getFullPath() + "]";  //$NON-NLS-1$
+		+ this.resource.getFullPath() + "]";  //$NON-NLS-1$
 }
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/State.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/State.java
index dfc9e01..fcc4894 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/State.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/State.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -40,7 +40,7 @@
 private StringSet structurallyChangedTypes;
 public static int MaxStructurallyChangedTypes = 100; // keep track of ? structurally changed types, otherwise consider all to be changed
 
-static final byte VERSION = 0x0007;
+static final byte VERSION = 0x0008;
 
 static final byte SOURCE_FOLDER = 1;
 static final byte BINARY_FOLDER = 2;
@@ -153,12 +153,17 @@
 
 void recordLocatorForType(String qualifiedTypeName, String typeLocator) {
 	this.knownPackageNames = null;
+	// in the common case, the qualifiedTypeName is a substring of the typeLocator so share the char[] by using String.substring()
+	int start = typeLocator.indexOf(qualifiedTypeName, 0);
+	if (start > 0)
+		qualifiedTypeName = typeLocator.substring(start, start + qualifiedTypeName.length());
 	typeLocators.put(qualifiedTypeName, typeLocator);
 }
 
 void recordStructuralDependency(IProject prereqProject, State prereqState) {
 	if (prereqState != null)
-		structuralBuildTimes.put(prereqProject.getName(), new Long(prereqState.lastStructuralBuildTime));
+		if (prereqState.lastStructuralBuildTime > 0) // can skip if 0 (full build) since its assumed to be 0 if unknown
+			structuralBuildTimes.put(prereqProject.getName(), new Long(prereqState.lastStructuralBuildTime));
 }
 
 void removeLocator(String typeLocatorToRemove) {
@@ -214,7 +219,7 @@
 		if ((folderName = in.readUTF()).length() > 0) sourceFolder = project.getFolder(folderName);
 		if ((folderName = in.readUTF()).length() > 0) outputFolder = project.getFolder(folderName);
 		ClasspathMultiDirectory md =
-			(ClasspathMultiDirectory) ClasspathLocation.forSourceFolder(sourceFolder, outputFolder, readNames(in));
+			(ClasspathMultiDirectory) ClasspathLocation.forSourceFolder(sourceFolder, outputFolder, readNames(in), readNames(in));
 		if (in.readBoolean())
 			md.hasIndependentOutputFolder = true;
 		newState.sourceLocations[i] = md;
@@ -253,7 +258,7 @@
 
 	newState.typeLocators = new SimpleLookupTable(length = in.readInt());
 	for (int i = 0; i < length; i++)
-		newState.typeLocators.put(in.readUTF(), internedTypeLocators[in.readInt()]);
+		newState.recordLocatorForType(in.readUTF(), internedTypeLocators[in.readInt()]);
 
 	char[][] internedSimpleNames = ReferenceCollection.internSimpleNames(readNames(in), false);
 	char[][][] internedQualifiedNames = new char[length = in.readInt()][][];
@@ -368,6 +373,7 @@
 		ClasspathMultiDirectory md = sourceLocations[i];
 		out.writeUTF(md.sourceFolder.getProjectRelativePath().toString());
 		out.writeUTF(md.binaryFolder.getProjectRelativePath().toString());
+		writeNames(md.inclusionPatterns, out);
 		writeNames(md.exclusionPatterns, out);
 		out.writeBoolean(md.hasIndependentOutputFolder);
 	}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/StringSet.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/StringSet.java
index 6688a04..a22ca99 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/StringSet.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/StringSet.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -18,10 +18,12 @@
 public int threshold;
 
 public StringSet(int size) {
-	if (size < 3) size = 3;
 	this.elementSize = 0;
-	this.threshold = size + 1; // size is the expected number of elements
-	this.values = new String[2 * size + 1];
+	this.threshold = size; // size represents the expected number of elements
+	int extraRoom = (int) (size * 1.5f);
+	if (this.threshold == extraRoom)
+		extraRoom++;
+	this.values = new String[extraRoom];
 }
 
 public boolean add(String value) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/WorkQueue.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/WorkQueue.java
index 1265eaa..c109954 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/WorkQueue.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/WorkQueue.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/eval/EvaluationContextWrapper.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/eval/EvaluationContextWrapper.java
index 70de004..ea0eb3d 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/eval/EvaluationContextWrapper.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/eval/EvaluationContextWrapper.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -92,28 +92,15 @@
  * @see org.eclipse.jdt.core.eval.IEvaluationContext#codeComplete(String, int, ICompletionRequestor, WorkingCopyOwner)
  */
 public void codeComplete(String codeSnippet, int position, ICompletionRequestor requestor, WorkingCopyOwner owner) throws JavaModelException {
-	NameLookup lookup = null;
-	try {
-		// set the units to look inside
-		lookup = this.project.getNameLookup();
-		JavaModelManager manager = JavaModelManager.getJavaModelManager();
-		ICompilationUnit[] workingCopies = manager.getWorkingCopies(owner, true/*add primary WCs*/);
-		lookup.setUnitsToLookInside(workingCopies);
-
-		// code complete
-		this.context.complete(
-			codeSnippet.toCharArray(),
-			position,
-			this.project.getSearchableNameEnvironment(),
-			new CompletionRequestorWrapper(requestor, lookup),
-			this.project.getOptions(true),
-			this.project
-		);
-	} finally {
-		if (lookup != null) {
-			lookup.setUnitsToLookInside(null);
-		}
-	}
+	SearchableEnvironment environment = (SearchableEnvironment) this.project.newSearchableNameEnvironment(owner);
+	this.context.complete(
+		codeSnippet.toCharArray(),
+		position,
+		environment,
+		new CompletionRequestorWrapper(requestor, environment.nameLookup),
+		this.project.getOptions(true),
+		this.project
+	);
 }
 /**
  * @see org.eclipse.jdt.core.eval.IEvaluationContext#codeSelect(String, int, int)
@@ -125,30 +112,17 @@
  * @see org.eclipse.jdt.core.eval.IEvaluationContext#codeSelect(String, int, int, WorkingCopyOwner)
  */
 public IJavaElement[] codeSelect(String codeSnippet, int offset, int length, WorkingCopyOwner owner) throws JavaModelException {
-	NameLookup lookup = null;
-	try {
-		// set the units to look inside
-		lookup = this.project.getNameLookup();
-		JavaModelManager manager = JavaModelManager.getJavaModelManager();
-		ICompilationUnit[] workingCopies = manager.getWorkingCopies(owner, true/*add primary WCs*/);
-		lookup.setUnitsToLookInside(workingCopies);
-
-		// code select
-		SelectionRequestor requestor= new SelectionRequestor(lookup, null); // null because there is no need to look inside the code snippet itself
-		this.context.select(
-			codeSnippet.toCharArray(),
-			offset,
-			offset + length - 1,
-			this.project.getSearchableNameEnvironment(),
-			requestor,
-			this.project.getOptions(true)
-		);
-		return requestor.getElements();
-	} finally {
-		if (lookup != null) {
-			lookup.setUnitsToLookInside(null);
-		}
-	}
+	SearchableEnvironment environment = (SearchableEnvironment) this.project.newSearchableNameEnvironment(owner);
+	SelectionRequestor requestor= new SelectionRequestor(environment.nameLookup, null); // null because there is no need to look inside the code snippet itself
+	this.context.select(
+		codeSnippet.toCharArray(),
+		offset,
+		offset + length - 1,
+		environment,
+		requestor,
+		this.project.getOptions(true)
+	);
+	return requestor.getElements();
 }
 /**
  * @see org.eclipse.jdt.core.eval.IEvaluationContext#deleteVariable(IGlobalVariable)
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/eval/GlobalVariableWrapper.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/eval/GlobalVariableWrapper.java
index ca48c0e..8a39a8b 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/eval/GlobalVariableWrapper.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/eval/GlobalVariableWrapper.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/eval/RequestorWrapper.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/eval/RequestorWrapper.java
index 35ffdfd..fc8bab9 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/eval/RequestorWrapper.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/eval/RequestorWrapper.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/ChangeCollector.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/ChangeCollector.java
index 256c18b..3e80c7d 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/ChangeCollector.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/ChangeCollector.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyBinaryType.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyBinaryType.java
index f2e4cc8..34f1d6e 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyBinaryType.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyBinaryType.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyBuilder.java
index d9cd7dc..b2d1383 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyBuilder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyBuilder.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -19,7 +19,7 @@
 import org.eclipse.jdt.core.IClassFile;
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.IType;
-import org.eclipse.jdt.core.JavaCore;
+//import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.internal.compiler.env.IBinaryType;
 import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
@@ -42,10 +42,6 @@
 	 */
 	protected TypeHierarchy hierarchy;
 	/**
-	 * The name environment used by the HierarchyResolver
-	 */
-	protected SearchableEnvironment searchableEnvironment;
-	/**
 	 * @see NameLookup
 	 */
 	protected NameLookup nameLookup;
@@ -65,12 +61,28 @@
 		
 		this.hierarchy = hierarchy;
 		JavaProject project = (JavaProject) hierarchy.javaProject();
-		this.searchableEnvironment =
-			(SearchableEnvironment) project.getSearchableNameEnvironment();
-		this.nameLookup = project.getNameLookup();
+		
+		IType focusType = hierarchy.getType();
+		org.eclipse.jdt.core.ICompilationUnit unitToLookInside = focusType == null ? null : focusType.getCompilationUnit();
+		org.eclipse.jdt.core.ICompilationUnit[] workingCopies = this.hierarchy.workingCopies;
+		org.eclipse.jdt.core.ICompilationUnit[] unitsToLookInside;
+		if (unitToLookInside != null) {
+			int wcLength = workingCopies == null ? 0 : workingCopies.length;
+			if (wcLength == 0) {
+				unitsToLookInside = new org.eclipse.jdt.core.ICompilationUnit[] {unitToLookInside};
+			} else {
+				unitsToLookInside = new org.eclipse.jdt.core.ICompilationUnit[wcLength+1];
+				unitsToLookInside[0] = unitToLookInside;
+				System.arraycopy(workingCopies, 0, unitsToLookInside, 1, wcLength);
+			}
+		} else {
+			unitsToLookInside = workingCopies;
+		}
+		SearchableEnvironment searchableEnvironment = (SearchableEnvironment) project.newSearchableNameEnvironment(unitsToLookInside);
+		this.nameLookup = searchableEnvironment.nameLookup;
 		this.hierarchyResolver =
 			new HierarchyResolver(
-				this.searchableEnvironment,
+				searchableEnvironment,
 				project.getOptions(true),
 				this,
 				new DefaultProblemFactory());
@@ -98,33 +110,8 @@
 		//NB: no need to set focus type on hierarchy resolver since no other type is injected
 		//    in the hierarchy resolver, thus there is no need to check that a type is 
 		//    a sub or super type of the focus type.
-		org.eclipse.jdt.core.ICompilationUnit unitToLookInside = focusType.getCompilationUnit();
-		if (nameLookup != null) {
-			org.eclipse.jdt.core.ICompilationUnit[] workingCopies = this.hierarchy.workingCopies;
-			org.eclipse.jdt.core.ICompilationUnit[] unitsToLookInside;
-			if (unitToLookInside != null) {
-				int wcLength = workingCopies == null ? 0 : workingCopies.length;
-				if (wcLength == 0) {
-					unitsToLookInside = new org.eclipse.jdt.core.ICompilationUnit[] {unitToLookInside};
-				} else {
-					unitsToLookInside = new org.eclipse.jdt.core.ICompilationUnit[wcLength+1];
-					unitsToLookInside[0] = unitToLookInside;
-					System.arraycopy(workingCopies, 0, unitsToLookInside, 1, wcLength);
-				}
-			} else {
-				unitsToLookInside = workingCopies;
-			}
-			try {
-				nameLookup.setUnitsToLookInside(unitsToLookInside); // NB: this uses a PerThreadObject, so it is thread safe
-				// resolve
-				this.hierarchyResolver.resolve(type);
-			} finally {
-				nameLookup.setUnitsToLookInside(null);
-			}
-		} else {
-			// resolve
-			this.hierarchyResolver.resolve(type);
-		}
+		this.hierarchyResolver.resolve(type);
+
 		// Add focus if not already in (case of a type with no explicit super type)
 		if (!this.hierarchy.contains(focusType)) {
 			this.hierarchy.addRootClass(focusType);
@@ -222,7 +209,14 @@
 	protected IType getHandle(IGenericType genericType) {
 		if (genericType == null)
 			return null;
-		if (genericType.isBinaryType()) {
+		if (genericType instanceof HierarchyType) {
+			IType handle = (IType)this.infoToHandle.get(genericType);
+			if (handle == null) {
+				handle = ((HierarchyType)genericType).typeHandle;
+				this.infoToHandle.put(genericType, handle);
+			}
+			return handle;
+		} else if (genericType.isBinaryType()) {
 			IClassFile classFile = (IClassFile) this.infoToHandle.get(genericType);
 			// if it's null, it's from outside the region, so do lookup
 			if (classFile == null) {
@@ -276,13 +270,12 @@
  * Create an ICompilationUnit info from the given compilation unit on disk.
  */
 protected ICompilationUnit createCompilationUnitFromPath(Openable handle, String osPath) {
-	String encoding = handle.getJavaProject().getOption(JavaCore.CORE_ENCODING, true);
 	return 
 		new BasicCompilationUnit(
 			null,
 			null,
 			osPath,
-			encoding);
+			handle);
 }
 	/**
  * Creates the type info from the given class file on disk and
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyResolver.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyResolver.java
index fd73dba..33e7a62 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyResolver.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyResolver.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -131,21 +131,23 @@
 	
 public HierarchyResolver(INameEnvironment nameEnvironment, Map settings, HierarchyBuilder requestor, IProblemFactory problemFactory) {
 	// create a problem handler with the 'exit after all problems' handling policy
-	options = new CompilerOptions(settings);
+	this.options = new CompilerOptions(settings);
 	IErrorHandlingPolicy policy = DefaultErrorHandlingPolicies.exitAfterAllProblems();
-	ProblemReporter problemReporter = new ProblemReporter(policy, options, problemFactory);
+	ProblemReporter problemReporter = new ProblemReporter(policy, this.options, problemFactory);
 
 	this.setEnvironment(
-		new LookupEnvironment(this, options, problemReporter, nameEnvironment),
+		new LookupEnvironment(this, this.options, problemReporter, nameEnvironment),
 		requestor);
 }
 public HierarchyResolver(LookupEnvironment lookupEnvironment, HierarchyBuilder requestor) {
 	this.setEnvironment(lookupEnvironment, requestor);
 }
+
 /**
  * Add an additional binary type
+ * @param binaryType
+ * @param packageBinding
  */
-
 public void accept(IBinaryType binaryType, PackageBinding packageBinding) {
 	BinaryTypeBinding typeBinding = this.lookupEnvironment.createBinaryTypeFrom(binaryType, packageBinding);
 	try {
@@ -154,10 +156,11 @@
 		// ignore
 	}
 }
+
 /**
  * Add an additional compilation unit.
+ * @param sourceUnit
  */
-
 public void accept(ICompilationUnit sourceUnit) {
 	//System.out.println("Cannot accept compilation units inside the HierarchyResolver.");
 	this.lookupEnvironment.problemReporter.abortDueToInternalError(
@@ -165,8 +168,11 @@
 			.append(sourceUnit.getFileName())
 			.toString());
 }
+
 /**
  * Add additional source types
+ * @param sourceTypes
+ * @param packageBinding
  */
 public void accept(ISourceType[] sourceTypes, PackageBinding packageBinding) {
 	// find most enclosing type first (needed when explicit askForType(...) is done 
@@ -182,7 +188,7 @@
 			new ISourceType[] {sourceType}, // ignore secondary types, to improve laziness
 			SourceTypeConverter.MEMBER_TYPE, // need member types
 			// no need for field initialization
-			lookupEnvironment.problemReporter, 
+			this.lookupEnvironment.problemReporter, 
 			result);
 		
 	// build bindings
@@ -232,9 +238,9 @@
 				}
 			}
 		}
-		for (int t = typeIndex; t >= 0; t--) {
-			if (typeBindings[t] == superBinding) {
-				return typeModels[t];
+		for (int t = this.typeIndex; t >= 0; t--) {
+			if (this.typeBindings[t] == superBinding) {
+				return this.typeModels[t];
 			}
 		}
 	} 
@@ -287,15 +293,23 @@
 		char[] superInterfaceName = superInterfaceNames[i];
 		int lastSeparator = CharOperation.lastIndexOf(separator, superInterfaceName);
 		char[] simpleName = lastSeparator == -1 ? superInterfaceName : CharOperation.subarray(superInterfaceName, lastSeparator+1, superInterfaceName.length);
+		
+		// case of binary inner type -> take the last part
+		int start = CharOperation.lastIndexOf('$', simpleName) + 1;
+		if (start != 0) {
+			int nameLength = simpleName.length - start;
+			System.arraycopy(simpleName, start, simpleName = new char[nameLength], 0, nameLength);
+		}
+		
 		if (bindingIndex < bindingLength) {
 			ReferenceBinding interfaceBinding = interfaceBindings[bindingIndex];
 
 			// ensure that the binding corresponds to the interface defined by the user
 			if (CharOperation.equals(simpleName, interfaceBinding.sourceName)) {
 				bindingIndex++;
-				for (int t = typeIndex; t >= 0; t--) {
-					if (typeBindings[t] == interfaceBinding) {
-						superinterfaces[i] = typeModels[t];
+				for (int t = this.typeIndex; t >= 0; t--) {
+					if (this.typeBindings[t] == interfaceBinding) {
+						superinterfaces[i] = this.typeModels[t];
 						continue next;
 					}
 				}
@@ -308,19 +322,12 @@
 private void remember(IGenericType suppliedType, ReferenceBinding typeBinding) {
 	if (typeBinding == null) return;
 	
-	if (suppliedType.isBinaryType()) {
-		// fault in its hierarchy...
-		// NB: AbortCompilation is handled by caller
-		typeBinding.superclass();
-		typeBinding.superInterfaces();
+	if (++this.typeIndex == this.typeModels.length) {
+		System.arraycopy(this.typeModels, 0, this.typeModels = new IGenericType[this.typeIndex * 2], 0, this.typeIndex);
+		System.arraycopy(this.typeBindings, 0, this.typeBindings = new ReferenceBinding[this.typeIndex * 2], 0, this.typeIndex);
 	}
-	
-	if (++typeIndex == typeModels.length) {
-		System.arraycopy(typeModels, 0, typeModels = new IGenericType[typeIndex * 2], 0, typeIndex);
-		System.arraycopy(typeBindings, 0, typeBindings = new ReferenceBinding[typeIndex * 2], 0, typeIndex);
-	}
-	typeModels[typeIndex] = suppliedType;
-	typeBindings[typeIndex] = typeBinding;
+	this.typeModels[this.typeIndex] = suppliedType;
+	this.typeBindings[this.typeIndex] = typeBinding;
 }
 private void remember(IType type, ReferenceBinding typeBinding) {
 	if (((CompilationUnit)type.getCompilationUnit()).isOpen()) {
@@ -408,7 +415,11 @@
 		}
 	}
 }
-private void reportHierarchy(IType focus, CompilationUnitDeclaration parsedUnit, BinaryTypeBinding binaryTypeBinding) {
+/*
+ * Reports the hierarchy from the remembered bindings.
+ * Note that 'binaryTypeBinding' is null if focus type is a source type.
+ */
+private void reportHierarchy(IType focus, CompilationUnitDeclaration parsedUnit, ReferenceBinding binaryTypeBinding) {
 	
 	// set focus type binding
 	if (focus != null) {
@@ -435,8 +446,8 @@
 	}
 	
 	int objectIndex = -1;
-	for (int current = typeIndex; current >= 0; current--) {
-		ReferenceBinding typeBinding = typeBindings[current];
+	for (int current = this.typeIndex; current >= 0; current--) {
+		ReferenceBinding typeBinding = this.typeBindings[current];
 
 		// java.lang.Object treated at the end
 		if (typeBinding.id == TypeIds.T_JavaLangObject) {
@@ -444,7 +455,7 @@
 			continue;
 		}
 
-		IGenericType suppliedType = typeModels[current];
+		IGenericType suppliedType = this.typeModels[current];
 
 		if (!subOrSuperOfFocus(typeBinding)) {
 			continue; // ignore types outside of hierarchy
@@ -454,15 +465,15 @@
 		if (typeBinding.isInterface()){ // do not connect interfaces to Object
 			superclass = null;
 		} else {
-			superclass = this.findSuperClass(suppliedType, typeBinding);
+			superclass = findSuperClass(suppliedType, typeBinding);
 		}
-		IGenericType[] superinterfaces = this.findSuperInterfaces(suppliedType, typeBinding);
+		IGenericType[] superinterfaces = findSuperInterfaces(suppliedType, typeBinding);
 		
-		requestor.connect(suppliedType, superclass, superinterfaces);
+		this.requestor.connect(suppliedType, superclass, superinterfaces);
 	}
 	// add java.lang.Object only if the super class is not missing
 	if (!this.hasMissingSuperClass && objectIndex > -1) {
-		requestor.connect(typeModels[objectIndex], null, null);
+		this.requestor.connect(this.typeModels[objectIndex], null, null);
 	}
 }
 private void reset(){
@@ -474,17 +485,33 @@
 	this.typeModels = new IGenericType[5];
 	this.typeBindings = new ReferenceBinding[5];
 }
+
 /**
  * Resolve the supertypes for the supplied source type.
  * Inform the requestor of the resolved supertypes using:
  *    connect(ISourceType suppliedType, IGenericType superclass, IGenericType[] superinterfaces)
+ * @param suppliedType
  */
-
 public void resolve(IGenericType suppliedType) {
 	try {
 		if (suppliedType.isBinaryType()) {
 			BinaryTypeBinding binaryTypeBinding = this.lookupEnvironment.cacheBinaryType((IBinaryType) suppliedType);
 			remember(suppliedType, binaryTypeBinding);
+			// We still need to add superclasses and superinterfaces bindings (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=53095)
+			int startIndex = this.typeIndex;
+			for (int i = startIndex; i <= this.typeIndex; i++) {
+				IGenericType igType = this.typeModels[i];
+				if (igType != null && igType.isBinaryType()) {
+					// fault in its hierarchy...
+					try {
+						ReferenceBinding typeBinding = this.typeBindings[i];
+						typeBinding.superclass();
+						typeBinding.superInterfaces();
+					} catch (AbortCompilation e) {
+						// classpath problem for this type: ignore
+					}
+				}
+			}		
 			this.superTypesOnly = true;
 			reportHierarchy(this.requestor.getType(), null, binaryTypeBinding);
 		} else {
@@ -499,6 +526,7 @@
 		reset();
 	}
 }
+
 /**
  * Resolve the supertypes for the types contained in the given openables (ICompilationUnits and/or IClassFiles).
  * Inform the requestor of the resolved supertypes for each
@@ -508,8 +536,10 @@
  * Also inform the requestor of the supertypes of each
  * additional requested super type which is also a source type
  * instead of a binary type.
+ * @param openables
+ * @param localTypes
+ * @param monitor
  */
-
 public void resolve(Openable[] openables, HashSet localTypes, IProgressMonitor monitor) {
 	try {
 		int openablesLength = openables.length;
@@ -519,7 +549,7 @@
 		int unitsIndex = 0;
 		
 		CompilationUnitDeclaration focusUnit = null;
-		BinaryTypeBinding focusBinaryBinding = null;
+		ReferenceBinding focusBinaryBinding = null;
 		IType focus = this.requestor.getType();
 		Openable focusOpenable = null;
 		if (focus != null) {
@@ -540,7 +570,7 @@
 				// contains a potential subtype as a local or anonymous type?
 				boolean containsLocalType = false;
 				if (localTypes == null) { // case of hierarchy on region
-					containsLocalType = false;
+					containsLocalType = true;
 				} else {
 					IPath path = cu.getPath();
 					containsLocalType = localTypes.contains(path.toString());
@@ -555,6 +585,7 @@
 					try {
 						IType[] topLevelTypes = cu.getTypes();
 						int topLevelLength = topLevelTypes.length;
+						if (topLevelLength == 0) continue; // empty cu: no need to parse (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=65677)
 						typeInfos = new SourceTypeElementInfo[topLevelLength];
 						for (int j = 0; j < topLevelLength; j++) {
 							IType topLevelType = topLevelTypes[j];
@@ -627,7 +658,7 @@
 				}
 				if (binaryType != null) {
 					try {
-						BinaryTypeBinding binaryTypeBinding = this.lookupEnvironment.cacheBinaryType(binaryType, false);
+						BinaryTypeBinding binaryTypeBinding = this.lookupEnvironment.cacheBinaryType(binaryType);
 						remember(binaryType, binaryTypeBinding);
 						if (openable.equals(focusOpenable)) {
 							focusBinaryBinding = binaryTypeBinding;
@@ -638,7 +669,20 @@
 				}
 			}
 		}
-				
+		
+		for (int i = 0; i <= this.typeIndex; i++) {
+			IGenericType suppliedType = this.typeModels[i];
+			if (suppliedType != null && suppliedType.isBinaryType()) {
+				// fault in its hierarchy...
+				try {
+					ReferenceBinding typeBinding = this.typeBindings[i];
+					typeBinding.superclass();
+					typeBinding.superInterfaces();
+				} catch (AbortCompilation e) {
+					// classpath problem for this type: ignore
+				}
+			}
+		}		
 		
 		// complete type bindings (ie. connect super types)
 		for (int i = 0; i < unitsIndex; i++) {
@@ -651,7 +695,8 @@
 					}
 					this.lookupEnvironment.completeTypeBindings(parsedUnit, true/*build constructor only*/);
 				} catch (AbortCompilation e) {
-					// classpath problem for this type: ignore
+					// classpath problem for this type: don't try to resolve (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=49809)
+					hasLocalType[i] = false;
 				}
 			}
 			worked(monitor, 1);
@@ -664,13 +709,20 @@
 				boolean containsLocalType = hasLocalType[i];
 				if (containsLocalType) {
 					parsedUnit.scope.faultInTypes();
-					parsedUnit.scope.verifyMethods(this.lookupEnvironment.methodVerifier());
 					parsedUnit.resolve();
 				}
 					
 				rememberAllTypes(parsedUnit, cus[i], containsLocalType);
 			}
 		}
+		
+		// if no potential subtype was a real subtype of the binary focus type, no need to go further
+		// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=54043)
+		if (focusBinaryBinding == null && focus != null && focus.isBinary()) {
+			char[] fullyQualifiedName = focus.getFullyQualifiedName().toCharArray();
+			focusBinaryBinding = this.lookupEnvironment.getCachedType(CharOperation.splitOn('.', fullyQualifiedName));
+			if (focusBinaryBinding == null) return;
+		}
 
 		reportHierarchy(focus, focusUnit, focusBinaryBinding);
 		
@@ -688,9 +740,12 @@
 	this.typeModels = new IGenericType[5];
 	this.typeBindings = new ReferenceBinding[5];
 }
+
 /**
  * Set the focus type (ie. the type that this resolver is computing the hierarch for.
  * Returns the binding of this focus type or null if it could not be found.
+ * @param compoundName
+ * @return
  */
 public ReferenceBinding setFocusType(char[][] compoundName) {
 	if (compoundName == null || this.lookupEnvironment == null) return null;
@@ -702,8 +757,12 @@
 }
 public boolean subOrSuperOfFocus(ReferenceBinding typeBinding) {
 	if (this.focusType == null) return true; // accept all types (case of hierarchy in a region)
-	if (this.subTypeOfType(this.focusType, typeBinding)) return true;
-	if (!this.superTypesOnly && this.subTypeOfType(typeBinding, this.focusType)) return true;
+	try {
+		if (this.subTypeOfType(this.focusType, typeBinding)) return true;
+		if (!this.superTypesOnly && this.subTypeOfType(typeBinding, this.focusType)) return true;
+	} catch (AbortCompilation e) {
+		// unresolved superclass/superinterface -> ignore
+	}
 	return false;
 }
 private boolean subTypeOfType(ReferenceBinding subType, ReferenceBinding typeBinding) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyType.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyType.java
index c7e0cd6..9e67421 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyType.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyType.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/IHierarchyRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/IHierarchyRequestor.java
index 2352827..ced2c2a 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/IHierarchyRequestor.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/IHierarchyRequestor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/IndexBasedHierarchyBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/IndexBasedHierarchyBuilder.java
index be926b8..69a85a0 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/IndexBasedHierarchyBuilder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/IndexBasedHierarchyBuilder.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -14,13 +14,14 @@
 
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.IJavaProject;
 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.internal.compiler.env.IBinaryType;
 import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
-import org.eclipse.jdt.internal.compiler.env.IGenericType;
 import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
 import org.eclipse.jdt.internal.compiler.util.HashtableOfObject;
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
@@ -30,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;
 
@@ -85,7 +87,7 @@
 		public String toString(){
 			StringBuffer buffer = new StringBuffer("Queue:\n"); //$NON-NLS-1$
 			for (int i = this.start; i <= this.end; i++){
-				buffer.append(names[i]).append('\n');		
+				buffer.append(this.names[i]).append('\n');		
 			}
 			return buffer.toString();
 		}
@@ -144,13 +146,11 @@
 
 	// resolve
 	if (openablesLength > 0) {
-		this.searchableEnvironment = (SearchableEnvironment)project.getSearchableNameEnvironment();
 		IType focusType = this.getType();
-		this.nameLookup = project.getNameLookup();
 		boolean inProjectOfFocusType = focusType != null && focusType.getJavaProject().equals(project);
+		org.eclipse.jdt.core.ICompilationUnit[] unitsToLookInside = null;
 		if (inProjectOfFocusType) {
 			org.eclipse.jdt.core.ICompilationUnit unitToLookInside = focusType.getCompilationUnit();
-			org.eclipse.jdt.core.ICompilationUnit[] unitsToLookInside;
 			if (unitToLookInside != null) {
 				int wcLength = workingCopies == null ? 0 : workingCopies.length;
 				if (wcLength == 0) {
@@ -163,40 +163,36 @@
 			} else {
 				unitsToLookInside = workingCopies;
 			}
-			this.nameLookup.setUnitsToLookInside(unitsToLookInside); // NB: this uses a PerThreadObject, so it is thread safe
 		}
-		try {
-			this.hierarchyResolver = 
-				new HierarchyResolver(this.searchableEnvironment, project.getOptions(true), this, new DefaultProblemFactory());
-			if (focusType != null) {
-				Member declaringMember = ((Member)focusType).getOuterMostLocalContext();
-				if (declaringMember == null) {
-					// top level or member type
-					char[] fullyQualifiedName = focusType.getFullyQualifiedName().toCharArray();
-					if (!inProjectOfFocusType && project.getSearchableNameEnvironment().findType(CharOperation.splitOn('.', fullyQualifiedName)) == null) {
-						// focus type is not visible in this project: no need to go further
-						return;
-					}
-				} else {
-					// local or anonymous type
-					Openable openable;
-					if (declaringMember.isBinary()) {
-						openable = (Openable)declaringMember.getClassFile();
-					} else {
-						openable = (Openable)declaringMember.getCompilationUnit();
-					}
-					localTypes = new HashSet();
-					localTypes.add(openable.getPath().toString());
-					this.hierarchyResolver.resolve(new Openable[] {openable}, localTypes, monitor);
+
+		SearchableEnvironment searchableEnvironment = (SearchableEnvironment)project.newSearchableNameEnvironment(unitsToLookInside);
+		this.nameLookup = searchableEnvironment.nameLookup;
+		this.hierarchyResolver = 
+			new HierarchyResolver(searchableEnvironment, project.getOptions(true), this, new DefaultProblemFactory());
+		if (focusType != null) {
+			Member declaringMember = ((Member)focusType).getOuterMostLocalContext();
+			if (declaringMember == null) {
+				// top level or member type
+				char[] fullyQualifiedName = focusType.getFullyQualifiedName().toCharArray();
+				if (!inProjectOfFocusType && searchableEnvironment.findType(CharOperation.splitOn('.', fullyQualifiedName)) == null) {
+					// focus type is not visible in this project: no need to go further
 					return;
 				}
-			}
-			this.hierarchyResolver.resolve(openables, localTypes, monitor);
-		} finally {
-			if (inProjectOfFocusType) {
-				this.nameLookup.setUnitsToLookInside(null);
+			} else {
+				// local or anonymous type
+				Openable openable;
+				if (declaringMember.isBinary()) {
+					openable = (Openable)declaringMember.getClassFile();
+				} else {
+					openable = (Openable)declaringMember.getCompilationUnit();
+				}
+				localTypes = new HashSet();
+				localTypes.add(openable.getPath().toString());
+				this.hierarchyResolver.resolve(new Openable[] {openable}, localTypes, monitor);
+				return;
 			}
 		}
+		this.hierarchyResolver.resolve(openables, localTypes, monitor);
 	}
 }
 /**
@@ -337,6 +333,29 @@
 	this.cuToHandle.put(unit, handle);
 	return unit;
 }
+protected IBinaryType createInfoFromClassFile(Openable classFile, String osPath) {
+	String documentPath = classFile.getPath().toString();
+	IBinaryType binaryType = (IBinaryType)this.binariesFromIndexMatches.get(documentPath);
+	if (binaryType != null) {
+		this.infoToHandle.put(binaryType, classFile);
+		return binaryType;
+	} else {
+		return super.createInfoFromClassFile(classFile, osPath);
+	}
+}
+protected IBinaryType createInfoFromClassFileInJar(Openable classFile) {
+	String filePath = (((ClassFile)classFile).getType().getFullyQualifiedName('$')).replace('.', '/') + SuffixConstants.SUFFIX_STRING_class;
+	IPackageFragmentRoot root = classFile.getPackageFragmentRoot();
+	String rootPath = root.isExternal() ? root.getPath().toOSString() : root.getPath().toString();
+	String documentPath = rootPath + IJavaSearchScope.JAR_FILE_ENTRY_SEPARATOR + filePath;
+	IBinaryType binaryType = (IBinaryType)this.binariesFromIndexMatches.get(documentPath);
+	if (binaryType != null) {
+		this.infoToHandle.put(binaryType, classFile);
+		return binaryType;
+	} else {
+		return super.createInfoFromClassFileInJar(classFile);
+	}
+}
 /**
  * Returns all of the possible subtypes of this type hierarchy.
  * Returns null if they could not be determine.
@@ -346,7 +365,7 @@
 	class PathCollector implements IPathRequestor {
 		HashSet paths = new HashSet(10);
 		public void acceptPath(String path, boolean containsLocalTypes) {
-			paths.add(path);
+			this.paths.add(path);
 			if (containsLocalTypes) {
 				localTypes.add(path);
 			}
@@ -376,20 +395,7 @@
 	} 
 	return result;
 }
-/**
- * Returns a handle for the given generic type or null if not found.
- */
-protected IType getHandle(IGenericType genericType) {
-	if (genericType instanceof HierarchyType) {
-		IType type = (IType)this.infoToHandle.get(genericType);
-		if (type == null) {
-			type = ((HierarchyType)genericType).typeHandle;
-			this.infoToHandle.put(genericType, type);
-		}
-		return type;
-	} else
-		return super.getHandle(genericType);
-}
+
 /**
  * Find the set of candidate subtypes of a given type.
  *
@@ -398,8 +404,13 @@
  * hierarchy.
  * The match locator is not used here to narrow down the results, the type hierarchy
  * resolver is rather used to compute the whole hierarchy at once.
+ * @param type
+ * @param scope
+ * @param binariesFromIndexMatches
+ * @param pathRequestor
+ * @param waitingPolicy
+ * @param progressMonitor
  */
-
 public static void searchAllPossibleSubTypes(
 	IType type,
 	IJavaSearchScope scope,
@@ -409,7 +420,7 @@
 	IProgressMonitor progressMonitor) {
 
 	/* embed constructs inside arrays so as to pass them to (inner) collector */
-	final Queue awaitings = new Queue();
+	final Queue queue = new Queue();
 	final HashtableOfObject foundSuperNames = new HashtableOfObject(5);
 
 	IndexManager indexManager = JavaModelManager.getJavaModelManager().getIndexManager();
@@ -427,11 +438,16 @@
 					char[] enclosingTypeName = record.enclosingTypeName;
 					if (enclosingTypeName == IIndexConstants.ONE_ZERO) { // local or anonymous type
 						int lastSlash = documentPath.lastIndexOf('/');
-						if (lastSlash == -1) return true;
 						int lastDollar = documentPath.lastIndexOf('$');
-						if (lastDollar == -1) return true;
-						enclosingTypeName = documentPath.substring(lastSlash+1, lastDollar).toCharArray();
-						typeName = documentPath.substring(lastDollar+1, suffix).toCharArray();
+						if (lastDollar == -1) {
+							// malformed local or anonymous type: it doesn't contain a $ in its name
+							// treat it as a top level type
+							enclosingTypeName = null;
+							typeName = documentPath.substring(lastSlash+1, suffix).toCharArray();
+						} else {
+							enclosingTypeName = documentPath.substring(lastSlash+1, lastDollar).toCharArray();
+							typeName = documentPath.substring(lastDollar+1, suffix).toCharArray();
+						}
 					}
 					binaryType = new HierarchyBinaryType(record.modifiers, record.pkgName, typeName, enclosingTypeName, record.classOrInterface);
 					binariesFromIndexMatches.put(documentPath, binaryType);
@@ -440,49 +456,43 @@
 			}
 			if (!foundSuperNames.containsKey(typeName)){
 				foundSuperNames.put(typeName, typeName);
-				awaitings.add(typeName);
+				queue.add(typeName);
 			}
 			return true;
 		}		
 	};
-	
-	SuperTypeReferencePattern pattern = new SuperTypeReferencePattern(null, null, SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE);
-	pattern.focus = type;
+
+	SuperTypeReferencePattern pattern =
+		new SuperTypeReferencePattern(null, null, false, SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE);
+	MatchLocator.setFocus(pattern, type);
 	SubTypeSearchJob job = new SubTypeSearchJob(
 		pattern, 
-		new JavaSearchParticipant(null), // java search only
+		new JavaSearchParticipant(), // java search only
 		scope, 
 		searchRequestor);
-	
-	/* initialize entry result cache */
-	pattern.entryResults = new HashMap();
-	/* iterate all queued names */
+
 	int ticks = 0;
-	awaitings.add(type.getElementName().toCharArray());
-	while (awaitings.start <= awaitings.end){
-		if (progressMonitor != null && progressMonitor.isCanceled()) return;
+	queue.add(type.getElementName().toCharArray());
+	try {
+		while (queue.start <= queue.end) {
+			if (progressMonitor != null && progressMonitor.isCanceled()) return;
 
-		char[] currentTypeName = awaitings.retrieve();
+			// all subclasses of OBJECT are actually all types
+			char[] currentTypeName = queue.retrieve();
+			if (CharOperation.equals(currentTypeName, IIndexConstants.OBJECT))
+				currentTypeName = null;
 
-		/* all subclasses of OBJECT are actually all types */
-		if (CharOperation.equals(currentTypeName, IIndexConstants.OBJECT)){
-			currentTypeName = null;
-		}			
-		/* search all index references to a given supertype */
-		pattern.superSimpleName = currentTypeName;
-		indexManager.performConcurrentJob(
-			job, 
-			waitingPolicy, 
-			null); // don't pass a sub progress monitor as this is too costly for deep hierarchies
-		if (progressMonitor != null && ++ticks <= MAXTICKS) {
-			progressMonitor.worked(1);
+			// search all index references to a given supertype
+			pattern.superSimpleName = currentTypeName;
+			indexManager.performConcurrentJob(job, waitingPolicy, null); // no sub progress monitor since its too costly for deep hierarchies
+			if (progressMonitor != null && ++ticks <= MAXTICKS)
+				progressMonitor.worked(1);
+
+			// in case, we search all subtypes, no need to search further
+			if (currentTypeName == null) break;
 		}
-		/* in case, we search all subtypes, no need to search further */
-		if (currentTypeName == null) break;
+	} finally {
+		job.finished();
 	}
-	/* close all cached index inputs */
-	job.closeAll();
-	/* flush entry result cache */
-	pattern.entryResults = null;
 }
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/RegionBasedHierarchyBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/RegionBasedHierarchyBuilder.java
index 1819f25..d198963 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/RegionBasedHierarchyBuilder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/RegionBasedHierarchyBuilder.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -12,7 +12,6 @@
 
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.HashSet;
 
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.SubProgressMonitor;
@@ -24,7 +23,6 @@
 import org.eclipse.jdt.core.IPackageFragmentRoot;
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.JavaModelException;
-import org.eclipse.jdt.internal.core.CompilationUnit;
 import org.eclipse.jdt.internal.core.JavaModelManager;
 import org.eclipse.jdt.internal.core.JavaProject;
 import org.eclipse.jdt.internal.core.Openable;
@@ -49,13 +47,13 @@
 				this.hierarchy.progressMonitor == null ? 
 					null : 
 					new SubProgressMonitor(this.hierarchy.progressMonitor, 30);
-			ArrayList allTypesInRegion = determineTypesInRegion(typeInRegionMonitor);
-			this.hierarchy.initialize(allTypesInRegion.size());
+			ArrayList allOpenablesInRegion = determineOpenablesInRegion(typeInRegionMonitor);
+			this.hierarchy.initialize(allOpenablesInRegion.size());
 			IProgressMonitor buildMonitor = 
 				this.hierarchy.progressMonitor == null ? 
 					null : 
 					new SubProgressMonitor(this.hierarchy.progressMonitor, 70);
-			createTypeHierarchyBasedOnRegion(allTypesInRegion, buildMonitor);
+			createTypeHierarchyBasedOnRegion(allOpenablesInRegion, buildMonitor);
 			((RegionBasedTypeHierarchy)this.hierarchy).pruneDeadBranches();
 		} else {
 			this.hierarchy.initialize(1);
@@ -68,50 +66,20 @@
 /**
  * Configure this type hierarchy that is based on a region.
  */
-private void createTypeHierarchyBasedOnRegion(ArrayList allTypesInRegion, IProgressMonitor monitor) {
+private void createTypeHierarchyBasedOnRegion(ArrayList allOpenablesInRegion, IProgressMonitor monitor) {
 	
-	int size = allTypesInRegion.size();
+	int size = allOpenablesInRegion.size();
 	if (size != 0) {
 		this.infoToHandle = new HashMap(size);
 	}
-	HashSet existingOpenables = new HashSet(size);
 	Openable[] openables = new Openable[size];
-	int openableIndex = 0;
-	for (int i = 0; i < size; i++) {
-		IType type = (IType)allTypesInRegion.get(i);
-		Openable openable;
-		if (type.isBinary()) {
-			openable = (Openable)type.getClassFile();
-		} else {
-			openable = (Openable)type.getCompilationUnit();
-		}
-		if (existingOpenables.add(openable)) {
-			openables[openableIndex++] = openable;
-		}
-	}
-	if (openableIndex < size) {
-		System.arraycopy(openables, 0, openables = new Openable[openableIndex], 0, openableIndex);
-	}
+	allOpenablesInRegion.toArray(openables);
 
 	try {
 		// resolve
-		if (monitor != null) monitor.beginTask("", openableIndex * 2/* 1 for build binding, 1 for connect hierarchy*/); //$NON-NLS-1$
-		if (openableIndex > 0) {
-			IType focusType = this.getType();
-			CompilationUnit unitToLookInside = null;
-			if (focusType != null) {
-				unitToLookInside = (CompilationUnit)focusType.getCompilationUnit();
-			}
-			if (this.nameLookup != null && unitToLookInside != null) {
-				try {
-					nameLookup.setUnitsToLookInside(new ICompilationUnit[] {unitToLookInside}); // NB: this uses a PerThreadObject, so it is thread safe
-					this.hierarchyResolver.resolve(openables, null, monitor);
-				} finally {
-					nameLookup.setUnitsToLookInside(null);
-				}
-			} else {
-				this.hierarchyResolver.resolve(openables, null, monitor);
-			}
+		if (monitor != null) monitor.beginTask("", size * 2/* 1 for build binding, 1 for connect hierarchy*/); //$NON-NLS-1$
+		if (size > 0) {
+			this.hierarchyResolver.resolve(openables, null, monitor);
 		}
 	} finally {
 		if (monitor != null) monitor.done();
@@ -119,62 +87,58 @@
 }
 	
 	/**
-	 * Returns all of the types defined in the region of this type hierarchy.
+	 * Returns all of the openables defined in the region of this type hierarchy.
 	 */
-	private ArrayList determineTypesInRegion(IProgressMonitor monitor) {
+	private ArrayList determineOpenablesInRegion(IProgressMonitor monitor) {
 
 		try {
-			ArrayList types = new ArrayList();
+			ArrayList openables = new ArrayList();
 			IJavaElement[] roots =
 				((RegionBasedTypeHierarchy) this.hierarchy).region.getElements();
 			int length = roots.length;
 			if (monitor != null) monitor.beginTask("", length); //$NON-NLS-1$
 			for (int i = 0; i <length; i++) {
-				try {
-					IJavaElement root = roots[i];
-					switch (root.getElementType()) {
-						case IJavaElement.JAVA_PROJECT :
-							injectAllTypesForJavaProject((IJavaProject) root, types);
-							break;
-						case IJavaElement.PACKAGE_FRAGMENT_ROOT :
-							injectAllTypesForPackageFragmentRoot((IPackageFragmentRoot) root, types);
-							break;
-						case IJavaElement.PACKAGE_FRAGMENT :
-							injectAllTypesForPackageFragment((IPackageFragment) root, types);
-							break;
-						case IJavaElement.CLASS_FILE :
-							types.add(((IClassFile) root).getType());
-							break;
-						case IJavaElement.COMPILATION_UNIT :
-							IType[] cuTypes = ((ICompilationUnit) root).getAllTypes();
-							for (int j = 0; j < cuTypes.length; j++) {
-								types.add(cuTypes[j]);
-							}
-							break;
-						case IJavaElement.TYPE :
-							types.add(root);
-							break;
-						default :
-							break;
-					}
-				} catch (JavaModelException e) {
-					// just continue
+				IJavaElement root = roots[i];
+				switch (root.getElementType()) {
+					case IJavaElement.JAVA_PROJECT :
+						injectAllOpenablesForJavaProject((IJavaProject) root, openables);
+						break;
+					case IJavaElement.PACKAGE_FRAGMENT_ROOT :
+						injectAllOpenablesForPackageFragmentRoot((IPackageFragmentRoot) root, openables);
+						break;
+					case IJavaElement.PACKAGE_FRAGMENT :
+						injectAllOpenablesForPackageFragment((IPackageFragment) root, openables);
+						break;
+					case IJavaElement.CLASS_FILE :
+					case IJavaElement.COMPILATION_UNIT :
+						openables.add(root);
+						break;
+					case IJavaElement.TYPE :
+						IType type = (IType)root;
+						if (type.isBinary()) {
+							openables.add(type.getClassFile());
+						} else {
+							openables.add(type.getCompilationUnit());
+						}
+						break;
+					default :
+						break;
 				}
 				worked(monitor, 1);
 			}
-			return types;
+			return openables;
 		} finally {
 			if (monitor != null) monitor.done();
 		}
 	}
 	
 	/**
-	 * Adds all of the types defined within this java project to the
+	 * Adds all of the openables defined within this java project to the
 	 * list.
 	 */
-	private void injectAllTypesForJavaProject(
+	private void injectAllOpenablesForJavaProject(
 		IJavaProject project,
-		ArrayList types) {
+		ArrayList openables) {
 		try {
 			IPackageFragmentRoot[] devPathRoots =
 				((JavaProject) project).getPackageFragmentRoots();
@@ -183,7 +147,7 @@
 			}
 			for (int j = 0; j < devPathRoots.length; j++) {
 				IPackageFragmentRoot root = devPathRoots[j];
-				injectAllTypesForPackageFragmentRoot(root, types);
+				injectAllOpenablesForPackageFragmentRoot(root, openables);
 			}
 		} catch (JavaModelException e) {
 			// ignore
@@ -191,12 +155,12 @@
 	}
 	
 	/**
-	 * Adds all of the types defined within this package fragment to the
+	 * Adds all of the openables defined within this package fragment to the
 	 * list.
 	 */
-	private void injectAllTypesForPackageFragment(
+	private void injectAllOpenablesForPackageFragment(
 		IPackageFragment packFrag,
-		ArrayList types) {
+		ArrayList openables) {
 			
 		try {
 			IPackageFragmentRoot root = (IPackageFragmentRoot) packFrag.getParent();
@@ -204,11 +168,15 @@
 			if (kind != 0) {
 				boolean isSourcePackageFragment = (kind == IPackageFragmentRoot.K_SOURCE);
 				if (isSourcePackageFragment) {
-					ICompilationUnit[] typeContainers = packFrag.getCompilationUnits();
-					injectAllTypesForTypeContainers(typeContainers, types);
+					ICompilationUnit[] cus = packFrag.getCompilationUnits();
+					for (int i = 0, length = cus.length; i < length; i++) {
+						openables.add(cus[i]);
+					}
 				} else {
-					IClassFile[] typeContainers = packFrag.getClassFiles();
-					injectAllTypesForTypeContainers(typeContainers, types);
+					IClassFile[] classFiles = packFrag.getClassFiles();
+					for (int i = 0, length = classFiles.length; i < length; i++) {
+						openables.add(classFiles[i]);
+					}
 				}
 			}
 		} catch (JavaModelException e) {
@@ -217,57 +185,21 @@
 	}
 	
 	/**
-	 * Adds all of the types defined within this package fragment root to the
+	 * Adds all of the openables defined within this package fragment root to the
 	 * list.
 	 */
-	private void injectAllTypesForPackageFragmentRoot(
+	private void injectAllOpenablesForPackageFragmentRoot(
 		IPackageFragmentRoot root,
-		ArrayList types) {
+		ArrayList openables) {
 		try {
 			IJavaElement[] packFrags = root.getChildren();
 			for (int k = 0; k < packFrags.length; k++) {
 				IPackageFragment packFrag = (IPackageFragment) packFrags[k];
-				injectAllTypesForPackageFragment(packFrag, types);
+				injectAllOpenablesForPackageFragment(packFrag, openables);
 			}
 		} catch (JavaModelException e) {
 			return;
 		}
 	}
 	
-	/**
-	 * Adds all of the types defined within the type containers (IClassFile).
-	 */
-	private void injectAllTypesForTypeContainers(
-		IClassFile[] containers,
-		ArrayList types) {
-			
-		try {
-			for (int i = 0; i < containers.length; i++) {
-				IClassFile cf = containers[i];
-				types.add(cf.getType());
-			}
-		} catch (JavaModelException e) {
-			// ignore
-		}
-	}
-	
-	/**
-	 * Adds all of the types defined within the type containers (ICompilationUnit).
-	 */
-	private void injectAllTypesForTypeContainers(
-		ICompilationUnit[] containers,
-		ArrayList types) {
-			
-		try {
-			for (int i = 0; i < containers.length; i++) {
-				ICompilationUnit cu = containers[i];
-				IType[] cuTypes = cu.getAllTypes();
-				for (int j = 0; j < cuTypes.length; j++) {
-					types.add(cuTypes[j]);
-				}
-			}
-		} catch (JavaModelException e) {
-			// ignore
-		}
-	}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/RegionBasedTypeHierarchy.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/RegionBasedTypeHierarchy.java
index 42039c9..512c05d 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/RegionBasedTypeHierarchy.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/RegionBasedTypeHierarchy.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -91,29 +91,23 @@
 	return this.project;
 }
 public void pruneDeadBranches() {
-	this.pruneDeadBranches(this.getRootClasses(), false);
+	pruneDeadBranches(getRootClasses());
 }
-private void pruneDeadBranches(IType[] types, boolean superInRegion) {
+/*
+ * Returns whether all subtypes of the given type have been pruned.
+ */
+private boolean pruneDeadBranches(IType type) {
+	TypeVector subtypes = (TypeVector)this.typeToSubtypes.get(type);
+	if (subtypes == null) return true;
+	pruneDeadBranches(subtypes.copy().elements());
+	subtypes = (TypeVector)this.typeToSubtypes.get(type);
+	return (subtypes == null || subtypes.size == 0);
+}
+private void pruneDeadBranches(IType[] types) {
 	for (int i = 0, length = types.length; i < length; i++) {
 		IType type = types[i];
-		if (this.region.contains(type)) {
-			TypeVector subtypes = (TypeVector)this.typeToSubtypes.get(type);
-			if (subtypes != null) {
-				this.pruneDeadBranches(subtypes.copy().elements(), true);
-			}
-		} else {
-			if (superInRegion) {
-				this.removeType(type);
-			} else {
-				TypeVector subtypes = (TypeVector)this.typeToSubtypes.get(type);
-				if (subtypes != null) {
-					this.pruneDeadBranches(subtypes.copy().elements(), false);
-				}
-				subtypes = (TypeVector)this.typeToSubtypes.get(type);
-				if (subtypes == null || subtypes.size == 0) {
-					this.removeType(type);
-				} 
-			}
+		if (pruneDeadBranches(type) && !this.region.contains(type)) {
+			removeType(type);
 		}
 	}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/TypeHierarchy.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/TypeHierarchy.java
index cefc9b9..2489c2e 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/TypeHierarchy.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/TypeHierarchy.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -420,7 +420,7 @@
 	return getAllSubtypesForType(type);
 }
 /**
- * @see getAllSubtypes(IType)
+ * @see #getAllSubtypes(IType)
  */
 private IType[] getAllSubtypesForType(IType type) {
 	ArrayList subTypes = new ArrayList();
@@ -540,7 +540,7 @@
 }
 /**
  * Assumes that the type is an interface
- * @see getExtendingInterfaces
+ * @see #getExtendingInterfaces
  */
 private IType[] getExtendingInterfaces0(IType extendedInterface) {
 	Iterator iter = this.typeToSuperInterfaces.keySet().iterator();
@@ -575,7 +575,7 @@
 }
 /**
  * Assumes that the type is an interface
- * @see getImplementingClasses
+ * @see #getImplementingClasses
  */
 private IType[] getImplementingClasses0(IType interfce) {
 	
@@ -733,7 +733,7 @@
 	if (this.focusType != null && this.focusType.getElementName().equals(simpleName)) {
 		return true;
 	}
-	IType[] types = this.getAllSubtypes(this.focusType);
+	IType[] types = this.focusType == null ? getAllTypes() : getAllSubtypes(this.focusType);
 	for (int i = 0, length = types.length; i < length; i++) {
 		if (types[i].getElementName().equals(simpleName)) {
 			return true;
@@ -926,9 +926,9 @@
 					IPath rootPath = root.getPath();
 					IJavaElement[] elements = this.projectRegion.getElements();
 					for (int i = 0; i < elements.length; i++) {
-						IJavaProject javaProject = (IJavaProject)elements[i];
+						JavaProject javaProject = (JavaProject)elements[i];
 						try {
-							IClasspathEntry[] classpath = javaProject.getResolvedClasspath(true);
+							IClasspathEntry[] classpath = javaProject.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
 							for (int j = 0; j < classpath.length; j++) {
 								IClasspathEntry entry = classpath[j];
 								if (entry.getPath().equals(rootPath)) {
@@ -1213,7 +1213,7 @@
 		this.progressMonitor = monitor;
 		if (monitor != null) {
 			if (this.focusType != null) {
-				monitor.beginTask(Util.bind("hierarchy.creatingOnType", focusType.getFullyQualifiedName()), 100); //$NON-NLS-1$
+				monitor.beginTask(Util.bind("hierarchy.creatingOnType", this.focusType.getFullyQualifiedName()), 100); //$NON-NLS-1$
 			} else {
 				monitor.beginTask(Util.bind("hierarchy.creating"), 100); //$NON-NLS-1$
 			}
@@ -1281,12 +1281,12 @@
 		Hashtable hashtable2 = new Hashtable();
 		int count = 0;
 		
-		if(focusType != null) {
+		if(this.focusType != null) {
 			Integer index = new Integer(count++);
-			hashtable.put(focusType, index);
-			hashtable2.put(index, focusType);
+			hashtable.put(this.focusType, index);
+			hashtable2.put(index, this.focusType);
 		}
-		Object[] types = classToSuperclass.keySet().toArray();
+		Object[] types = this.classToSuperclass.keySet().toArray();
 		for (int i = 0; i < types.length; i++) {
 			Object t = types[i];
 			if(hashtable.get(t) == null) {
@@ -1294,14 +1294,14 @@
 				hashtable.put(t, index);
 				hashtable2.put(index, t);
 			}
-			Object superClass = classToSuperclass.get(t);
+			Object superClass = this.classToSuperclass.get(t);
 			if(superClass != null && hashtable.get(superClass) == null) {
 				Integer index = new Integer(count++);
 				hashtable.put(superClass, index);
 				hashtable2.put(index, superClass);
 			}
 		}
-		types = typeToSuperInterfaces.keySet().toArray();
+		types = this.typeToSuperInterfaces.keySet().toArray();
 		for (int i = 0; i < types.length; i++) {
 			Object t = types[i];
 			if(hashtable.get(t) == null) {
@@ -1309,7 +1309,7 @@
 				hashtable.put(t, index);
 				hashtable2.put(index, t);
 			}
-			Object[] sp = (Object[])typeToSuperInterfaces.get(t);
+			Object[] sp = (Object[])this.typeToSuperInterfaces.get(t);
 			if(sp != null) {
 				for (int j = 0; j < sp.length; j++) {
 					Object superInterface = sp[j];
@@ -1326,23 +1326,23 @@
 		
 		// save general info
 		byte generalInfo = 0;
-		if(computeSubtypes) {
+		if(this.computeSubtypes) {
 			generalInfo |= COMPUTE_SUBTYPES;
 		}
 		output.write(generalInfo);
 		
 		// save project
-		if(project != null) {
-			output.write(project.getHandleIdentifier().getBytes());
+		if(this.project != null) {
+			output.write(this.project.getHandleIdentifier().getBytes());
 		}
 		output.write(SEPARATOR1);
 		
 		// save missing types
-		for (int i = 0; i < missingTypes.size(); i++) {
+		for (int i = 0; i < this.missingTypes.size(); i++) {
 			if(i != 0) {
 				output.write(SEPARATOR2);
 			}
-			output.write(((String)missingTypes.get(i)).getBytes());
+			output.write(((String)this.missingTypes.get(i)).getBytes());
 			
 		}
 		output.write(SEPARATOR1);
@@ -1354,16 +1354,16 @@
 			// n bytes
 			output.write(t.getHandleIdentifier().getBytes());
 			output.write(SEPARATOR4);
-			output.write(flagsToBytes((Integer)typeFlags.get(t)));
+			output.write(flagsToBytes((Integer)this.typeFlags.get(t)));
 			output.write(SEPARATOR4);
 			byte info = CLASS;
-			if(focusType != null && focusType.equals(t)) {
+			if(this.focusType != null && this.focusType.equals(t)) {
 				info |= COMPUTED_FOR;
 			}
-			if(interfaces.contains(t)) {
+			if(this.interfaces.contains(t)) {
 				info |= INTERFACE;
 			}
-			if(rootClasses.contains(t)) {
+			if(this.rootClasses.contains(t)) {
 				info |= ROOT;
 			}
 			output.write(info);
@@ -1371,10 +1371,10 @@
 		output.write(SEPARATOR1);
 		
 		// save superclasses
-		types = classToSuperclass.keySet().toArray();
+		types = this.classToSuperclass.keySet().toArray();
 		for (int i = 0; i < types.length; i++) {
 			IJavaElement key = (IJavaElement)types[i];
-			IJavaElement value = (IJavaElement)classToSuperclass.get(key);
+			IJavaElement value = (IJavaElement)this.classToSuperclass.get(key);
 			
 			output.write(((Integer)hashtable.get(key)).toString().getBytes());
 			output.write('>');
@@ -1384,10 +1384,10 @@
 		output.write(SEPARATOR1);
 		
 		// save superinterfaces
-		types = typeToSuperInterfaces.keySet().toArray();
+		types = this.typeToSuperInterfaces.keySet().toArray();
 		for (int i = 0; i < types.length; i++) {
 			IJavaElement key = (IJavaElement)types[i];
-			IJavaElement[] values = (IJavaElement[])typeToSuperInterfaces.get(key);
+			IJavaElement[] values = (IJavaElement[])this.typeToSuperInterfaces.get(key);
 			
 			if(values.length > 0) {
 				output.write(((Integer)hashtable.get(key)).toString().getBytes());
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/AbstractDOMBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/AbstractDOMBuilder.java
index 99d2ed0..e7530f0 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/AbstractDOMBuilder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/AbstractDOMBuilder.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -12,13 +12,15 @@
 
 import java.util.Stack;
 
-import org.eclipse.jdt.core.jdom.IDOMCompilationUnit;
-import org.eclipse.jdt.core.jdom.IDOMNode;
+import org.eclipse.jdt.core.jdom.*;
 import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
 import org.eclipse.jdt.internal.core.util.ReferenceInfoAdapter;
 
 /**
  * An abstract DOM builder that contains shared functionality of DOMBuilder and SimpleDOMBuilder.
+ * @deprecated The JDOM was made obsolete by the addition in 2.0 of the more
+ * powerful, fine-grained DOM/AST API found in the 
+ * org.eclipse.jdt.core.dom package.
  */
 public class AbstractDOMBuilder extends ReferenceInfoAdapter implements ILineStartFinder {
 	/**
@@ -81,7 +83,7 @@
  *
  * <p>A line separator might corresponds to several characters in the source.
  *
- * @see IDocumentElementRequestor#acceptLineSeparatorPositions(int[])
+ * @see org.eclipse.jdt.internal.compiler.IDocumentElementRequestor#acceptLineSeparatorPositions(int[])
  */
 public void acceptLineSeparatorPositions(int[] positions) {
 	if (positions != null) {
@@ -145,11 +147,11 @@
 	return (IDOMCompilationUnit)fNode;
 }
 /**
- * @see IDocumentElementRequestor#enterClass(int, int[], int, int, int, char[], int, int, char[], int, int, char[][], int[], int[], int)
+ * @see org.eclipse.jdt.internal.compiler.IDocumentElementRequestor#enterClass(int, int[], int, int, int, char[], int, int, char[], int, int, char[][], int[], int[], int)
  */
 public void enterCompilationUnit() {
  	if (fBuildingCU) {
-	 	IDOMCompilationUnit cu= new DOMCompilationUnit(fDocument, new int[] {0, fDocument.length - 1});
+ 		IDOMCompilationUnit cu= new DOMCompilationUnit(fDocument, new int[] {0, fDocument.length - 1});
  		fStack.push(cu);
  	}
 }
@@ -157,7 +159,7 @@
  * Finishes the configuration of the compilation unit DOM object which
  * was created by a previous enterCompilationUnit call.
  *
- * @see IDocumentElementRequestor#exitCompilationUnit(int)
+ * @see org.eclipse.jdt.internal.compiler.IDocumentElementRequestor#exitCompilationUnit(int)
  */
 public void exitCompilationUnit(int declarationEnd) {
 	DOMCompilationUnit cu = (DOMCompilationUnit) fStack.pop();
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/CompilationUnit.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/CompilationUnit.java
index 225874c..e5eaf1d 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/CompilationUnit.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/CompilationUnit.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMBuilder.java
index 319fe36..fdc627e 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMBuilder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMBuilder.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -28,8 +28,10 @@
  * DOMFactory to hide the implmentation of node creation and the
  * public Requestor API methods.
  * 
+ * @deprecated The JDOM was made obsolete by the addition in 2.0 of the more
+ * powerful, fine-grained DOM/AST API found in the 
+ * org.eclipse.jdt.core.dom package.
  */
-
 public class DOMBuilder extends AbstractDOMBuilder implements IDocumentElementRequestor {
 	
 	/**
@@ -318,7 +320,7 @@
 	int[] commentRange = {-1, -1};
 	if (javaDocPositions != null) {
 		int length = javaDocPositions.length;
-		commentRange[0] = javaDocPositions[0];
+		commentRange[0] = javaDocPositions[length - 2]; // get last javadoc comment (see bug 68772)
 		commentRange[1] = javaDocPositions[length - 1];
 	}
 	int[] modifiersRange = {-1, -1};
@@ -454,7 +456,7 @@
 	int[] commentRange = {-1, -1};
 		if (javaDocPositions != null) {
 			int length = javaDocPositions.length;
-			commentRange[0] = javaDocPositions[0];
+			commentRange[0] = javaDocPositions[length - 2]; // get last javadoc comment (see bug 68772)
 			commentRange[1] = javaDocPositions[length - 1];
 		}
 	int[] modifiersRange = {-1, -1};
@@ -553,7 +555,7 @@
 		int[] commentRange = {-1, -1};
 		if (javaDocPositions != null) {
 			int length = javaDocPositions.length;
-			commentRange[0] = javaDocPositions[0];
+			commentRange[0] = javaDocPositions[length - 2];  // get last javadoc comment (see bug 68772)
 			commentRange[1] = javaDocPositions[length - 1];
 		}
 		int[] modifiersRange = {-1, -1};
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMCompilationUnit.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMCompilationUnit.java
index f5c2316..aab682b 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMCompilationUnit.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMCompilationUnit.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -14,9 +14,7 @@
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.IPackageFragment;
 import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.core.jdom.IDOMCompilationUnit;
-import org.eclipse.jdt.core.jdom.IDOMNode;
-import org.eclipse.jdt.core.jdom.IDOMType;
+import org.eclipse.jdt.core.jdom.*;
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
 import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
 import org.eclipse.jdt.internal.core.util.Util;
@@ -25,6 +23,9 @@
  *
  * @see IDOMCompilationUnit
  * @see DOMNode
+ * @deprecated The JDOM was made obsolete by the addition in 2.0 of the more
+ * powerful, fine-grained DOM/AST API found in the 
+ * org.eclipse.jdt.core.dom package.
  */
 class DOMCompilationUnit extends DOMNode implements IDOMCompilationUnit, SuffixConstants {
 
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMField.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMField.java
index b77e7a7..6f430e7 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMField.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMField.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -15,9 +15,7 @@
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.core.jdom.DOMException;
-import org.eclipse.jdt.core.jdom.IDOMField;
-import org.eclipse.jdt.core.jdom.IDOMNode;
+import org.eclipse.jdt.core.jdom.*;
 import org.eclipse.jdt.internal.compiler.util.Util;
 import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
 /**
@@ -25,6 +23,9 @@
  *
  * @see IDOMField
  * @see DOMNode
+ * @deprecated The JDOM was made obsolete by the addition in 2.0 of the more
+ * powerful, fine-grained DOM/AST API found in the 
+ * org.eclipse.jdt.core.dom package.
  */
 class DOMField extends DOMMember implements IDOMField {
 	
@@ -545,7 +546,7 @@
 	setMask(MASK_FIELD_HAS_INITIALIZER, hasInitializer);
 }
 /**
- * @see IDOMField#setInitializer(char[])
+ * @see IDOMField#setInitializer(String)
  */
 public void setInitializer(String initializer) {
 	becomeDetailed();
@@ -569,7 +570,7 @@
 	setMask(MASK_FIELD_IS_VARIABLE_DECLARATOR, isVariableDeclarator);
 }
 /**
- * @see IDOMField#setName(char[])
+ * @see IDOMField#setName(String)
  */
 public void setName(String name) throws IllegalArgumentException {
 	if (name == null) {
@@ -580,7 +581,7 @@
 	}
 }
 /**
- * @see IDOMField#setType(char[])
+ * @see IDOMField#setType(String)
  */
 public void setType(String typeName) throws IllegalArgumentException {
 	if (typeName == null) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMImport.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMImport.java
index 6278d94..a3e76ef 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMImport.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMImport.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -10,10 +10,10 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.jdom;
 
+import org.eclipse.jdt.core.Flags;
 import org.eclipse.jdt.core.ICompilationUnit;
 import org.eclipse.jdt.core.IJavaElement;
-import org.eclipse.jdt.core.jdom.IDOMImport;
-import org.eclipse.jdt.core.jdom.IDOMNode;
+import org.eclipse.jdt.core.jdom.*;
 import org.eclipse.jdt.internal.compiler.util.Util;
 import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
 
@@ -22,12 +22,23 @@
  *
  * @see IDOMImport
  * @see DOMNode
+ * @deprecated The JDOM was made obsolete by the addition in 2.0 of the more
+ * powerful, fine-grained DOM/AST API found in the 
+ * org.eclipse.jdt.core.dom package.
  */
+// TODO (jerome) - add implementation support for 1.5 features
 class DOMImport extends DOMNode implements IDOMImport {
 	/**
 	 * Indicates if this import is an on demand type import
 	 */
 	protected boolean fOnDemand;
+	
+	/**
+	 * Modifiers for this import.
+	 * @since 3.0
+	 */
+	protected int fFlags = Flags.AccDefault;
+	
 /**
  * Creates a new empty IMPORT node.
  */
@@ -139,7 +150,7 @@
 	return new DOMImport();
 }
 /**
- * @see IDOMNode#setName(char[])
+ * @see IDOMNode#setName(String)
  */
 public void setName(String name) {
 	if (name == null) {
@@ -155,4 +166,20 @@
 public String toString() {
 	return "IMPORT: " + getName(); //$NON-NLS-1$
 }
+
+/**
+ * @see IDOMImport#getFlags()
+ * @since 3.0
+ */
+public int getFlags() {
+	return this.fFlags;
+}
+
+/**
+ * @see IDOMImport#setFlags(int)
+ * @since 3.0
+ */
+public void setFlags(int flags) {
+	this.fFlags = flags;
+}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMInitializer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMInitializer.java
index 6f79e53..43e02cc 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMInitializer.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMInitializer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -13,8 +13,7 @@
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.core.jdom.IDOMInitializer;
-import org.eclipse.jdt.core.jdom.IDOMNode;
+import org.eclipse.jdt.core.jdom.*;
 import org.eclipse.jdt.internal.compiler.util.Util;
 import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
 /**
@@ -22,6 +21,9 @@
  *
  * @see IDOMInitializer
  * @see DOMNode
+ * @deprecated The JDOM was made obsolete by the addition in 2.0 of the more
+ * powerful, fine-grained DOM/AST API found in the 
+ * org.eclipse.jdt.core.dom package.
  */
 class DOMInitializer extends DOMMember implements IDOMInitializer {
 
@@ -116,7 +118,7 @@
 	// nothing to do
 }
 /**
- * @see DOMNode#appendSimpleContents(CharArrayBuffer)
+ * @see DOMMember#appendSimpleContents(CharArrayBuffer)
  */
 protected void appendSimpleContents(CharArrayBuffer buffer) {
 	// append eveything before my name
@@ -178,7 +180,7 @@
 	return IDOMNode.INITIALIZER;
 }
 /**
- * @see IDOMNode#isSigantureEqual(IDOMNode).
+ * @see IDOMNode#isSignatureEqual(IDOMNode)
  *
  * <p>This method always answers false since an initializer
  * does not have a signature.
@@ -200,7 +202,7 @@
 	offsetRange(fBodyRange, offset);
 }
 /**
- * @see IDOMInitializer#setBody(char[])
+ * @see IDOMInitializer#setBody(String)
  */
 public void setBody(String body) {
 	becomeDetailed();
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMMember.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMMember.java
index 9a1611f..4ff50a3 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMMember.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMMember.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -12,7 +12,7 @@
 
 import org.eclipse.jdt.core.Flags;
 import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.core.jdom.IDOMMember;
+import org.eclipse.jdt.core.jdom.*;
 import org.eclipse.jdt.internal.compiler.env.IConstants;
 import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
 /**
@@ -20,8 +20,10 @@
  *
  * @see IDOMMember
  * @see DOMNode
+ * @deprecated The JDOM was made obsolete by the addition in 2.0 of the more
+ * powerful, fine-grained DOM/AST API found in the 
+ * org.eclipse.jdt.core.dom package.
  */
-
 abstract class DOMMember extends DOMNode implements IDOMMember {
 
 	/**
@@ -233,9 +235,6 @@
 /**
  * Returns the location of the first character in the member's declaration
  * section.
- *
- * @see DOMMember#getMemberDeclarationContents()
- * @see DOMMember#getFragmentedContents()
  */
 protected abstract int getMemberDeclarationStartPosition();
 /**
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMMethod.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMMethod.java
index 7ac184f..e78a655 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMMethod.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMMethod.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -14,8 +14,7 @@
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.Signature;
 import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.core.jdom.IDOMMethod;
-import org.eclipse.jdt.core.jdom.IDOMNode;
+import org.eclipse.jdt.core.jdom.*;
 import org.eclipse.jdt.internal.compiler.util.Util;
 import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
 /**
@@ -23,8 +22,11 @@
  *
  * @see IDOMMethod
  * @see DOMNode
+ * @deprecated The JDOM was made obsolete by the addition in 2.0 of the more
+ * powerful, fine-grained DOM/AST API found in the 
+ * org.eclipse.jdt.core.dom package.
  */
- 
+// TODO (jerome) - add implementation support for 1.5 features
 class DOMMethod extends DOMMember implements IDOMMethod {
 
 	/**
@@ -110,6 +112,18 @@
 	 */
 	protected String[] fExceptions;
 
+	/**
+	 * The formal type parameters.
+	 * @since 3.0
+	 */
+	protected String[] fTypeParameters = new String[0];
+
+	/**
+	 * Default value for this attotation type member (only),
+	 * or <code>null</code> if none.
+	 * @since 3.0
+	 */
+	protected String fDefaultValue = null;
 	
 /**
  * Constructs an empty method node.
@@ -336,7 +350,7 @@
 	
 }
 /**
- * @see DOMNode#appendSimpleContents(CharArrayBuffer)
+ * @see DOMMember#appendSimpleContents(CharArrayBuffer)
  */
 protected void appendSimpleContents(CharArrayBuffer buffer) {
 	// append eveything before my name
@@ -505,7 +519,7 @@
 	return getMask(MASK_RETURN_TYPE_ALTERED);
 }
 /**
- * @see IDOMNode#isSigantureEqual(IDOMNode).
+ * @see IDOMNode#isSignatureEqual(IDOMNode)
  *
  * <p>Two methods have equal signatures if there names are the same
  * and their parameter types are the same.
@@ -595,7 +609,7 @@
 	fragment();
 }
 /**
- * @see IDOMMethod#setExceptions(char[][])
+ * @see IDOMMethod#setExceptions(String[])
  */
 public void setExceptions(String[] names) {
 	becomeDetailed();
@@ -625,7 +639,7 @@
 	}
 }
 /**
- * @see IDOMMethod#setParameters(char[][], char[][])
+ * @see IDOMMethod#setParameters(String[], String[])
  */
 public void setParameters(String[] types, String[] names) throws IllegalArgumentException {
 	becomeDetailed();
@@ -662,7 +676,7 @@
 	fragment();
 }
 /**
- * @see IDOMMethod#setReturnType(char[])
+ * @see IDOMMethod#setReturnType(String)
  */
 public void setReturnType(String name) throws IllegalArgumentException {
 	if (name == null) {
@@ -714,4 +728,36 @@
 		return "METHOD: " + getName(); //$NON-NLS-1$
 	}
 }
+
+/**
+ * @see IDOMMethod#setDefault(java.lang.String)
+ * @since 3.0
+ */
+public void setDefault(String defaultValue) {
+	this.fDefaultValue =  defaultValue;
+}
+
+/**
+ * @see IDOMMethod#getDefault()
+ * @since 3.0
+ */
+public String getDefault() {
+	return this.fDefaultValue;
+}
+
+/**
+ * @see IDOMMethod#getTypeParameters()
+ * @since 3.0
+ */
+public String[] getTypeParameters() {
+	return this.fTypeParameters;
+}
+
+/**
+ * @see IDOMMethod#setTypeParameters(java.lang.String[])
+ * @since 3.0
+ */
+public void setTypeParameters(String[] typeParameters) {
+	this.fTypeParameters = typeParameters;
+}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMNode.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMNode.java
index 05e58a9..3af11f0 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMNode.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMNode.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -12,12 +12,7 @@
 
 import java.util.Enumeration;
 
-import org.eclipse.jdt.core.jdom.DOMException;
-import org.eclipse.jdt.core.jdom.DOMFactory;
-import org.eclipse.jdt.core.jdom.IDOMCompilationUnit;
-import org.eclipse.jdt.core.jdom.IDOMFactory;
-import org.eclipse.jdt.core.jdom.IDOMMethod;
-import org.eclipse.jdt.core.jdom.IDOMNode;
+import org.eclipse.jdt.core.jdom.*;
 import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
 import org.eclipse.jdt.internal.core.util.Util;
 
@@ -53,6 +48,9 @@
  * node. 
  *
  * @see IDOMNode
+ * @deprecated The JDOM was made obsolete by the addition in 2.0 of the more
+ * powerful, fine-grained DOM/AST API found in the 
+ * org.eclipse.jdt.core.dom package.
  */
 public abstract class DOMNode implements IDOMNode {
 
@@ -753,7 +751,7 @@
 	return getMask(MASK_NAME_ALTERED);
 }
 /**
- * @see IDOMNode#isSignatureEqual(IDOMNode).
+ * @see IDOMNode#isSignatureEqual(IDOMNode)
  *
  * <p>By default, the signatures of two nodes are equal if their
  * type and names are equal. Node types that have other requirements
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMPackage.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMPackage.java
index 870cbc2..cffb592 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMPackage.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMPackage.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -12,8 +12,7 @@
 
 import org.eclipse.jdt.core.ICompilationUnit;
 import org.eclipse.jdt.core.IJavaElement;
-import org.eclipse.jdt.core.jdom.IDOMNode;
-import org.eclipse.jdt.core.jdom.IDOMPackage;
+import org.eclipse.jdt.core.jdom.*;
 import org.eclipse.jdt.internal.compiler.util.Util;
 import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
 
@@ -22,6 +21,9 @@
  *
  * @see IDOMPackage
  * @see DOMNode
+ * @deprecated The JDOM was made obsolete by the addition in 2.0 of the more
+ * powerful, fine-grained DOM/AST API found in the 
+ * org.eclipse.jdt.core.dom package.
  */
 class DOMPackage extends DOMNode implements IDOMPackage {
 
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMType.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMType.java
index 565278f..bc43ee3 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMType.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMType.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -17,9 +17,7 @@
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.compiler.InvalidInputException;
-import org.eclipse.jdt.core.jdom.IDOMMethod;
-import org.eclipse.jdt.core.jdom.IDOMNode;
-import org.eclipse.jdt.core.jdom.IDOMType;
+import org.eclipse.jdt.core.jdom.*;
 import org.eclipse.jdt.internal.compiler.parser.Scanner;
 import org.eclipse.jdt.internal.compiler.parser.TerminalTokens;
 import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
@@ -29,8 +27,11 @@
  *
  * @see IDOMType
  * @see DOMNode
- */
- 
+ * @deprecated The JDOM was made obsolete by the addition in 2.0 of the more
+ * powerful, fine-grained DOM/AST API found in the 
+ * org.eclipse.jdt.core.dom package.
+ */ 
+// TODO (jerome) - add implementation support for 1.5 features
 /* package */ class DOMType extends DOMMember implements IDOMType {
 
 	private static final String[] EMPTY_SUPERINTERFACES = new String[] {};
@@ -117,6 +118,24 @@
 	protected String[] fSuperInterfaces= new String[0];
 	
 	/**
+	 * The formal type parameters.
+	 * @since 3.0
+	 */
+	protected String[] fTypeParameters = new String[0];
+
+	/**
+	 * Indicates this type is an enum class.
+	 * @since 3.0
+	 */
+	protected boolean fIsEnum= false;
+	
+	/**
+	 * Indicates this type is an annotatation type (interface).
+	 * @since 3.0
+	 */
+	protected boolean fIsAnnotation= false;
+	
+	/**
 	 * This position is the position of the end of the last line separator before the closing brace starting
 	 * position of the receiver.
 	 */
@@ -331,7 +350,7 @@
 	
 }
 /**
- * @see DOMNode#appendSimpleContents(CharArrayBuffer)
+ * @see DOMMember#appendSimpleContents(CharArrayBuffer)
  */
 protected void appendSimpleContents(CharArrayBuffer buffer) {
 	// append eveything before my name
@@ -623,7 +642,7 @@
  * as fragmented, since the names of the constructors must reflect the name
  * of this type.
  *
- * @see IDOMNode#setName(char[])
+ * @see IDOMNode#setName(String)
  */
 public void setName(String name) throws IllegalArgumentException {
 	if (name == null) {
@@ -651,7 +670,7 @@
 	fOpenBodyRange[0] = start;
 }
 /**
- * @see IDOMType#setSuperclass(char[])
+ * @see IDOMType#setSuperclass(String)
  */
 public void setSuperclass(String superclassName) {
 	becomeDetailed();
@@ -715,4 +734,63 @@
 public String toString() {
 	return "TYPE: " + getName(); //$NON-NLS-1$
 }
+
+/**
+ * @see IDOMType#getTypeParameters()
+ * @since 3.0
+ */
+public String[] getTypeParameters() {
+	return this.fTypeParameters;
+}
+
+/**
+ * @see IDOMType#isEnum()
+ * @since 3.0
+ */
+public boolean isEnum() {
+	return this.fIsEnum;
+}
+
+/**
+ * @see IDOMType#isAnnotation()
+ * @since 3.0
+ */
+public boolean isAnnotation() {
+	return this.fIsAnnotation;
+}
+
+/**
+ * @see IDOMType#setEnum(boolean)
+ * @since 3.0
+ */
+public void setEnum(boolean b) {
+	this.fIsEnum = b;
+	if (this.fIsEnum) {
+		// enums are always classes with no superclass
+		setClass(true);
+		setSuperclass(null);
+	}
+}
+
+/**
+ * @see IDOMType#setAnnotation(boolean)
+ * @since 3.0
+ */
+public void setAnnotation(boolean b) {
+	this.fIsAnnotation= b;
+	if (this.fIsAnnotation) {
+		// annotation types are always interface with no superclass or superinterfaces
+		setClass(false);
+		setSuperclass(null);
+		setSuperInterfaces(new String[0]);
+	}
+}
+
+/**
+ * @see IDOMType#setTypeParameters(java.lang.String[])
+ * @since 3.0
+ */
+public void setTypeParameters(String[] typeParameters) {
+	this.fTypeParameters = typeParameters;
+}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/ILineStartFinder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/ILineStartFinder.java
index 4e9da50..8569c62 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/ILineStartFinder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/ILineStartFinder.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/SiblingEnumeration.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/SiblingEnumeration.java
index 62ed3bc..f258b16 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/SiblingEnumeration.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/SiblingEnumeration.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -12,15 +12,17 @@
 
 import java.util.Enumeration;
 
-import org.eclipse.jdt.core.jdom.IDOMNode;
+import org.eclipse.jdt.core.jdom.*;
 
 /**
  * SiblingEnumeration provides an enumeration on a linked list
  * of sibling DOM nodes.
  *
  * @see java.util.Enumeration
+ * @deprecated The JDOM was made obsolete by the addition in 2.0 of the more
+ * powerful, fine-grained DOM/AST API found in the 
+ * org.eclipse.jdt.core.dom package.
  */
-
 /* package */ class SiblingEnumeration implements Enumeration {
 
 	/**
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/SimpleDOMBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/SimpleDOMBuilder.java
index 957f0a1..dd8a0df 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/SimpleDOMBuilder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/SimpleDOMBuilder.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -15,7 +15,7 @@
 import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.compiler.IProblem;
-import org.eclipse.jdt.core.jdom.IDOMCompilationUnit;
+import org.eclipse.jdt.core.jdom.*;
 import org.eclipse.jdt.internal.compiler.ISourceElementRequestor;
 import org.eclipse.jdt.internal.compiler.SourceElementParser;
 import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
@@ -23,6 +23,9 @@
 import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
 /**
  * A DOM builder that uses the SourceElementParser
+ * @deprecated The JDOM was made obsolete by the addition in 2.0 of the more
+ * powerful, fine-grained DOM/AST API found in the 
+ * org.eclipse.jdt.core.dom package.
  */
 public class SimpleDOMBuilder extends AbstractDOMBuilder implements ISourceElementRequestor {
 
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ASTNodeFinder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ASTNodeFinder.java
index a109a51..e1476c3 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ASTNodeFinder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ASTNodeFinder.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -90,7 +90,8 @@
 				AbstractMethodDeclaration method = methods[i];
 				if (CharOperation.equals(selector, method.selector)) {
 					Argument[] args = method.arguments;
-					if (args != null && args.length == parameterCount) {
+					int argsLength = args == null ? 0 : args.length;
+					if (argsLength == parameterCount) {
 						for (int j = 0; j < parameterCount; j++) {
 							TypeReference type = args[j].type;
 							String signature = Util.typeSignature(type);
@@ -101,7 +102,6 @@
 						return method;
 					}
 				}
-					
 			}
 		}
 		return null;
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/AnonymousFileSource.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/AnonymousFileSource.java
index 3775071..a34b2df 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/AnonymousFileSource.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/AnonymousFileSource.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/CharArrayBuffer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/CharArrayBuffer.java
index ed8bb41..55bf6c7 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/CharArrayBuffer.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/CharArrayBuffer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -136,7 +136,7 @@
 /**
  * Appends the given char.  Given for convenience.
  *
- * @param src - a char which is appended to the end of the buffer.
+ * @param c - a char which is appended to the end of the buffer.
  */
 public CharArrayBuffer append(char c) {
 	append(new char[] {c}, 0, 1);
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ClassFileAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ClassFileAttribute.java
index f003e94..586a3aa 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ClassFileAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ClassFileAttribute.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ClassFileReader.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ClassFileReader.java
index 5b5ca48..27e104b 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ClassFileReader.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ClassFileReader.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ClassFileStruct.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ClassFileStruct.java
index eccbf1d..0893dfb 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ClassFileStruct.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ClassFileStruct.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -64,24 +64,21 @@
 				+ (reference[position] & 0xFF));
 	}
 	protected char[] utf8At(byte[] reference, int relativeOffset, int structOffset, int bytesAvailable) {
-		int x, y, z;
 		int length = bytesAvailable;
 		char outputBuf[] = new char[bytesAvailable];
 		int outputPos = 0;
 		int readOffset = structOffset + relativeOffset;
 
 		while (length != 0) {
-			x = reference[readOffset++] & 0xFF;
+			int x = reference[readOffset++] & 0xFF;
 			length--;
 			if ((0x80 & x) != 0) {
-				y = reference[readOffset++] & 0xFF;
-				length--;
 				if ((x & 0x20) != 0) {
-					z = reference[readOffset++] & 0xFF;
-					length--;
-					x = ((x & 0x1F) << 12) + ((y & 0x3F) << 6) + (z & 0x3F);
+					length-=2;
+					x = ((x & 0xF) << 12) + ((reference[readOffset++] & 0x3F) << 6) + (reference[readOffset++] & 0x3F);
 				} else {
-					x = ((x & 0x1F) << 6) + (y & 0x3F);
+					length--;
+					x = ((x & 0x1F) << 6) + (reference[readOffset++] & 0x3F);
 				}
 			}
 			outputBuf[outputPos++] = (char) x;
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/CodeAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/CodeAttribute.java
index 4d05b56..e712318 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/CodeAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/CodeAttribute.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/CodeSnippetParsingUtil.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/CodeSnippetParsingUtil.java
new file mode 100644
index 0000000..8842843
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/CodeSnippetParsingUtil.java
@@ -0,0 +1,200 @@
+/*******************************************************************************
+ * Copyright (c) 2002, 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 java.util.Locale;
+import java.util.Map;
+
+import org.eclipse.jdt.core.compiler.IProblem;
+import org.eclipse.jdt.internal.compiler.CompilationResult;
+import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
+import org.eclipse.jdt.internal.compiler.ast.ASTNode;
+import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.Expression;
+import org.eclipse.jdt.internal.compiler.batch.CompilationUnit;
+import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
+import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
+
+/**
+ * Utility class to parse different code snippets
+ */
+public class CodeSnippetParsingUtil {
+
+	public RecordedParsingInformation recordedParsingInformation;
+
+	private RecordedParsingInformation getRecordedParsingInformation(CompilationResult compilationResult, CommentRecorderParser parser) {
+		int problemsCount = compilationResult.problemCount;
+		IProblem[] problems = null;
+		if (problemsCount != 0) {
+			final IProblem[] compilationResultProblems = compilationResult.problems;
+			if (compilationResultProblems.length == problemsCount) {
+				problems = compilationResultProblems;
+			} else {
+				System.arraycopy(compilationResultProblems, 0, (problems = new IProblem[problemsCount]), 0, problemsCount);
+			}
+		}
+		return new RecordedParsingInformation(problems, compilationResult.lineSeparatorPositions, parser.getCommentsPositions());
+	}
+
+	public ASTNode[] parseClassBodyDeclarations(char[] source, Map settings, boolean recordParsingInformation) {
+		return parseClassBodyDeclarations(source, 0, source.length, settings, recordParsingInformation);
+	}	
+
+	public ASTNode[] parseClassBodyDeclarations(char[] source, int offset, int length, Map settings, boolean recordParsingInformation) {
+		if (source == null) {
+			throw new IllegalArgumentException();
+		}
+		CompilerOptions compilerOptions = new CompilerOptions(settings);
+		final ProblemReporter problemReporter = new ProblemReporter(
+					DefaultErrorHandlingPolicies.proceedWithAllProblems(), 
+					compilerOptions, 
+					new DefaultProblemFactory(Locale.getDefault()));
+					
+		CommentRecorderParser parser = new CommentRecorderParser(problemReporter, false);
+
+		ICompilationUnit sourceUnit = 
+			new CompilationUnit(
+				source, 
+				"", //$NON-NLS-1$
+				compilerOptions.defaultEncoding);
+
+		CompilationResult compilationResult = new CompilationResult(sourceUnit, 0, 0, compilerOptions.maxProblemsPerUnit);
+		final CompilationUnitDeclaration compilationUnitDeclaration = new CompilationUnitDeclaration(problemReporter, compilationResult, source.length);
+		ASTNode[] result = parser.parseClassBodyDeclarations(source, offset, length, compilationUnitDeclaration);
+		
+		if (recordParsingInformation) {
+			this.recordedParsingInformation = getRecordedParsingInformation(compilationResult, parser);
+		}
+		return result;
+	}
+
+	public CompilationUnitDeclaration parseCompilationUnit(char[] source, Map settings, boolean recordParsingInformation) {
+		if (source == null) {
+			throw new IllegalArgumentException();
+		}
+		CompilerOptions compilerOptions = new CompilerOptions(settings);
+		CommentRecorderParser parser =
+			new CommentRecorderParser(
+				new ProblemReporter(
+					DefaultErrorHandlingPolicies.proceedWithAllProblems(), 
+					compilerOptions, 
+					new DefaultProblemFactory(Locale.getDefault())),
+			false);
+		
+		ICompilationUnit sourceUnit = 
+			new CompilationUnit(
+				source, 
+				"", //$NON-NLS-1$
+				compilerOptions.defaultEncoding);
+		final CompilationResult compilationResult = new CompilationResult(sourceUnit, 0, 0, compilerOptions.maxProblemsPerUnit);
+		CompilationUnitDeclaration compilationUnitDeclaration = parser.dietParse(sourceUnit, compilationResult);
+
+		if (recordParsingInformation) {
+			this.recordedParsingInformation = getRecordedParsingInformation(compilationResult, parser);
+		}
+		
+		if (compilationUnitDeclaration.ignoreMethodBodies) {
+			compilationUnitDeclaration.ignoreFurtherInvestigation = true;
+			// if initial diet parse did not work, no need to dig into method bodies.
+			return compilationUnitDeclaration; 
+		}
+		
+		//fill the methods bodies in order for the code to be generated
+		//real parse of the method....
+		parser.scanner.setSource(source);
+		org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] types = compilationUnitDeclaration.types;
+		if (types != null) {
+			for (int i = types.length; --i >= 0;) {
+				types[i].parseMethod(parser, compilationUnitDeclaration);
+			}
+		}
+		
+		if (recordParsingInformation) {
+			this.recordedParsingInformation.updateRecordedParsingInformation(compilationResult);
+		}
+		return compilationUnitDeclaration;
+	}
+
+	public Expression parseExpression(char[] source, Map settings, boolean recordParsingInformation) {
+		return parseExpression(source, 0, source.length, settings, recordParsingInformation);
+	}
+	
+	public Expression parseExpression(char[] source, int offset, int length, Map settings, boolean recordParsingInformation) {
+		
+		if (source == null) {
+			throw new IllegalArgumentException();
+		}
+		CompilerOptions compilerOptions = new CompilerOptions(settings);
+		final ProblemReporter problemReporter = new ProblemReporter(
+					DefaultErrorHandlingPolicies.proceedWithAllProblems(), 
+					compilerOptions, 
+					new DefaultProblemFactory(Locale.getDefault()));
+					
+		CommentRecorderParser parser = new CommentRecorderParser(problemReporter, false);
+
+		ICompilationUnit sourceUnit = 
+			new CompilationUnit(
+				source, 
+				"", //$NON-NLS-1$
+				compilerOptions.defaultEncoding);
+
+		CompilationResult compilationResult = new CompilationResult(sourceUnit, 0, 0, compilerOptions.maxProblemsPerUnit);
+		Expression result = parser.parseExpression(source, offset, length, new CompilationUnitDeclaration(problemReporter, compilationResult, source.length));
+		
+		if (recordParsingInformation) {
+			this.recordedParsingInformation = getRecordedParsingInformation(compilationResult, parser);
+		}
+		return result;
+	}
+
+	public ConstructorDeclaration parseStatements(char[] source, Map settings, boolean recordParsingInformation) {
+		return parseStatements(source, 0, source.length, settings, recordParsingInformation);
+	}
+	
+	public ConstructorDeclaration parseStatements(char[] source, int offset, int length, Map settings, boolean recordParsingInformation) {
+		if (source == null) {
+			throw new IllegalArgumentException();
+		}
+		CompilerOptions compilerOptions = new CompilerOptions(settings);
+		final ProblemReporter problemReporter = new ProblemReporter(
+					DefaultErrorHandlingPolicies.proceedWithAllProblems(), 
+					compilerOptions, 
+					new DefaultProblemFactory(Locale.getDefault()));
+		CommentRecorderParser parser = new CommentRecorderParser(problemReporter, false);
+		
+		ICompilationUnit sourceUnit = 
+			new CompilationUnit(
+				source, 
+				"", //$NON-NLS-1$
+				compilerOptions.defaultEncoding);
+
+		final CompilationResult compilationResult = new CompilationResult(sourceUnit, 0, 0, compilerOptions.maxProblemsPerUnit);
+		CompilationUnitDeclaration compilationUnitDeclaration = new CompilationUnitDeclaration(problemReporter, compilationResult, length);		
+
+		ConstructorDeclaration constructorDeclaration = new ConstructorDeclaration(compilationResult);
+		constructorDeclaration.sourceEnd  = -1;
+		constructorDeclaration.declarationSourceEnd = offset + length - 1;
+		constructorDeclaration.bodyStart = offset;
+		constructorDeclaration.bodyEnd = offset + length - 1;
+		
+		parser.scanner.setSource(source);
+		parser.scanner.resetTo(offset, offset + length);
+		parser.parse(constructorDeclaration, compilationUnitDeclaration, true);
+		
+		if (recordParsingInformation) {
+			this.recordedParsingInformation = getRecordedParsingInformation(compilationResult, parser);
+		}
+		return constructorDeclaration;
+	}
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/CommentRecorderParser.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/CommentRecorderParser.java
new file mode 100644
index 0000000..c926580
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/CommentRecorderParser.java
@@ -0,0 +1,261 @@
+/*******************************************************************************
+ * 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.util;
+
+import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.jdt.internal.compiler.parser.Parser;
+import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
+import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
+
+/**
+ * Internal parser used for parsing source to create DOM AST nodes.
+ * 
+ * @since 3.0
+ */
+public class CommentRecorderParser extends Parser {
+	
+	// support for comments
+	int[] commentStops = new int[10];
+	int[] commentStarts = new int[10];
+	int commentPtr = -1; // no comment test with commentPtr value -1
+	protected final static int CommentIncrement = 100;
+
+	/**
+	 * @param problemReporter
+	 * @param optimizeStringLiterals
+	 */
+	public CommentRecorderParser(ProblemReporter problemReporter, boolean optimizeStringLiterals) {
+		super(problemReporter, optimizeStringLiterals);
+	}
+
+	// old javadoc style check which doesn't include all leading comments into declaration
+	// for backward compatibility with 2.1 DOM 
+	public void checkComment() {
+
+		if (this.currentElement != null && this.scanner.commentPtr >= 0) {
+			flushCommentsDefinedPriorTo(this.endStatementPosition); // discard obsolete comments
+		}
+		boolean deprecated = false;
+		boolean checkDeprecated = false;
+		int lastCommentIndex = -1;
+		
+		// 
+		
+		//since jdk1.2 look only in the last java doc comment...
+		nextComment : for (lastCommentIndex = this.scanner.commentPtr; lastCommentIndex >= 0; lastCommentIndex--){
+			//look for @deprecated into the first javadoc comment preceeding the declaration
+			int commentSourceStart = this.scanner.commentStarts[lastCommentIndex];
+			// javadoc only (non javadoc comment have negative end positions.)
+			if ((commentSourceStart < 0) ||
+				(this.modifiersSourceStart != -1 && this.modifiersSourceStart < commentSourceStart) ||
+				(this.scanner.commentStops[lastCommentIndex] < 0))
+			{
+				continue nextComment;
+			}
+			checkDeprecated = true;
+			int commentSourceEnd = this.scanner.commentStops[lastCommentIndex] - 1; //stop is one over
+			
+			deprecated = this.javadocParser.checkDeprecation(commentSourceStart, commentSourceEnd);
+			this.javadoc = this.javadocParser.docComment;
+			break nextComment;
+		}
+		if (deprecated) {
+			checkAndSetModifiers(AccDeprecated);
+		}
+		// modify the modifier source start to point at the first comment
+		if (lastCommentIndex >= 0 && checkDeprecated) {
+			this.modifiersSourceStart = this.scanner.commentStarts[lastCommentIndex]; 
+			if (this.modifiersSourceStart < 0) {
+				this.modifiersSourceStart = -this.modifiersSourceStart;
+			}
+		}
+
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.jdt.internal.compiler.parser.Parser#consumeClassHeader()
+	 */
+	protected void consumeClassHeader() {
+		pushOnCommentsStack(0, this.scanner.commentPtr);
+		super.consumeClassHeader();
+	}
+	/* (non-Javadoc)
+	 * @see org.eclipse.jdt.internal.compiler.parser.Parser#consumeEmptyClassMemberDeclaration()
+	 */
+	protected void consumeEmptyClassMemberDeclaration() {
+		pushOnCommentsStack(0, this.scanner.commentPtr);
+		super.consumeEmptyClassMemberDeclaration();
+	}
+	/* (non-Javadoc)
+	 * @see org.eclipse.jdt.internal.compiler.parser.Parser#consumeEmptyTypeDeclaration()
+	 */
+	protected void consumeEmptyTypeDeclaration() {
+		pushOnCommentsStack(0, this.scanner.commentPtr);
+		super.consumeEmptyTypeDeclaration();
+	}
+	/* (non-Javadoc)
+	 * @see org.eclipse.jdt.internal.compiler.parser.Parser#consumeInterfaceHeader()
+	 */
+	protected void consumeInterfaceHeader() {
+		pushOnCommentsStack(0, this.scanner.commentPtr);
+		super.consumeInterfaceHeader();
+	}
+
+	/**
+	 * Insure that start position is always positive.
+	 * @see org.eclipse.jdt.internal.compiler.parser.Parser#containsComment(int, int)
+	 */
+	public boolean containsComment(int sourceStart, int sourceEnd) {
+		int iComment = this.scanner.commentPtr;
+		for (; iComment >= 0; iComment--) {
+			int commentStart = this.scanner.commentStarts[iComment];
+			if (commentStart < 0) {
+				commentStart = -commentStart;
+			}
+			// ignore comments before start
+			if (commentStart < sourceStart) continue;
+			// ignore comments after end
+			if (commentStart > sourceEnd) continue;
+			return true;
+		}
+		return false;
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.jdt.internal.compiler.parser.Parser#endParse(int)
+	 */
+	protected CompilationUnitDeclaration endParse(int act) {
+		CompilationUnitDeclaration unit = super.endParse(act);
+		if (unit.comments == null) {
+			pushOnCommentsStack(0, this.scanner.commentPtr);
+			unit.comments = getCommentsPositions();
+		}
+		return unit;
+	}
+
+	/* (non-Javadoc)
+	 * Save all source comments currently stored before flushing them.
+	 * @see org.eclipse.jdt.internal.compiler.parser.Parser#flushCommentsDefinedPriorTo(int)
+	 */
+	public int flushCommentsDefinedPriorTo(int position) {
+
+		int lastCommentIndex = this.scanner.commentPtr;
+		if (lastCommentIndex < 0) return position; // no comment
+	
+		// compute the index of the first obsolete comment
+		int index = lastCommentIndex;
+		int validCount = 0;
+		while (index >= 0){
+			int commentEnd = this.scanner.commentStops[index];
+			if (commentEnd < 0) commentEnd = -commentEnd; // negative end position for non-javadoc comments
+			if (commentEnd <= position){
+				break;
+			}
+			index--;
+			validCount++;
+		}
+		// if the source at <position> is immediately followed by a line comment, then
+		// flush this comment and shift <position> to the comment end.
+		if (validCount > 0){
+			int immediateCommentEnd = 0;
+			while (index<lastCommentIndex && (immediateCommentEnd = -this.scanner.commentStops[index+1])  > 0){ // only tolerating non-javadoc comments (non-javadoc comment end positions are negative)
+				// is there any line break until the end of the immediate comment ? (thus only tolerating line comment)
+				immediateCommentEnd--; // comment end in one char too far
+				if (this.scanner.getLineNumber(position) != this.scanner.getLineNumber(immediateCommentEnd)) break;
+				position = immediateCommentEnd;
+				validCount--; // flush this comment
+				index++;
+			}
+		}
+	
+		if (index < 0) return position; // no obsolete comment
+		pushOnCommentsStack(0, index); // store comment before flushing them
+
+		if (validCount > 0){ // move valid comment infos, overriding obsolete comment infos
+			System.arraycopy(this.scanner.commentStarts, index + 1, this.scanner.commentStarts, 0, validCount);
+			System.arraycopy(this.scanner.commentStops, index + 1, this.scanner.commentStops, 0, validCount);		
+		}
+		this.scanner.commentPtr = validCount - 1;
+		return position;
+	}
+
+	/*
+	 * Build a n*2 matrix of comments positions.
+	 * For each position, 0 is for start position and 1 for end position of the comment.
+	 */
+	public int[][] getCommentsPositions() {
+		int[][] positions = new int[this.commentPtr+1][2];
+		for (int i = 0, max = this.commentPtr; i <= max; i++){
+			positions[i][0] = this.commentStarts[i];
+			positions[i][1] = this.commentStops[i];
+		}
+		return positions;
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.jdt.internal.compiler.parser.Parser#initialize()
+	 */
+	public void initialize() {
+		super.initialize();
+		this.commentPtr = -1;
+	}
+	
+	/* (non-Javadoc)
+	 * Create and store a specific comment recorder scanner.
+	 * @see org.eclipse.jdt.internal.compiler.parser.Parser#initializeScanner()
+	 */
+	public void initializeScanner() {
+		this.scanner = new CommentRecorderScanner(
+				false /*comment*/, 
+				false /*whitespace*/, 
+				this.options.getSeverity(CompilerOptions.NonExternalizedString) != ProblemSeverities.Ignore /*nls*/, 
+				this.options.sourceLevel /*sourceLevel*/, 
+				this.options.taskTags/*taskTags*/,
+				this.options.taskPriorites/*taskPriorities*/,
+				this.options.isTaskCaseSensitive/*taskCaseSensitive*/);
+	}
+
+	/*
+	 * Push all stored comments in stack.
+	 */
+	private void pushOnCommentsStack(int start, int end) {
+	
+		for (int i=start; i<=end; i++) {
+			// First see if comment hasn't been already stored
+			int scannerStart = this.scanner.commentStarts[i]<0 ? -this.scanner.commentStarts[i] : this.scanner.commentStarts[i];
+			int commentStart = this.commentPtr == -1 ? -1 : (this.commentStarts[this.commentPtr]<0 ? -this.commentStarts[this.commentPtr] : this.commentStarts[this.commentPtr]);
+			if (commentStart == -1 ||  scannerStart > commentStart) {
+				int stackLength = this.commentStarts.length;
+				if (++this.commentPtr >= stackLength) {
+					System.arraycopy(
+						this.commentStarts, 0,
+						this.commentStarts = new int[stackLength + CommentIncrement], 0,
+						stackLength);
+					System.arraycopy(
+						this.commentStops, 0,
+						this.commentStops = new int[stackLength + CommentIncrement], 0,
+						stackLength);
+				}
+				this.commentStarts[this.commentPtr] = this.scanner.commentStarts[i];
+				this.commentStops[this.commentPtr] = this.scanner.commentStops[i];
+			}
+		}
+	}
+	/* (non-Javadoc)
+	 * Save all source comments currently stored before flushing them.
+	 * @see org.eclipse.jdt.internal.compiler.parser.Parser#resetModifiers()
+	 */
+	protected void resetModifiers() {
+		pushOnCommentsStack(0, this.scanner.commentPtr);
+		super.resetModifiers();
+	}
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/CommentRecorderScanner.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/CommentRecorderScanner.java
new file mode 100644
index 0000000..9c20bef
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/CommentRecorderScanner.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * 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.internal.compiler.parser.Scanner;
+
+/**
+ * Internal scanner used for DOM AST nodes.
+ * 
+ * @since 3.0
+ */
+public class CommentRecorderScanner extends Scanner {
+
+	public CommentRecorderScanner(
+		boolean tokenizeComments,
+		boolean tokenizeWhiteSpace,
+		boolean checkNonExternalizedStringLiterals,
+		long sourceLevel,
+		char[][] taskTags,
+		char[][] taskPriorities,
+		boolean isTaskCaseSensitive) {
+		super(tokenizeComments, tokenizeWhiteSpace, checkNonExternalizedStringLiterals, sourceLevel, taskTags, taskPriorities, isTaskCaseSensitive);
+	}
+	
+	/**
+	 * Set start position negative for line comments.
+	 * @see org.eclipse.jdt.internal.compiler.parser.Scanner#recordComment(int)
+	 */
+	public void recordComment(int token) {
+		super.recordComment(token);
+		if (token == TokenNameCOMMENT_LINE) {
+			// for comment line both positions are negative
+			this.commentStarts[this.commentPtr] = -this.commentStarts[this.commentPtr];
+		}
+	}
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ConstantPool.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ConstantPool.java
index 046b5ea..2b92bd3 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ConstantPool.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ConstantPool.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ConstantPoolEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ConstantPoolEntry.java
index eb5a010..7384eaa 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ConstantPoolEntry.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ConstantPoolEntry.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ConstantValueAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ConstantValueAttribute.java
index b56e9f5..d8688ef 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ConstantValueAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ConstantValueAttribute.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/DefaultBytecodeVisitor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/DefaultBytecodeVisitor.java
index 4cfd770..f9fa129 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/DefaultBytecodeVisitor.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/DefaultBytecodeVisitor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -10,8 +10,6 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.util;
 
-import org.eclipse.jdt.core.Signature;
-import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.util.IBytecodeVisitor;
 import org.eclipse.jdt.core.util.IConstantPoolConstant;
 import org.eclipse.jdt.core.util.IConstantPoolEntry;
@@ -22,8 +20,7 @@
  * Default implementation of ByteCodeVisitor
  */
 public class DefaultBytecodeVisitor implements IBytecodeVisitor {
-	private static final char[] INIT	= "<init>".toCharArray(); //$NON-NLS-1$
-	private static final char[] EMPTY_NAME = CharOperation.NO_CHAR;
+	private static final String EMPTY_CLASS_NAME = "\"\""; //$NON-NLS-1$
 	private static final int T_BOOLEAN = 4;
 	private static final int T_CHAR = 5;
 	private static final int T_FLOAT = 6;
@@ -42,7 +39,7 @@
 		this.buffer = buffer;
 		this.lineSeparator = lineSeparator;
 		this.tabNumber = tabNumber + 1;
-		this.digitNumberForPC = (int) (Math.log(codeLength) / Math.log(10));
+		this.digitNumberForPC = (int) (Math.log(codeLength - 1) / Math.log(10));
 	}
 	/**
 	 * @see IBytecodeVisitor#_aaload(int)
@@ -829,7 +826,7 @@
 			.append(Util.bind("disassembler.classmemberseparator")) //$NON-NLS-1$
 			.append(constantFieldref.getFieldName())
 			.append(Util.bind("disassembler.space")) //$NON-NLS-1$
-			.append(returnFieldrefDescriptor(constantFieldref))
+			.append(constantFieldref.getFieldDescriptor())
 			.append(Util.bind("classformat.getfieldclose")); //$NON-NLS-1$
 		writeNewLine();
 	}
@@ -847,7 +844,7 @@
 			.append(Util.bind("disassembler.classmemberseparator")) //$NON-NLS-1$
 			.append(constantFieldref.getFieldName())
 			.append(Util.bind("disassembler.space")) //$NON-NLS-1$
-			.append(returnFieldrefDescriptor(constantFieldref))
+			.append(constantFieldref.getFieldDescriptor())
 			.append(Util.bind("classformat.getstaticclose")); //$NON-NLS-1$
 		writeNewLine();
 	}
@@ -1312,11 +1309,6 @@
 		byte nargs,
 		IConstantPoolEntry constantInterfaceMethodref) {
 
-		char[] methodDescriptor = constantInterfaceMethodref.getMethodDescriptor();
-		CharOperation.replace(methodDescriptor, '/', '.');
-		char[] returnType = Signature.getReturnType(methodDescriptor);
-		CharOperation.replace(returnType, '/', '.');
-		
 		dumpPcNumber(pc);
 		buffer.append(OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.INVOKEINTERFACE])
 			.append(Util.bind("classformat.nargs")) //$NON-NLS-1$
@@ -1326,15 +1318,8 @@
 			.append(Util.bind("classformat.invokeinterfacemethod")) //$NON-NLS-1$
 			.append(returnDeclaringClassName(constantInterfaceMethodref))
 			.append(Util.bind("disassembler.classmemberseparator")) //$NON-NLS-1$
-			.append(
-				Signature.toCharArray(
-					methodDescriptor,
-					constantInterfaceMethodref.getMethodName(),
-					getParameterNames(methodDescriptor),
-					true,
-					false))
-			.append(Util.bind("disassembler.space")) //$NON-NLS-1$
-			.append(Signature.toCharArray(returnType))
+			.append(constantInterfaceMethodref.getMethodName())
+			.append(constantInterfaceMethodref.getMethodDescriptor())
 			.append(Util.bind("classformat.invokeinterfacemethodclose")); //$NON-NLS-1$
 		writeNewLine();
 	}
@@ -1343,62 +1328,23 @@
 	 * @see IBytecodeVisitor#_invokespecial(int, int, IConstantPoolEntry)
 	 */
 	public void _invokespecial(int pc, int index, IConstantPoolEntry constantMethodref) {
-
-		char[] methodDescriptor = constantMethodref.getMethodDescriptor();
-		CharOperation.replace(methodDescriptor, '/', '.');
-		char[] methodName = constantMethodref.getMethodName();
-		char[] returnType = Signature.getReturnType(methodDescriptor);
-		CharOperation.replace(returnType, '/', '.');
-		
-		if (CharOperation.equals(INIT, methodName)) {
-			methodName = EMPTY_NAME;
-			dumpPcNumber(pc);
-			buffer.append(OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.INVOKESPECIAL])
-				.append(Util.bind("disassembler.constantpoolindex")) //$NON-NLS-1$
-				.append(index)
-				.append(Util.bind("classformat.invokespecialconstructor")) //$NON-NLS-1$
-				.append(returnDeclaringClassName(constantMethodref))
-				.append(
-					Signature.toCharArray(
-						methodDescriptor,
-						methodName,
-						getParameterNames(methodDescriptor),
-						true,
-						false))
-				.append(Util.bind("classformat.invokespecialconstructorclose")); //$NON-NLS-1$
-			writeNewLine();
-		} else {
-			dumpPcNumber(pc);
-			buffer.append(OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.INVOKESPECIAL])
-				.append(Util.bind("disassembler.constantpoolindex")) //$NON-NLS-1$
-				.append(index)
-				.append(Util.bind("classformat.invokespecialmethod")) //$NON-NLS-1$
-				.append(returnDeclaringClassName(constantMethodref))
-				.append(Util.bind("disassembler.classmemberseparator")) //$NON-NLS-1$
-				.append(
-					Signature.toCharArray(
-						methodDescriptor,
-						constantMethodref.getMethodName(),
-						getParameterNames(methodDescriptor),
-						true,
-						false))
-				.append(Util.bind("disassembler.space")) //$NON-NLS-1$
-			.append(Signature.toCharArray(returnType))
-				.append(Util.bind("classformat.invokespecialmethodclose")); //$NON-NLS-1$
-			writeNewLine();
-		}
+		dumpPcNumber(pc);
+		buffer.append(OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.INVOKESPECIAL])
+			.append(Util.bind("disassembler.constantpoolindex")) //$NON-NLS-1$
+			.append(index)
+			.append(Util.bind("classformat.invokespecialmethod")) //$NON-NLS-1$
+			.append(returnDeclaringClassName(constantMethodref))
+			.append(Util.bind("disassembler.classmemberseparator")) //$NON-NLS-1$
+			.append(constantMethodref.getMethodName())
+			.append(constantMethodref.getMethodDescriptor())
+			.append(Util.bind("classformat.invokespecialmethodclose")); //$NON-NLS-1$
+		writeNewLine();
 	}
 
 	/**
 	 * @see IBytecodeVisitor#_invokestatic(int, int, IConstantPoolEntry)
 	 */
 	public void _invokestatic(int pc, int index, IConstantPoolEntry constantMethodref) {
-
-		char[] methodDescriptor = constantMethodref.getMethodDescriptor();
-		CharOperation.replace(methodDescriptor, '/', '.');
-		char[] returnType = Signature.getReturnType(methodDescriptor);
-		CharOperation.replace(returnType, '/', '.');
-		
 		dumpPcNumber(pc);
 		buffer.append(OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.INVOKESTATIC])
 			.append(Util.bind("disassembler.constantpoolindex")) //$NON-NLS-1$
@@ -1406,15 +1352,8 @@
 			.append(Util.bind("classformat.invokestaticmethod")) //$NON-NLS-1$
 			.append(returnDeclaringClassName(constantMethodref))
 			.append(Util.bind("disassembler.classmemberseparator")) //$NON-NLS-1$
-			.append(
-				Signature.toCharArray(
-					methodDescriptor,
-					constantMethodref.getMethodName(),
-					getParameterNames(methodDescriptor),
-					true,
-					false))
-			.append(Util.bind("disassembler.space")) //$NON-NLS-1$
-			.append(Signature.toCharArray(returnType))
+			.append(constantMethodref.getMethodName())
+			.append(constantMethodref.getMethodDescriptor())
 			.append(Util.bind("classformat.invokestaticmethodclose")); //$NON-NLS-1$
 		writeNewLine();
 	}
@@ -1423,12 +1362,6 @@
 	 * @see IBytecodeVisitor#_invokevirtual(int, int, IConstantPoolEntry)
 	 */
 	public void _invokevirtual(int pc, int index, IConstantPoolEntry constantMethodref) {
-
-		char[] methodDescriptor = constantMethodref.getMethodDescriptor();
-		CharOperation.replace(methodDescriptor, '/', '.');
-		char[] returnType = Signature.getReturnType(methodDescriptor);
-		CharOperation.replace(returnType, '/', '.');
-		
 		dumpPcNumber(pc);
 		buffer.append(OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.INVOKEVIRTUAL])
 			.append(Util.bind("disassembler.constantpoolindex")) //$NON-NLS-1$
@@ -1436,15 +1369,8 @@
 			.append(Util.bind("classformat.invokevirtualmethod")) //$NON-NLS-1$
 			.append(returnDeclaringClassName(constantMethodref))
 			.append(Util.bind("disassembler.classmemberseparator")) //$NON-NLS-1$
-			.append(
-				Signature.toCharArray(
-					methodDescriptor,
-					constantMethodref.getMethodName(),
-					getParameterNames(methodDescriptor),
-					true,
-					false))
-			.append(Util.bind("disassembler.space")) //$NON-NLS-1$
-			.append(Signature.toCharArray(returnType))
+			.append(constantMethodref.getMethodName())
+			.append(constantMethodref.getMethodDescriptor())
 			.append(Util.bind("classformat.invokevirtualmethodclose")); //$NON-NLS-1$
 		writeNewLine();
 	}
@@ -1698,6 +1624,7 @@
 				break;
 			case IConstantPoolConstant.CONSTANT_String :
 				appendOutputForConstantString(constantPoolEntry);
+				break;
 			case IConstantPoolConstant.CONSTANT_Class :
 				appendOutputForConstantClass(constantPoolEntry);
 		}
@@ -1722,6 +1649,9 @@
 				break;
 			case IConstantPoolConstant.CONSTANT_String :
 				appendOutputForConstantString(constantPoolEntry);
+				break;
+			case IConstantPoolConstant.CONSTANT_Class :
+				appendOutputForConstantClass(constantPoolEntry);
 		}
 		writeNewLine();
 	}
@@ -2060,7 +1990,7 @@
 			.append(Util.bind("disassembler.classmemberseparator")) //$NON-NLS-1$
 			.append(constantFieldref.getFieldName())
 			.append(Util.bind("disassembler.space")) //$NON-NLS-1$
-			.append(returnFieldrefDescriptor(constantFieldref))
+			.append(constantFieldref.getFieldDescriptor())
 			.append(Util.bind("classformat.putfieldclose")); //$NON-NLS-1$
 		writeNewLine();
 	}
@@ -2078,17 +2008,11 @@
 			.append(Util.bind("disassembler.classmemberseparator")) //$NON-NLS-1$
 			.append(constantFieldref.getFieldName())
 			.append(Util.bind("disassembler.space")) //$NON-NLS-1$
-			.append(returnFieldrefDescriptor(constantFieldref))
+			.append(constantFieldref.getFieldDescriptor())
 			.append(Util.bind("classformat.putstaticclose")); //$NON-NLS-1$
 		writeNewLine();
 	}
 
-	private char[] returnFieldrefDescriptor(IConstantPoolEntry constantFieldref) throws IllegalArgumentException {
-		char[] fieldDescriptor = constantFieldref.getFieldDescriptor();
-		CharOperation.replace(fieldDescriptor, '/', '.');
-		return Signature.toCharArray(fieldDescriptor);
-	}
-
 	/**
 	 * @see IBytecodeVisitor#_ret(int, int)
 	 */
@@ -2288,20 +2212,16 @@
 	}
 
 	private String returnConstantClassName(IConstantPoolEntry constantClass) {
-		return new String(constantClass.getClassInfoName()).replace('/', '.');
+		char[] classInfoName = constantClass.getClassInfoName();
+		if (classInfoName.length == 0) {
+			return EMPTY_CLASS_NAME;
+		} else {
+			return new String(classInfoName);
+		}
 	}
 
 	private String returnDeclaringClassName(IConstantPoolEntry constantRef) {
-		return new String(constantRef.getClassName()).replace('/', '.');
-	}
-
-	private char[][] getParameterNames(char[] methodDescriptor) {
-		int paramCount = Signature.getParameterCount(methodDescriptor);
-		char[][] parameterNames = new char[paramCount][];
-		for (int i = 0; i < paramCount; i++) {
-			parameterNames[i] = Util.bind("disassembler.parametername").toCharArray(); //$NON-NLS-1$
-		}
-		return parameterNames;
+		return new String(constantRef.getClassName());
 	}
 
 	private void appendOutputForConstantDouble(IConstantPoolEntry constantPoolEntry) {
@@ -2362,4 +2282,4 @@
 		}
 	}	
 
-}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Disassembler.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Disassembler.java
index e587fe8..a571781 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Disassembler.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Disassembler.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -10,6 +10,7 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.util;
 
+import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.core.Signature;
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.util.*;
@@ -40,17 +41,7 @@
 
 	private static final char[] ANY_EXCEPTION = Util.bind("classfileformat.anyexceptionhandler").toCharArray();	 //$NON-NLS-1$
 	private static final String EMPTY_OUTPUT = ""; //$NON-NLS-1$
-	
-	private void checkSuperFlags(StringBuffer buffer, int accessFlags, String lineSeparator, int tabNumber) {
-		buffer.append(Util.bind("disassembler.commentstart")); //$NON-NLS-1$
-		if ((accessFlags & IModifierConstants.ACC_SUPER) != 0) {
-			buffer.append(Util.bind("classfileformat.superflagisset")); //$NON-NLS-1$
-		} else {
-			buffer.append(Util.bind("classfileformat.superflagisnotset")); //$NON-NLS-1$
-		}
-		buffer.append(Util.bind("disassembler.commentend")); //$NON-NLS-1$
-		writeNewLine(buffer, lineSeparator, tabNumber);
-	}
+	private static final String VERSION_UNKNOWN = "unknown";//$NON-NLS-1$
 
 	private void decodeModifiersForField(StringBuffer buffer, int accessFlags) {
 		boolean firstModifier = true;
@@ -117,6 +108,15 @@
 			}
 			buffer.append("volatile"); //$NON-NLS-1$
 		}
+		if ((accessFlags & IModifierConstants.ACC_ENUM) != 0) {
+			if (!firstModifier) {
+				buffer.append(Util.bind("disassembler.space")); //$NON-NLS-1$
+			}
+			if (firstModifier) {
+				firstModifier = false;
+			}
+			buffer.append("enum"); //$NON-NLS-1$
+		}
 		if (!firstModifier) {
 			buffer.append(Util.bind("disassembler.space")); //$NON-NLS-1$
 		}
@@ -266,6 +266,24 @@
 			}
 			buffer.append("synchronized"); //$NON-NLS-1$
 		}
+		if ((accessFlags & IModifierConstants.ACC_BRIDGE) != 0) {
+			if (!firstModifier) {
+				buffer.append(Util.bind("disassembler.space")); //$NON-NLS-1$
+			}
+			if (firstModifier) {
+				firstModifier = false;
+			}
+			buffer.append("bridge"); //$NON-NLS-1$
+		}		
+		if ((accessFlags & IModifierConstants.ACC_VARARGS) != 0) {
+			if (!firstModifier) {
+				buffer.append(Util.bind("disassembler.space")); //$NON-NLS-1$
+			}
+			if (firstModifier) {
+				firstModifier = false;
+			}
+			buffer.append("varargs"); //$NON-NLS-1$
+		}
 		if (!firstModifier) {
 			buffer.append(Util.bind("disassembler.space")); //$NON-NLS-1$
 		}
@@ -300,6 +318,15 @@
 			}
 			buffer.append("public"); //$NON-NLS-1$
 		}
+		if ((accessFlags & IModifierConstants.ACC_ANNOTATION) != 0) {
+			if (!firstModifier) {
+				buffer.append(Util.bind("disassembler.space")); //$NON-NLS-1$
+			}
+			if (firstModifier) {
+				firstModifier = false;
+			}
+			buffer.append("@"); //$NON-NLS-1$
+		}
 		if (!firstModifier) {
 			buffer.append(Util.bind("disassembler.space")); //$NON-NLS-1$
 		}
@@ -381,58 +408,70 @@
 	}
 
 	/**
-	 * @see org.eclipse.jdt.core.util.IClassFileDisassembler#disassemble(org.eclipse.jdt.core.util.IClassFileReader, java.lang.String)
+	 * @see #disassemble(org.eclipse.jdt.core.util.IClassFileReader, java.lang.String, int)
 	 */
 	public String disassemble(IClassFileReader classFileReader, String lineSeparator) {
 		return disassemble(classFileReader, lineSeparator, ClassFileBytesDisassembler.DEFAULT);
 	}
 
 	/**
-	 * @see org.eclipse.jdt.core.util.IClassFileDisassembler#disassemble(org.eclipse.jdt.core.util.IClassFileReader, java.lang.String, int)
+	 * Answers back the disassembled string of the IClassFileReader according to the
+	 * mode.
+	 * This is an output quite similar to the javap tool.
+	 * 
+	 * @param classFileReader The classFileReader to be disassembled
+	 * @param lineSeparator the line separator to use.
+	 * @param mode the mode used to disassemble the IClassFileReader
+	 * 
+	 * @return the disassembled string of the IClassFileReader according to the mode
 	 */
 	public String disassemble(IClassFileReader classFileReader, String lineSeparator, int mode) {
 		if (classFileReader == null) return EMPTY_OUTPUT;
-		
 		StringBuffer buffer = new StringBuffer();
 
+		ISourceAttribute sourceAttribute = classFileReader.getSourceFileAttribute();
+		IClassFileAttribute classFileAttribute = Util.getAttribute(classFileReader, IAttributeNamesConstants.SIGNATURE);
+		ISignatureAttribute signatureAttribute = (ISignatureAttribute) classFileAttribute;
+		final int accesssFlags = classFileReader.getAccessFlags();
 		if (mode == ClassFileBytesDisassembler.DETAILED) {
 			int minorVersion = classFileReader.getMinorVersion();
 			int majorVersion = classFileReader.getMajorVersion();
-			buffer.append(Util.bind("disassembler.commentstart")); //$NON-NLS-1$
-			writeNewLine(buffer, lineSeparator, 0);
-			buffer.append(Util.bind("disassembler.begincommentline"));			 //$NON-NLS-1$
-			if (minorVersion == 3 && majorVersion == 45) {
-				buffer.append(Util.bind("classfileformat.targetoption", " 1.1"));//$NON-NLS-1$//$NON-NLS-2$
-			} else if (minorVersion == 0 && majorVersion == 46) {
-				buffer.append(Util.bind("classfileformat.targetoption", "1.2"));//$NON-NLS-1$//$NON-NLS-2$
-			} else if (minorVersion == 0 && majorVersion == 47) {
-				buffer.append(Util.bind("classfileformat.targetoption", "1.3"));//$NON-NLS-1$//$NON-NLS-2$
-			} else if (minorVersion == 0 && majorVersion == 48) {
-				buffer.append(Util.bind("classfileformat.targetoption", "1.4"));//$NON-NLS-1$//$NON-NLS-2$
-			} else if (minorVersion == 0 && majorVersion == 49) {
-				buffer.append(Util.bind("classfileformat.targetoption", "1.5"));//$NON-NLS-1$//$NON-NLS-2$
+			buffer.append(Util.bind("disassembler.begincommentline")); //$NON-NLS-1$
+			if (sourceAttribute != null) {
+				buffer.append(Util.bind("disassembler.sourceattributeheader")); //$NON-NLS-1$
+				buffer.append(sourceAttribute.getSourceFileName());
 			}
+			String versionNumber = VERSION_UNKNOWN;//$NON-NLS-1$
+			if (minorVersion == 3 && majorVersion == 45) {
+				versionNumber = JavaCore.VERSION_1_1;
+			} else if (minorVersion == 0 && majorVersion == 46) {
+				versionNumber = JavaCore.VERSION_1_2;
+			} else if (minorVersion == 0 && majorVersion == 47) {
+				versionNumber = JavaCore.VERSION_1_3;
+			} else if (minorVersion == 0 && majorVersion == 48) {
+				versionNumber = JavaCore.VERSION_1_4;
+			} else if (minorVersion == 0 && majorVersion == 49) {
+				versionNumber = JavaCore.VERSION_1_5;
+			}
+			buffer.append(
+				Util.bind("classfileformat.versiondetails",//$NON-NLS-1$
+				new String[] {
+					versionNumber,
+					Integer.toString(majorVersion),
+					Integer.toString(minorVersion),
+					((accesssFlags & IModifierConstants.ACC_SUPER) != 0
+							? Util.bind("classfileformat.superflagisset")//$NON-NLS-1$
+							: Util.bind("classfileformat.superflagisnotset"))//$NON-NLS-1$
+					+ (isDeprecated(classFileReader) ? ", deprecated" : EMPTY_OUTPUT)//$NON-NLS-1$
+				}));
 			writeNewLine(buffer, lineSeparator, 0);
-			buffer.append(Util.bind("disassembler.begincommentline"));			 //$NON-NLS-1$
-			buffer.append(Util.bind("classfileformat.magicnumber")); //$NON-NLS-1$
-			buffer.append(Integer.toHexString(classFileReader.getMagic()).toUpperCase());
-			writeNewLine(buffer, lineSeparator, 0);
-			buffer.append(Util.bind("disassembler.begincommentline"));			 //$NON-NLS-1$
-			buffer.append(Util.bind("classfileformat.minorversion")); //$NON-NLS-1$
-			buffer.append(minorVersion);
-			writeNewLine(buffer, lineSeparator, 0);
-			buffer.append(Util.bind("disassembler.begincommentline"));			 //$NON-NLS-1$
-			buffer.append(Util.bind("classfileformat.majorversion")); //$NON-NLS-1$
-			buffer.append(majorVersion);
-			writeNewLine(buffer, lineSeparator, 0);
-			buffer.append(Util.bind("disassembler.commentend")); //$NON-NLS-1$
-			writeNewLine(buffer, lineSeparator, 0);
-		}
-		ISourceAttribute sourceAttribute = classFileReader.getSourceFileAttribute();
-		if (sourceAttribute != null) {
-			buffer.append(Util.bind("classfileformat.sourcename")); //$NON-NLS-1$
-			buffer.append(sourceAttribute.getSourceFileName());
-			writeNewLine(buffer, lineSeparator, 0);
+			if (signatureAttribute != null) {
+				buffer
+					.append(Util.bind("disassembler.begincommentline"))	 //$NON-NLS-1$
+					.append(Util.bind("disassembler.signatureattributeheader")) //$NON-NLS-1$
+					.append(signatureAttribute.getSignature());
+				writeNewLine(buffer, lineSeparator, 0);
+			}
 		}
 		char[] className = classFileReader.getClassName();
 		if (className == null) {
@@ -455,9 +494,15 @@
 				}
 			}
 		} else {
-			decodeModifiersForType(buffer, classFileReader.getAccessFlags());
+			decodeModifiersForType(buffer, accesssFlags);
+			if (isSynthetic(classFileReader)) {
+				buffer.append("synthetic"); //$NON-NLS-1$
+				buffer.append(Util.bind("disassembler.space")); //$NON-NLS-1$
+			}
 		}
-		if (classFileReader.isClass()) {
+		if ((accesssFlags & IModifierConstants.ACC_ENUM) != 0) {
+			buffer.append("enum "); //$NON-NLS-1$
+		} else if (classFileReader.isClass()) {
 			buffer.append("class "); //$NON-NLS-1$
 		} else {
 			buffer.append("interface "); //$NON-NLS-1$
@@ -480,27 +525,50 @@
 				CharOperation.replace(superinterface, '/', '.');
 				buffer
 					.append(superinterface)
-					.append(Util.bind("disassembler.comma")); //$NON-NLS-1$
+					.append(Util.bind("disassembler.comma"))//$NON-NLS-1$
+					.append(Util.bind("disassembler.space")); //$NON-NLS-1$
 			}
 			char[] superinterface = superclassInterfaces[length - 1];
 			CharOperation.replace(superinterface, '/', '.');
 			buffer.append(superinterface);
 		}
 		buffer.append(Util.bind("disassembler.opentypedeclaration")); //$NON-NLS-1$
-		writeNewLine(buffer, lineSeparator, 1);
-		checkSuperFlags(buffer, classFileReader.getAccessFlags(), lineSeparator, 1);
 		disassembleTypeMembers(classFileReader, buffer, lineSeparator, 1, mode);
 		if (mode == ClassFileBytesDisassembler.DETAILED) {
+			IClassFileAttribute[] attributes = classFileReader.getAttributes();
+			length = attributes.length;
+			IEnclosingMethodAttribute enclosingMethodAttribute = getEnclosingMethodAttribute(classFileReader);
+			int remainingAttributesLength = length;
+			if (innerClassesAttribute != null) {
+				remainingAttributesLength--;
+			}
+			if (enclosingMethodAttribute != null) {
+				remainingAttributesLength--;
+			}
+			if (sourceAttribute != null) {
+				remainingAttributesLength--;
+			}
+			if (signatureAttribute != null) {
+				remainingAttributesLength--;
+			}
+			if (innerClassesAttribute != null || enclosingMethodAttribute != null || remainingAttributesLength != 0) {
+				writeNewLine(buffer, lineSeparator, 0);
+			}
 			if (innerClassesAttribute != null) {
 				disassemble(innerClassesAttribute, buffer, lineSeparator, 1);
 			}
-			IClassFileAttribute[] attributes = classFileReader.getAttributes();
-			length = attributes.length;
+			if (enclosingMethodAttribute != null) {
+				disassemble(enclosingMethodAttribute, buffer, lineSeparator, 0);
+			}
 			if (length != 0) {
 				for (int i = 0; i < length; i++) {
 					IClassFileAttribute attribute = attributes[i];
 					if (attribute != innerClassesAttribute
-						&& attribute != sourceAttribute) {
+						&& attribute != sourceAttribute
+						&& attribute != signatureAttribute
+						&& attribute != enclosingMethodAttribute
+						&& !CharOperation.equals(attribute.getAttributeName(), IAttributeNamesConstants.DEPRECATED)
+						&& !CharOperation.equals(attribute.getAttributeName(), IAttributeNamesConstants.SYNTHETIC)) {
 						disassemble(attribute, buffer, lineSeparator, 0);
 					}
 				}
@@ -525,10 +593,8 @@
 			outerClassNameIndex = innerClassesAttributeEntry.getOuterClassNameIndex();
 			innerNameIndex = innerClassesAttributeEntry.getInnerNameIndex();
 			accessFlags = innerClassesAttributeEntry.getAccessFlags();
-			buffer.append(Util.bind("disassembler.openinnerclassentry")); //$NON-NLS-1$
-			writeNewLine(buffer, lineSeparator, tabNumber);
-			dumpTab(tabNumber + 1, buffer);
 			buffer
+				.append(Util.bind("disassembler.openinnerclassentry")) //$NON-NLS-1$
 				.append(Util.bind("disassembler.inner_class_info_name")) //$NON-NLS-1$
 				.append(Util.bind("disassembler.constantpoolindex")) //$NON-NLS-1$
 				.append(innerClassNameIndex);
@@ -537,9 +603,9 @@
 					.append(Util.bind("disassembler.space")) //$NON-NLS-1$
 					.append(innerClassesAttributeEntry.getInnerClassName());
 			}
-			writeNewLine(buffer, lineSeparator, tabNumber);
-			dumpTab(tabNumber + 1, buffer);
 			buffer
+				.append(Util.bind("disassembler.comma")) //$NON-NLS-1$
+				.append(Util.bind("disassembler.space")) //$NON-NLS-1$
 				.append(Util.bind("disassembler.outer_class_info_name")) //$NON-NLS-1$
 				.append(Util.bind("disassembler.constantpoolindex")) //$NON-NLS-1$
 				.append(outerClassNameIndex);
@@ -549,7 +615,8 @@
 					.append(innerClassesAttributeEntry.getOuterClassName());
 			}
 			writeNewLine(buffer, lineSeparator, tabNumber);
-			dumpTab(tabNumber + 1, buffer);
+			dumpTab(tabNumber, buffer);
+			buffer.append(Util.bind("disassembler.space")); //$NON-NLS-1$
 			buffer
 				.append(Util.bind("disassembler.inner_name")) //$NON-NLS-1$
 				.append(Util.bind("disassembler.constantpoolindex")) //$NON-NLS-1$
@@ -559,9 +626,9 @@
 					.append(Util.bind("disassembler.space")) //$NON-NLS-1$
 					.append(innerClassesAttributeEntry.getInnerName());
 			}
-			writeNewLine(buffer, lineSeparator, tabNumber);
-			dumpTab(tabNumber + 1, buffer);
 			buffer
+				.append(Util.bind("disassembler.comma")) //$NON-NLS-1$
+				.append(Util.bind("disassembler.space")) //$NON-NLS-1$
 				.append(Util.bind("disassembler.inner_accessflags")) //$NON-NLS-1$
 				.append(accessFlags)
 				.append(Util.bind("disassembler.space")); //$NON-NLS-1$
@@ -577,10 +644,8 @@
 		outerClassNameIndex = innerClassesAttributeEntry.getOuterClassNameIndex();
 		innerNameIndex = innerClassesAttributeEntry.getInnerNameIndex();
 		accessFlags = innerClassesAttributeEntry.getAccessFlags();
-		buffer.append(Util.bind("disassembler.openinnerclassentry")); //$NON-NLS-1$
-		writeNewLine(buffer, lineSeparator, tabNumber);
-		dumpTab(tabNumber + 1, buffer);
 		buffer
+			.append(Util.bind("disassembler.openinnerclassentry")) //$NON-NLS-1$
 			.append(Util.bind("disassembler.inner_class_info_name")) //$NON-NLS-1$
 			.append(Util.bind("disassembler.constantpoolindex")) //$NON-NLS-1$
 			.append(innerClassNameIndex);
@@ -589,9 +654,9 @@
 				.append(Util.bind("disassembler.space")) //$NON-NLS-1$
 				.append(innerClassesAttributeEntry.getInnerClassName());
 		}
-		writeNewLine(buffer, lineSeparator, tabNumber);
-		dumpTab(tabNumber + 1, buffer);
 		buffer
+			.append(Util.bind("disassembler.comma")) //$NON-NLS-1$
+			.append(Util.bind("disassembler.space")) //$NON-NLS-1$
 			.append(Util.bind("disassembler.outer_class_info_name")) //$NON-NLS-1$
 			.append(Util.bind("disassembler.constantpoolindex")) //$NON-NLS-1$
 			.append(outerClassNameIndex);
@@ -601,7 +666,8 @@
 				.append(innerClassesAttributeEntry.getOuterClassName());
 		}
 		writeNewLine(buffer, lineSeparator, tabNumber);
-		dumpTab(tabNumber + 1, buffer);
+		dumpTab(tabNumber, buffer);
+		buffer.append(Util.bind("disassembler.space")); //$NON-NLS-1$
 		buffer
 			.append(Util.bind("disassembler.inner_name")) //$NON-NLS-1$
 			.append(Util.bind("disassembler.constantpoolindex")) //$NON-NLS-1$
@@ -611,9 +677,9 @@
 				.append(Util.bind("disassembler.space")) //$NON-NLS-1$
 				.append(innerClassesAttributeEntry.getInnerName());
 		}
-		writeNewLine(buffer, lineSeparator, tabNumber);
-		dumpTab(tabNumber + 1, buffer);
 		buffer
+			.append(Util.bind("disassembler.comma")) //$NON-NLS-1$
+			.append(Util.bind("disassembler.space")) //$NON-NLS-1$
 			.append(Util.bind("disassembler.inner_accessflags")) //$NON-NLS-1$
 			.append(accessFlags)
 			.append(Util.bind("disassembler.space")); //$NON-NLS-1$
@@ -626,10 +692,35 @@
 	 */
 	private void disassemble(IFieldInfo fieldInfo, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
 		writeNewLine(buffer, lineSeparator, tabNumber);
-		decodeModifiersForField(buffer, fieldInfo.getAccessFlags());
 		char[] fieldDescriptor = fieldInfo.getDescriptor();
-		CharOperation.replace(fieldDescriptor, '/', '.');
-		buffer.append(Signature.toCharArray(fieldDescriptor));
+		IClassFileAttribute classFileAttribute = Util.getAttribute(fieldInfo, IAttributeNamesConstants.SIGNATURE);
+		ISignatureAttribute signatureAttribute = (ISignatureAttribute) classFileAttribute;
+		if (mode == DETAILED) {
+			buffer
+				.append(Util.bind("disassembler.begincommentline")) //$NON-NLS-1$
+				.append(Util.bind("classfileformat.fieldddescriptor")) //$NON-NLS-1$
+				.append(Util.bind("classfileformat.fielddescriptorindex")) //$NON-NLS-1$
+				.append(fieldInfo.getDescriptorIndex())
+				.append(Util.bind("disassembler.space")) //$NON-NLS-1$
+				.append(fieldDescriptor);
+			if (fieldInfo.isDeprecated()) {
+				buffer.append(Util.bind("disassembler.deprecated"));//$NON-NLS-1$
+			}
+			writeNewLine(buffer, lineSeparator, tabNumber);
+			if (signatureAttribute != null) {
+				buffer
+					.append(Util.bind("disassembler.begincommentline"))	 //$NON-NLS-1$
+					.append(Util.bind("disassembler.signatureattributeheader")) //$NON-NLS-1$
+					.append(signatureAttribute.getSignature());
+				writeNewLine(buffer, lineSeparator, tabNumber);
+			}
+		}
+		decodeModifiersForField(buffer, fieldInfo.getAccessFlags());
+		if (fieldInfo.isSynthetic()) {
+			buffer.append("synthetic"); //$NON-NLS-1$
+			buffer.append(Util.bind("disassembler.space")); //$NON-NLS-1$
+		}
+		buffer.append(getSignatureForField(fieldDescriptor));
 		buffer.append(Util.bind("disassembler.space")); //$NON-NLS-1$
 		buffer.append(new String(fieldInfo.getName()));
 		IConstantValueAttribute constantValueAttribute = fieldInfo.getConstantValueAttribute();
@@ -669,52 +760,69 @@
 			}
 		}
 		buffer.append(Util.bind("disassembler.endoffieldheader")); //$NON-NLS-1$
-		IClassFileAttribute[] attributes = fieldInfo.getAttributes();
-		int length = attributes.length;
-		if (length != 0) {
-			for (int i = 0; i < length; i++) {
-				IClassFileAttribute attribute = attributes[i];
-				if (attribute != constantValueAttribute) {
-					disassemble(attribute, buffer, lineSeparator, tabNumber);
+		if (mode == DETAILED) {
+			IClassFileAttribute[] attributes = fieldInfo.getAttributes();
+			int length = attributes.length;
+			if (length != 0) {
+				for (int i = 0; i < length; i++) {
+					IClassFileAttribute attribute = attributes[i];
+					if (attribute != constantValueAttribute
+						&& attribute != signatureAttribute
+						&& !CharOperation.equals(attribute.getAttributeName(), IAttributeNamesConstants.DEPRECATED)
+						&& !CharOperation.equals(attribute.getAttributeName(), IAttributeNamesConstants.SYNTHETIC)) {
+						disassemble(attribute, buffer, lineSeparator, tabNumber);
+					}
 				}
 			}
 		}
-		if (mode == ClassFileBytesDisassembler.DETAILED) {
-			writeNewLine(buffer, lineSeparator, tabNumber);
-			CharOperation.replace(fieldDescriptor, '.', '/');
-			buffer
-				.append(Util.bind("disassembler.commentstart")) //$NON-NLS-1$
-				.append(Util.bind("classfileformat.fieldddescriptor")) //$NON-NLS-1$
-				.append(Util.bind("classfileformat.fielddescriptorindex")) //$NON-NLS-1$
-				.append(fieldInfo.getDescriptorIndex())
-				.append(Util.bind("disassembler.space")) //$NON-NLS-1$
-				.append(fieldDescriptor)
-				.append(Util.bind("disassembler.commentend")); //$NON-NLS-1$
-		}
-		writeNewLine(buffer, lineSeparator, tabNumber);
 	}
 
 	/**
 	 * Disassemble a method info header
 	 */
 	private void disassemble(IClassFileReader classFileReader, IMethodInfo methodInfo, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
-		ICodeAttribute codeAttribute = methodInfo.getCodeAttribute();
 		writeNewLine(buffer, lineSeparator, tabNumber);
+		ICodeAttribute codeAttribute = methodInfo.getCodeAttribute();
 		char[] methodDescriptor = methodInfo.getDescriptor();
-		if (mode == ClassFileBytesDisassembler.DETAILED) {
-			CharOperation.replace(methodDescriptor, '.', '/');
+		IClassFileAttribute classFileAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.SIGNATURE);
+		ISignatureAttribute signatureAttribute = (ISignatureAttribute) classFileAttribute;
+		if (mode == DETAILED) {
 			buffer
-				.append(Util.bind("disassembler.commentstart")) //$NON-NLS-1$
+				.append(Util.bind("disassembler.begincommentline")) //$NON-NLS-1$
 				.append(Util.bind("classfileformat.methoddescriptor")) //$NON-NLS-1$
 				.append(Util.bind("disassembler.constantpoolindex")) //$NON-NLS-1$
 				.append(methodInfo.getDescriptorIndex())
 				.append(Util.bind("disassembler.space")) //$NON-NLS-1$
-				.append(methodDescriptor)
-				.append(Util.bind("disassembler.commentend")); //$NON-NLS-1$
+				.append(methodDescriptor);
+			if (methodInfo.isDeprecated()) {
+				buffer.append(Util.bind("disassembler.deprecated"));//$NON-NLS-1$
+			}			
+			writeNewLine(buffer, lineSeparator, tabNumber);
+			if (signatureAttribute != null) {
+				buffer
+					.append(Util.bind("disassembler.begincommentline"))	 //$NON-NLS-1$
+					.append(Util.bind("disassembler.signatureattributeheader")) //$NON-NLS-1$
+					.append(signatureAttribute.getSignature());
+				writeNewLine(buffer, lineSeparator, tabNumber);
+			}
+			if (codeAttribute != null) {
+				buffer
+					.append(Util.bind("disassembler.begincommentline")) //$NON-NLS-1$
+					.append(Util.bind("classfileformat.maxStack")) //$NON-NLS-1$
+					.append(codeAttribute.getMaxStack())
+					.append(Util.bind("disassembler.comma"))//$NON-NLS-1$
+					.append(Util.bind("disassembler.space"))//$NON-NLS-1$
+					.append(Util.bind("classfileformat.maxLocals")) //$NON-NLS-1$
+					.append(codeAttribute.getMaxLocals());
+				writeNewLine(buffer, lineSeparator, tabNumber);
+			}
 		}		
-		writeNewLine(buffer, lineSeparator, tabNumber);
 		int accessFlags = methodInfo.getAccessFlags();
 		decodeModifiersForMethod(buffer, accessFlags);
+		if (methodInfo.isSynthetic()) {
+			buffer.append("synthetic"); //$NON-NLS-1$
+			buffer.append(Util.bind("disassembler.space")); //$NON-NLS-1$
+		}
 		CharOperation.replace(methodDescriptor, '/', '.');
 		char[] methodName = null;
 		if (methodInfo.isConstructor()) {
@@ -737,35 +845,39 @@
 				CharOperation.replace(exceptionName, '/', '.');
 				buffer
 					.append(exceptionName)
-					.append(Util.bind("disassembler.comma")); //$NON-NLS-1$
+					.append(Util.bind("disassembler.comma"))//$NON-NLS-1$
+					.append(Util.bind("disassembler.space")); //$NON-NLS-1$
 			}
 			char[] exceptionName = exceptionNames[length - 1];
 			CharOperation.replace(exceptionName, '/', '.');
 			buffer.append(exceptionName);
 		}
 		buffer.append(Util.bind("disassembler.endofmethodheader")); //$NON-NLS-1$
-		writeNewLine(buffer, lineSeparator, tabNumber + 1);
-		IClassFileAttribute[] attributes = methodInfo.getAttributes();
-		int length = attributes.length;
-		if (length != 0) {
-			for (int i = 0; i < length; i++) {
-				IClassFileAttribute attribute = attributes[i];
-				if ((attribute != codeAttribute) && (attribute != exceptionAttribute)) {
-					disassemble(attribute, buffer, lineSeparator, tabNumber);
-					writeNewLine(buffer, lineSeparator, tabNumber);
+		if (mode == DETAILED) {
+			IClassFileAttribute[] attributes = methodInfo.getAttributes();
+			int length = attributes.length;
+			if (length != 0) {
+				for (int i = 0; i < length; i++) {
+					IClassFileAttribute attribute = attributes[i];
+					if (attribute != codeAttribute
+							&& attribute != exceptionAttribute
+							&& attribute != signatureAttribute
+							&& !CharOperation.equals(attribute.getAttributeName(), IAttributeNamesConstants.DEPRECATED)
+							&& !CharOperation.equals(attribute.getAttributeName(), IAttributeNamesConstants.SYNTHETIC)) {
+						disassemble(attribute, buffer, lineSeparator, tabNumber);
+						writeNewLine(buffer, lineSeparator, tabNumber);
+					}
 				}
 			}
-		}
-		if (codeAttribute != null) {
-			disassemble(codeAttribute, buffer, lineSeparator, tabNumber);
-			writeNewLine(buffer, lineSeparator, tabNumber);
+			if (codeAttribute != null) {
+				disassemble(codeAttribute, buffer, lineSeparator, tabNumber);
+			}
 		}
 	}
 
 	private void disassemble(IClassFileAttribute classFileAttribute, StringBuffer buffer, String lineSeparator, int tabNumber) {
 		writeNewLine(buffer, lineSeparator, tabNumber + 1);
 		buffer.append(Util.bind("disassembler.genericattributeheader")); //$NON-NLS-1$
-		writeNewLine(buffer, lineSeparator, tabNumber + 2);
 		buffer
 			.append(Util.bind("disassembler.genericattributename")) //$NON-NLS-1$
 			.append(classFileAttribute.getAttributeName())
@@ -774,18 +886,8 @@
 	}
 	
 	private void disassemble(ICodeAttribute codeAttribute, StringBuffer buffer, String lineSeparator, int tabNumber) {
-		buffer
-			.append(Util.bind("disassembler.commentstart")) //$NON-NLS-1$
-			.append(Util.bind("classfileformat.maxStack")) //$NON-NLS-1$
-			.append(codeAttribute.getMaxStack())
-			.append(Util.bind("disassembler.comma")) //$NON-NLS-1$
-			.append(Util.bind("classfileformat.maxLocals")) //$NON-NLS-1$
-			.append(codeAttribute.getMaxLocals())
-			.append(Util.bind("disassembler.commentend")); //$NON-NLS-1$
-		writeNewLine(buffer, lineSeparator, tabNumber + 1);
-		buffer.append(Util.bind("disassembler.codeattributeheader")); //$NON-NLS-1$
 		writeNewLine(buffer, lineSeparator, tabNumber - 1);
-		DefaultBytecodeVisitor visitor = new DefaultBytecodeVisitor(codeAttribute.getCodeLength(), buffer, lineSeparator, tabNumber + 1);
+		DefaultBytecodeVisitor visitor = new DefaultBytecodeVisitor(codeAttribute.getCodeLength(), buffer, lineSeparator, tabNumber);
 		try {
 			codeAttribute.traverse(visitor);
 		} catch(ClassFormatException e) {
@@ -795,11 +897,12 @@
 		}
 		int exceptionTableLength = codeAttribute.getExceptionTableLength();
 		if (exceptionTableLength != 0) {
-			writeNewLine(buffer, lineSeparator, tabNumber + 1);
+			final int tabNumberForExceptionAttribute = tabNumber + 2;
+			dumpTab(tabNumberForExceptionAttribute, buffer);
 			IExceptionTableEntry[] exceptionTableEntries = codeAttribute.getExceptionTable();
 			buffer.append(Util.bind("disassembler.exceptiontableheader")); //$NON-NLS-1$
-			writeNewLine(buffer, lineSeparator, tabNumber + 2);
-			for (int i = 0; i < exceptionTableLength; i++) {
+			writeNewLine(buffer, lineSeparator, tabNumberForExceptionAttribute + 1);
+			for (int i = 0; i < exceptionTableLength - 1; i++) {
 				IExceptionTableEntry exceptionTableEntry = exceptionTableEntries[i];
 				buffer
 					.append(Util.bind("classfileformat.exceptiontablefrom")) //$NON-NLS-1$
@@ -816,15 +919,33 @@
 					CharOperation.replace(catchType, '/', '.');
 					buffer.append(catchType);
 				}
-				writeNewLine(buffer, lineSeparator, tabNumber + 2);
+				writeNewLine(buffer, lineSeparator, tabNumberForExceptionAttribute + 1);
 			}
+			IExceptionTableEntry exceptionTableEntry = exceptionTableEntries[exceptionTableLength - 1];
+			buffer
+				.append(Util.bind("classfileformat.exceptiontablefrom")) //$NON-NLS-1$
+				.append(exceptionTableEntry.getStartPC())
+				.append(Util.bind("classfileformat.exceptiontableto")) //$NON-NLS-1$
+				.append(exceptionTableEntry.getEndPC())
+				.append(Util.bind("classfileformat.exceptiontablegoto")) //$NON-NLS-1$
+				.append(exceptionTableEntry.getHandlerPC())
+				.append(Util.bind("classfileformat.exceptiontablewhen")); //$NON-NLS-1$
+			if (exceptionTableEntry.getCatchTypeIndex() == 0) {
+				buffer.append(ANY_EXCEPTION);
+			} else {
+				char[] catchType = exceptionTableEntry.getCatchType();
+				CharOperation.replace(catchType, '/', '.');
+				buffer.append(catchType);
+			}
+			writeNewLine(buffer, lineSeparator, 0);
 		}
 		ILineNumberAttribute lineNumberAttribute = codeAttribute.getLineNumberAttribute();
 		int lineAttributeLength = lineNumberAttribute == null ? 0 : lineNumberAttribute.getLineNumberTableLength();
 		if (lineAttributeLength != 0) {
-			writeNewLine(buffer, lineSeparator, tabNumber + 1);
+			int tabNumberForLineAttribute = tabNumber + 2;
+			dumpTab(tabNumberForLineAttribute, buffer);
 			buffer.append(Util.bind("disassembler.linenumberattributeheader")); //$NON-NLS-1$
-			writeNewLine(buffer, lineSeparator, tabNumber + 2);
+			writeNewLine(buffer, lineSeparator, tabNumberForLineAttribute + 1);
 			int[][] lineattributesEntries = lineNumberAttribute.getLineNumberTable();
 			for (int i = 0; i < lineAttributeLength - 1; i++) {
 				buffer
@@ -833,7 +954,7 @@
 					.append(Util.bind("classfileformat.linenumbertableto")) //$NON-NLS-1$
 					.append(lineattributesEntries[i][1])
 					.append(Util.bind("classfileformat.linenumbertableclose")); //$NON-NLS-1$
-				writeNewLine(buffer, lineSeparator, tabNumber + 2);
+				writeNewLine(buffer, lineSeparator, tabNumberForLineAttribute + 1);
 			}
 			buffer
 				.append(Util.bind("classfileformat.linenumbertablefrom")) //$NON-NLS-1$
@@ -845,12 +966,14 @@
 		ILocalVariableAttribute localVariableAttribute = codeAttribute.getLocalVariableAttribute();
 		int localVariableAttributeLength = localVariableAttribute == null ? 0 : localVariableAttribute.getLocalVariableTableLength();
 		if (localVariableAttributeLength != 0) {
-			writeNewLine(buffer, lineSeparator, tabNumber + 1);
+			int tabNumberForLocalVariableAttribute = tabNumber + 2;
+			writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute);
 			buffer.append(Util.bind("disassembler.localvariabletableattributeheader")); //$NON-NLS-1$
-			writeNewLine(buffer, lineSeparator, tabNumber + 2);
+			writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute + 1);
 			ILocalVariableTableEntry[] localVariableTableEntries = localVariableAttribute.getLocalVariableTable();
 			for (int i = 0; i < localVariableAttributeLength - 1; i++) {
 				ILocalVariableTableEntry localVariableTableEntry = localVariableTableEntries[i];
+				int index= localVariableTableEntry.getIndex();
 				int startPC = localVariableTableEntry.getStartPC();
 				int length  = localVariableTableEntry.getLength();
 				buffer
@@ -861,12 +984,13 @@
 					.append(Util.bind("classfileformat.localvariabletablelocalname")) //$NON-NLS-1$
 					.append(localVariableTableEntry.getName())
 					.append(Util.bind("classfileformat.localvariabletablelocalindex")) //$NON-NLS-1$
-					.append(localVariableTableEntry.getIndex())
-					.append(Util.bind("classfileformat.localvariabletablelocaltype")) //$NON-NLS-1$
-					.append(Signature.toCharArray(localVariableTableEntry.getDescriptor()));
-				writeNewLine(buffer, lineSeparator, tabNumber + 2);
+					.append(index)
+					.append(Util.bind("classfileformat.localvariabletablelocaltype")); //$NON-NLS-1$
+				buffer.append(localVariableTableEntry.getDescriptor());
+				writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute + 1);
 			}
 			ILocalVariableTableEntry localVariableTableEntry = localVariableTableEntries[localVariableAttributeLength - 1];
+			int index= localVariableTableEntry.getIndex();
 			int startPC = localVariableTableEntry.getStartPC();
 			int length  = localVariableTableEntry.getLength();
 			buffer
@@ -877,19 +1001,79 @@
 				.append(Util.bind("classfileformat.localvariabletablelocalname")) //$NON-NLS-1$
 				.append(localVariableTableEntry.getName())
 				.append(Util.bind("classfileformat.localvariabletablelocalindex")) //$NON-NLS-1$
-				.append(localVariableTableEntry.getIndex())
-				.append(Util.bind("classfileformat.localvariabletablelocaltype")) //$NON-NLS-1$
-				.append(Signature.toCharArray(localVariableTableEntry.getDescriptor()));
+				.append(index)
+				.append(Util.bind("classfileformat.localvariabletablelocaltype")); //$NON-NLS-1$
+			buffer.append(localVariableTableEntry.getDescriptor());
 		} 
+		ILocalVariableTypeTableAttribute localVariableTypeAttribute= getLocalVariableTypeAttribute(codeAttribute);
+		int localVariableTypeTableLength = localVariableTypeAttribute == null ? 0 : localVariableTypeAttribute.getLocalVariableTypeTableLength();
+		if (localVariableTypeTableLength != 0) {
+			int tabNumberForLocalVariableAttribute = tabNumber + 2;
+			writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute);
+			buffer.append(Util.bind("disassembler.localvariabletypetableattributeheader")); //$NON-NLS-1$
+			writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute + 1);
+			ILocalVariableTypeTableEntry[] localVariableTypeTableEntries = localVariableTypeAttribute.getLocalVariableTypeTable();
+			for (int i = 0; i < localVariableTypeTableLength - 1; i++) {
+				ILocalVariableTypeTableEntry localVariableTypeTableEntry = localVariableTypeTableEntries[i];
+				int index= localVariableTypeTableEntry.getIndex();
+				int startPC = localVariableTypeTableEntry.getStartPC();
+				int length  = localVariableTypeTableEntry.getLength();
+				buffer
+					.append(Util.bind("classfileformat.localvariabletablefrom")) //$NON-NLS-1$
+					.append(startPC)
+					.append(Util.bind("classfileformat.localvariabletableto")) //$NON-NLS-1$
+					.append(startPC + length)
+					.append(Util.bind("classfileformat.localvariabletablelocalname")) //$NON-NLS-1$
+					.append(localVariableTypeTableEntry.getName())
+					.append(Util.bind("classfileformat.localvariabletablelocalindex")) //$NON-NLS-1$
+					.append(index)
+					.append(Util.bind("classfileformat.localvariabletablelocaltype")); //$NON-NLS-1$
+				buffer.append(localVariableTypeTableEntry.getSignature());
+				writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute + 1);
+			}
+			ILocalVariableTypeTableEntry localVariableTypeTableEntry = localVariableTypeTableEntries[localVariableTypeTableLength - 1];
+			int index= localVariableTypeTableEntry.getIndex();
+			int startPC = localVariableTypeTableEntry.getStartPC();
+			int length  = localVariableTypeTableEntry.getLength();
+			buffer
+				.append(Util.bind("classfileformat.localvariabletablefrom")) //$NON-NLS-1$
+				.append(startPC)
+				.append(Util.bind("classfileformat.localvariabletableto")) //$NON-NLS-1$
+				.append(startPC + length)
+				.append(Util.bind("classfileformat.localvariabletablelocalname")) //$NON-NLS-1$
+				.append(localVariableTypeTableEntry.getName())
+				.append(Util.bind("classfileformat.localvariabletablelocalindex")) //$NON-NLS-1$
+				.append(index)
+				.append(Util.bind("classfileformat.localvariabletablelocaltype")) //$NON-NLS-1$
+				.append(localVariableTypeTableEntry.getSignature());
+		} 
+	}
+
+	private void disassemble(IEnclosingMethodAttribute enclosingMethodAttribute, StringBuffer buffer, String lineSeparator, int tabNumber) {
+		writeNewLine(buffer, lineSeparator, tabNumber + 1);
+		buffer.append(Util.bind("disassembler.enclosingmethodheader")); //$NON-NLS-1$
+		buffer
+			.append(Util.bind("disassembler.constantpoolindex")) //$NON-NLS-1$
+			.append(enclosingMethodAttribute.getEnclosingClassIndex())
+			.append(" ")//$NON-NLS-1$
+			.append(Util.bind("disassembler.constantpoolindex")) //$NON-NLS-1$
+			.append(enclosingMethodAttribute.getMethodNameAndTypeIndex())
+			.append(" ")//$NON-NLS-1$
+			.append(enclosingMethodAttribute.getEnclosingClass()) //$NON-NLS-1$
+			.append(".")//$NON-NLS-1$
+			.append(enclosingMethodAttribute.getMethodName()) //$NON-NLS-1$
+			.append(enclosingMethodAttribute.getMethodDescriptor()); //$NON-NLS-1$
 	}
 	
 	private void disassembleTypeMembers(IClassFileReader classFileReader, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
 		IFieldInfo[] fields = classFileReader.getFieldInfos();
 		for (int i = 0, max = fields.length; i < max; i++) {
+			writeNewLine(buffer, lineSeparator, tabNumber);
 			disassemble(fields[i], buffer, lineSeparator, tabNumber, mode);
 		}
 		IMethodInfo[] methods = classFileReader.getMethodInfos();
 		for (int i = 0, max = methods.length; i < max; i++) {
+			writeNewLine(buffer, lineSeparator, tabNumber);
 			disassemble(classFileReader, methods[i], buffer, lineSeparator, tabNumber, mode);
 		}
 	}
@@ -907,7 +1091,78 @@
 		return Util.bind("disassembler.description"); //$NON-NLS-1$
 	}
 
+	private IEnclosingMethodAttribute getEnclosingMethodAttribute(IClassFileReader classFileReader) {
+		IClassFileAttribute[] attributes = classFileReader.getAttributes();
+		for (int i = 0, max = attributes.length; i < max; i++) {
+			if (CharOperation.equals(attributes[i].getAttributeName(), IAttributeNamesConstants.ENCLOSING_METHOD)) {
+				return (IEnclosingMethodAttribute) attributes[i];
+			}
+		}
+		return null;
+	}
+	/**
+	 * Method getEntryFor.
+	 * @param localIndex
+	 * @param entries
+	 * @return ILocalVariableTableEntry
+	 */
+	private ILocalVariableTableEntry getEntryFor(
+		int localIndex,
+		ILocalVariableTableEntry[] entries) {
+			
+			for (int i = 0, max = entries.length; i < max; i++) {
+				ILocalVariableTableEntry entry = entries[i];
+				if (localIndex == entry.getIndex()) {
+					return entry;
+				}
+			}
+			return null;
+	}
+	private ILocalVariableTypeTableAttribute getLocalVariableTypeAttribute(ICodeAttribute codeAttribute) {
+		IClassFileAttribute[] attributes = codeAttribute.getAttributes();
+		for (int i = 0, max = attributes.length; i < max; i++) {
+			if (CharOperation.equals(attributes[i].getAttributeName(), IAttributeNamesConstants.LOCAL_VARIABLE_TYPE_TABLE)) {
+				return (ILocalVariableTypeTableAttribute) attributes[i];
+			}
+		}
+		return null;
+	}
 
+	private char[] getSignatureForField(char[] fieldDescriptor) {
+		final int length = fieldDescriptor.length;
+		char[] newFieldDescriptor = new char[length];
+		System.arraycopy(fieldDescriptor, 0, newFieldDescriptor, 0, length);
+		CharOperation.replace(newFieldDescriptor, '/', '.');
+		CharOperation.replace(newFieldDescriptor, '$', '~');
+		char[] fieldDescriptorSignature = Signature.toCharArray(newFieldDescriptor);
+		CharOperation.replace(fieldDescriptorSignature, '~', '$');
+		return fieldDescriptorSignature;
+	}
+	
+	private boolean isDeprecated(IClassFileReader classFileReader) {
+		IClassFileAttribute[] attributes = classFileReader.getAttributes();
+		for (int i = 0, max = attributes.length; i < max; i++) {
+			if (CharOperation.equals(attributes[i].getAttributeName(), IAttributeNamesConstants.DEPRECATED)) {
+				return true;
+			}
+		}
+		return false;
+	}
+	
+	private boolean isSynthetic(IClassFileReader classFileReader) {
+		int flags = classFileReader.getAccessFlags();
+		if ((flags & IModifierConstants.ACC_SYNTHETIC) != 0) {
+			return true;
+		}
+		IClassFileAttribute[] attributes = classFileReader.getAttributes();
+		for (int i = 0, max = attributes.length; i < max; i++) {
+			if (CharOperation.equals(attributes[i].getAttributeName(), IAttributeNamesConstants.SYNTHETIC)) {
+				return true;
+			}
+		}
+		return false;
+	}
+	
 	private char[][] getParameterNames(char[] methodDescriptor, ICodeAttribute codeAttribute, int accessFlags) {
 		int paramCount = Signature.getParameterCount(methodDescriptor);
 		char[][] parameterNames = new char[paramCount][];
@@ -937,27 +1192,9 @@
 		}
 		return parameterNames;
 	}
-	/**
-	 * Method getEntryFor.
-	 * @param localIndex
-	 * @param entries
-	 * @return ILocalVariableTableEntry
-	 */
-	private ILocalVariableTableEntry getEntryFor(
-		int localIndex,
-		ILocalVariableTableEntry[] entries) {
-			
-			for (int i = 0, max = entries.length; i < max; i++) {
-				ILocalVariableTableEntry entry = entries[i];
-				if (localIndex == entry.getIndex()) {
-					return entry;
-				}
-			}
-			return null;
-	}
 	
 	private void writeNewLine(StringBuffer buffer, String lineSeparator, int tabNumber) {
 		buffer.append(lineSeparator);
 		dumpTab(tabNumber, buffer);
 	}
-}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Dumper.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Dumper.java
deleted file mode 100644
index 74c40e4..0000000
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Dumper.java
+++ /dev/null
@@ -1,301 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 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 java.io.*;
-
-/**
- * A dumper knows how to dump objects in a human-readable representation to a PrintWriter.
- * Objects which implement IDumpable know how to dump themselves to a Dumper, otherwise
- * the dumper just uses toString() on the object.
- * Example:
- * <pre>
- *   Dumper dumper = new Dumper(System.out);
- *   dumper.dump(myObject);
- *   dumper.flush();
- * </pre>
- *
- * @see IDumpable
- * @see PrintWriter
- */
-public class Dumper {
-	int fTabLevel = 0;
-	PrintWriter fWriter;
-/**
- * Creates a dumper which sends output to System.out.
- */
-public Dumper() {
-	this(System.out);
-}
-/**
- * Creates a dumper which sends output to the given OutputStream.
- */
-public Dumper(OutputStream out) {
-	this(new PrintWriter(out));
-}
-/**
- * Creates a dumper which sends output to the given PrintWriter.
- */
-public Dumper(PrintWriter writer) {
-	fWriter = writer;
-}
-/**
- * Returns the class name to use for the given object.
- */
-String classNameFor(Object val) {
-	String name = val.getClass().getName();
-	int i = name.lastIndexOf('.');
-	if (i != -1) {
-		name = name.substring(i+1);
-	}
-	return name;
-}
-/**
- * Dumps the given array.
- * Prints a maximum of maxPerLine items per line.
- */
-public void dump(int[] val, int maxPerLine) {
-	int len = val.length;
-	boolean oneLine = (len <= maxPerLine);
-	if (!oneLine) {
-		++fTabLevel;
-	}
-	fWriter.print("["); //$NON-NLS-1$
-	for (int i = 0; i < len; ++i) {
-		if (!oneLine) {
-			if ((i % maxPerLine) == 0) {
-				fWriter.println();
-				tabIfNeeded();
-				fWriter.print(i);
-				fWriter.print(": "); //$NON-NLS-1$
-			}
-		}
-		fWriter.print(val[i]);
-		if (i + 1 < len) {
-			fWriter.print(", "); //$NON-NLS-1$
-		}
-	}
-	if (oneLine) {
-		fWriter.print("]"); //$NON-NLS-1$
-		fWriter.println();
-	}
-	else {
-		fWriter.println();
-		--fTabLevel;
-		tabIfNeeded();
-		fWriter.print("]"); //$NON-NLS-1$
-		fWriter.println();
-	}
-}
-/**
- * Dumps the given array.
- */
-public void dump(Object[] val) {
-	int len = val.length;
-	fWriter.print("["); //$NON-NLS-1$
-	if (len > 0) {
-		fWriter.println();
-		++fTabLevel;
-		for (int i = 0; i < len; ++i) {
-			dump(val[i]);
-		}
-		--fTabLevel;
-		tabIfNeeded();
-	}
-	fWriter.println("]"); //$NON-NLS-1$
-}
-/**
- * Dumps the given array.
- * Prints a maximum of maxPerLine items per line.
- */
-public void dump(String[] val, int maxPerLine) {
-	int len = val.length;
-	boolean oneLine = (len <= maxPerLine);
-	if (!oneLine) {
-		++fTabLevel;
-	}
-	fWriter.print("["); //$NON-NLS-1$
-	boolean newLine = !oneLine;
-	for (int i = 0; i < len; ++i) {
-		if (newLine) {
-			fWriter.println();
-			tabIfNeeded();
-		}
-		fWriter.print("\"" + val[i] + "\""); //$NON-NLS-1$ //$NON-NLS-2$
-		if (i + 1 < len) {
-			fWriter.print(", "); //$NON-NLS-1$
-		}
-		newLine = (i != 0 && (i % maxPerLine) == 0);
-	}
-	fWriter.print("]"); //$NON-NLS-1$
-	if (oneLine || newLine) {
-		fWriter.println();
-	}
-	if (!oneLine) {
-		--fTabLevel;
-	}
-}
-/**
- * Dumps the given value.
- */
-public void dump(Object val) {
-	tabIfNeeded();
-	if (val instanceof IDumpable) {
-		IDumpable dumpable = (IDumpable) val;
-		fWriter.println(classNameFor(val) + " {"); //$NON-NLS-1$
-		int originalLevel = fTabLevel;
-		++fTabLevel;
-		try {
-			dumpable.dump(this);
-		}
-		catch (Throwable t) {
-			fWriter.println("*ERR*"); //$NON-NLS-1$
-		}
-		fTabLevel = originalLevel;
-		tabIfNeeded();
-		fWriter.println("}"); //$NON-NLS-1$
-	}
-	else {
-		fWriter.println(val);
-	}
-}
-/**
- * Dumps the given value, with the given name as a prefix.
- */
-public void dump(String name, int[] val) {
-	dump(name, val, 10);
-}
-/**
- * Dumps the given array, with the given name as a prefix.
- * Prints a maximum of maxPerLine items per line.
- */
-public void dump(String name, int[] val, int maxPerLine) {
-	prefix(name);
-	dump(val, maxPerLine);
-}
-/**
- * Dumps the given value, with the given name as a prefix.
- */
-public void dump(String name, Object[] val) {
-	prefix(name);
-	dump(val);
-}
-/**
- * Dumps the given value, with the given name as a prefix.
- */
-public void dump(String name, String[] val) {
-	prefix(name);
-	dump(val, 5);
-}
-/**
- * Dumps the given value, with the given name as a prefix.
- */
-public void dump(String name, int val) {
-	prefix(name);
-	fWriter.println(val);
-}
-/**
- * Dumps the given value, with the given name as a prefix.
- */
-public void dump(String name, Object val) {
-	prefix(name);
-	fWriter.println();
-	++fTabLevel;
-	dump(val);
-	--fTabLevel;
-}
-/**
- * Dumps the given value, with the given name as a prefix.
- */
-public void dump(String name, String val) {
-	prefix(name);
-	fWriter.println(val == null ? "null" : "\"" + val + "\""); //$NON-NLS-1$ //$NON-NLS-3$ //$NON-NLS-2$
-}
-/**
- * Dumps the given value, with the given name as a prefix.
- */
-public void dump(String name, boolean val) {
-	prefix(name);
-	fWriter.println(val);
-}
-/**
- * Dumps the given message, with the given name as a prefix.
- */
-public void dumpMessage(String name, String msg) {
-	prefix(name);
-	fWriter.println(msg);
-}
-/**
- * Flushes the output writer.
- */
-public void flush() {
-	fWriter.flush();
-}
-/**
- * Returns the current tab level.
- */
-public int getTabLevel() {
-	return fTabLevel;
-}
-/**
- * Returns the underlying PrintWriter.
- */
-public PrintWriter getWriter() {
-	return fWriter;
-}
-/**
- * Increase the current tab level.
- */
-public void indent() {
-	++fTabLevel;
-}
-/**
- * Decrease the current tab level.
- */
-public void outdent() {
-	if (--fTabLevel < 0) 
-		fTabLevel = 0;
-}
-/**
- * Outputs the given prefix, tabbing first if needed.
- */
-void prefix(String name) {
-	tabIfNeeded();
-	fWriter.print(name);
-	fWriter.print(": "); //$NON-NLS-1$
-}
-/**
- * Print an object directly, without a newline.
- */
-public void print(Object obj) {
-	fWriter.print(obj);
-}
-/**
- * Print a newline directly.
- */
-public void println() {
-	fWriter.println();
-}
-/**
- * Print an object directly, with a newline.
- */
-public void println(Object obj) {
-	fWriter.println(obj);
-}
-/**
- * Outputs tabs if needed.
- */
-void tabIfNeeded() {
-	for (int i = 0; i < fTabLevel; ++i) {
-		fWriter.print("  "); //$NON-NLS-1$
-	}
-}
-}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ElementInfoConverter.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ElementInfoConverter.java
index 62b36eb..4578f63 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ElementInfoConverter.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ElementInfoConverter.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ExceptionAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ExceptionAttribute.java
index 92bde34..e9b178f 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ExceptionAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ExceptionAttribute.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ExceptionTableEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ExceptionTableEntry.java
index 128aca6..844de07 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ExceptionTableEntry.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ExceptionTableEntry.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/FieldInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/FieldInfo.java
index 8fd7dee..56aed05 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/FieldInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/FieldInfo.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -37,7 +37,7 @@
 	
 	/**
 	 * @param classFileBytes byte[]
-	 * @param offsets int[]
+	 * @param constantPool IConstantPool
 	 * @param offset int
 	 */
 	public FieldInfo(byte classFileBytes[], IConstantPool constantPool, int offset)
@@ -65,7 +65,7 @@
 			this.attributes = new IClassFileAttribute[this.attributesCount];
 		}
 		int attributesIndex = 0;
-		for (int i = 0; i < attributesCount; i++) {
+		for (int i = 0; i < this.attributesCount; i++) {
 			constantPoolEntry = constantPool.decodeEntry(u2At(classFileBytes, readOffset, offset));
 			if (constantPoolEntry.getKind() != IConstantPoolConstant.CONSTANT_Utf8) {
 				throw new ClassFormatException(ClassFormatException.INVALID_CONSTANT_POOL_ENTRY);
@@ -86,7 +86,7 @@
 			readOffset += (6 + u4At(classFileBytes, readOffset + 2, offset));
 		}
 
-		attributeBytes = readOffset;
+		this.attributeBytes = readOffset;
 	}
 	/**
 	 * @see IFieldInfo#getAccessFlags()
@@ -138,7 +138,7 @@
 	}
 
 	int sizeInBytes() {
-		return attributeBytes;
+		return this.attributeBytes;
 	}
 	/**
 	 * @see IFieldInfo#getAttributeCount()
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/HandleFactory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/HandleFactory.java
index ac570e0..fac7046 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/HandleFactory.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/HandleFactory.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -162,16 +162,13 @@
 		    int nodeIndex = -1;
 			
 		    public void push(ASTNode node) {
-		        try {
-		            this.nodeStack[++this.nodeIndex] = node;
-		        } catch (IndexOutOfBoundsException e) {
+		    	if (++this.nodeIndex >= this.nodeStack.length) 
 		            System.arraycopy(this.nodeStack, 0, this.nodeStack = new ASTNode[this.nodeStack.length*2], 0, this.nodeIndex-1);
-		            this.nodeStack[this.nodeIndex] = node;
-		        }
+	            this.nodeStack[this.nodeIndex] = node;
 		    }
 		    
 		    public void pop(ASTNode node) {
-		    	while (this.nodeIndex >= 0 && this.nodeStack[this.nodeIndex--] != node);
+		    	while (this.nodeIndex >= 0 && this.nodeStack[this.nodeIndex--] != node){/*empty*/}
 		    }
 		    
 			public boolean visit(Argument node, BlockScope scope) {
@@ -484,10 +481,10 @@
 			//  e.g. org.eclipse.swt.win32/ws/win32/swt.jar 
 			//        is NOT on the classpath of org.eclipse.swt.win32
 			IFile jarFile = (IFile)target;
-			IJavaProject javaProject = this.javaModel.getJavaProject(jarFile);
+			JavaProject javaProject = (JavaProject) this.javaModel.getJavaProject(jarFile);
 			IClasspathEntry[] classpathEntries;
 			try {
-				classpathEntries = javaProject.getResolvedClasspath(true);
+				classpathEntries = javaProject.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
 				for (int j= 0, entryCount= classpathEntries.length; j < entryCount; j++) {
 					if (classpathEntries[j].getPath().equals(jarPath)) {
 						return javaProject.getPackageFragmentRoot(jarFile);
@@ -537,7 +534,7 @@
 		for (int i= 0, projectCount= projects.length; i < projectCount; i++) {
 			try {
 				JavaProject javaProject= (JavaProject)projects[i];
-				IClasspathEntry[] classpathEntries= javaProject.getResolvedClasspath(true);
+				IClasspathEntry[] classpathEntries= javaProject.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
 				for (int j= 0, entryCount= classpathEntries.length; j < entryCount; j++) {
 					if (classpathEntries[j].getPath().equals(jarPath)) {
 						if (target instanceof IFile) {
@@ -607,7 +604,7 @@
 				IPackageFragmentRoot[] roots= javaProject.getPackageFragmentRoots();
 				for (int j= 0, rootCount= roots.length; j < rootCount; j++) {
 					PackageFragmentRoot root= (PackageFragmentRoot)roots[j];
-					if (root.getPath().isPrefixOf(path) && !Util.isExcluded(path, root.fullExclusionPatternChars())) {
+					if (root.getPath().isPrefixOf(path) && !Util.isExcluded(path, root.fullInclusionPatternChars(), root.fullExclusionPatternChars(), false)) {
 						return root;
 					}
 				}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ICacheEnumeration.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ICacheEnumeration.java
index 42a69f8..d63bd65 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ICacheEnumeration.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ICacheEnumeration.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/IDumpable.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/IDumpable.java
deleted file mode 100644
index 9ef7372..0000000
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/IDumpable.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 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;
-
-/**
- * An interface useful for debugging.  
- * Implementors know how to dump their internal state in a human-readable way
- * to a Dumper.
- *
- * @see Dumper
- */
-public interface IDumpable {
-	/**
-	 * Dumps the internal state of this object in a human-readable way.
-	 */
-	public void dump(Dumper dumper);
-}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ILRUCacheable.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ILRUCacheable.java
index 9120d5f..8df7805 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ILRUCacheable.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ILRUCacheable.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/InnerClassesAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/InnerClassesAttribute.java
index 0c24221..3ce5827 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/InnerClassesAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/InnerClassesAttribute.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -37,16 +37,16 @@
 		throws ClassFormatException {
 		super(classFileBytes, constantPool, offset);
 		this.numberOfClasses = u2At(classFileBytes, 6, offset);
-		int readOffset = 8;
 		int length = this.numberOfClasses;
 		this.entries = NO_ENTRIES;
 		if (length != 0) {
+			int readOffset = 8;
 			this.entries = new IInnerClassesAttributeEntry[length];
+			for (int i = 0; i < length; i++) {
+				this.entries[i] = new InnerClassesAttributeEntry(classFileBytes, constantPool, offset + readOffset);
+				readOffset += 8;
+			}		
 		}
-		for (int i = 0; i < length; i++) {
-			this.entries[i] = new InnerClassesAttributeEntry(classFileBytes, constantPool, offset + readOffset);
-			readOffset += 8;
-		}		
 	}
 
 	/**
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/InnerClassesAttributeEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/InnerClassesAttributeEntry.java
index 0f37fa0..c44e9b2 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/InnerClassesAttributeEntry.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/InnerClassesAttributeEntry.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/LRUCache.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/LRUCache.java
index 79dfecb..1f93358 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/LRUCache.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/LRUCache.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/LineNumberAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/LineNumberAttribute.java
index dc76f55..3b6820e 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/LineNumberAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/LineNumberAttribute.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/LocalVariableAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/LocalVariableAttribute.java
index 8b83fb9..8ca2c27 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/LocalVariableAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/LocalVariableAttribute.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/LocalVariableTableEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/LocalVariableTableEntry.java
index 0f2ea5d..0784822 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/LocalVariableTableEntry.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/LocalVariableTableEntry.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/MementoTokenizer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/MementoTokenizer.java
new file mode 100644
index 0000000..d053a83
--- /dev/null
+++ b/org.eclipse.jdt.core/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/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/MethodInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/MethodInfo.java
index ac77bcf..84186c0 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/MethodInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/MethodInfo.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -41,7 +41,7 @@
 	
 	/**
 	 * @param classFileBytes byte[]
-	 * @param offsets int[]
+	 * @param constantPool IConstantPool
 	 * @param offset int
 	 * @param decodingFlags int
 	 */
@@ -49,7 +49,7 @@
 		throws ClassFormatException {
 			
 		boolean no_code_attribute = (decodingFlags & IClassFileReader.METHOD_BODIES) == 0;
-		accessFlags = u2At(classFileBytes, 0, offset);
+		this.accessFlags = u2At(classFileBytes, 0, offset);
 		
 		this.nameIndex = u2At(classFileBytes, 2, offset);
 		IConstantPoolEntry constantPoolEntry = constantPool.decodeEntry(this.nameIndex);
@@ -103,7 +103,7 @@
 			}
 			readOffset += (6 + u4At(classFileBytes, readOffset + 2, offset));
 		}
-		attributeBytes = readOffset;
+		this.attributeBytes = readOffset;
 	}
 	/**
 	 * @see IMethodInfo#getAccessFlags()
@@ -137,14 +137,14 @@
 	 * @see IMethodInfo#isClinit()
 	 */
 	public boolean isClinit() {
-		return name[0] == '<' && name.length == 8; // Can only match <clinit>
+		return this.name[0] == '<' && this.name.length == 8; // Can only match <clinit>
 	}
 
 	/**
 	 * @see IMethodInfo#isConstructor()
 	 */
 	public boolean isConstructor() {
-		return name[0] == '<' && name.length == 6; // Can only match <init>
+		return this.name[0] == '<' && this.name.length == 6; // Can only match <init>
 	}
 
 	/**
@@ -190,7 +190,7 @@
 	}
 
 	int sizeInBytes() {
-		return attributeBytes;
+		return this.attributeBytes;
 	}
 	/**
 	 * @see IMethodInfo#getAttributes()
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/PublicScanner.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/PublicScanner.java
index 0641b66..d90b1ca 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/PublicScanner.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/PublicScanner.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -62,6 +62,7 @@
 	public int[] commentStops = new int[10];
 	public int[] commentStarts = new int[10];
 	public int commentPtr = -1; // no comment test with commentPtr value -1
+	protected int lastCommentLinePosition = -1;
 	
 	// task tag support
 	public char[][] foundTaskTags = null;
@@ -71,6 +72,7 @@
 	public int foundTaskCount = 0;
 	public char[][] taskTags = null;
 	public char[][] taskPriorities = null;
+	public boolean isTaskCaseSensitive = true;
 	
 	//diet parsing support - jump over some method body when requested
 	public boolean diet = false;
@@ -144,7 +146,7 @@
 		for (int i = 0; i < 6; i++) {
 			for (int j = 0; j < TableSize; j++) {
 				for (int k = 0; k < InternalTableSize; k++) {
-					charArray_length[i][j][k] = initCharArray;
+					this.charArray_length[i][j][k] = initCharArray;
 				}
 			}
 		}
@@ -161,7 +163,7 @@
 	public static final int BracketKinds = 3;
 
 public PublicScanner() {
-	this(false /*comment*/, false /*whitespace*/, false /*nls*/, ClassFileConstants.JDK1_3 /*sourceLevel*/, null/*taskTag*/, null/*taskPriorities*/);
+	this(false /*comment*/, false /*whitespace*/, false /*nls*/, ClassFileConstants.JDK1_3 /*sourceLevel*/, null/*taskTag*/, null/*taskPriorities*/, true /*taskCaseSensitive*/);
 }
 
 public PublicScanner(
@@ -170,7 +172,8 @@
 	boolean checkNonExternalizedStringLiterals, 
 	long sourceLevel,
 	char[][] taskTags,
-	char[][] taskPriorities) {
+	char[][] taskPriorities,
+	boolean isTaskCaseSensitive) {
 
 	this.eofPosition = Integer.MAX_VALUE;
 	this.tokenizeComments = tokenizeComments;
@@ -179,22 +182,24 @@
 	this.assertMode = sourceLevel >= ClassFileConstants.JDK1_4;
 	this.taskTags = taskTags;
 	this.taskPriorities = taskPriorities;
+	this.isTaskCaseSensitive = isTaskCaseSensitive;
 }
 
 public  final boolean atEnd() {
 	// This code is not relevant if source is 
 	// Only a part of the real stream input
 
-	return source.length == currentPosition;
+	return this.source.length == this.currentPosition;
 }
 
 private void checkNonExternalizedString() {
-	if (currentLine == null) 
+	if (this.currentLine == null) 
 		return;
-	parseTags(currentLine);
+	parseTags(this.currentLine);
 }
 
 // chech presence of task: tags
+// TODO (frederic) see if we need to take unicode characters into account...
 public void checkTaskTag(int commentStart, int commentEnd) {
 	char[] src = this.source;
 	
@@ -204,56 +209,64 @@
 		return;
 	}
 	int foundTaskIndex = this.foundTaskCount;
-	char previous = '/';
+	char previous = src[commentStart+1]; // should be '*' or '/'
 	nextChar : for (
-		int i = commentStart + 1; i < commentEnd && i < this.eofPosition; i++) {
+		int i = commentStart + 2; i < commentEnd && i < this.eofPosition; i++) {
 		char[] tag = null;
 		char[] priority = null;
-		// check for tag occurrence
-		nextTag : for (int itag = 0; itag < this.taskTags.length; itag++) {
-			tag = this.taskTags[itag];
-			int tagLength = tag.length;
-			if (tagLength == 0) continue nextTag;
-
-			// ensure tag is not leaded with letter if tag starts with a letter
-			if (Character.isLetterOrDigit(tag[0])) {
-				if (Character.isLetterOrDigit(previous)) {
-					continue nextTag;
+		// check for tag occurrence only if not ambiguous with javadoc tag
+		if (previous != '@') {
+			nextTag : for (int itag = 0; itag < this.taskTags.length; itag++) {
+				tag = this.taskTags[itag];
+				int tagLength = tag.length;
+				if (tagLength == 0) continue nextTag;
+	
+				// ensure tag is not leaded with letter if tag starts with a letter
+				if (Character.isJavaIdentifierStart(tag[0])) {
+					if (Character.isJavaIdentifierPart(previous)) {
+						continue nextTag;
+					}
 				}
+	
+				for (int t = 0; t < tagLength; t++) {
+					char sc, tc;
+					int x = i+t;
+					if (x >= this.eofPosition || x >= commentEnd) continue nextTag;
+					if ((sc = src[i + t]) != (tc = tag[t])) { 																					// case sensitive check
+						if (this.isTaskCaseSensitive || (Character.toLowerCase(sc) != Character.toLowerCase(tc))) { 	// case insensitive check
+							continue nextTag;
+						}
+					}
+				}
+				// ensure tag is not followed with letter if tag finishes with a letter
+				if (i+tagLength < commentEnd && Character.isJavaIdentifierPart(src[i+tagLength-1])) {
+					if (Character.isJavaIdentifierPart(src[i + tagLength]))
+						continue nextTag;
+				}
+				if (this.foundTaskTags == null) {
+					this.foundTaskTags = new char[5][];
+					this.foundTaskMessages = new char[5][];
+					this.foundTaskPriorities = new char[5][];
+					this.foundTaskPositions = new int[5][];
+				} else if (this.foundTaskCount == this.foundTaskTags.length) {
+					System.arraycopy(this.foundTaskTags, 0, this.foundTaskTags = new char[this.foundTaskCount * 2][], 0, this.foundTaskCount);
+					System.arraycopy(this.foundTaskMessages, 0, this.foundTaskMessages = new char[this.foundTaskCount * 2][], 0, this.foundTaskCount);
+					System.arraycopy(this.foundTaskPriorities, 0, this.foundTaskPriorities = new char[this.foundTaskCount * 2][], 0, this.foundTaskCount);
+					System.arraycopy(this.foundTaskPositions, 0, this.foundTaskPositions = new int[this.foundTaskCount * 2][], 0, this.foundTaskCount);
+				}
+				
+				priority = this.taskPriorities != null && itag < this.taskPriorities.length
+							? this.taskPriorities[itag]
+							: null;
+				
+				this.foundTaskTags[this.foundTaskCount] = tag;
+				this.foundTaskPriorities[this.foundTaskCount] = priority;
+				this.foundTaskPositions[this.foundTaskCount] = new int[] { i, i + tagLength - 1 };
+				this.foundTaskMessages[this.foundTaskCount] = CharOperation.NO_CHAR;
+				this.foundTaskCount++;
+				i += tagLength - 1; // will be incremented when looping
+				break nextTag;
 			}
-
-			for (int t = 0; t < tagLength; t++) {
-				if (src[i + t] != tag[t])
-					continue nextTag;
-			}
-			// ensure tag is not followed with letter if tag finishes with a letter
-			if (i+tagLength < commentEnd && Character.isLetterOrDigit(src[i+tagLength-1])) {
-				if (Character.isLetterOrDigit(src[i + tagLength]))
-					continue nextTag;
-			}
-			if (this.foundTaskTags == null) {
-				this.foundTaskTags = new char[5][];
-				this.foundTaskMessages = new char[5][];
-				this.foundTaskPriorities = new char[5][];
-				this.foundTaskPositions = new int[5][];
-			} else if (this.foundTaskCount == this.foundTaskTags.length) {
-				System.arraycopy(this.foundTaskTags, 0, this.foundTaskTags = new char[this.foundTaskCount * 2][], 0, this.foundTaskCount);
-				System.arraycopy(this.foundTaskMessages, 0, this.foundTaskMessages = new char[this.foundTaskCount * 2][], 0, this.foundTaskCount);
-				System.arraycopy(this.foundTaskPriorities, 0, this.foundTaskPriorities = new char[this.foundTaskCount * 2][], 0, this.foundTaskCount);
-				System.arraycopy(this.foundTaskPositions, 0, this.foundTaskPositions = new int[this.foundTaskCount * 2][], 0, this.foundTaskCount);
-			}
-			
-			priority = this.taskPriorities != null && itag < this.taskPriorities.length
-						? this.taskPriorities[itag]
-						: null;
-			
-			this.foundTaskTags[this.foundTaskCount] = tag;
-			this.foundTaskPriorities[this.foundTaskCount] = priority;
-			this.foundTaskPositions[this.foundTaskCount] = new int[] { i, i + tagLength - 1 };
-			this.foundTaskMessages[this.foundTaskCount] = CharOperation.NO_CHAR;
-			this.foundTaskCount++;
-			i += tagLength - 1; // will be incremented when looping
-			break nextTag;
 		}
 		previous = src[i];
 	}
@@ -305,16 +318,16 @@
 	//return the token REAL source (aka unicodes are precomputed)
 
 	char[] result;
-	if (withoutUnicodePtr != 0) {
+	if (this.withoutUnicodePtr != 0) {
 		//0 is used as a fast test flag so the real first char is in position 1
 		System.arraycopy(
-			withoutUnicodeBuffer, 
+			this.withoutUnicodeBuffer, 
 			1, 
-			result = new char[withoutUnicodePtr], 
+			result = new char[this.withoutUnicodePtr], 
 			0, 
-			withoutUnicodePtr); 
+			this.withoutUnicodePtr); 
 	} else {
-		int length = currentPosition - startPosition;
+		int length = this.currentPosition - this.startPosition;
 		if (length == this.source.length) return this.source;
 		switch (length) { // see OptimizedLength
 			case 1 :
@@ -331,7 +344,7 @@
 				return optimizedCurrentTokenSource6();
 		}
 		//no optimization
-		System.arraycopy(source, startPosition, result = new char[length], 0, length);
+		System.arraycopy(this.source, this.startPosition, result = new char[length], 0, length);
 	}
 	return result;
 }
@@ -342,20 +355,20 @@
 	// Return the token REAL source (aka unicodes are precomputed)
 
 	char[] result;
-	if (withoutUnicodePtr != 0)
+	if (this.withoutUnicodePtr != 0)
 		// 0 is used as a fast test flag so the real first char is in position 1
 		System.arraycopy(
-			withoutUnicodeBuffer, 
+			this.withoutUnicodeBuffer, 
 			1, 
-			result = new char[withoutUnicodePtr], 
+			result = new char[this.withoutUnicodePtr], 
 			0, 
-			withoutUnicodePtr); 
+			this.withoutUnicodePtr); 
 	else {
 		int length;
 		System.arraycopy(
-			source, 
-			startPosition, 
-			result = new char[length = currentPosition - startPosition], 
+			this.source, 
+			this.startPosition, 
+			result = new char[length = this.currentPosition - this.startPosition], 
 			0, 
 			length); 
 	}
@@ -366,17 +379,17 @@
 	//REMOVE the two " that are at the beginning and the end.
 
 	char[] result;
-	if (withoutUnicodePtr != 0)
+	if (this.withoutUnicodePtr != 0)
 		//0 is used as a fast test flag so the real first char is in position 1
-		System.arraycopy(withoutUnicodeBuffer, 2,
+		System.arraycopy(this.withoutUnicodeBuffer, 2,
 		//2 is 1 (real start) + 1 (to jump over the ")
-		result = new char[withoutUnicodePtr - 2], 0, withoutUnicodePtr - 2);
+		result = new char[this.withoutUnicodePtr - 2], 0, this.withoutUnicodePtr - 2);
 	else {
 		int length;
 		System.arraycopy(
-			source, 
-			startPosition + 1, 
-			result = new char[length = currentPosition - startPosition - 2], 
+			this.source, 
+			this.startPosition + 1, 
+			result = new char[length = this.currentPosition - this.startPosition - 2], 
 			0, 
 			length); 
 	}
@@ -386,10 +399,17 @@
 public final char[] getRawTokenSource() {
 	int length = this.currentPosition - this.startPosition;
 	char[] tokenSource = new char[length];
-	System.arraycopy(source, this.startPosition, tokenSource, 0, length);
+	System.arraycopy(this.source, this.startPosition, tokenSource, 0, length);
 	return tokenSource;	
 }
 	
+public final char[] getRawTokenSourceEnd() {
+	int length = this.eofPosition - this.currentPosition - 1;
+	char[] sourceEnd = new char[length];
+	System.arraycopy(this.source, this.currentPosition, sourceEnd, 0, length);
+	return sourceEnd;	
+}
+	
 public int getCurrentTokenStartPosition(){
 	return this.startPosition;
 }
@@ -403,22 +423,22 @@
  */
 public final int getLineEnd(int lineNumber) {
 
-	if (lineEnds == null) 
+	if (this.lineEnds == null) 
 		return -1;
-	if (lineNumber > lineEnds.length+1) 
+	if (lineNumber > this.lineEnds.length+1) 
 		return -1;
 	if (lineNumber <= 0) 
 		return -1;
-	if (lineNumber == lineEnds.length + 1) 
-		return eofPosition;
-	return lineEnds[lineNumber-1]; // next line start one character behind the lineEnd of the previous line
+	if (lineNumber == this.lineEnds.length + 1) 
+		return this.eofPosition;
+	return this.lineEnds[lineNumber-1]; // next line start one character behind the lineEnd of the previous line
 }
 
 public final int[] getLineEnds() {
 	//return a bounded copy of this.lineEnds 
 
 	int[] copy;
-	System.arraycopy(lineEnds, 0, copy = new int[linePtr + 1], 0, linePtr + 1);
+	System.arraycopy(this.lineEnds, 0, copy = new int[this.linePtr + 1], 0, this.linePtr + 1);
 	return copy;
 }
 
@@ -431,67 +451,64 @@
  * e.g.	getLineStart(1) --> 0	indicates that the first line starts at character 0.
  *
  * In case the given line number is inconsistent, answers -1.
+ * 
+ * @param lineNumber int
+ * @return int
  */
 public final int getLineStart(int lineNumber) {
 
-	if (lineEnds == null) 
+	if (this.lineEnds == null) 
 		return -1;
-	if (lineNumber > lineEnds.length + 1) 
+	if (lineNumber > this.lineEnds.length + 1) 
 		return -1;
 	if (lineNumber <= 0) 
 		return -1;
 	
 	if (lineNumber == 1) 
-		return initialPosition;
-	return lineEnds[lineNumber-2]+1; // next line start one character behind the lineEnd of the previous line
+		return this.initialPosition;
+	return this.lineEnds[lineNumber-2]+1; // next line start one character behind the lineEnd of the previous line
 }
 public final int getNextChar() {
 	try {
-		if (((currentCharacter = source[currentPosition++]) == '\\')
-			&& (source[currentPosition] == 'u')) {
+		if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
+			&& (this.source[this.currentPosition] == 'u')) {
 			//-------------unicode traitement ------------
 			int c1, c2, c3, c4;
 			int unicodeSize = 6;
-			currentPosition++;
-			while (source[currentPosition] == 'u') {
-				currentPosition++;
+			this.currentPosition++;
+			while (this.source[this.currentPosition] == 'u') {
+				this.currentPosition++;
 				unicodeSize++;
 			}
 
-			if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15
+			if (((c1 = Character.getNumericValue(this.source[this.currentPosition++])) > 15
 				|| c1 < 0)
-				|| ((c2 = Character.getNumericValue(source[currentPosition++])) > 15 || c2 < 0)
-				|| ((c3 = Character.getNumericValue(source[currentPosition++])) > 15 || c3 < 0)
-				|| ((c4 = Character.getNumericValue(source[currentPosition++])) > 15 || c4 < 0)) {
+				|| ((c2 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c2 < 0)
+				|| ((c3 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c3 < 0)
+				|| ((c4 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c4 < 0)) {
 				return -1;
 			}
 
-			currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+			this.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
 
-			unicodeAsBackSlash = currentCharacter == '\\';
+			this.unicodeAsBackSlash = this.currentCharacter == '\\';
 
 			//need the unicode buffer
-			if (withoutUnicodePtr == 0) {
+			if (this.withoutUnicodePtr == 0) {
 				//buffer all the entries that have been left aside....
-				withoutUnicodePtr = currentPosition - unicodeSize - startPosition;
-				System.arraycopy(
-					source, 
-					startPosition, 
-					withoutUnicodeBuffer, 
-					1, 
-					withoutUnicodePtr); 
+			    unicodeInitializeBuffer(this.currentPosition - unicodeSize - this.startPosition);
 			}
 			//fill the buffer with the char
-			withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
-			return currentCharacter;
+			unicodeStoreAt(++this.withoutUnicodePtr);
+			return this.currentCharacter;
 
 		} //-------------end unicode traitement--------------
 		else {
-			unicodeAsBackSlash = false;
-			if (withoutUnicodePtr != 0) {
-				withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+			this.unicodeAsBackSlash = false;
+			if (this.withoutUnicodePtr != 0) {
+			    unicodeStoreAt(++this.withoutUnicodePtr);
 			}
-			return currentCharacter;
+			return this.currentCharacter;
 		}
 	} catch (IndexOutOfBoundsException e) {
 		return -1;
@@ -508,64 +525,63 @@
 
 	//ALL getNextChar.... ARE OPTIMIZED COPIES 
 
-	int temp = currentPosition;
+	if (this.currentPosition >= this.source.length) { // handle the obvious case upfront
+		this.unicodeAsBackSlash = false;
+		return false;
+	}
+
+	int temp = this.currentPosition;
 	try {
-		if (((currentCharacter = source[currentPosition++]) == '\\')
-			&& (source[currentPosition] == 'u')) {
+		if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
+			&& (this.source[this.currentPosition] == 'u')) {
 			//-------------unicode traitement ------------
 			int c1, c2, c3, c4;
 			int unicodeSize = 6;
-			currentPosition++;
-			while (source[currentPosition] == 'u') {
-				currentPosition++;
+			this.currentPosition++;
+			while (this.source[this.currentPosition] == 'u') {
+				this.currentPosition++;
 				unicodeSize++;
 			}
 
-			if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15
+			if (((c1 = Character.getNumericValue(this.source[this.currentPosition++])) > 15
 				|| c1 < 0)
-				|| ((c2 = Character.getNumericValue(source[currentPosition++])) > 15 || c2 < 0)
-				|| ((c3 = Character.getNumericValue(source[currentPosition++])) > 15 || c3 < 0)
-				|| ((c4 = Character.getNumericValue(source[currentPosition++])) > 15 || c4 < 0)) {
-				currentPosition = temp;
+				|| ((c2 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c2 < 0)
+				|| ((c3 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c3 < 0)
+				|| ((c4 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c4 < 0)) {
+				this.currentPosition = temp;
 				return false;
 			}
 
-			currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
-			if (currentCharacter != testedChar) {
-				currentPosition = temp;
+			this.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+			if (this.currentCharacter != testedChar) {
+				this.currentPosition = temp;
 				return false;
 			}
-			unicodeAsBackSlash = currentCharacter == '\\';
+			this.unicodeAsBackSlash = this.currentCharacter == '\\';
 
 			//need the unicode buffer
-			if (withoutUnicodePtr == 0) {
+			if (this.withoutUnicodePtr == 0) {
 				//buffer all the entries that have been left aside....
-				withoutUnicodePtr = currentPosition - unicodeSize - startPosition;
-				System.arraycopy(
-					source, 
-					startPosition, 
-					withoutUnicodeBuffer, 
-					1, 
-					withoutUnicodePtr); 
+			    unicodeInitializeBuffer(this.currentPosition - unicodeSize - this.startPosition);
 			}
 			//fill the buffer with the char
-			withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+			unicodeStoreAt(++this.withoutUnicodePtr);
 			return true;
 
 		} //-------------end unicode traitement--------------
 		else {
-			if (currentCharacter != testedChar) {
-				currentPosition = temp;
+			if (this.currentCharacter != testedChar) {
+				this.currentPosition = temp;
 				return false;
 			}
-			unicodeAsBackSlash = false;
-			if (withoutUnicodePtr != 0)
-				withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+			this.unicodeAsBackSlash = false;
+			if (this.withoutUnicodePtr != 0)
+				unicodeStoreAt(++this.withoutUnicodePtr);
 			return true;
 		}
 	} catch (IndexOutOfBoundsException e) {
-		unicodeAsBackSlash = false;
-		currentPosition = temp;
+		this.unicodeAsBackSlash = false;
+		this.currentPosition = temp;
 		return false;
 	}
 }
@@ -580,73 +596,69 @@
 	//On false, no side effect has occured.
 
 	//ALL getNextChar.... ARE OPTIMIZED COPIES 
+	if (this.currentPosition >= this.source.length) // handle the obvious case upfront
+		return -1;
 
-	int temp = currentPosition;
+	int temp = this.currentPosition;
 	try {
 		int result;
-		if (((currentCharacter = source[currentPosition++]) == '\\')
-			&& (source[currentPosition] == 'u')) {
+		if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
+			&& (this.source[this.currentPosition] == 'u')) {
 			//-------------unicode traitement ------------
 			int c1, c2, c3, c4;
 			int unicodeSize = 6;
-			currentPosition++;
-			while (source[currentPosition] == 'u') {
-				currentPosition++;
+			this.currentPosition++;
+			while (this.source[this.currentPosition] == 'u') {
+				this.currentPosition++;
 				unicodeSize++;
 			}
 
-			if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15
+			if (((c1 = Character.getNumericValue(this.source[this.currentPosition++])) > 15
 				|| c1 < 0)
-				|| ((c2 = Character.getNumericValue(source[currentPosition++])) > 15 || c2 < 0)
-				|| ((c3 = Character.getNumericValue(source[currentPosition++])) > 15 || c3 < 0)
-				|| ((c4 = Character.getNumericValue(source[currentPosition++])) > 15 || c4 < 0)) {
-				currentPosition = temp;
+				|| ((c2 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c2 < 0)
+				|| ((c3 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c3 < 0)
+				|| ((c4 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c4 < 0)) {
+				this.currentPosition = temp;
 				return 2;
 			}
 
-			currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
-			if (currentCharacter == testedChar1)
+			this.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+			if (this.currentCharacter == testedChar1)
 				result = 0;
 			else
-				if (currentCharacter == testedChar2)
+				if (this.currentCharacter == testedChar2)
 					result = 1;
 				else {
-					currentPosition = temp;
+					this.currentPosition = temp;
 					return -1;
 				}
 
 			//need the unicode buffer
-			if (withoutUnicodePtr == 0) {
+			if (this.withoutUnicodePtr == 0) {
 				//buffer all the entries that have been left aside....
-				withoutUnicodePtr = currentPosition - unicodeSize - startPosition;
-				System.arraycopy(
-					source, 
-					startPosition, 
-					withoutUnicodeBuffer, 
-					1, 
-					withoutUnicodePtr); 
+				unicodeInitializeBuffer(this.currentPosition - unicodeSize - this.startPosition);
 			}
 			//fill the buffer with the char
-			withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+			unicodeStoreAt(++this.withoutUnicodePtr);
 			return result;
 		} //-------------end unicode traitement--------------
 		else {
-			if (currentCharacter == testedChar1)
+			if (this.currentCharacter == testedChar1)
 				result = 0;
 			else
-				if (currentCharacter == testedChar2)
+				if (this.currentCharacter == testedChar2)
 					result = 1;
 				else {
-					currentPosition = temp;
+					this.currentPosition = temp;
 					return -1;
 				}
 
-			if (withoutUnicodePtr != 0)
-				withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+			if (this.withoutUnicodePtr != 0)
+				unicodeStoreAt(++this.withoutUnicodePtr);
 			return result;
 		}
 	} catch (IndexOutOfBoundsException e) {
-		currentPosition = temp;
+		this.currentPosition = temp;
 		return -1;
 	}
 }
@@ -660,61 +672,57 @@
 	//On false, no side effect has occured.
 
 	//ALL getNextChar.... ARE OPTIMIZED COPIES 
+	if (this.currentPosition >= this.source.length) // handle the obvious case upfront
+		return false;
 
-	int temp = currentPosition;
+	int temp = this.currentPosition;
 	try {
-		if (((currentCharacter = source[currentPosition++]) == '\\')
-			&& (source[currentPosition] == 'u')) {
+		if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
+			&& (this.source[this.currentPosition] == 'u')) {
 			//-------------unicode traitement ------------
 			int c1, c2, c3, c4;
 			int unicodeSize = 6;
-			currentPosition++;
-			while (source[currentPosition] == 'u') {
-				currentPosition++;
+			this.currentPosition++;
+			while (this.source[this.currentPosition] == 'u') {
+				this.currentPosition++;
 				unicodeSize++;
 			}
 
-			if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15
+			if (((c1 = Character.getNumericValue(this.source[this.currentPosition++])) > 15
 				|| c1 < 0)
-				|| ((c2 = Character.getNumericValue(source[currentPosition++])) > 15 || c2 < 0)
-				|| ((c3 = Character.getNumericValue(source[currentPosition++])) > 15 || c3 < 0)
-				|| ((c4 = Character.getNumericValue(source[currentPosition++])) > 15 || c4 < 0)) {
-				currentPosition = temp;
+				|| ((c2 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c2 < 0)
+				|| ((c3 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c3 < 0)
+				|| ((c4 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c4 < 0)) {
+				this.currentPosition = temp;
 				return false;
 			}
 
-			currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
-			if (!Character.isDigit(currentCharacter)) {
-				currentPosition = temp;
+			this.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+			if (!Character.isDigit(this.currentCharacter)) {
+				this.currentPosition = temp;
 				return false;
 			}
 
 			//need the unicode buffer
-			if (withoutUnicodePtr == 0) {
+			if (this.withoutUnicodePtr == 0) {
 				//buffer all the entries that have been left aside....
-				withoutUnicodePtr = currentPosition - unicodeSize - startPosition;
-				System.arraycopy(
-					source, 
-					startPosition, 
-					withoutUnicodeBuffer, 
-					1, 
-					withoutUnicodePtr); 
+				unicodeInitializeBuffer(this.currentPosition - unicodeSize - this.startPosition);
 			}
 			//fill the buffer with the char
-			withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+			unicodeStoreAt(++this.withoutUnicodePtr);
 			return true;
 		} //-------------end unicode traitement--------------
 		else {
-			if (!Character.isDigit(currentCharacter)) {
-				currentPosition = temp;
+			if (!Character.isDigit(this.currentCharacter)) {
+				this.currentPosition = temp;
 				return false;
 			}
-			if (withoutUnicodePtr != 0)
-				withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+			if (this.withoutUnicodePtr != 0)
+				unicodeStoreAt(++this.withoutUnicodePtr);
 			return true;
 		}
 	} catch (IndexOutOfBoundsException e) {
-		currentPosition = temp;
+		this.currentPosition = temp;
 		return false;
 	}
 }
@@ -728,61 +736,57 @@
 	//On false, no side effect has occured.
 
 	//ALL getNextChar.... ARE OPTIMIZED COPIES 
+	if (this.currentPosition >= this.source.length) // handle the obvious case upfront
+		return false;
 
-	int temp = currentPosition;
+	int temp = this.currentPosition;
 	try {
-		if (((currentCharacter = source[currentPosition++]) == '\\')
-			&& (source[currentPosition] == 'u')) {
+		if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
+			&& (this.source[this.currentPosition] == 'u')) {
 			//-------------unicode traitement ------------
 			int c1, c2, c3, c4;
 			int unicodeSize = 6;
-			currentPosition++;
-			while (source[currentPosition] == 'u') {
-				currentPosition++;
+			this.currentPosition++;
+			while (this.source[this.currentPosition] == 'u') {
+				this.currentPosition++;
 				unicodeSize++;
 			}
 
-			if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15
+			if (((c1 = Character.getNumericValue(this.source[this.currentPosition++])) > 15
 				|| c1 < 0)
-				|| ((c2 = Character.getNumericValue(source[currentPosition++])) > 15 || c2 < 0)
-				|| ((c3 = Character.getNumericValue(source[currentPosition++])) > 15 || c3 < 0)
-				|| ((c4 = Character.getNumericValue(source[currentPosition++])) > 15 || c4 < 0)) {
-				currentPosition = temp;
+				|| ((c2 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c2 < 0)
+				|| ((c3 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c3 < 0)
+				|| ((c4 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c4 < 0)) {
+				this.currentPosition = temp;
 				return false;
 			}
 
-			currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
-			if (Character.digit(currentCharacter, radix) == -1) {
-				currentPosition = temp;
+			this.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+			if (Character.digit(this.currentCharacter, radix) == -1) {
+				this.currentPosition = temp;
 				return false;
 			}
 
 			//need the unicode buffer
-			if (withoutUnicodePtr == 0) {
+			if (this.withoutUnicodePtr == 0) {
 				//buffer all the entries that have been left aside....
-				withoutUnicodePtr = currentPosition - unicodeSize - startPosition;
-				System.arraycopy(
-					source, 
-					startPosition, 
-					withoutUnicodeBuffer, 
-					1, 
-					withoutUnicodePtr); 
+				unicodeInitializeBuffer(this.currentPosition - unicodeSize - this.startPosition);
 			}
 			//fill the buffer with the char
-			withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+			unicodeStoreAt(++this.withoutUnicodePtr);
 			return true;
 		} //-------------end unicode traitement--------------
 		else {
-			if (Character.digit(currentCharacter, radix) == -1) {
-				currentPosition = temp;
+			if (Character.digit(this.currentCharacter, radix) == -1) {
+				this.currentPosition = temp;
 				return false;
 			}
-			if (withoutUnicodePtr != 0)
-				withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+			if (this.withoutUnicodePtr != 0)
+				unicodeStoreAt(++this.withoutUnicodePtr);
 			return true;
 		}
 	} catch (IndexOutOfBoundsException e) {
-		currentPosition = temp;
+		this.currentPosition = temp;
 		return false;
 	}
 }
@@ -796,96 +800,92 @@
 	//On false, no side effect has occured.
 
 	//ALL getNextChar.... ARE OPTIMIZED COPIES 
+	if (this.currentPosition >= this.source.length) // handle the obvious case upfront
+		return false;
 
-	int temp = currentPosition;
+	int temp = this.currentPosition;
 	try {
-		if (((currentCharacter = source[currentPosition++]) == '\\')
-			&& (source[currentPosition] == 'u')) {
+		if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
+			&& (this.source[this.currentPosition] == 'u')) {
 			//-------------unicode traitement ------------
 			int c1, c2, c3, c4;
 			int unicodeSize = 6;
-			currentPosition++;
-			while (source[currentPosition] == 'u') {
-				currentPosition++;
+			this.currentPosition++;
+			while (this.source[this.currentPosition] == 'u') {
+				this.currentPosition++;
 				unicodeSize++;
 			}
 
-			if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15
+			if (((c1 = Character.getNumericValue(this.source[this.currentPosition++])) > 15
 				|| c1 < 0)
-				|| ((c2 = Character.getNumericValue(source[currentPosition++])) > 15 || c2 < 0)
-				|| ((c3 = Character.getNumericValue(source[currentPosition++])) > 15 || c3 < 0)
-				|| ((c4 = Character.getNumericValue(source[currentPosition++])) > 15 || c4 < 0)) {
-				currentPosition = temp;
+				|| ((c2 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c2 < 0)
+				|| ((c3 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c3 < 0)
+				|| ((c4 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c4 < 0)) {
+				this.currentPosition = temp;
 				return false;
 			}
 
-			currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
-			if (!Character.isJavaIdentifierPart(currentCharacter)) {
-				currentPosition = temp;
+			this.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+			if (!Character.isJavaIdentifierPart(this.currentCharacter)) {
+				this.currentPosition = temp;
 				return false;
 			}
 
 			//need the unicode buffer
-			if (withoutUnicodePtr == 0) {
+			if (this.withoutUnicodePtr == 0) {
 				//buffer all the entries that have been left aside....
-				withoutUnicodePtr = currentPosition - unicodeSize - startPosition;
-				System.arraycopy(
-					source, 
-					startPosition, 
-					withoutUnicodeBuffer, 
-					1, 
-					withoutUnicodePtr); 
+				unicodeInitializeBuffer(this.currentPosition - unicodeSize - this.startPosition);
 			}
 			//fill the buffer with the char
-			withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+		    unicodeStoreAt(++this.withoutUnicodePtr);
 			return true;
 		} //-------------end unicode traitement--------------
 		else {
-			if (!Character.isJavaIdentifierPart(currentCharacter)) {
-				currentPosition = temp;
+			if (!Character.isJavaIdentifierPart(this.currentCharacter)) {
+				this.currentPosition = temp;
 				return false;
 			}
 
-			if (withoutUnicodePtr != 0)
-				withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+			if (this.withoutUnicodePtr != 0)
+			    unicodeStoreAt(++this.withoutUnicodePtr);
 			return true;
 		}
 	} catch (IndexOutOfBoundsException e) {
-		currentPosition = temp;
+		this.currentPosition = temp;
 		return false;
 	}
 }
 public int getNextToken() throws InvalidInputException {
 	this.wasAcr = false;
-	if (diet) {
+	if (this.diet) {
 		jumpOverMethodBody();
-		diet = false;
-		return currentPosition > source.length ? TokenNameEOF : TokenNameRBRACE;
+		this.diet = false;
+		return this.currentPosition > this.source.length ? TokenNameEOF : TokenNameRBRACE;
 	}
 	int whiteStart = 0;
 	try {
 		while (true) { //loop for jumping over comments
-			withoutUnicodePtr = 0;
+			this.withoutUnicodePtr = 0;
 			//start with a new token (even comment written with unicode )
 
 			// ---------Consume white space and handles startPosition---------
-			whiteStart = currentPosition;
+			whiteStart = this.currentPosition;
 			boolean isWhiteSpace, hasWhiteSpaces = false;
 			int offset = 0;
 			do {
-				startPosition = currentPosition;
+				this.startPosition = this.currentPosition;
 				boolean checkIfUnicode = false;
 				try {
-					checkIfUnicode = ((currentCharacter = source[currentPosition++]) == '\\')
-					&& (source[currentPosition] == 'u');
+					checkIfUnicode = ((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
+						&& (this.source[this.currentPosition] == 'u');
 				} catch(IndexOutOfBoundsException e) {
-					if (tokenizeWhiteSpace && (whiteStart != currentPosition - 1)) {
+					if (this.tokenizeWhiteSpace && (whiteStart != this.currentPosition - 1)) {
 						// reposition scanner in case we are interested by spaces as tokens
-						currentPosition--;
-						startPosition = whiteStart;
+						this.currentPosition--;
+						this.startPosition = whiteStart;
 						return TokenNameWHITESPACE;
 					}
-					if (currentPosition > eofPosition)
+					if (this.currentPosition > this.eofPosition)
 						return TokenNameEOF;
 				}
 				if (checkIfUnicode) {
@@ -893,34 +893,34 @@
 					offset = 6;
 				} else {
 					offset = 1;
-					if ((currentCharacter == '\r') || (currentCharacter == '\n')) {
+					if ((this.currentCharacter == '\r') || (this.currentCharacter == '\n')) {
 						checkNonExternalizedString();
-						if (recordLineSeparator) {
+						if (this.recordLineSeparator) {
 							pushLineSeparator();
 						} else {
-							currentLine = null;
+							this.currentLine = null;
 						}
 					}
 					isWhiteSpace = 
-						(currentCharacter == ' ') || CharOperation.isWhitespace(currentCharacter); 
+						(this.currentCharacter == ' ') || CharOperation.isWhitespace(this.currentCharacter); 
 				}
 				if (isWhiteSpace) {
 					hasWhiteSpaces = true;
 				}
 			} while (isWhiteSpace);
-			if (tokenizeWhiteSpace && hasWhiteSpaces) {
+			if (this.tokenizeWhiteSpace && hasWhiteSpaces) {
 				// reposition scanner in case we are interested by spaces as tokens
-				currentPosition-=offset;
-				startPosition = whiteStart;
+				this.currentPosition-=offset;
+				this.startPosition = whiteStart;
 				return TokenNameWHITESPACE;
 			}
 			//little trick to get out in the middle of a source compuation
-			if (currentPosition > eofPosition)
+			if (this.currentPosition > this.eofPosition)
 				return TokenNameEOF;
 
 			// ---------Identify the next token-------------
 
-			switch (currentCharacter) {
+			switch (this.currentCharacter) {
 				case '(' :
 					return TokenNameLPAREN;
 				case ')' :
@@ -1041,12 +1041,12 @@
 						if (test > 0) {
 							// relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
 							for (int lookAhead = 0; lookAhead < 3; lookAhead++) {
-								if (currentPosition + lookAhead == source.length)
+								if (this.currentPosition + lookAhead == this.source.length)
 									break;
-								if (source[currentPosition + lookAhead] == '\n')
+								if (this.source[this.currentPosition + lookAhead] == '\n')
 									break;
-								if (source[currentPosition + lookAhead] == '\'') {
-									currentPosition += lookAhead + 1;
+								if (this.source[this.currentPosition + lookAhead] == '\'') {
+									this.currentPosition += lookAhead + 1;
 									break;
 								}
 							}
@@ -1056,12 +1056,12 @@
 					if (getNextChar('\'')) {
 						// relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
 						for (int lookAhead = 0; lookAhead < 3; lookAhead++) {
-							if (currentPosition + lookAhead == source.length)
+							if (this.currentPosition + lookAhead == this.source.length)
 								break;
-							if (source[currentPosition + lookAhead] == '\n')
+							if (this.source[this.currentPosition + lookAhead] == '\n')
 								break;
-							if (source[currentPosition + lookAhead] == '\'') {
-								currentPosition += lookAhead + 1;
+							if (this.source[this.currentPosition + lookAhead] == '\'') {
+								this.currentPosition += lookAhead + 1;
 								break;
 							}
 						}
@@ -1070,21 +1070,20 @@
 					if (getNextChar('\\'))
 						scanEscapeCharacter();
 					else { // consume next character
-						unicodeAsBackSlash = false;
+						this.unicodeAsBackSlash = false;
 						boolean checkIfUnicode = false;
 						try {
-							checkIfUnicode = ((currentCharacter = source[currentPosition++]) == '\\')
-							&& (source[currentPosition] == 'u');
+							checkIfUnicode = ((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
+							&& (this.source[this.currentPosition] == 'u');
 						} catch(IndexOutOfBoundsException e) {
-							if (currentPosition > eofPosition)
-								return TokenNameEOF;
+							this.currentPosition--;
 							throw new InvalidInputException(INVALID_CHARACTER_CONSTANT);
 						}
 						if (checkIfUnicode) {
 							getNextUnicodeChar();
 						} else {
-							if (withoutUnicodePtr != 0) {
-								withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+							if (this.withoutUnicodePtr != 0) {
+								unicodeStoreAt(++this.withoutUnicodePtr);
 							}
 						}
 					}
@@ -1092,12 +1091,12 @@
 						return TokenNameCharacterLiteral;
 					// relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
 					for (int lookAhead = 0; lookAhead < 20; lookAhead++) {
-						if (currentPosition + lookAhead == source.length)
+						if (this.currentPosition + lookAhead == this.source.length)
 							break;
-						if (source[currentPosition + lookAhead] == '\n')
+						if (this.source[this.currentPosition + lookAhead] == '\n')
 							break;
-						if (source[currentPosition + lookAhead] == '\'') {
-							currentPosition += lookAhead + 1;
+						if (this.source[this.currentPosition + lookAhead] == '\'') {
+							this.currentPosition += lookAhead + 1;
 							break;
 						}
 					}
@@ -1105,79 +1104,90 @@
 				case '"' :
 					try {
 						// consume next character
-						unicodeAsBackSlash = false;
-						if (((currentCharacter = source[currentPosition++]) == '\\')
-							&& (source[currentPosition] == 'u')) {
+						this.unicodeAsBackSlash = false;
+						boolean isUnicode = false;
+						if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
+							&& (this.source[this.currentPosition] == 'u')) {
 							getNextUnicodeChar();
+							isUnicode = true;
 						} else {
-							if (withoutUnicodePtr != 0) {
-								withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+							if (this.withoutUnicodePtr != 0) {
+								unicodeStoreAt(++this.withoutUnicodePtr);
 							}
 						}
 
-						while (currentCharacter != '"') {
+						while (this.currentCharacter != '"') {
 							/**** \r and \n are not valid in string literals ****/
-							if ((currentCharacter == '\n') || (currentCharacter == '\r')) {
+							if ((this.currentCharacter == '\n') || (this.currentCharacter == '\r')) {
 								// relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
-								for (int lookAhead = 0; lookAhead < 50; lookAhead++) {
-									if (currentPosition + lookAhead == source.length)
-										break;
-									if (source[currentPosition + lookAhead] == '\n')
-										break;
-									if (source[currentPosition + lookAhead] == '\"') {
-										currentPosition += lookAhead + 1;
-										break;
+								if (isUnicode) {
+									int start = this.currentPosition;
+									for (int lookAhead = 0; lookAhead < 50; lookAhead++) {
+										if (this.currentPosition >= this.eofPosition) {
+											this.currentPosition = start;
+											break;
+										}
+										if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') && (this.source[this.currentPosition] == 'u')) {
+											isUnicode = true;
+											getNextUnicodeChar();
+										} else {
+											isUnicode = false;
+										}
+										if (!isUnicode && this.currentCharacter == '\n') {
+											this.currentPosition--; // set current position on new line character
+											break;
+										}
+										if (this.currentCharacter == '\"') {
+											throw new InvalidInputException(INVALID_CHAR_IN_STRING);
+										}
 									}
+								} else {
+									this.currentPosition--; // set current position on new line character
 								}
 								throw new InvalidInputException(INVALID_CHAR_IN_STRING);
 							}
-							if (currentCharacter == '\\') {
-								int escapeSize = currentPosition;
-								boolean backSlashAsUnicodeInString = unicodeAsBackSlash;
+							if (this.currentCharacter == '\\') {
+								int escapeSize = this.currentPosition;
+								boolean backSlashAsUnicodeInString = this.unicodeAsBackSlash;
 								//scanEscapeCharacter make a side effect on this value and we need the previous value few lines down this one
 								scanEscapeCharacter();
-								escapeSize = currentPosition - escapeSize;
-								if (withoutUnicodePtr == 0) {
+								escapeSize = this.currentPosition - escapeSize;
+								if (this.withoutUnicodePtr == 0) {
 									//buffer all the entries that have been left aside....
-									withoutUnicodePtr = currentPosition - escapeSize - 1 - startPosition;
-									System.arraycopy(
-										source, 
-										startPosition, 
-										withoutUnicodeBuffer, 
-										1, 
-										withoutUnicodePtr); 
-									withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+								    unicodeInitializeBuffer(this.currentPosition - escapeSize - 1 - this.startPosition);
+								    unicodeStoreAt(++this.withoutUnicodePtr);
 								} else { //overwrite the / in the buffer
-									withoutUnicodeBuffer[withoutUnicodePtr] = currentCharacter;
+								    unicodeStoreAt(this.withoutUnicodePtr);
 									if (backSlashAsUnicodeInString) { //there are TWO \ in the stream where only one is correct
-										withoutUnicodePtr--;
+										this.withoutUnicodePtr--;
 									}
 								}
 							}
 							// consume next character
-							unicodeAsBackSlash = false;
-							if (((currentCharacter = source[currentPosition++]) == '\\')
-								&& (source[currentPosition] == 'u')) {
+							this.unicodeAsBackSlash = false;
+							if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
+								&& (this.source[this.currentPosition] == 'u')) {
 								getNextUnicodeChar();
 							} else {
-								if (withoutUnicodePtr != 0) {
-									withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+								if (this.withoutUnicodePtr != 0) {
+									unicodeStoreAt(++this.withoutUnicodePtr);
 								}
 							}
 
 						}
 					} catch (IndexOutOfBoundsException e) {
+						this.currentPosition--;
 						throw new InvalidInputException(UNTERMINATED_STRING);
 					} catch (InvalidInputException e) {
 						if (e.getMessage().equals(INVALID_ESCAPE)) {
 							// relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
 							for (int lookAhead = 0; lookAhead < 50; lookAhead++) {
-								if (currentPosition + lookAhead == source.length)
+								if (this.currentPosition + lookAhead == this.source.length)
 									break;
-								if (source[currentPosition + lookAhead] == '\n')
+								if (this.source[this.currentPosition + lookAhead] == '\n')
 									break;
-								if (source[currentPosition + lookAhead] == '\"') {
-									currentPosition += lookAhead + 1;
+								if (this.source[this.currentPosition + lookAhead] == '\"') {
+									this.currentPosition += lookAhead + 1;
 									break;
 								}
 							}
@@ -1185,141 +1195,143 @@
 						}
 						throw e; // rethrow
 					}
-					if (checkNonExternalizedStringLiterals){ // check for presence of	NLS tags //$NON-NLS-?$ where ? is an int.
-						if (currentLine == null) {
-							currentLine = new NLSLine();
+					if (this.checkNonExternalizedStringLiterals){ // check for presence of	NLS tags //$NON-NLS-?$ where ? is an int.
+						if (this.currentLine == null) {
+							this.currentLine = new NLSLine();
 						}
-						currentLine.add(
+						this.currentLine.add(
 							new StringLiteral(
 								getCurrentTokenSourceString(), 
-								startPosition, 
-								currentPosition - 1));
+								this.startPosition, 
+								this.currentPosition - 1));
 					}
 					return TokenNameStringLiteral;
 				case '/' :
 					{
 						int test;
 						if ((test = getNextChar('/', '*')) == 0) { //line comment 
+							this.lastCommentLinePosition = this.currentPosition;
 							try { //get the next char 
-								if (((currentCharacter = source[currentPosition++]) == '\\')
-									&& (source[currentPosition] == 'u')) {
+								if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
+									&& (this.source[this.currentPosition] == 'u')) {
 									//-------------unicode traitement ------------
 									int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
-									currentPosition++;
-									while (source[currentPosition] == 'u') {
-										currentPosition++;
+									this.currentPosition++;
+									while (this.source[this.currentPosition] == 'u') {
+										this.currentPosition++;
 									}
-									if ((c1 = Character.getNumericValue(source[currentPosition++])) > 15
+									if ((c1 = Character.getNumericValue(this.source[this.currentPosition++])) > 15
 										|| c1 < 0
-										|| (c2 = Character.getNumericValue(source[currentPosition++])) > 15
+										|| (c2 = Character.getNumericValue(this.source[this.currentPosition++])) > 15
 										|| c2 < 0
-										|| (c3 = Character.getNumericValue(source[currentPosition++])) > 15
+										|| (c3 = Character.getNumericValue(this.source[this.currentPosition++])) > 15
 										|| c3 < 0
-										|| (c4 = Character.getNumericValue(source[currentPosition++])) > 15
+										|| (c4 = Character.getNumericValue(this.source[this.currentPosition++])) > 15
 										|| c4 < 0) {
 										throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
 									} else {
-										currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+										this.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
 									}
 								}
 
 								//handle the \\u case manually into comment
-								if (currentCharacter == '\\') {
-									if (source[currentPosition] == '\\')
-										currentPosition++;
+								if (this.currentCharacter == '\\') {
+									if (this.source[this.currentPosition] == '\\')
+										this.currentPosition++;
 								} //jump over the \\
 								boolean isUnicode = false;
-								while (currentCharacter != '\r' && currentCharacter != '\n') {
+								while (this.currentCharacter != '\r' && this.currentCharacter != '\n') {
+									this.lastCommentLinePosition = this.currentPosition;
 									//get the next char
 									isUnicode = false;									
-									if (((currentCharacter = source[currentPosition++]) == '\\')
-										&& (source[currentPosition] == 'u')) {
+									if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
+										&& (this.source[this.currentPosition] == 'u')) {
 										isUnicode = true;											
 										//-------------unicode traitement ------------
 										int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
-										currentPosition++;
-										while (source[currentPosition] == 'u') {
-											currentPosition++;
+										this.currentPosition++;
+										while (this.source[this.currentPosition] == 'u') {
+											this.currentPosition++;
 										}
-										if ((c1 = Character.getNumericValue(source[currentPosition++])) > 15
+										if ((c1 = Character.getNumericValue(this.source[this.currentPosition++])) > 15
 											|| c1 < 0
-											|| (c2 = Character.getNumericValue(source[currentPosition++])) > 15
+											|| (c2 = Character.getNumericValue(this.source[this.currentPosition++])) > 15
 											|| c2 < 0
-											|| (c3 = Character.getNumericValue(source[currentPosition++])) > 15
+											|| (c3 = Character.getNumericValue(this.source[this.currentPosition++])) > 15
 											|| c3 < 0
-											|| (c4 = Character.getNumericValue(source[currentPosition++])) > 15
+											|| (c4 = Character.getNumericValue(this.source[this.currentPosition++])) > 15
 											|| c4 < 0) {
 											throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
 										} else {
-											currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+											this.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
 										}
 									}
 									//handle the \\u case manually into comment
-									if (currentCharacter == '\\') {
-										if (source[currentPosition] == '\\')
-											currentPosition++;
+									if (this.currentCharacter == '\\') {
+										if (this.source[this.currentPosition] == '\\')
+											this.currentPosition++;
 									} //jump over the \\
 								}
 								/*
 								 * We need to completely consume the line break
 								 */
-								if (currentCharacter == '\r'
-								   && source.length > currentPosition) {
-								   	if (source[currentPosition] == '\n') {
-										currentPosition++;
-										currentCharacter = '\n';
-								   	} else if ((source[currentPosition] == '\\')
-										&& (source[currentPosition + 1] == 'u')) {
+								if (this.currentCharacter == '\r'
+								   && this.source.length > this.currentPosition) {
+								   	if (this.source[this.currentPosition] == '\n') {
+										this.currentPosition++;
+										this.currentCharacter = '\n';
+								   	} else if ((this.source[this.currentPosition] == '\\')
+										&& (this.source[this.currentPosition + 1] == 'u')) {
 										isUnicode = true;
 										char unicodeChar;
-										int index = currentPosition + 1;
+										int index = this.currentPosition + 1;
 										index++;
-										while (source[index] == 'u') {
+										while (this.source[index] == 'u') {
 											index++;
 										}
 										//-------------unicode traitement ------------
 										int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
-										if ((c1 = Character.getNumericValue(source[index++])) > 15
+										if ((c1 = Character.getNumericValue(this.source[index++])) > 15
 											|| c1 < 0
-											|| (c2 = Character.getNumericValue(source[index++])) > 15
+											|| (c2 = Character.getNumericValue(this.source[index++])) > 15
 											|| c2 < 0
-											|| (c3 = Character.getNumericValue(source[index++])) > 15
+											|| (c3 = Character.getNumericValue(this.source[index++])) > 15
 											|| c3 < 0
-											|| (c4 = Character.getNumericValue(source[index++])) > 15
+											|| (c4 = Character.getNumericValue(this.source[index++])) > 15
 											|| c4 < 0) {
-											currentPosition = index;
+											this.currentPosition = index;
 											throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
 										} else {
 											unicodeChar = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
 										}
 										if (unicodeChar == '\n') {
-											currentPosition = index;
-											currentCharacter = '\n';
+											this.currentPosition = index;
+											this.currentCharacter = '\n';
 										}
 									}
 							   	}
-								recordComment(false);
+								recordComment(TokenNameCOMMENT_LINE);
 								if (this.taskTags != null) checkTaskTag(this.startPosition, this.currentPosition);
-								if ((currentCharacter == '\r') || (currentCharacter == '\n')) {
+								if ((this.currentCharacter == '\r') || (this.currentCharacter == '\n')) {
 									checkNonExternalizedString();
-									if (recordLineSeparator) {
+									if (this.recordLineSeparator) {
 										if (isUnicode) {
 											pushUnicodeLineSeparator();
 										} else {
 											pushLineSeparator();
 										}
 									} else {
-										currentLine = null;
+										this.currentLine = null;
 									}
 								}
-								if (tokenizeComments) {
+								if (this.tokenizeComments) {
 									return TokenNameCOMMENT_LINE;
 								}
 							} catch (IndexOutOfBoundsException e) {
-								currentPosition--;
-								recordComment(false);
+								this.currentPosition--;
+								recordComment(TokenNameCOMMENT_LINE);
 								if (this.taskTags != null) checkTaskTag(this.startPosition, this.currentPosition);
-								if (tokenizeComments) {
+								if (this.tokenizeComments) {
 									return TokenNameCOMMENT_LINE;
 								} else {
 									this.currentPosition++; 
@@ -1332,35 +1344,35 @@
 								boolean isJavadoc = false, star = false;
 								boolean isUnicode = false;
 								// consume next character
-								unicodeAsBackSlash = false;
-								if (((currentCharacter = source[currentPosition++]) == '\\')
-									&& (source[currentPosition] == 'u')) {
+								this.unicodeAsBackSlash = false;
+								if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
+									&& (this.source[this.currentPosition] == 'u')) {
 									getNextUnicodeChar();
 									isUnicode = true;
 								} else {
 									isUnicode = false;
-									if (withoutUnicodePtr != 0) {
-										withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+									if (this.withoutUnicodePtr != 0) {
+										unicodeStoreAt(++this.withoutUnicodePtr);
 									}
 								}
 	
-								if (currentCharacter == '*') {
+								if (this.currentCharacter == '*') {
 									isJavadoc = true;
 									star = true;
 								}
-								if ((currentCharacter == '\r') || (currentCharacter == '\n')) {
+								if ((this.currentCharacter == '\r') || (this.currentCharacter == '\n')) {
 									checkNonExternalizedString();
-									if (recordLineSeparator) {
+									if (this.recordLineSeparator) {
 										if (!isUnicode) {
 											pushLineSeparator();
 										}
 									} else {
-										currentLine = null;
+										this.currentLine = null;
 									}
 								}
 								isUnicode = false;
-								if (((currentCharacter = source[currentPosition++]) == '\\')
-									&& (source[currentPosition] == 'u')) {
+								if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
+									&& (this.source[this.currentPosition] == 'u')) {
 									//-------------unicode traitement ------------
 									getNextUnicodeChar();
 									isUnicode = true;
@@ -1368,26 +1380,30 @@
 									isUnicode = false;
 								}
 								//handle the \\u case manually into comment
-								if (currentCharacter == '\\') {
-									if (source[currentPosition] == '\\')
-										currentPosition++; //jump over the \\
+								if (this.currentCharacter == '\\') {
+									if (this.source[this.currentPosition] == '\\')
+										this.currentPosition++; //jump over the \\
+								}
+								// empty comment is not a javadoc /**/
+								if (this.currentCharacter == '/') { 
+									isJavadoc = false;
 								}
 								//loop until end of comment */
-								while ((currentCharacter != '/') || (!star)) {
-									if ((currentCharacter == '\r') || (currentCharacter == '\n')) {
+								while ((this.currentCharacter != '/') || (!star)) {
+									if ((this.currentCharacter == '\r') || (this.currentCharacter == '\n')) {
 										checkNonExternalizedString();
-										if (recordLineSeparator) {
+										if (this.recordLineSeparator) {
 											if (!isUnicode) {
 												pushLineSeparator();
 											}
 										} else {
-											currentLine = null;
+											this.currentLine = null;
 										}
 									}
-									star = currentCharacter == '*';
+									star = this.currentCharacter == '*';
 									//get next char
-									if (((currentCharacter = source[currentPosition++]) == '\\')
-										&& (source[currentPosition] == 'u')) {
+									if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
+										&& (this.source[this.currentPosition] == 'u')) {
 										//-------------unicode traitement ------------
 										getNextUnicodeChar();
 										isUnicode = true;
@@ -1395,19 +1411,24 @@
 										isUnicode = false;
 									}
 									//handle the \\u case manually into comment
-									if (currentCharacter == '\\') {
-										if (source[currentPosition] == '\\')
-											currentPosition++;
+									if (this.currentCharacter == '\\') {
+										if (this.source[this.currentPosition] == '\\')
+											this.currentPosition++;
 									} //jump over the \\
 								}
-								recordComment(isJavadoc);
+								int token = isJavadoc ? TokenNameCOMMENT_JAVADOC : TokenNameCOMMENT_BLOCK;
+								recordComment(token);
 								if (this.taskTags != null) checkTaskTag(this.startPosition, this.currentPosition);
-								if (tokenizeComments) {
+								if (this.tokenizeComments) {
+									/*
 									if (isJavadoc)
 										return TokenNameCOMMENT_JAVADOC;
 									return TokenNameCOMMENT_BLOCK;
+									*/
+									return token;
 								}
 							} catch (IndexOutOfBoundsException e) {
+								this.currentPosition--;
 								throw new InvalidInputException(UNTERMINATED_COMMENT);
 							}
 							break;
@@ -1423,26 +1444,26 @@
 					throw new InvalidInputException("Ctrl-Z"); //$NON-NLS-1$
 
 				default :
-					if (Character.isJavaIdentifierStart(currentCharacter))
+					if (Character.isJavaIdentifierStart(this.currentCharacter))
 						return scanIdentifierOrKeyword();
-					if (Character.isDigit(currentCharacter))
+					if (Character.isDigit(this.currentCharacter))
 						return scanNumber(false);
 					return TokenNameERROR;
 			}
 		}
 	} //-----------------end switch while try--------------------
 	catch (IndexOutOfBoundsException e) {
-		if (tokenizeWhiteSpace && (whiteStart != currentPosition - 1)) {
+		if (this.tokenizeWhiteSpace && (whiteStart != this.currentPosition - 1)) {
 			// reposition scanner in case we are interested by spaces as tokens
-			currentPosition--;
-			startPosition = whiteStart;
+			this.currentPosition--;
+			this.startPosition = whiteStart;
 			return TokenNameWHITESPACE;
 		}
 	}
 	return TokenNameEOF;
 }
 public final void getNextUnicodeChar()
-	throws IndexOutOfBoundsException, InvalidInputException {
+	throws InvalidInputException {
 	//VOID
 	//handle the case of unicode.
 	//when a unicode appears then we must use a buffer that holds char internal values
@@ -1451,39 +1472,38 @@
 
 	//ALL getNextChar.... ARE OPTIMIZED COPIES 
 
-	int c1 = 0, c2 = 0, c3 = 0, c4 = 0, unicodeSize = 6;
-	currentPosition++;
-	while (source[currentPosition] == 'u') {
-		currentPosition++;
-		unicodeSize++;
-	}
-
-	if ((c1 = Character.getNumericValue(source[currentPosition++])) > 15
-		|| c1 < 0
-		|| (c2 = Character.getNumericValue(source[currentPosition++])) > 15
-		|| c2 < 0
-		|| (c3 = Character.getNumericValue(source[currentPosition++])) > 15
-		|| c3 < 0
-		|| (c4 = Character.getNumericValue(source[currentPosition++])) > 15
-		|| c4 < 0){
-		throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
-	} else {
-		currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
-		//need the unicode buffer
-		if (withoutUnicodePtr == 0) {
-			//buffer all the entries that have been left aside....
-			withoutUnicodePtr = currentPosition - unicodeSize - startPosition;
-			System.arraycopy(
-				source, 
-				startPosition, 
-				withoutUnicodeBuffer, 
-				1, 
-				withoutUnicodePtr); 
+	try {
+		int c1 = 0, c2 = 0, c3 = 0, c4 = 0, unicodeSize = 6;
+		this.currentPosition++;
+		while (this.source[this.currentPosition] == 'u') {
+			this.currentPosition++;
+			unicodeSize++;
 		}
-		//fill the buffer with the char
-		withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+
+		if ((c1 = Character.getNumericValue(this.source[this.currentPosition++])) > 15
+			|| c1 < 0
+			|| (c2 = Character.getNumericValue(this.source[this.currentPosition++])) > 15
+			|| c2 < 0
+			|| (c3 = Character.getNumericValue(this.source[this.currentPosition++])) > 15
+			|| c3 < 0
+			|| (c4 = Character.getNumericValue(this.source[this.currentPosition++])) > 15
+			|| c4 < 0){
+			throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
+		} else {
+			this.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+			//need the unicode buffer
+			if (this.withoutUnicodePtr == 0) {
+				//buffer all the entries that have been left aside....
+				unicodeInitializeBuffer(this.currentPosition - unicodeSize - this.startPosition);
+			}
+			//fill the buffer with the char
+			unicodeStoreAt(++this.withoutUnicodePtr);
+		}
+		this.unicodeAsBackSlash = this.currentCharacter == '\\';
+	} catch (ArrayIndexOutOfBoundsException e) {
+		this.currentPosition--;
+		throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
 	}
-	unicodeAsBackSlash = currentCharacter == '\\';
 }
 
 public char[] getSource(){
@@ -1501,20 +1521,20 @@
 			// ---------Consume white space and handles startPosition---------
 			boolean isWhiteSpace;
 			do {
-				startPosition = currentPosition;
-				if (((currentCharacter = source[currentPosition++]) == '\\')
-					&& (source[currentPosition] == 'u')) {
+				this.startPosition = this.currentPosition;
+				if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
+					&& (this.source[this.currentPosition] == 'u')) {
 					isWhiteSpace = jumpOverUnicodeWhiteSpace();
 				} else {
-					if (recordLineSeparator
-						&& ((currentCharacter == '\r') || (currentCharacter == '\n')))
+					if (this.recordLineSeparator
+						&& ((this.currentCharacter == '\r') || (this.currentCharacter == '\n')))
 						pushLineSeparator();
-					isWhiteSpace = CharOperation.isWhitespace(currentCharacter);
+					isWhiteSpace = CharOperation.isWhitespace(this.currentCharacter);
 				}
 			} while (isWhiteSpace);
 
 			// -------consume token until } is found---------
-			switch (currentCharacter) {
+			switch (this.currentCharacter) {
 				case '{' :
 					found++;
 					break;
@@ -1535,13 +1555,13 @@
 							}
 						} else {
 							try { // consume next character
-								unicodeAsBackSlash = false;
-								if (((currentCharacter = source[currentPosition++]) == '\\')
-									&& (source[currentPosition] == 'u')) {
+								this.unicodeAsBackSlash = false;
+								if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
+									&& (this.source[this.currentPosition] == 'u')) {
 									getNextUnicodeChar();
 								} else {
-									if (withoutUnicodePtr != 0) {
-										withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+									if (this.withoutUnicodePtr != 0) {
+										unicodeStoreAt(++this.withoutUnicodePtr);
 									}
 								}
 							} catch (InvalidInputException ex) {
@@ -1554,27 +1574,27 @@
 				case '"' :
 					try {
 						try { // consume next character
-							unicodeAsBackSlash = false;
-							if (((currentCharacter = source[currentPosition++]) == '\\')
-								&& (source[currentPosition] == 'u')) {
+							this.unicodeAsBackSlash = false;
+							if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
+								&& (this.source[this.currentPosition] == 'u')) {
 								getNextUnicodeChar();
 							} else {
-								if (withoutUnicodePtr != 0) {
-									withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+								if (this.withoutUnicodePtr != 0) {
+								    unicodeStoreAt(++this.withoutUnicodePtr);
 								}
 							}
 						} catch (InvalidInputException ex) {
 								// ignore
 						}
-						while (currentCharacter != '"') {
-							if (currentCharacter == '\r'){
-								if (source[currentPosition] == '\n') currentPosition++;
+						while (this.currentCharacter != '"') {
+							if (this.currentCharacter == '\r'){
+								if (this.source[this.currentPosition] == '\n') this.currentPosition++;
 								break; // the string cannot go further that the line
 							}
-							if (currentCharacter == '\n'){
+							if (this.currentCharacter == '\n'){
 								break; // the string cannot go further that the line
 							}
-							if (currentCharacter == '\\') {
+							if (this.currentCharacter == '\\') {
 								try {
 									scanEscapeCharacter();
 								} catch (InvalidInputException ex) {
@@ -1582,13 +1602,13 @@
 								}
 							}
 							try { // consume next character
-								unicodeAsBackSlash = false;
-								if (((currentCharacter = source[currentPosition++]) == '\\')
-									&& (source[currentPosition] == 'u')) {
+								this.unicodeAsBackSlash = false;
+								if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
+									&& (this.source[this.currentPosition] == 'u')) {
 									getNextUnicodeChar();
 								} else {
-									if (withoutUnicodePtr != 0) {
-										withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+									if (this.withoutUnicodePtr != 0) {
+										unicodeStoreAt(++this.withoutUnicodePtr);
 									}
 								}
 							} catch (InvalidInputException ex) {
@@ -1602,164 +1622,208 @@
 				case '/' :
 					{
 						int test;
-						boolean isUnicode;
 						if ((test = getNextChar('/', '*')) == 0) { //line comment 
 							try {
+								this.lastCommentLinePosition = this.currentPosition;
 								//get the next char 
-								if (((currentCharacter = source[currentPosition++]) == '\\')
-									&& (source[currentPosition] == 'u')) {
+								if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
+									&& (this.source[this.currentPosition] == 'u')) {
 									//-------------unicode traitement ------------
-									isUnicode = true;
 									int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
-									currentPosition++;
-									while (source[currentPosition] == 'u') {
-										currentPosition++;
+									this.currentPosition++;
+									while (this.source[this.currentPosition] == 'u') {
+										this.currentPosition++;
 									}
-									if ((c1 = Character.getNumericValue(source[currentPosition++])) > 15
+									if ((c1 = Character.getNumericValue(this.source[this.currentPosition++])) > 15
 										|| c1 < 0
-										|| (c2 = Character.getNumericValue(source[currentPosition++])) > 15
+										|| (c2 = Character.getNumericValue(this.source[this.currentPosition++])) > 15
 										|| c2 < 0
-										|| (c3 = Character.getNumericValue(source[currentPosition++])) > 15
+										|| (c3 = Character.getNumericValue(this.source[this.currentPosition++])) > 15
 										|| c3 < 0
-										|| (c4 = Character.getNumericValue(source[currentPosition++])) > 15
+										|| (c4 = Character.getNumericValue(this.source[this.currentPosition++])) > 15
 										|| c4 < 0) { //error don't care of the value
-										currentCharacter = 'A';
+										this.currentCharacter = 'A';
 									} //something different from \n and \r
 									else {
-										currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+										this.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
 									}
-								} else {
-									isUnicode = false;
 								}
-
-								while (currentCharacter != '\r' && currentCharacter != '\n') {
+								//handle the \\u case manually into comment
+								if (this.currentCharacter == '\\') {
+									if (this.source[this.currentPosition] == '\\')
+										this.currentPosition++;
+								} //jump over the \\
+								boolean isUnicode = false;
+								while (this.currentCharacter != '\r' && this.currentCharacter != '\n') {
+									this.lastCommentLinePosition = this.currentPosition;
 									//get the next char 
-									if (((currentCharacter = source[currentPosition++]) == '\\')
-										&& (source[currentPosition] == 'u')) {
+									isUnicode = false;
+									if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
+										&& (this.source[this.currentPosition] == 'u')) {
+										isUnicode = true;
 										//-------------unicode traitement ------------
 										int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
-										currentPosition++;
-										isUnicode = true;
-										while (source[currentPosition] == 'u') {
-											currentPosition++;
+										this.currentPosition++;
+										while (this.source[this.currentPosition] == 'u') {
+											this.currentPosition++;
 										}
-										if ((c1 = Character.getNumericValue(source[currentPosition++])) > 15
+										if ((c1 = Character.getNumericValue(this.source[this.currentPosition++])) > 15
 											|| c1 < 0
-											|| (c2 = Character.getNumericValue(source[currentPosition++])) > 15
+											|| (c2 = Character.getNumericValue(this.source[this.currentPosition++])) > 15
 											|| c2 < 0
-											|| (c3 = Character.getNumericValue(source[currentPosition++])) > 15
+											|| (c3 = Character.getNumericValue(this.source[this.currentPosition++])) > 15
 											|| c3 < 0
-											|| (c4 = Character.getNumericValue(source[currentPosition++])) > 15
+											|| (c4 = Character.getNumericValue(this.source[this.currentPosition++])) > 15
 											|| c4 < 0) { //error don't care of the value
-											currentCharacter = 'A';
+											this.currentCharacter = 'A';
 										} //something different from \n and \r
 										else {
-											currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+											this.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
 										}
-									} else {
-										isUnicode = false;
 									}
+									//handle the \\u case manually into comment
+									if (this.currentCharacter == '\\') {
+										if (this.source[this.currentPosition] == '\\')
+											this.currentPosition++;
+									} //jump over the \\
 								}
-								if (recordLineSeparator
-									&& ((currentCharacter == '\r') || (currentCharacter == '\n'))) {
-										if (!isUnicode) {
+								/*
+								 * We need to completely consume the line break
+								 */
+								if (this.currentCharacter == '\r'
+								   && this.source.length > this.currentPosition) {
+								   	if (this.source[this.currentPosition] == '\n') {
+										this.currentPosition++;
+										this.currentCharacter = '\n';
+								   	} else if ((this.source[this.currentPosition] == '\\')
+										&& (this.source[this.currentPosition + 1] == 'u')) {
+										isUnicode = true;
+										char unicodeChar;
+										int index = this.currentPosition + 1;
+										index++;
+										while (this.source[index] == 'u') {
+											index++;
+										}
+										//-------------unicode traitement ------------
+										int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
+										if ((c1 = Character.getNumericValue(this.source[index++])) > 15
+											|| c1 < 0
+											|| (c2 = Character.getNumericValue(this.source[index++])) > 15
+											|| c2 < 0
+											|| (c3 = Character.getNumericValue(this.source[index++])) > 15
+											|| c3 < 0
+											|| (c4 = Character.getNumericValue(this.source[index++])) > 15
+											|| c4 < 0) { //error don't care of the value
+											unicodeChar = 'A';
+										} else {
+											unicodeChar = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+										}
+										if (unicodeChar == '\n') {
+											this.currentPosition = index;
+											this.currentCharacter = '\n';
+										}
+									}
+							   	}
+								recordComment(TokenNameCOMMENT_LINE);
+								if (this.recordLineSeparator
+									&& ((this.currentCharacter == '\r') || (this.currentCharacter == '\n'))) {
+										if (isUnicode) {
+											pushUnicodeLineSeparator();
+										} else {
 											pushLineSeparator();
 										}
 									}
 							} catch (IndexOutOfBoundsException e) {
 								 //an eof will then be generated
+								this.currentPosition--;
+								recordComment(TokenNameCOMMENT_LINE);
+								if (!this.tokenizeComments) {
+									this.currentPosition++; 
+								}
 							}
 							break;
 						}
 						if (test > 0) { //traditional and javadoc comment
-							isUnicode = false;
-							boolean star = false;
-							try { // consume next character
-								unicodeAsBackSlash = false;
-								if (((currentCharacter = source[currentPosition++]) == '\\')
-									&& (source[currentPosition] == 'u')) {
+							boolean isJavadoc = false;
+							try { //get the next char
+								boolean star = false;
+								boolean isUnicode = false;
+								// consume next character
+								this.unicodeAsBackSlash = false;
+								if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
+									&& (this.source[this.currentPosition] == 'u')) {
 									getNextUnicodeChar();
 									isUnicode = true;
 								} else {
 									isUnicode = false;
-									if (withoutUnicodePtr != 0) {
-										withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+									if (this.withoutUnicodePtr != 0) {
+    								    unicodeStoreAt(++this.withoutUnicodePtr);
 									}
 								}
-							} catch (InvalidInputException ex) {
- 								// ignore
- 							}
-							if (currentCharacter == '*') {
-								star = true;
-							}
-							if (recordLineSeparator
-								&& ((currentCharacter == '\r') || (currentCharacter == '\n'))) {
-									if (!isUnicode) {
-										pushLineSeparator();
+	
+								if (this.currentCharacter == '*') {
+									isJavadoc = true;
+									star = true;
+								}
+								if ((this.currentCharacter == '\r') || (this.currentCharacter == '\n')) {
+									if (this.recordLineSeparator) {
+										if (isUnicode) {
+											pushUnicodeLineSeparator();
+										} else {
+											pushLineSeparator();
+										}
+									} else {
+										this.currentLine = null;
 									}
-							}
-							try { //get the next char 
-								if (((currentCharacter = source[currentPosition++]) == '\\')
-									&& (source[currentPosition] == 'u')) {
+								}
+								isUnicode = false;
+								if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
+									&& (this.source[this.currentPosition] == 'u')) {
 									//-------------unicode traitement ------------
+									getNextUnicodeChar();
 									isUnicode = true;
-									int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
-									currentPosition++;
-									while (source[currentPosition] == 'u') {
-										currentPosition++;
-									}
-									if ((c1 = Character.getNumericValue(source[currentPosition++])) > 15
-										|| c1 < 0
-										|| (c2 = Character.getNumericValue(source[currentPosition++])) > 15
-										|| c2 < 0
-										|| (c3 = Character.getNumericValue(source[currentPosition++])) > 15
-										|| c3 < 0
-										|| (c4 = Character.getNumericValue(source[currentPosition++])) > 15
-										|| c4 < 0) { //error don't care of the value
-										currentCharacter = 'A';
-									} //something different from * and /
-									else {
-										currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
-									}
 								} else {
 									isUnicode = false;
 								}
-								//loop until end of comment */ 
-								while ((currentCharacter != '/') || (!star)) {
-									if (recordLineSeparator
-										&& ((currentCharacter == '\r') || (currentCharacter == '\n'))) {
-											if (!isUnicode) {
+								//handle the \\u case manually into comment
+								if (this.currentCharacter == '\\') {
+									if (this.source[this.currentPosition] == '\\')
+										this.currentPosition++; //jump over the \\
+								}
+								// empty comment is not a javadoc /**/
+								if (this.currentCharacter == '/') { 
+									isJavadoc = false;
+								}
+								//loop until end of comment */
+								while ((this.currentCharacter != '/') || (!star)) {
+									if ((this.currentCharacter == '\r') || (this.currentCharacter == '\n')) {
+										if (this.recordLineSeparator) {
+											if (isUnicode) {
+												pushUnicodeLineSeparator();
+											} else {
 												pushLineSeparator();
 											}
+										} else {
+											this.currentLine = null;
+										}
 									}
-									star = currentCharacter == '*';
+									star = this.currentCharacter == '*';
 									//get next char
-									if (((currentCharacter = source[currentPosition++]) == '\\')
-										&& (source[currentPosition] == 'u')) {
+									if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
+										&& (this.source[this.currentPosition] == 'u')) {
 										//-------------unicode traitement ------------
+										getNextUnicodeChar();
 										isUnicode = true;
-										int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
-										currentPosition++;
-										while (source[currentPosition] == 'u') {
-											currentPosition++;
-										}
-										if ((c1 = Character.getNumericValue(source[currentPosition++])) > 15
-											|| c1 < 0
-											|| (c2 = Character.getNumericValue(source[currentPosition++])) > 15
-											|| c2 < 0
-											|| (c3 = Character.getNumericValue(source[currentPosition++])) > 15
-											|| c3 < 0
-											|| (c4 = Character.getNumericValue(source[currentPosition++])) > 15
-											|| c4 < 0) { //error don't care of the value
-											currentCharacter = 'A';
-										} //something different from * and /
-										else {
-											currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
-										}
 									} else {
 										isUnicode = false;
 									}
+									//handle the \\u case manually into comment
+									if (this.currentCharacter == '\\') {
+										if (this.source[this.currentPosition] == '\\')
+											this.currentPosition++;
+									} //jump over the \\
 								}
+								recordComment(isJavadoc ? TokenNameCOMMENT_JAVADOC : TokenNameCOMMENT_BLOCK);
 							} catch (IndexOutOfBoundsException e) {
 								return;
 							}
@@ -1769,11 +1833,11 @@
 					}
 
 				default :
-					if (Character.isJavaIdentifierStart(currentCharacter)) {
+					if (Character.isJavaIdentifierStart(this.currentCharacter)) {
 						scanIdentifierOrKeyword();
 						break;
 					}
-					if (Character.isDigit(currentCharacter)) {
+					if (Character.isDigit(this.currentCharacter)) {
 						try {
 							scanNumber(false);
 						} catch (InvalidInputException ex) {
@@ -1802,29 +1866,30 @@
 		this.wasAcr = false;
 		int c1, c2, c3, c4;
 		int unicodeSize = 6;
-		currentPosition++;
-		while (source[currentPosition] == 'u') {
-			currentPosition++;
+		this.currentPosition++;
+		while (this.source[this.currentPosition] == 'u') {
+			this.currentPosition++;
 			unicodeSize++;
 		}
 
-		if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15
+		if (((c1 = Character.getNumericValue(this.source[this.currentPosition++])) > 15
 			|| c1 < 0)
-			|| ((c2 = Character.getNumericValue(source[currentPosition++])) > 15 || c2 < 0)
-			|| ((c3 = Character.getNumericValue(source[currentPosition++])) > 15 || c3 < 0)
-			|| ((c4 = Character.getNumericValue(source[currentPosition++])) > 15 || c4 < 0)) {
+			|| ((c2 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c2 < 0)
+			|| ((c3 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c3 < 0)
+			|| ((c4 = Character.getNumericValue(this.source[this.currentPosition++])) > 15 || c4 < 0)) {
 			throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
 		}
 
-		currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
-		if (CharOperation.isWhitespace(currentCharacter))
+		this.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+		if (CharOperation.isWhitespace(this.currentCharacter))
 			return true;
 
 		//buffer the new char which is not a white space
-		withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
-		//withoutUnicodePtr == 1 is true here
+		unicodeStoreAt(++this.withoutUnicodePtr);
+		//this.withoutUnicodePtr == 1 is true here
 		return false;
 	} catch (IndexOutOfBoundsException e){
+		this.currentPosition--;
 		throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
 	}
 }
@@ -1833,7 +1898,7 @@
 	//return always the same char[] build only once
 
 	//optimization at no speed cost of 99.5 % of the singleCharIdentifier
-	char charOne = source[startPosition];
+	char charOne = this.source[this.startPosition];
 	switch (charOne) {
 		case 'a' :
 			return charArray_a;
@@ -1896,9 +1961,9 @@
 
 	char c0, c1;
 	int hash = 
-		(((c0 = source[startPosition]) << 6) + (c1 = source[startPosition + 1]))
+		(((c0 = this.source[this.startPosition]) << 6) + (c1 = this.source[this.startPosition + 1]))
 			% TableSize; 
-	char[][] table = charArray_length[0][hash];
+	char[][] table = this.charArray_length[0][hash];
 	int i = newEntry2;
 	while (++i < InternalTableSize) {
 		char[] charArray = table[i];
@@ -1925,11 +1990,11 @@
 
 	char c0, c1, c2;
 	int hash = 
-		(((c0 = source[startPosition]) << 12)
-			+ ((c1 = source[startPosition + 1]) << 6)
-			+ (c2 = source[startPosition + 2]))
+		(((c0 = this.source[this.startPosition]) << 12)
+			+ ((c1 = this.source[this.startPosition + 1]) << 6)
+			+ (c2 = this.source[this.startPosition + 2]))
 			% TableSize; 
-	char[][] table = charArray_length[1][hash];
+	char[][] table = this.charArray_length[1][hash];
 	int i = newEntry3;
 	while (++i < InternalTableSize) {
 		char[] charArray = table[i];
@@ -1956,12 +2021,12 @@
 
 	char c0, c1, c2, c3;
 	long hash = 
-		((((long) (c0 = source[startPosition])) << 18)
-			+ ((c1 = source[startPosition + 1]) << 12)
-			+ ((c2 = source[startPosition + 2]) << 6)
-			+ (c3 = source[startPosition + 3]))
+		((((long) (c0 = this.source[this.startPosition])) << 18)
+			+ ((c1 = this.source[this.startPosition + 1]) << 12)
+			+ ((c2 = this.source[this.startPosition + 2]) << 6)
+			+ (c3 = this.source[this.startPosition + 3]))
 			% TableSize; 
-	char[][] table = charArray_length[2][(int) hash];
+	char[][] table = this.charArray_length[2][(int) hash];
 	int i = newEntry4;
 	while (++i < InternalTableSize) {
 		char[] charArray = table[i];
@@ -1995,13 +2060,13 @@
 
 	char c0, c1, c2, c3, c4;
 	long hash = 
-		((((long) (c0 = source[startPosition])) << 24)
-			+ (((long) (c1 = source[startPosition + 1])) << 18)
-			+ ((c2 = source[startPosition + 2]) << 12)
-			+ ((c3 = source[startPosition + 3]) << 6)
-			+ (c4 = source[startPosition + 4]))
+		((((long) (c0 = this.source[this.startPosition])) << 24)
+			+ (((long) (c1 = this.source[this.startPosition + 1])) << 18)
+			+ ((c2 = this.source[this.startPosition + 2]) << 12)
+			+ ((c3 = this.source[this.startPosition + 3]) << 6)
+			+ (c4 = this.source[this.startPosition + 4]))
 			% TableSize; 
-	char[][] table = charArray_length[3][(int) hash];
+	char[][] table = this.charArray_length[3][(int) hash];
 	int i = newEntry5;
 	while (++i < InternalTableSize) {
 		char[] charArray = table[i];
@@ -2037,14 +2102,14 @@
 
 	char c0, c1, c2, c3, c4, c5;
 	long hash = 
-		((((long) (c0 = source[startPosition])) << 32)
-			+ (((long) (c1 = source[startPosition + 1])) << 24)
-			+ (((long) (c2 = source[startPosition + 2])) << 18)
-			+ ((c3 = source[startPosition + 3]) << 12)
-			+ ((c4 = source[startPosition + 4]) << 6)
-			+ (c5 = source[startPosition + 5]))
+		((((long) (c0 = this.source[this.startPosition])) << 32)
+			+ (((long) (c1 = this.source[this.startPosition + 1])) << 24)
+			+ (((long) (c2 = this.source[this.startPosition + 2])) << 18)
+			+ ((c3 = this.source[this.startPosition + 3]) << 12)
+			+ ((c4 = this.source[this.startPosition + 4]) << 6)
+			+ (c5 = this.source[this.startPosition + 5]))
 			% TableSize; 
-	char[][] table = charArray_length[4][(int) hash];
+	char[][] table = this.charArray_length[4][(int) hash];
 	int i = newEntry6;
 	while (++i < InternalTableSize) {
 		char[] charArray = table[i];
@@ -2108,14 +2173,14 @@
 	}
 	if (nonNLSCounter == 0) {
 		this.nonNLSStrings = null;
-		currentLine = null;
+		this.currentLine = null;
 		return;
 	} 
 	this.wasNonExternalizedStringLiteral = true;
 	if (nonNLSCounter != lineLength) {
 		System.arraycopy(this.nonNLSStrings, 0, (this.nonNLSStrings = new StringLiteral[nonNLSCounter]), 0, nonNLSCounter);
 	}
-	currentLine = null;
+	this.currentLine = null;
 }
 
 public final void pushLineSeparator() {
@@ -2124,103 +2189,93 @@
 	
 	if (this.checkNonExternalizedStringLiterals) {
 	// reinitialize the current line for non externalize strings purpose
-		currentLine = null;
+		this.currentLine = null;
 	}
 	//currentCharacter is at position currentPosition-1
 
 	// cr 000D
-	if (currentCharacter == '\r') {
-		int separatorPos = currentPosition - 1;
-		//TODO (olivier) david - why the following line was "if ((linePtr > 0) && (lineEnds[linePtr] >= separatorPos)) return;" ?
-		if ((linePtr >= 0) && (lineEnds[linePtr] >= separatorPos)) return;
+	if (this.currentCharacter == '\r') {
+		int separatorPos = this.currentPosition - 1;
+		//TODO (olivier) david - why the following line was "if ((this.linePtr > 0) && (this.lineEnds[this.linePtr] >= separatorPos)) return;" ?
+		if ((this.linePtr >= 0) && (this.lineEnds[this.linePtr] >= separatorPos)) return;
 		//System.out.println("CR-" + separatorPos);
-		try {
-			lineEnds[++linePtr] = separatorPos;
-		} catch (IndexOutOfBoundsException e) {
-			//linePtr value is correct
-			int oldLength = lineEnds.length;
-			int[] old = lineEnds;
-			lineEnds = new int[oldLength + INCREMENT];
-			System.arraycopy(old, 0, lineEnds, 0, oldLength);
-			lineEnds[linePtr] = separatorPos;
-		}
+		int length = this.lineEnds.length;
+		if (++this.linePtr >=  length)
+			System.arraycopy(this.lineEnds, 0, this.lineEnds = new int[length + INCREMENT], 0, length);
+		this.lineEnds[this.linePtr] = separatorPos;
 		// look-ahead for merged cr+lf
 		try {
-			if (source[currentPosition] == '\n') {
-				//System.out.println("look-ahead LF-" + currentPosition);			
-				lineEnds[linePtr] = currentPosition;
-				currentPosition++;
-				wasAcr = false;
+			if (this.source[this.currentPosition] == '\n') {
+				//System.out.println("look-ahead LF-" + this.currentPosition);			
+				this.lineEnds[this.linePtr] = this.currentPosition;
+				this.currentPosition++;
+				this.wasAcr = false;
 			} else {
-				wasAcr = true;
+				this.wasAcr = true;
 			}
 		} catch(IndexOutOfBoundsException e) {
-			wasAcr = true;
+			this.wasAcr = true;
 		}
 	} else {
 		// lf 000A
-		if (currentCharacter == '\n') { //must merge eventual cr followed by lf
-			if (wasAcr && (lineEnds[linePtr] == (currentPosition - 2))) {
-				//System.out.println("merge LF-" + (currentPosition - 1));							
-				lineEnds[linePtr] = currentPosition - 1;
+		if (this.currentCharacter == '\n') { //must merge eventual cr followed by lf
+			if (this.wasAcr && (this.lineEnds[this.linePtr] == (this.currentPosition - 2))) {
+				//System.out.println("merge LF-" + (this.currentPosition - 1));							
+				this.lineEnds[this.linePtr] = this.currentPosition - 1;
 			} else {
-				int separatorPos = currentPosition - 1;
-				//TODO (olivier) david - why the following line was "if ((linePtr > 0) && (lineEnds[linePtr] >= separatorPos)) return;" ?
-				if ((linePtr >= 0) && (lineEnds[linePtr] >= separatorPos)) return;
-				// System.out.println("LF-" + separatorPos);							
-				try {
-					lineEnds[++linePtr] = separatorPos;
-				} catch (IndexOutOfBoundsException e) {
-					//linePtr value is correct
-					int oldLength = lineEnds.length;
-					int[] old = lineEnds;
-					lineEnds = new int[oldLength + INCREMENT];
-					System.arraycopy(old, 0, lineEnds, 0, oldLength);
-					lineEnds[linePtr] = separatorPos;
-				}
+				int separatorPos = this.currentPosition - 1;
+				//TODO (olivier) david - why the following line was "if ((this.linePtr > 0) && (this.lineEnds[this.linePtr] >= separatorPos)) return;" ?
+				if ((this.linePtr >= 0) && (this.lineEnds[this.linePtr] >= separatorPos)) return;
+				// System.out.println("LF-" + separatorPos);
+				int length = this.lineEnds.length;
+				if (++this.linePtr >=  length)
+					System.arraycopy(this.lineEnds, 0, this.lineEnds = new int[length + INCREMENT], 0, length);
+				this.lineEnds[this.linePtr] = separatorPos;
 			}
-			wasAcr = false;
+			this.wasAcr = false;
 		}
 	}
 }
 public final void pushUnicodeLineSeparator() {
 	if (this.checkNonExternalizedStringLiterals) {
 	// reinitialize the current line for non externalize strings purpose
-		currentLine = null;
+		this.currentLine = null;
 	}
 	
 	// cr 000D
-	if (currentCharacter == '\r') {
-		if (source[currentPosition] == '\n') {
-			wasAcr = false;
+	if (this.currentCharacter == '\r') {
+		if (this.source[this.currentPosition] == '\n') {
+			this.wasAcr = false;
 		} else {
-			wasAcr = true;
+			this.wasAcr = true;
 		}
 	} else {
 		// lf 000A
-		if (currentCharacter == '\n') { //must merge eventual cr followed by lf
-			wasAcr = false;
+		if (this.currentCharacter == '\n') { //must merge eventual cr followed by lf
+			this.wasAcr = false;
 		}
 	}
 }
-public final void recordComment(boolean isJavadoc) {
-
-	// a new comment is recorded
-	try {
-		this.commentStops[++this.commentPtr] = isJavadoc ? this.currentPosition : -this.currentPosition;
-	} catch (IndexOutOfBoundsException e) {
-		int oldStackLength = this.commentStops.length;
-		int[] oldStack = this.commentStops;
-		this.commentStops = new int[oldStackLength + 30];
-		System.arraycopy(oldStack, 0, this.commentStops, 0, oldStackLength);
-		this.commentStops[this.commentPtr] = isJavadoc ? this.currentPosition : -this.currentPosition;
-		//grows the positions buffers too
-		int[] old = this.commentStarts;
-		this.commentStarts = new int[oldStackLength + 30];
-		System.arraycopy(old, 0, this.commentStarts, 0, oldStackLength);
+public void recordComment(int token) {
+	// compute position
+	int stopPosition = this.currentPosition;
+	switch (token) {
+		case TokenNameCOMMENT_LINE:
+			stopPosition = -this.lastCommentLinePosition;
+			break;
+		case TokenNameCOMMENT_BLOCK:
+			stopPosition = -this.currentPosition;
+			break;
 	}
 
-	//the buffer is of a correct size here
+	// a new comment is recorded
+	int length = this.commentStops.length;
+	if (++this.commentPtr >=  length) {
+		System.arraycopy(this.commentStops, 0, this.commentStops = new int[length + 30], 0, length);
+		//grows the positions buffers too
+		System.arraycopy(this.commentStarts, 0, this.commentStarts = new int[length + 30], 0, length);
+	}
+	this.commentStops[this.commentPtr] = stopPosition;
 	this.commentStarts[this.commentPtr] = this.startPosition;
 }
 
@@ -2228,21 +2283,21 @@
  * Reposition the scanner on some portion of the original source. The given endPosition is the last valid position.
  * Beyond this position, the scanner will answer EOF tokens (<code>ITerminalSymbols.TokenNameEOF</code>).
  * 
- * @param startPosition the given start position
- * @param endPosition the given end position
+ * @param begin the given start position
+ * @param end the given end position
  */
 public void resetTo(int begin, int end) {
 	//reset the scanner to a given position where it may rescan again
 
-	diet = false;
-	initialPosition = startPosition = currentPosition = begin;
-	eofPosition = end < Integer.MAX_VALUE ? end + 1 : end;
-	commentPtr = -1; // reset comment stack
-	foundTaskCount = 0;
+	this.diet = false;
+	this.initialPosition = this.startPosition = this.currentPosition = begin;
+	this.eofPosition = end < Integer.MAX_VALUE ? end + 1 : end;
+	this.commentPtr = -1; // reset comment stack
+	this.foundTaskCount = 0;
 	
 //	// if resetTo is used with being > than end.
-//	if (begin > eofPosition) {
-//		begin = eofPosition;
+//	if (begin > this.eofPosition) {
+//		begin = this.eofPosition;
 //	}
 }
 
@@ -2250,42 +2305,42 @@
 	// the string with "\\u" is a legal string of two chars \ and u
 	//thus we use a direct access to the source (for regular cases).
 
-	if (unicodeAsBackSlash) {
+	if (this.unicodeAsBackSlash) {
 		// consume next character
-		unicodeAsBackSlash = false;
-		if (((currentCharacter = source[currentPosition++]) == '\\') && (source[currentPosition] == 'u')) {
+		this.unicodeAsBackSlash = false;
+		if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') && (this.source[this.currentPosition] == 'u')) {
 			getNextUnicodeChar();
 		} else {
-			if (withoutUnicodePtr != 0) {
-				withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+			if (this.withoutUnicodePtr != 0) {
+				unicodeStoreAt(++this.withoutUnicodePtr);
 			}
 		}
 	} else
-		currentCharacter = source[currentPosition++];
-	switch (currentCharacter) {
+		this.currentCharacter = this.source[this.currentPosition++];
+	switch (this.currentCharacter) {
 		case 'b' :
-			currentCharacter = '\b';
+			this.currentCharacter = '\b';
 			break;
 		case 't' :
-			currentCharacter = '\t';
+			this.currentCharacter = '\t';
 			break;
 		case 'n' :
-			currentCharacter = '\n';
+			this.currentCharacter = '\n';
 			break;
 		case 'f' :
-			currentCharacter = '\f';
+			this.currentCharacter = '\f';
 			break;
 		case 'r' :
-			currentCharacter = '\r';
+			this.currentCharacter = '\r';
 			break;
 		case '\"' :
-			currentCharacter = '\"';
+			this.currentCharacter = '\"';
 			break;
 		case '\'' :
-			currentCharacter = '\'';
+			this.currentCharacter = '\'';
 			break;
 		case '\\' :
-			currentCharacter = '\\';
+			this.currentCharacter = '\\';
 			break;
 		default :
 			// -----------octal escape--------------
@@ -2293,36 +2348,36 @@
 			// OctalDigit OctalDigit
 			// ZeroToThree OctalDigit OctalDigit
 
-			int number = Character.getNumericValue(currentCharacter);
+			int number = Character.getNumericValue(this.currentCharacter);
 			if (number >= 0 && number <= 7) {
 				boolean zeroToThreeNot = number > 3;
-				if (Character.isDigit(currentCharacter = source[currentPosition++])) {
-					int digit = Character.getNumericValue(currentCharacter);
+				if (Character.isDigit(this.currentCharacter = this.source[this.currentPosition++])) {
+					int digit = Character.getNumericValue(this.currentCharacter);
 					if (digit >= 0 && digit <= 7) {
 						number = (number * 8) + digit;
-						if (Character.isDigit(currentCharacter = source[currentPosition++])) {
+						if (Character.isDigit(this.currentCharacter = this.source[this.currentPosition++])) {
 							if (zeroToThreeNot) {// has read \NotZeroToThree OctalDigit Digit --> ignore last character
-								currentPosition--;
+								this.currentPosition--;
 							} else {
-								digit = Character.getNumericValue(currentCharacter);
+								digit = Character.getNumericValue(this.currentCharacter);
 								if (digit >= 0 && digit <= 7){ // has read \ZeroToThree OctalDigit OctalDigit
 									number = (number * 8) + digit;
 								} else {// has read \ZeroToThree OctalDigit NonOctalDigit --> ignore last character
-									currentPosition--;
+									this.currentPosition--;
 								}
 							}
 						} else { // has read \OctalDigit NonDigit--> ignore last character
-							currentPosition--;
+							this.currentPosition--;
 						}
 					} else { // has read \OctalDigit NonOctalDigit--> ignore last character						
-						currentPosition--;
+						this.currentPosition--;
 					}
 				} else { // has read \OctalDigit --> ignore last character
-					currentPosition--;
+					this.currentPosition--;
 				}
 				if (number > 255)
 					throw new InvalidInputException(INVALID_ESCAPE);
-				currentCharacter = (char) number;
+				this.currentCharacter = (char) number;
 			} else
 				throw new InvalidInputException(INVALID_ESCAPE);
 	}
@@ -2334,27 +2389,27 @@
 	//then the length. If there are several
 	//keywors with the same length AND the same first char, then do another
 	//dispatch on the second char 
-	useAssertAsAnIndentifier = false;
-	while (getNextCharAsJavaIdentifierPart());
+	this.useAssertAsAnIndentifier = false;
+	while (getNextCharAsJavaIdentifierPart()){/*empty*/}
 
 	int index, length;
 	char[] data;
 	char firstLetter;
-	if (withoutUnicodePtr == 0)
+	if (this.withoutUnicodePtr == 0)
 
 		//quick test on length == 1 but not on length > 12 while most identifier
 		//have a length which is <= 12...but there are lots of identifier with
 		//only one char....
 
 		{
-		if ((length = currentPosition - startPosition) == 1)
+		if ((length = this.currentPosition - this.startPosition) == 1)
 			return TokenNameIdentifier;
-		data = source;
-		index = startPosition;
+		data = this.source;
+		index = this.startPosition;
 	} else {
-		if ((length = withoutUnicodePtr) == 1)
+		if ((length = this.withoutUnicodePtr) == 1)
 			return TokenNameIdentifier;
-		data = withoutUnicodeBuffer;
+		data = this.withoutUnicodeBuffer;
 		index = 1;
 	}
 
@@ -2381,11 +2436,11 @@
 						&& (data[++index] == 'e')
 						&& (data[++index] == 'r')
 						&& (data[++index] == 't')) {
-							if (assertMode) {
-								containsAssertKeyword = true;
+							if (this.assertMode) {
+								this.containsAssertKeyword = true;
 								return TokenNameassert;
 							} else {
-								useAssertAsAnIndentifier = true;
+								this.useAssertAsAnIndentifier = true;
 								return TokenNameIdentifier;								
 							}
 						} else {
@@ -2443,19 +2498,20 @@
 						else
 							return TokenNameIdentifier;
 					else
-						if ((data[index] == 'l')
-							&& (data[++index] == 'a')
-							&& (data[++index] == 's')
-							&& (data[++index] == 's'))
-							return TokenNameclass;
-						else
-							if ((data[index] == 'o')
-								&& (data[++index] == 'n')
+						if (data[index] == 'l')
+							if ((data[++index] == 'a')
 								&& (data[++index] == 's')
-								&& (data[++index] == 't'))
-								return TokenNameERROR; //const is not used in java ???????
-					else
-						return TokenNameIdentifier;
+								&& (data[++index] == 's'))
+								return TokenNameclass;
+							else
+								return TokenNameIdentifier;
+						else if ((data[index] == 'o')
+							&& (data[++index] == 'n')
+							&& (data[++index] == 's')
+							&& (data[++index] == 't'))
+							return TokenNameERROR; //const is not used in java ???????
+						else
+							return TokenNameIdentifier;
 				case 8 :
 					if ((data[++index] == 'o')
 						&& (data[++index] == 'n')
@@ -2537,11 +2593,13 @@
 						} else
 							return TokenNameIdentifier;
 					else
-						if ((data[index] == 'l')
-							&& (data[++index] == 'o')
-							&& (data[++index] == 'a')
-							&& (data[++index] == 't'))
-							return TokenNamefloat;
+						if (data[index] == 'l')
+							if ((data[++index] == 'o')
+								&& (data[++index] == 'a')
+								&& (data[++index] == 't'))
+								return TokenNamefloat;
+							else
+								return TokenNameIdentifier;
 						else
 							if ((data[index] == 'a')
 								&& (data[++index] == 'l')
@@ -2806,8 +2864,11 @@
 					else
 						return TokenNameIdentifier;
 				case 4 :
-					if ((data[++index] == 'h') && (data[++index] == 'i') && (data[++index] == 's'))
-						return TokenNamethis;
+					if (data[++index] == 'h') 
+						if ((data[++index] == 'i') && (data[++index] == 's'))
+							return TokenNamethis;
+						else
+							return TokenNameIdentifier;
 					else
 						if ((data[index] == 'r') && (data[++index] == 'u') && (data[++index] == 'e'))
 							return TokenNametrue;
@@ -2899,23 +2960,23 @@
 	//dotPrefix is true
 
 	boolean floating = dotPrefix;
-	if ((!dotPrefix) && (currentCharacter == '0')) {
+	if ((!dotPrefix) && (this.currentCharacter == '0')) {
 		if (getNextChar('x', 'X') >= 0) { //----------hexa-----------------
 			//force the first char of the hexa number do exist...
 			// consume next character
-			unicodeAsBackSlash = false;
-			if (((currentCharacter = source[currentPosition++]) == '\\')
-				&& (source[currentPosition] == 'u')) {
+			this.unicodeAsBackSlash = false;
+			if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
+				&& (this.source[this.currentPosition] == 'u')) {
 				getNextUnicodeChar();
 			} else {
-				if (withoutUnicodePtr != 0) {
-					withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+				if (this.withoutUnicodePtr != 0) {
+					unicodeStoreAt(++this.withoutUnicodePtr);
 				}
 			}
-			if (Character.digit(currentCharacter, 16) == -1)
+			if (Character.digit(this.currentCharacter, 16) == -1)
 				throw new InvalidInputException(INVALID_HEXA);
 			//---end forcing--
-			while (getNextCharAsDigit(16));
+			while (getNextCharAsDigit(16)){/*empty*/}
 			if (getNextChar('l', 'L') >= 0)
 				return TokenNameLongLiteral;
 			else
@@ -2925,7 +2986,7 @@
 		//there is x or X in the number
 		//potential octal ! ... some one may write 000099.0 ! thus 00100 < 00078.0 is true !!!!! crazy language
 		if (getNextCharAsDigit()) { //-------------potential octal-----------------
-			while (getNextCharAsDigit());
+			while (getNextCharAsDigit()){/*empty*/}
 
 			if (getNextChar('l', 'L') >= 0) {
 				return TokenNameLongLiteral;
@@ -2941,35 +3002,35 @@
 				boolean isInteger = true;
 				if (getNextChar('.')) { 
 					isInteger = false;
-					while (getNextCharAsDigit());
+					while (getNextCharAsDigit()){/*empty*/}
 				}
 				if (getNextChar('e', 'E') >= 0) { // consume next character
 					isInteger = false;
-					unicodeAsBackSlash = false;
-					if (((currentCharacter = source[currentPosition++]) == '\\')
-						&& (source[currentPosition] == 'u')) {
+					this.unicodeAsBackSlash = false;
+					if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
+						&& (this.source[this.currentPosition] == 'u')) {
 						getNextUnicodeChar();
 					} else {
-						if (withoutUnicodePtr != 0) {
-							withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+						if (this.withoutUnicodePtr != 0) {
+							unicodeStoreAt(++this.withoutUnicodePtr);
 						}
 					}
 
-					if ((currentCharacter == '-')
-						|| (currentCharacter == '+')) { // consume next character
-						unicodeAsBackSlash = false;
-						if (((currentCharacter = source[currentPosition++]) == '\\')
-							&& (source[currentPosition] == 'u')) {
+					if ((this.currentCharacter == '-')
+						|| (this.currentCharacter == '+')) { // consume next character
+						this.unicodeAsBackSlash = false;
+						if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
+							&& (this.source[this.currentPosition] == 'u')) {
 							getNextUnicodeChar();
 						} else {
-							if (withoutUnicodePtr != 0) {
-								withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+							if (this.withoutUnicodePtr != 0) {
+								unicodeStoreAt(++this.withoutUnicodePtr);
 							}
 						}
 					}
-					if (!Character.isDigit(currentCharacter))
+					if (!Character.isDigit(this.currentCharacter))
 						throw new InvalidInputException(INVALID_FLOAT);
-					while (getNextCharAsDigit());
+					while (getNextCharAsDigit()){/*empty*/}
 				}
 				if (getNextChar('f', 'F') >= 0)
 					return TokenNameFloatingPointLiteral;
@@ -2982,13 +3043,13 @@
 		}
 	}
 
-	while (getNextCharAsDigit());
+	while (getNextCharAsDigit()){/*empty*/}
 
 	if ((!dotPrefix) && (getNextChar('l', 'L') >= 0))
 		return TokenNameLongLiteral;
 
 	if ((!dotPrefix) && (getNextChar('.'))) { //decimal part that can be empty
-		while (getNextCharAsDigit());
+		while (getNextCharAsDigit()){/*empty*/}
 		floating = true;
 	}
 
@@ -2997,31 +3058,31 @@
 	if (getNextChar('e', 'E') >= 0) {
 		floating = true;
 		// consume next character
-		unicodeAsBackSlash = false;
-		if (((currentCharacter = source[currentPosition++]) == '\\')
-			&& (source[currentPosition] == 'u')) {
+		this.unicodeAsBackSlash = false;
+		if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
+			&& (this.source[this.currentPosition] == 'u')) {
 			getNextUnicodeChar();
 		} else {
-			if (withoutUnicodePtr != 0) {
-				withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+			if (this.withoutUnicodePtr != 0) {
+				unicodeStoreAt(++this.withoutUnicodePtr);
 			}
 		}
 
-		if ((currentCharacter == '-')
-			|| (currentCharacter == '+')) { // consume next character
-			unicodeAsBackSlash = false;
-			if (((currentCharacter = source[currentPosition++]) == '\\')
-				&& (source[currentPosition] == 'u')) {
+		if ((this.currentCharacter == '-')
+			|| (this.currentCharacter == '+')) { // consume next character
+			this.unicodeAsBackSlash = false;
+			if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
+				&& (this.source[this.currentPosition] == 'u')) {
 				getNextUnicodeChar();
 			} else {
-				if (withoutUnicodePtr != 0) {
-					withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter;
+				if (this.withoutUnicodePtr != 0) {
+					unicodeStoreAt(++this.withoutUnicodePtr);
 				}
 			}
 		}
-		if (!Character.isDigit(currentCharacter))
+		if (!Character.isDigit(this.currentCharacter))
 			throw new InvalidInputException(INVALID_FLOAT);
-		while (getNextCharAsDigit());
+		while (getNextCharAsDigit()){/*empty*/}
 	}
 
 	if (getNextChar('d', 'D') >= 0)
@@ -3035,28 +3096,29 @@
 }
 /**
  * Search the line number corresponding to a specific position
- *
+ * @param position int
+ * @return int
  */
 public final int getLineNumber(int position) {
 
-	if (lineEnds == null)
+	if (this.lineEnds == null)
 		return 1;
-	int length = linePtr+1;
+	int length = this.linePtr+1;
 	if (length == 0)
 		return 1;
 	int g = 0, d = length - 1;
 	int m = 0;
 	while (g <= d) {
 		m = (g + d) /2;
-		if (position < lineEnds[m]) {
+		if (position < this.lineEnds[m]) {
 			d = m-1;
-		} else if (position > lineEnds[m]) {
+		} else if (position > this.lineEnds[m]) {
 			g = m+1;
 		} else {
 			return m + 1;
 		}
 	}
-	if (position < lineEnds[m]) {
+	if (position < this.lineEnds[m]) {
 		return m+1;
 	}
 	return m+2;
@@ -3072,29 +3134,28 @@
 		this.source = sourceString;
 		sourceLength = sourceString.length;
 	}
-	startPosition = -1;
-	eofPosition = sourceLength;
-	initialPosition = currentPosition = 0;
-	containsAssertKeyword = false;
-	withoutUnicodeBuffer = new char[sourceLength];
+	this.startPosition = -1;
+	this.eofPosition = sourceLength;
+	this.initialPosition = this.currentPosition = 0;
+	this.containsAssertKeyword = false;
 }
 
 public String toString() {
-	if (startPosition == source.length)
-		return "EOF\n\n" + new String(source); //$NON-NLS-1$
-	if (currentPosition > source.length)
-		return "behind the EOF\n\n" + new String(source); //$NON-NLS-1$
+	if (this.startPosition == this.source.length)
+		return "EOF\n\n" + new String(this.source); //$NON-NLS-1$
+	if (this.currentPosition > this.source.length)
+		return "behind the EOF\n\n" + new String(this.source); //$NON-NLS-1$
 
-	char front[] = new char[startPosition];
-	System.arraycopy(source, 0, front, 0, startPosition);
+	char front[] = new char[this.startPosition];
+	System.arraycopy(this.source, 0, front, 0, this.startPosition);
 
-	int middleLength = (currentPosition - 1) - startPosition + 1;
+	int middleLength = (this.currentPosition - 1) - this.startPosition + 1;
 	char middle[];
 	if (middleLength > -1) {
 		middle = new char[middleLength];
 		System.arraycopy(
-			source, 
-			startPosition, 
+			this.source, 
+			this.startPosition, 
 			middle, 
 			0, 
 			middleLength);
@@ -3102,13 +3163,13 @@
 		middle = CharOperation.NO_CHAR;
 	}
 	
-	char end[] = new char[source.length - (currentPosition - 1)];
+	char end[] = new char[this.source.length - (this.currentPosition - 1)];
 	System.arraycopy(
-		source, 
-		(currentPosition - 1) + 1, 
+		this.source, 
+		(this.currentPosition - 1) + 1, 
 		end, 
 		0, 
-		source.length - (currentPosition - 1) - 1);
+		this.source.length - (this.currentPosition - 1) - 1);
 	
 	return new String(front)
 		+ "\n===============================\nStarts here -->" //$NON-NLS-1$
@@ -3328,4 +3389,21 @@
 			return "not-a-token"; //$NON-NLS-1$
 	}
 }
+public void unicodeInitializeBuffer(int length) {
+	this.withoutUnicodePtr = length;	
+    if (this.withoutUnicodeBuffer == null) this.withoutUnicodeBuffer = new char[length+(1+10)];
+    int bLength = this.withoutUnicodeBuffer.length;
+    if (1+length >= bLength) {
+        System.arraycopy(this.withoutUnicodeBuffer, 0, this.withoutUnicodeBuffer = new char[length + (1+10)], 0, bLength);
+    }
+	System.arraycopy(this.source, this.startPosition, this.withoutUnicodeBuffer, 1, length);    
+}
+public void unicodeStoreAt(int pos) {
+    if (this.withoutUnicodeBuffer == null) this.withoutUnicodeBuffer = new char[10];
+    int length = this.withoutUnicodeBuffer.length;
+    if (pos == length) {
+        System.arraycopy(this.withoutUnicodeBuffer, 0, this.withoutUnicodeBuffer = new char[length * 2], 0, length);
+    }
+	this.withoutUnicodeBuffer[pos] = this.currentCharacter;
+}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/RecordedParsingInformation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/RecordedParsingInformation.java
new file mode 100644
index 0000000..69fa248
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/RecordedParsingInformation.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2002, 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.IProblem;
+import org.eclipse.jdt.internal.compiler.CompilationResult;
+
+/**
+ * Use to keep track of recorded information during the parsing like comment positions,
+ * line ends or problems.
+ */
+public class RecordedParsingInformation {
+	public IProblem[] problems;
+	public int problemsCount;
+	public int[] lineEnds;
+	public int[][] commentPositions;
+	
+	public RecordedParsingInformation(IProblem[] problems, int[] lineEnds, int[][] commentPositions) {
+		this.problems = problems;
+		this.lineEnds = lineEnds;
+		this.commentPositions = commentPositions;
+		this.problemsCount = problems != null ? problems.length : 0;
+	}
+	
+	void updateRecordedParsingInformation(CompilationResult compilationResult) {
+		if (compilationResult.problems != null) {
+			this.problems = compilationResult.problems;
+			this.problemsCount = this.problems.length;
+		}
+	}
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ReferenceInfoAdapter.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ReferenceInfoAdapter.java
index c1d395d..3fedd9c 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ReferenceInfoAdapter.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ReferenceInfoAdapter.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/SimpleDocument.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/SimpleDocument.java
index 46e4214..9996bc3 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/SimpleDocument.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/SimpleDocument.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/SimpleLookupTable.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/SimpleLookupTable.java
index 554a343..5f411a4 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/SimpleLookupTable.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/SimpleLookupTable.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -28,12 +28,13 @@
 }
 
 public SimpleLookupTable(int size) {
-	if (size < 3) size = 3;
 	this.elementSize = 0;
-	this.threshold = size + 1; // size is the expected number of elements
-	int tableLength = 2 * size + 1;
-	this.keyTable = new Object[tableLength];
-	this.valueTable = new Object[tableLength];
+	this.threshold = size; // size represents the expected number of elements
+	int extraRoom = (int) (size * 1.5f);
+	if (this.threshold == extraRoom)
+		extraRoom++;
+	this.keyTable = new Object[extraRoom];
+	this.valueTable = new Object[extraRoom];
 }
 
 public Object clone() throws CloneNotSupportedException {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/SimpleSet.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/SimpleSet.java
index 4f42684..d8fc095 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/SimpleSet.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/SimpleSet.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/SimpleWordSet.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/SimpleWordSet.java
new file mode 100644
index 0000000..acaff10
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/SimpleWordSet.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * 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.util;
+
+import org.eclipse.jdt.core.compiler.CharOperation;
+
+public final class SimpleWordSet {
+
+// to avoid using Enumerations, walk the individual values skipping nulls
+public char[][] words;
+public int elementSize; // number of elements in the table
+public int threshold;
+
+public SimpleWordSet(int size) {
+	this.elementSize = 0;
+	this.threshold = size; // size represents the expected number of elements
+	int extraRoom = (int) (size * 1.5f);
+	if (this.threshold == extraRoom)
+		extraRoom++;
+	this.words = new char[extraRoom][];
+}
+
+public char[] add(char[] word) {
+	int length = this.words.length;
+	int index = CharOperation.hashCode(word) % length;
+	char[] current;
+	while ((current = words[index]) != null) {
+		if (CharOperation.equals(current, word)) return current;
+		if (++index == length) index = 0;
+	}
+	words[index] = word;
+
+	// assumes the threshold is never equal to the size of the table
+	if (++elementSize > threshold) rehash();
+	return word;
+}
+
+public boolean includes(char[] word) {
+	int length = this.words.length;
+	int index = CharOperation.hashCode(word) % length;
+	char[] current;
+	while ((current = words[index]) != null) {
+		if (CharOperation.equals(current, word)) return true;
+		if (++index == length) index = 0;
+	}
+	return false;
+}
+
+private void rehash() {
+	SimpleWordSet newSet = new SimpleWordSet(elementSize * 2); // double the number of expected elements
+	char[] current;
+	for (int i = words.length; --i >= 0;)
+		if ((current = words[i]) != null)
+			newSet.add(current);
+
+	this.words = newSet.words;
+	this.elementSize = newSet.elementSize;
+	this.threshold = newSet.threshold;
+}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/SourceFileAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/SourceFileAttribute.java
index a2f3b41..43d151c 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/SourceFileAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/SourceFileAttribute.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ToStringSorter.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ToStringSorter.java
index a69e341..a51c7d8 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ToStringSorter.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ToStringSorter.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Util.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Util.java
index 3f9a6d8..58f6713 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Util.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Util.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -21,6 +21,11 @@
 import org.eclipse.core.runtime.*;
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.core.util.IClassFileAttribute;
+import org.eclipse.jdt.core.util.IClassFileReader;
+import org.eclipse.jdt.core.util.ICodeAttribute;
+import org.eclipse.jdt.core.util.IFieldInfo;
+import org.eclipse.jdt.core.util.IMethodInfo;
 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.Argument;
 import org.eclipse.jdt.internal.compiler.ast.TypeReference;
@@ -29,8 +34,6 @@
 import org.eclipse.jdt.internal.core.Assert;
 import org.eclipse.jdt.internal.core.JavaModelManager;
 import org.eclipse.jdt.internal.core.PackageFragmentRoot;
-import org.eclipse.jdt.internal.core.index.impl.IndexedFile;
-import org.eclipse.jdt.internal.core.index.impl.WordEntry;
 import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.text.edits.MalformedTreeException;
 import org.eclipse.text.edits.TextEdit;
@@ -116,24 +119,24 @@
 		// for compatibility with MessageFormat which eliminates double quotes in original message
 		char[] messageWithNoDoubleQuotes =
 			CharOperation.replace(message.toCharArray(), DOUBLE_QUOTES, SINGLE_QUOTE);
-		message = new String(messageWithNoDoubleQuotes);
-		if (bindings == null) return message;
-
-		int length = message.length();
-		int start = -1;
+	
+		if (bindings == null) return new String(messageWithNoDoubleQuotes);
+	
+		int length = messageWithNoDoubleQuotes.length;
+		int start = 0;
 		int end = length;
 		StringBuffer output = null;
 		while (true) {
-			if ((end = message.indexOf('{', start)) > -1) {
-				if (output == null) output = new StringBuffer(80);
-				output.append(message.substring(start + 1, end));
-				if ((start = message.indexOf('}', end)) > -1) {
+			if ((end = CharOperation.indexOf('{', messageWithNoDoubleQuotes, start)) > -1) {
+				if (output == null) output = new StringBuffer(length+bindings.length*20);
+				output.append(messageWithNoDoubleQuotes, start, end - start);
+				if ((start = CharOperation.indexOf('}', messageWithNoDoubleQuotes, end + 1)) > -1) {
 					int index = -1;
+					String argId = new String(messageWithNoDoubleQuotes, end + 1, start - end - 1);
 					try {
-						index = Integer.parseInt(message.substring(end + 1, start));
+						index = Integer.parseInt(argId);
 						output.append(bindings[index]);
 					} catch (NumberFormatException nfe) { // could be nested message ID {compiler.name}
-						String argId = message.substring(end + 1, start);
 						boolean done = false;
 						if (!id.equals(argId)) {
 							String argMessage = null;
@@ -145,17 +148,18 @@
 								// unable to bind argument, ignore (will leave argument in)
 							}
 						}
-						if (!done) output.append(message.substring(end + 1, start + 1));
+						if (!done) output.append(messageWithNoDoubleQuotes, end + 1, start - end);
 					} catch (ArrayIndexOutOfBoundsException e) {
 						output.append("{missing " + Integer.toString(index) + "}"); //$NON-NLS-2$ //$NON-NLS-1$
 					}
+					start++;
 				} else {
-					output.append(message.substring(end, length));
+					output.append(messageWithNoDoubleQuotes, end, length);
 					break;
 				}
 			} else {
-				if (output == null) return message;
-				output.append(message.substring(start + 1, length));
+				if (output == null) return new String(messageWithNoDoubleQuotes);
+				output.append(messageWithNoDoubleQuotes, start, length - start);
 				break;
 			}
 		}
@@ -317,7 +321,7 @@
 		s3.getChars(0, l3, buf, l1 + l2);
 		return new String(buf);
 	}
-	
+		
 	/**
 	 * Converts a type signature from the IBinaryType representation to the DC representation.
 	 */
@@ -580,7 +584,46 @@
 		// not found
 		return null;
 	}
+	
+	public static IClassFileAttribute getAttribute(IClassFileReader classFileReader, char[] attributeName) {
+		IClassFileAttribute[] attributes = classFileReader.getAttributes();
+		for (int i = 0, max = attributes.length; i < max; i++) {
+			if (CharOperation.equals(attributes[i].getAttributeName(), attributeName)) {
+				return attributes[i];
+			}
+		}
+		return null;
+	}
+	
+	public static IClassFileAttribute getAttribute(ICodeAttribute codeAttribute, char[] attributeName) {
+		IClassFileAttribute[] attributes = codeAttribute.getAttributes();
+		for (int i = 0, max = attributes.length; i < max; i++) {
+			if (CharOperation.equals(attributes[i].getAttributeName(), attributeName)) {
+				return attributes[i];
+			}
+		}
+		return null;
+	}	
+	
+	public static IClassFileAttribute getAttribute(IFieldInfo fieldInfo, char[] attributeName) {
+		IClassFileAttribute[] attributes = fieldInfo.getAttributes();
+		for (int i = 0, max = attributes.length; i < max; i++) {
+			if (CharOperation.equals(attributes[i].getAttributeName(), attributeName)) {
+				return attributes[i];
+			}
+		}
+		return null;
+	}
 
+	public static IClassFileAttribute getAttribute(IMethodInfo methodInfo, char[] attributeName) {
+		IClassFileAttribute[] attributes = methodInfo.getAttributes();
+		for (int i = 0, max = attributes.length; i < max; i++) {
+			if (CharOperation.equals(attributes[i].getAttributeName(), attributeName)) {
+				return attributes[i];
+			}
+		}
+		return null;
+	}
 	/**
 	 * Get the jdk level of this root.
 	 * The value can be:
@@ -779,11 +822,19 @@
 	 * Returns the given file's contents as a character array.
 	 */
 	public static char[] getResourceContentsAsCharArray(IFile file) throws JavaModelException {
-		String encoding = JavaCore.create(file.getProject()).getOption(JavaCore.CORE_ENCODING, true);
+		// Get encoding from file
+		String encoding = null;
+		try {
+			encoding = file.getCharset();
+		}
+		catch(CoreException ce) {
+			// do not use any encoding
+		}
 		return getResourceContentsAsCharArray(file, encoding);
 	}
 
 	public static char[] getResourceContentsAsCharArray(IFile file, String encoding) throws JavaModelException {
+		// Get resource contents
 		InputStream stream= null;
 		try {
 			stream = new BufferedInputStream(file.getContents(true));
@@ -816,15 +867,22 @@
 	}
 	
 		/*
-	 * Returns the index of the first argument paths which is strictly enclosing the path to check
+	 * Returns the index of the most specific argument paths which is strictly enclosing the path to check
 	 */
 	public static int indexOfEnclosingPath(IPath checkedPath, IPath[] paths, int pathCount) {
 
+	    int bestMatch = -1, bestLength = -1;
 		for (int i = 0; i < pathCount; i++){
 			if (paths[i].equals(checkedPath)) continue;
-			if (paths[i].isPrefixOf(checkedPath)) return i;
+			if (paths[i].isPrefixOf(checkedPath)) {
+			    int currentLength = paths[i].segmentCount();
+			    if (currentLength > bestLength) {
+			        bestLength = currentLength;
+			        bestMatch = i;
+			    }
+			}
 		}
-		return -1;
+		return bestMatch;
 	}
 	
 	/*
@@ -852,51 +910,87 @@
 
 	/*
 	 * Returns whether the given java element is exluded from its root's classpath.
+	 * It doesn't check whether the root itself is on the classpath or not
 	 */
 	public static final boolean isExcluded(IJavaElement element) {
 		int elementType = element.getElementType();
 		switch (elementType) {
+			case IJavaElement.JAVA_MODEL:
+			case IJavaElement.JAVA_PROJECT:
+			case IJavaElement.PACKAGE_FRAGMENT_ROOT:
+				return false;
+
 			case IJavaElement.PACKAGE_FRAGMENT:
 				PackageFragmentRoot root = (PackageFragmentRoot)element.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
 				IResource resource = element.getResource();
-				return resource != null && Util.isExcluded(resource, root.fullExclusionPatternChars());
+				return resource != null && isExcluded(resource, root.fullInclusionPatternChars(), root.fullExclusionPatternChars());
+				
 			case IJavaElement.COMPILATION_UNIT:
 				root = (PackageFragmentRoot)element.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
 				resource = element.getResource();
-				if (resource != null && Util.isExcluded(resource, root.fullExclusionPatternChars()))
+				if (resource != null && isExcluded(resource, root.fullInclusionPatternChars(), root.fullExclusionPatternChars()))
 					return true;
 				return isExcluded(element.getParent());
+				
 			default:
 				IJavaElement cu = element.getAncestor(IJavaElement.COMPILATION_UNIT);
 				return cu != null && isExcluded(cu);
 		}
 	}
 	/*
-	 * Returns whether the given resource path matches one of the exclusion
+	 * Returns whether the given resource path matches one of the inclusion/exclusion
 	 * patterns.
-	 * 
+	 * NOTE: should not be asked directly using pkg root pathes
+	 * @see IClasspathEntry#getInclusionPatterns
 	 * @see IClasspathEntry#getExclusionPatterns
 	 */
-	public final static boolean isExcluded(IPath resourcePath, char[][] exclusionPatterns) {
-		if (exclusionPatterns == null) return false;
+	public final static boolean isExcluded(IPath resourcePath, char[][] inclusionPatterns, char[][] exclusionPatterns, boolean isFolderPath) {
+		if (inclusionPatterns == null && exclusionPatterns == null) return false;
 		char[] path = resourcePath.toString().toCharArray();
-		for (int i = 0, length = exclusionPatterns.length; i < length; i++)
-			if (CharOperation.pathMatch(exclusionPatterns[i], path, true, '/'))
-				return true;
+
+		inclusionCheck: if (inclusionPatterns != null) {
+			for (int i = 0, length = inclusionPatterns.length; i < length; i++) {
+				char[] pattern = inclusionPatterns[i];
+				char[] folderPattern = pattern;
+				if (isFolderPath) {
+					int lastSlash = CharOperation.lastIndexOf('/', pattern);
+					if (lastSlash != -1 && lastSlash != pattern.length-1){ // trailing slash -> adds '**' for free (see http://ant.apache.org/manual/dirtasks.html)
+						int star = CharOperation.indexOf('*', pattern, lastSlash);
+						if ((star == -1
+								|| star >= pattern.length-1 
+								|| pattern[star+1] != '*')) {
+							folderPattern = CharOperation.subarray(pattern, 0, lastSlash);
+						}
+					}
+				}
+				if (CharOperation.pathMatch(folderPattern, path, true, '/')) {
+					break inclusionCheck;
+				}
+			}
+			return true; // never included
+		}
+		if (isFolderPath) {
+			path = CharOperation.concat(path, new char[] {'*'}, '/');
+		}
+		exclusionCheck: if (exclusionPatterns != null) {
+			for (int i = 0, length = exclusionPatterns.length; i < length; i++) {
+				if (CharOperation.pathMatch(exclusionPatterns[i], path, true, '/')) {
+					return true;
+				}
+			}
+		}
 		return false;
 	}	
 	
 	/*
 	 * Returns whether the given resource matches one of the exclusion patterns.
-	 * 
+	 * NOTE: should not be asked directly using pkg root pathes
 	 * @see IClasspathEntry#getExclusionPatterns
 	 */
-	public final static boolean isExcluded(IResource resource, char[][] exclusionPatterns) {
+	public final static boolean isExcluded(IResource resource, char[][] inclusionPatterns, char[][] exclusionPatterns) {
 		IPath path = resource.getFullPath();
 		// ensure that folders are only excluded if all of their children are excluded
-		if (resource.getType() == IResource.FOLDER)
-			path = path.append("*"); //$NON-NLS-1$
-		return isExcluded(path, exclusionPatterns);
+		return isExcluded(path, inclusionPatterns, exclusionPatterns, resource.getType() == IResource.FOLDER);
 	}
 
 	/**
@@ -985,7 +1079,7 @@
 		}
 		IStatus status= new Status(
 			IStatus.ERROR, 
-			JavaCore.getPlugin().getDescriptor().getUniqueIdentifier(), 
+			JavaCore.PLUGIN_ID, 
 			IStatus.ERROR, 
 			message, 
 			e); 
@@ -1048,9 +1142,8 @@
 				result.append(lastLine);
 			}
 			return result.getContents();
-		} else {
-			return text;
 		}
+		return text;
 	}
 
 	/**
@@ -1156,32 +1249,6 @@
 			quickSort(sortedCollection, left, original_right);
 		}
 	}
-	private static void quickSort(IndexedFile[] list, int left, int right) {
-		int original_left= left;
-		int original_right= right;
-		String mid= list[(left + right) / 2].path;
-		do {
-			while (list[left].path.compareTo(mid) < 0) {
-				left++;
-			}
-			while (mid.compareTo(list[right].path) < 0) {
-				right--;
-			}
-			if (left <= right) {
-				IndexedFile tmp= list[left];
-				list[left]= list[right];
-				list[right]= tmp;
-				left++;
-				right--;
-			}
-		} while (left <= right);
-		if (original_left < right) {
-			quickSort(list, original_left, right);
-		}
-		if (left < original_right) {
-			quickSort(list, left, original_right);
-		}
-	}
 	private static void quickSort(int[] list, int left, int right) {
 		int original_left= left;
 		int original_right= right;
@@ -1301,32 +1368,6 @@
 			quickSort(sortedCollection, left, original_right);
 		}
 	}
-	private static void quickSort(WordEntry[] list, int left, int right) {
-		int original_left= left;
-		int original_right= right;
-		char[] mid= list[(left + right) / 2].fWord;
-		do {
-			while (compare(list[left].fWord, mid) < 0) {
-				left++;
-			}
-			while (compare(mid, list[right].fWord) < 0) {
-				right--;
-			}
-			if (left <= right) {
-				WordEntry tmp= list[left];
-				list[left]= list[right];
-				list[right]= tmp;
-				left++;
-				right--;
-			}
-		} while (left <= right);
-		if (original_left < right) {
-			quickSort(list, original_left, right);
-		}
-		if (left < original_right) {
-			quickSort(list, left, original_right);
-		}
-	}
 
 	/**
 	 * Sort the strings in the given collection in reverse alphabetical order.
@@ -1457,10 +1498,6 @@
 		if (objects.length > 1)
 			quickSort(objects, 0, objects.length - 1);
 	}
-	public static void sort(IndexedFile[] list) {
-		if (list.length > 1)
-			quickSort(list, 0, list.length - 1);
-	}
 	public static void sort(int[] list) {
 		if (list.length > 1)
 			quickSort(list, 0, list.length - 1);
@@ -1490,10 +1527,6 @@
 		if (strings.length > 1)
 			quickSort(strings, 0, strings.length - 1);
 	}
-	public static void sort(WordEntry[] list) {
-		if (list.length > 1)
-			quickSort(list, 0, list.length - 1);
-	}
 
 	/**
 	 * Sorts an array of Comparable objects, returning a new array
@@ -1665,6 +1698,20 @@
 	public static void validateTypeSignature(String sig, boolean allowVoid) {
 		Assert.isTrue(isValidTypeSignature(sig, allowVoid));
 	}
+	public static void verbose(String log) {
+		verbose(log, System.out);
+	}
+	public static synchronized void verbose(String log, PrintStream printStream) {
+		int start = 0;
+		do {
+			int end = log.indexOf('\n', start);
+			printStream.print(Thread.currentThread());
+			printStream.print(" "); //$NON-NLS-1$
+			printStream.print(log.substring(start, end == -1 ? log.length() : end+1));
+			start = end+1;
+		} while (start != 0);
+		printStream.println();
+	}
 	/**
 	 * Writes a string to the given output stream using UTF-8 
 	 * encoding in a machine-independent manner. 
@@ -1677,10 +1724,11 @@
 	 * for the character. 
 	 *
 	 * @param      str   a string to be written.
+	 * @return     the number of bytes written to the stream.
 	 * @exception  IOException  if an I/O error occurs.
 	 * @since      JDK1.0
 	 */
-	public static void writeUTF(OutputStream out, char[] str) throws IOException {
+	public static int writeUTF(OutputStream out, char[] str) throws IOException {
 		int strlen= str.length;
 		int utflen= 0;
 		for (int i= 0; i < strlen; i++) {
@@ -1697,18 +1745,24 @@
 			throw new UTFDataFormatException();
 		out.write((utflen >>> 8) & 0xFF);
 		out.write((utflen >>> 0) & 0xFF);
-		for (int i= 0; i < strlen; i++) {
-			int c= str[i];
-			if ((c >= 0x0001) && (c <= 0x007F)) {
-				out.write(c);
-			} else if (c > 0x07FF) {
-				out.write(0xE0 | ((c >> 12) & 0x0F));
-				out.write(0x80 | ((c >> 6) & 0x3F));
-				out.write(0x80 | ((c >> 0) & 0x3F));
-			} else {
-				out.write(0xC0 | ((c >> 6) & 0x1F));
-				out.write(0x80 | ((c >> 0) & 0x3F));
+		if (strlen == utflen) {
+			for (int i= 0; i < strlen; i++)
+				out.write(str[i]);
+		} else {
+			for (int i= 0; i < strlen; i++) {
+				int c= str[i];
+				if ((c >= 0x0001) && (c <= 0x007F)) {
+					out.write(c);
+				} else if (c > 0x07FF) {
+					out.write(0xE0 | ((c >> 12) & 0x0F));
+					out.write(0x80 | ((c >> 6) & 0x3F));
+					out.write(0x80 | ((c >> 0) & 0x3F));
+				} else {
+					out.write(0xC0 | ((c >> 6) & 0x1F));
+					out.write(0x80 | ((c >> 0) & 0x3F));
+				}
 			}
 		}
+		return utflen + 2; // the number of bytes written to the stream
 	}	
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/messages.properties b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/messages.properties
index b6021e2..8670c8f 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/messages.properties
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/messages.properties
@@ -1,5 +1,5 @@
 ###############################################################################
-# Copyright (c) 2000, 2003 IBM Corporation and others.
+# 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
@@ -12,34 +12,34 @@
 ### JavaModel messages.
 
 ### hierarchy
-hierarchy.nullProject = Project argument cannot be null.
-hierarchy.nullRegion = Region cannot be null.
-hierarchy.nullFocusType = Type focus cannot be null.
+hierarchy.nullProject = Project argument cannot be null
+hierarchy.nullRegion = Region cannot be null
+hierarchy.nullFocusType = Type focus cannot be null
 hierarchy.creating = Creating type hierarchy...
 hierarchy.creatingOnType = Creating type hierarchy on {0}...
 
 ### java element
-element.doesNotExist = {0} does not exist.
-element.invalidClassFileName = Class file name must end with .class.
+element.doesNotExist = {0} does not exist
+element.invalidClassFileName = Class file name must end with .class
 element.reconciling = Reconciling...
 element.attachingSource = Attaching source...
-element.invalidType = Type is not one of the defined constants.
+element.invalidType = Type is not one of the defined constants
 element.invalidResourceForProject = Illegal argument - must be one of IProject, IFolder, or IFile
-element.nullName = Name cannot be null.
-element.nullType = Type cannot be null.
-element.illegalParent = Illegal parent argument.
+element.nullName = Name cannot be null
+element.nullType = Type cannot be null
+element.illegalParent = Illegal parent argument
 sourcetype.invalidName = The source type has an invalid name: {0}
 
 ### java model operations
-operation.needElements = Operation requires one or more elements.
-operation.needName = Operation requires a name.
-operation.needPath = Operation requires a path.
+operation.needElements = Operation requires one or more elements
+operation.needName = Operation requires a name
+operation.needPath = Operation requires a path
 operation.needAbsolutePath = Operation requires an absolute path. Relative path specified was: ''{0}''
 operation.needString = Operation requires a String.
 operation.notSupported = Operation not supported for specified element type(s):
-operation.cancelled = Operation cancelled.
-operation.nullContainer = Container cannot be null.
-operation.nullName = Name cannot be null.
+operation.cancelled = Operation cancelled
+operation.nullContainer = Container cannot be null
+operation.nullName = Name cannot be null
 operation.copyElementProgress = Copying elements...
 operation.moveElementProgress = Moving elements...
 operation.renameElementProgress = Renaming elements...
@@ -56,7 +56,7 @@
 operation.createTypeProgress = Creating a type...
 operation.deleteElementProgress = Deleting elements...
 operation.deleteResourceProgress = Deleting resources...
-operation.cannotRenameDefaultPackage = Default package cannot be renamed.
+operation.cannotRenameDefaultPackage = Default package cannot be renamed
 operation.pathOutsideProject = Path ''{0}'' must denote location inside project {1}
 operation.sortelements = Sorting elements...
 
@@ -83,115 +83,118 @@
 build.done = Build done
 
 ### build errors
-build.wrongFileFormat = Wrong file format.
-build.cannotSaveState = Error saving last build state for project {0}.
-build.cannotSaveStates = Error saving build states.
-build.initializationError = Builder initialization error.
-build.serializationError = Builder serialization error.
+build.wrongFileFormat = Wrong file format
+build.cannotSaveState = Error saving last build state for project {0}
+build.cannotSaveStates = Error saving build states
+build.initializationError = Builder initialization error
+build.serializationError = Builder serialization error
 
 ### build inconsistencies
-build.classFileCollision = Class file collision. {0}
-build.duplicateClassFile = The type {0} is already defined.
-build.duplicateResource = The resource is a duplicate of {0} and was not copied to the output folder.
-build.inconsistentClassFile = A class file was not written. The project may be inconsistent, if so try refreshing this project and rebuilding it.
-build.inconsistentProject = The project was not built due to "{0}". Fix the problem, then try refreshing this project and rebuilding it since it may be inconsistent.
-build.incompleteClassPath = The project was not built since its build path is incomplete. Cannot find the class file for {0}. Fix the build path then try rebuilding this project.
-build.missingSourceFile = The project was not built since the source file {0} could not be read.
-build.prereqProjectHasClasspathProblems = The project was not built since it depends on {0}, which has build path errors.
-build.prereqProjectMustBeRebuilt = The project cannot be built until its prerequisite {0} is rebuilt. Rebuilding all projects is recommended.
-build.abortDueToClasspathProblems = The project cannot be built until build path errors are resolved.
+build.classFileCollision = Class file collision: {0}
+build.duplicateClassFile = The type {0} is already defined
+build.duplicateResource = The resource is a duplicate of {0} and was not copied to the output folder
+build.inconsistentClassFile = A class file was not written. The project may be inconsistent, if so try refreshing this project and building it
+build.inconsistentProject = The project was not built due to "{0}". Fix the problem, then try refreshing this project and building it since it may be inconsistent
+build.incompleteClassPath = The project was not built since its build path is incomplete. Cannot find the class file for {0}. Fix the build path then try building this project
+build.missingSourceFile = The project was not built since the source file {0} could not be read
+build.prereqProjectHasClasspathProblems = The project was not built since it depends on {0}, which has build path errors
+build.prereqProjectMustBeRebuilt = The project cannot be built until its prerequisite {0} is built. Cleaning and building all projects is recommended
+build.abortDueToClasspathProblems = The project cannot be built until build path errors are resolved
 
 ### status
 status.cannotUseDeviceOnPath = Operation requires a path with no device. Path specified was: {0}
-status.coreException = Core exception.
-status.defaultPackageReadOnly = Default package is read-only.
-status.evaluationError = Evaluation error: {0}.
-status.JDOMError = JDOM error.
-status.IOException = I/O exception.
-status.indexOutOfBounds = Index out of bounds.
-status.invalidContents = Invalid contents specified.
-status.invalidDestination = Invalid destination: ''{0}''.
-status.invalidName = Invalid name specified: {0}.
-status.invalidPackage = Invalid package: {0}.
-status.invalidPath = Invalid path: ''{0}''.
-status.invalidProject = Invalid project: {0}.
-status.invalidResource = Invalid resource: {0}.
-status.invalidResourceType = Invalid resource type for {0}.
-status.invalidSibling = Invalid sibling: {0}.
-status.nameCollision = {0} already exists in target.
+status.coreException = Core exception
+status.defaultPackageReadOnly = Default package is read-only
+status.evaluationError = Evaluation error: {0}
+status.JDOMError = JDOM error
+status.IOException = I/O exception
+status.indexOutOfBounds = Index out of bounds
+status.invalidContents = Invalid contents specified
+status.invalidDestination = Invalid destination: ''{0}''
+status.invalidName = Invalid name specified: {0}
+status.invalidPackage = Invalid package: {0}
+status.invalidPath = Invalid path: ''{0}''
+status.invalidProject = Invalid project: {0}
+status.invalidResource = Invalid resource: {0}
+status.invalidResourceType = Invalid resource type for {0}
+status.invalidSibling = Invalid sibling: {0}
+status.nameCollision = {0} already exists in target
 status.noLocalContents = Cannot find local contents for resource: {0}
 status.OK = OK
-status.readOnly = {0} is read-only.
-status.targetException = Target exception.
-status.updateConflict = Update conflict.
+status.readOnly = {0} is read-only
+status.targetException = Target exception
+status.updateConflict = Update conflict
 
 ### classpath
 classpath.buildPath = Build path
-classpath.cannotNestEntryInEntry = Cannot nest ''{0}'' inside ''{1}''. To enable the nesting exclude ''{2}'' from ''{1}''.
-classpath.cannotNestEntryInLibrary = Cannot nest ''{0}'' inside library ''{1}''.
-classpath.cannotNestEntryInOutput = Cannot nest ''{0}'' inside output folder ''{1}''.
-classpath.cannotNestOutputInEntry = Cannot nest output folder ''{0}'' inside ''{1}''.
-classpath.cannotNestOutputInOutput = Cannot nest output folder ''{0}'' inside output folder ''{1}''.
-classpath.cannotReadClasspathFile = Unable to read ''.classpath'' file of project {0}.
+classpath.cannotNestEntryInEntry = Cannot nest ''{0}'' inside ''{1}''. To enable the nesting exclude ''{2}'' from ''{1}''
+classpath.cannotNestEntryInLibrary = Cannot nest ''{0}'' inside library ''{1}''
+classpath.cannotNestEntryInOutput = Cannot nest ''{0}'' inside output folder ''{1}''
+classpath.cannotNestOutputInEntry = Cannot nest output folder ''{0}'' inside ''{1}''
+classpath.cannotNestOutputInOutput = Cannot nest output folder ''{0}'' inside output folder ''{1}''
+classpath.cannotReadClasspathFile = Unable to read ''.classpath'' file of project {0}
 classpath.cannotReferToItself = Project cannot reference itself: {0}
-classpath.cannotUseDistinctSourceFolderAsOutput = Source folder ''{0}'' in project {2} cannot output to distinct source folder ''{1}''.
-classpath.cannotUseLibraryAsOutput = Source folder ''{0}'' in project {2} cannot output to library ''{1}''.
-classpath.closedProject = Required project: {0} needs to be open.
+classpath.cannotUseDistinctSourceFolderAsOutput = Source folder ''{0}'' in project {2} cannot output to distinct source folder ''{1}''
+classpath.cannotUseLibraryAsOutput = Source folder ''{0}'' in project {2} cannot output to library ''{1}''
+classpath.closedProject = Required project: {0} needs to be open
 classpath.couldNotWriteClasspathFile = Could not write ''.classpath'' file of project {0}: {1}
 classpath.cycle = A cycle was detected in the build path of project: {0}
 classpath.duplicateEntryPath = Build path contains duplicate entry: ''{0}'' for project {1}
-classpath.illegalContainerPath = Illegal classpath container path: ''{0}'' in project {1}, must have at least one segment (containerID+hints).
+classpath.illegalContainerPath = Illegal classpath container path: ''{0}'' in project {1}, must have at least one segment (containerID+hints)
 classpath.illegalEntryInClasspathFile = Illegal entry in ''.classpath'' of project {0} file: {1}
-classpath.illegalLibraryPath = Illegal path for required library: ''{0}'' in project {1}.
-classpath.illegalProjectPath = Illegal path for required project: ''{0}'' in project {1}.
-classpath.illegalSourceFolderPath = Illegal path for required source folder: ''{0}'' in project {1}.
-classpath.illegalVariablePath = Illegal classpath variable path: ''{0}'' in project {1}, must have at least one segment.
+classpath.illegalLibraryPath = Illegal path for required library: ''{0}'' in project {1}
+classpath.illegalLibraryArchive = Illegal type of archive for required library: ''{0}'' in project {1}
+classpath.illegalExternalFolder = Required library cannot denote external folder: ''{0}'' for project {1}
+classpath.illegalProjectPath = Illegal path for required project: ''{0}'' in project {1}
+classpath.illegalSourceFolderPath = Illegal path for required source folder: ''{0}'' in project {1}
+classpath.illegalVariablePath = Illegal classpath variable path: ''{0}'' in project {1}, must have at least one segment
 classpath.invalidClasspathInClasspathFile = Invalid build path in ''.classpath'' file of project {0}: {1}
-classpath.invalidContainer = Invalid classpath container: ''{0}'' in project {1}.
-classpath.mustEndWithSlash = End exclusion filter ''{0}'' with / to fully exclude ''{1}''.
-classpath.unboundContainerPath = Unbound classpath container: ''{0}'' in project {1}.
-classpath.unboundLibrary = Project {1} is missing required library: ''{0}''.
-classpath.unboundProject = Project {1} is missing required Java project: ''{0}''.
+classpath.invalidContainer = Invalid classpath container: ''{0}'' in project {1}
+classpath.mustEndWithSlash = End exclusion filter ''{0}'' with / to fully exclude ''{1}''
+classpath.unboundContainerPath = Unbound classpath container: ''{0}'' in project {1}
+classpath.unboundLibrary = Project {1} is missing required library: ''{0}''
+classpath.unboundProject = Project {1} is missing required Java project: ''{0}''
 classpath.settingOutputLocationProgress = Setting output location for: ''{0}''
 classpath.settingProgress = Setting classpath for: {0}
-classpath.unboundSourceAttachment = Invalid source attachment: ''{0}'' for required library ''{1}'' in project {1}.
-classpath.unboundSourceFolder = Project {1} is missing required source folder: ''{0}''.
-classpath.unboundVariablePath = Unbound classpath variable: ''{0}'' in project {1}.
+classpath.unboundSourceAttachment = Invalid source attachment: ''{0}'' for required library ''{1}'' in project {1}
+classpath.unboundSourceFolder = Project {1} is missing required source folder: ''{0}''
+classpath.unboundVariablePath = Unbound classpath variable: ''{0}'' in project {1}
 classpath.unknownKind = Unknown kind: ''{0}''
 classpath.xmlFormatError = XML format error in ''.classpath'' file of project {0}: {1}
-classpath.disabledExclusionPatterns = Exclusion patterns are disabled in project {1}, cannot exclude from entry: ''{0}''.
-classpath.disabledMultipleOutputLocations = Multiple output locations are disabled in project {1}, cannot associate entry: ''{0}'' with a specific output.
-classpath.incompatibleLibraryJDKLevel = Incompatible .class files version in required binaries. Project ''{0}'' is targeting a {1} runtime, but is compiled against ''{2}'' which requires a {3} runtime.
+classpath.disabledInclusionExclusionPatterns = Inclusion or exclusion patterns are disabled in project {1}, cannot selectively include or exclude from entry: ''{0}''
+classpath.disabledMultipleOutputLocations = Multiple output locations are disabled in project {1}, cannot associate entry: ''{0}'' with a specific output
+classpath.incompatibleLibraryJDKLevel = Incompatible .class files version in required binaries. Project ''{0}'' is targeting a {1} runtime, but is compiled against ''{2}'' which requires a {3} runtime
 
 ### miscellaneous
-file.notFound = File not found: ''{0}''.
-file.badFormat = Bad format.
-path.nullPath = Path cannot be null.
-path.mustBeAbsolute = Path must be absolute.
+file.notFound = File not found: ''{0}''
+file.badFormat = Bad format
+path.nullPath = Path cannot be null
+path.mustBeAbsolute = Path must be absolute
 cache.invalidLoadFactor = Incorrect load factor
+savedState.jobName = Processing Java changes since last activation
 
 ### java conventions
-convention.unit.nullName = Compilation unit name must not be null.
-convention.unit.notJavaName = Compilation unit name must end with .java.
-convention.classFile.nullName = .class file name must not be null.
-convention.classFile.notClassFileName = .class file name must end with .class.
-convention.illegalIdentifier = ''{0}'' is not a valid Java identifier.
-convention.import.nullImport = An import declaration must not be null.
-convention.import.unqualifiedImport = An import declaration must not end with an unqualified *.
-convention.type.nullName = A Java type name must not be null.
-convention.type.nameWithBlanks = A Java type name must not start or end with a blank.
-convention.type.dollarName = By convention, Java type names usually don''t contain the $ character.
-convention.type.lowercaseName = By convention, Java type names usually start with an uppercase letter.
-convention.type.invalidName = The type name ''{0}'' is not a valid identifier.
-convention.package.nullName = A package name must not be null.
-convention.package.emptyName = A package name must not be empty.
-convention.package.dotName = A package name cannot start or end with a dot.
-convention.package.nameWithBlanks = A package name must not start or end with a blank.
-convention.package.consecutiveDotsName = A package name must not contain two consecutive dots.
-convention.package.uppercaseName = By convention, package names usually start with a lowercase letter.
+convention.unit.nullName = Compilation unit name must not be null
+convention.unit.notJavaName = Compilation unit name must end with .java
+convention.classFile.nullName = .class file name must not be null
+convention.classFile.notClassFileName = .class file name must end with .class
+convention.illegalIdentifier = ''{0}'' is not a valid Java identifier
+convention.import.nullImport = An import declaration must not be null
+convention.import.unqualifiedImport = An import declaration must not end with an unqualified *
+convention.type.nullName = A Java type name must not be null
+convention.type.nameWithBlanks = A Java type name must not start or end with a blank
+convention.type.dollarName = By convention, Java type names usually don''t contain the $ character
+convention.type.lowercaseName = By convention, Java type names usually start with an uppercase letter
+convention.type.invalidName = The type name ''{0}'' is not a valid identifier
+convention.package.nullName = A package name must not be null
+convention.package.emptyName = A package name must not be empty
+convention.package.dotName = A package name cannot start or end with a dot
+convention.package.nameWithBlanks = A package name must not start or end with a blank
+convention.package.consecutiveDotsName = A package name must not contain two consecutive dots
+convention.package.uppercaseName = By convention, package names usually start with a lowercase letter
 
 ### DOM
-dom.cannotDetail = Unable to generate detailed source indexes.
+dom.cannotDetail = Unable to generate detailed source indexes
 dom.nullTypeParameter = Cannot add parameter with null type
 dom.nullNameParameter = Cannot add parameter with null name
 dom.nullReturnType = Return type cannot be null
@@ -211,8 +214,8 @@
 dom.nullInterfaces = Illegal to set super interfaces to null
 
 ### correction
-correction.nullRequestor = Requestor cannot be null.
-correction.nullUnit = Compilation unit cannot be null.
+correction.nullRequestor = Requestor cannot be null
+correction.nullUnit = Compilation unit cannot be null
 
 ### Eclipse Java Core Search messages.
 
@@ -220,54 +223,54 @@
 exception.wrongFormat = Wrong format
 process.name = Java indexing
 manager.filesToIndex = {0} files to index
+manager.indexingInProgress = Java indexing in progress
 
 ### Disassembler messages
 
 ### disassembler
-classfileformat.targetoption = Version (target {0}) 
 disassembler.description = Default classfile disassembler
 disassembler.opentypedeclaration =\ {
 disassembler.closetypedeclaration = }
 disassembler.parametername = arg
 disassembler.endofmethodheader = ;
-disassembler.commentstart = /* 
-disassembler.commentend = \ */
-disassembler.begincommentline = \ *\ 
+disassembler.begincommentline = //\ 
 disassembler.fieldhasconstant =\ =\ 
 disassembler.endoffieldheader = ;
+disassembler.sourceattributeheader = Compiled from 
+disassembler.enclosingmethodheader = Enclosing Method:
 disassembler.exceptiontableheader = Exception Table:
-disassembler.linenumberattributeheader = Line number attribute:
-disassembler.localvariabletableattributeheader = Local variable table attribute:
+disassembler.linenumberattributeheader = Line numbers:
+disassembler.localvariabletableattributeheader = Local variable table:
+disassembler.localvariabletypetableattributeheader = Local variable type table:
 disassembler.arraydimensions = []
-disassembler.innerattributesheader = Inner classes attributes:
-disassembler.inner_class_info_name = inner class info name:
-disassembler.outer_class_info_name = outer class info name:
+disassembler.innerattributesheader = Inner classes:
+disassembler.inner_class_info_name = inner class info:
+disassembler.outer_class_info_name = outer class info:
 disassembler.inner_name = inner name:
 disassembler.inner_accessflags = accessflags: 
-disassembler.genericattributeheader = Attribute:
+disassembler.genericattributeheader = Attribute:\ 
 disassembler.genericattributename = Name: 
 disassembler.genericattributelength =\ Length: 
-disassembler.codeattributeheader = Code attribute:
+disassembler.signatureattributeheader = Signature:\ 
 disassembler.identation = \  
 disassembler.constantpoolindex =\ #
-disassembler.classmemberseparator = #
+disassembler.classmemberseparator = .
 disassembler.space = \ 
-disassembler.comma = , 
+disassembler.comma = ,
 disassembler.openinnerclassentry = [
 disassembler.closeinnerclassentry = ]
+disassembler.deprecated =\ (deprecated)
 
 ### classfileformat decoding
-classfileformat.sourcename = // Compiled from 
-classfileformat.magicnumber = - magic:\ 
-classfileformat.minorversion = - minor:\ 
-classfileformat.majorversion =  - major:\ 
-classfileformat.methoddescriptor =\ Method descriptor 
-classfileformat.fieldddescriptor =\ Field descriptor 
+classfileformat.versiondetails =\ (version {0} : {1}.{2}, {3})
+classfileformat.methoddescriptor =Method descriptor 
+classfileformat.fieldddescriptor =Field descriptor 
 classfileformat.maxStack = Stack: 
 classfileformat.maxLocals = Locals: 
-classfileformat.superflagisnotset = The ACC_SUPER bit is not set
-classfileformat.superflagisset = The ACC_SUPER bit is set
+classfileformat.superflagisnotset = no super bit
+classfileformat.superflagisset = super bit
 classfileformat.clinitname = {}
+
 ### string displayed for each opcode
 classformat.invokeinterfacemethod =\ <Interface method 
 classformat.invokeinterfacemethodclose = >
diff --git a/org.eclipse.jdt.core/notes/porting_guide.html b/org.eclipse.jdt.core/notes/porting_guide.html
index 64ffd06..cd27d06 100644
--- a/org.eclipse.jdt.core/notes/porting_guide.html
+++ b/org.eclipse.jdt.core/notes/porting_guide.html
@@ -2,206 +2,345 @@
 
 <head>
 <title>JDT Core Porting Guide</title>
+<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
+<meta name="ProgId" content="FrontPage.Editor.Document">
 </head>
 
 <body>
 
 <h1>JDT Core 3.0 Porting Guide</h1>
-<p>Last modified 19:00 CET November 20, 2003</p>
-
-<a name="bug_36987"></a>
-<h4>Interface IWorkingCopy (package org.eclipse.jdt.core; plug-in org.eclipse.jdt.core)</h4>
+<p>Last modified January 30, 2004</p>
+<p>These entries for the porting guide cover Debug-related items.</p>
+<h2>Required changes for 3.0</h2>
+<p>None.</p>
+<h2>Recommended changes for 3.0</h2>
+<b><font face="Times New Roman">
+<p>[JDT only] Improved support for working copies (package org.eclipse.jdt.core)</p>
+</font></b>
+<p>The Java model working copy facility has been reworked in 3.0 to provide
+greatly increased functionality. Prior to 3.0, the Java model allowed creation
+of individual working copies of compilation units. Changes could be made to the
+working copy and later committed. There was support for limited analysis of a
+working copy in the context of the rest of the Java model. However, there was no
+way these these analyses could ever take into account more than one of the
+working copies at a time.</p>
+<p>The changes in 3.0 make it possible to create and manage sets of working
+copies of compilation units, and to perform analyses in the presence of all
+working copies in a set. For example, it is now possible for a client like JDT
+refactoring to create working copies for one or more compilation units that it
+is considering modifying and then to resolve type references between the working
+copies. Formerly this was only possible after the changes to the compilation
+unit working copies had been committed.</p>
+<p>The Java model API changes in 2 ways to add this improved support:</p>
+<p>(1) The functionality formerly found on IWorkingCopy and inherited by
+ICompilationUnit has been consolidated into ICompilationUnit. The IWorkingCopy
+interface was only used in this one place, and was gratuitously more general
+that in needed to be. This change simplifies the API. IWorkingCopy has been
+deprecated. Other places in the API where IWorkingCopy is used as a parameter or
+result type have been deprecated as well; the replacement API methods mention
+ICompilationUnit instead of IWorkingCopy.</p>
+<p>(2) The interface IBufferFactory has been replaced by WorkingCopyOwner. The
+improved support for working copies requires that there be an object to own the
+working copies. Although IBufferFactory is in the right place, the name does not
+adequately convey how the new working copy mechanism works. WorkingCopyOwner is
+much more suggestive. In addition, WorkingCopyOwner is declared as an abstract
+class, rather than as an interface, to allow the notion of working copy owner to
+evolve in the future. The one method on IBufferFactory moves to WorkingCopyOwner
+unaffected. WorkingCopyOwner does not implement IBufferFactory to make it clear
+that IBufferFactory is a thing of the past. IBufferFactory has been deprecated.
+Other places in the API where IBufferFactory&nbsp; appears as a parameter or
+result type have been deprecated as well; the replacement API methods mention
+WorkingCopyOwner instead of IBufferFactory.</p>
+<p>These changes do not break binary compatibility.</p>
+<p>When migrating, all references to the type IWorkingCopy should instead
+reference ICompilationUnit. The sole implementation of IWorkingCopy implements
+ICompilationUnit as well, meaning objects of type IWorkingCopy can be safely
+cast to ICompilationUnit.</p>
+<p>A class that implements IBufferFactory will need to replaced by a subclass of
+WorkingCopyOwner. Although WorkingCopyOwner does not implement IBufferFactory
+itself, it would be possible to declare the subclass of WorkingCopyOwner that
+implements IBufferFactory thereby creating a bridge between old and new (IBufferFactory
+declares createBuffer(IOpenable) whereas WorkingCopyOwner declares
+createBuffer(ICompilationUnit); ICompilationUnit extends IOpenable).</p>
+<p>Because the changes involving IWorkingCopy and IBufferFactory are interwined,
+we recommend dealing with both at the same time. The detail</p>
 <ul>
-	<li>Prior to 3.0, <code>IWorkingCopy</code> gathered all working copy concerns, and <code>ICompilationUnit</code> 
-  		implemented this interface. However, though only the factory method made sense for compilation units, they still had to implement
-  		the entire working copy contract., which was not relevant to clients (implementation detail).
-        <code>IWorkingCopy</code> also implemented the spec'ed factory method, but it didn't work for these.
-    </li>
-	<li>One possible solution would have been to inverse the hierarchy and make <code>IWorkingCopy</code> implement
-	     <code>ICompilationUnit</code>. However as explained in the next <a href="#bug_36888">section</a>, closing the gap 
-	     between resource based compilation units and working copies required to merge these two interfaces. As a consequence 
-	     the interface <code>IWorkingCopy</code> is removed and all its functionality is merged into <code>ICompilationUnit</code>. 
-	</li>
-	<li>Clients using <code>IWorkingCopy</code> and <code>ICompilationUnit</code> can adapt to this change by referencing 
-	     <code>ICompilationUnit</code> instead of <code>IWorkingCopy</code> when a working copy is needed. For example:
-         <pre>
-         ICompilationUnit compilationUnit = ...;
-         IWorkingCopy workingCopy = (IWorkingCopy)compilationUnit.getWorkingCopy();
-         workingCopy.reconcile(true/*force problem detection*/, null/*no progress monitor*/);
-         </pre>
-         should be converted into:
-         <pre>
-         ICompilationUnit compilationUnit = ...;
-         ICompilationUnit workingCopy = compilationUnit.getWorkingCopy(null/*no progress monitor*/);
-         workingCopy.reconcile(true/*force problem detection*/, null/*no progress monitor*/);
-         </pre>
-	</li>
-	<li>To convert usage of <code>IWorkingCopy</code> functionality into usage of <code>ICompilationUnit</code> use this table:
-		<p>
-		<table BORDER CELLSPACING=2 CELLPADDING=2 >
-		<th>IWorkingCopy</th>
-		<th>ICompilationUnit</th>
-		<th>Note</th>
-		<tr>
-		<td>commit(boolean, IProgressMonitor)</td>
-		<td>commitWorkingCopy(boolean, IProgressMonitor)</td>
-		<td>&nbsp;</td>
-		</tr>
-		<tr>
-		<td>destroy()</td>
-		<td>discardWorkingCopy()</td>
-		<td>&nbsp;</td>
-		</tr>
-		<tr>
-		<td>findElements(IJavaElement)</td>
-		<td>findElements(IJavaElement)</td>
-		<td>&nbsp;</td>
-		</tr>
-		<tr>
-		<td>findPrimaryType()</td>
-		<td>findPrimaryType()</td>
-		<td>&nbsp;</td>
-		</tr>
-		<tr>
-		<td>findSharedWorkingCopy(IBufferFactory)</td>
-		<td>findWorkingCopy(WorkingCopyOwner)</td>
-		<td>See <a href="#bug_36888">next section</a> for details.</td>
-		</tr>
-		<tr>
-		<td>getOriginal(IJavaElement)</td>
-		<td>&nbsp;</td>
-		<td>Use IJavaElement.getPrimaryElement() instead. Note that this no longer returns <code>null</code> if the receiver
-		        is not a working copy but this returns the receiver.</td>
-		</tr>
-		<tr>
-		<td>getOriginalElement()</td>
-		<td>getPrimary()</td>
-		<td>This no longer returns <code>null</code> if the receiver is not a working copy but this returns the receiver.
-				The returned object is no longer an <code>IJavaElement</code> but an <code>ICompilationUnit</code>.</td>
-		</tr>
-		<tr>
-		<td>getSharedWorkingCopy(IProgressMonitor, IBufferFactory, IProblemRequestor)</td>
-		<td>getWorkingCopy(WorkingCopyOwner, IProblemRequestor, IProgressMonitor)</td>
-		<td>See <a href="#bug_36888">next section</a> for details.
-				The returned object is no longer an <code>IJavaElement</code> but an <code>ICompilationUnit</code>.</td>
-		</tr>
-		<tr>
-		<td>getWorkingCopy()</td>
-		<td>getWorkingCopy(IProgressMonitor)</td>
-		<td>The returned object is no longer an <code>IJavaElement</code> but an <code>ICompilationUnit</code>.</td>
-		</tr>
-		<tr>
-		<td>getWorkingCopy(IProgressMonitor, IBufferFactory, IProblemRequestor)</td>
-		<td>getWorkingCopy(WorkingCopyOwner, IProblemRequestor, IProgressMonitor)</td>
-		<td>Working copies are now implicitely shared. See <a href="#bug_36888">next section</a> for details.
-				The returned object is no longer an <code>IJavaElement</code> but an <code>ICompilationUnit</code>.</td>
-		</tr>
-		<tr>
-		<td>isBasedOn(IResource)</td>
-		<td>hasResourceChanged()</td>
-		<td>The IResource was always the working copy's resource. There was no need to pass it in.</td>
-		</tr>
-		<tr>
-		<td>isWorkingCopy()</td>
-		<td>isWorkingCopy()</td>
-		<td>&nbsp;</td>
-		</tr>
-		<tr>
-		<td>reconcile()</td>
-		<td>reconcile(boolean, IProgressMonitor)</td>
-		<td>Pass in <code>false</code> and <code>null</code> to have the equivalent functionality. Note that this method doesn't 
-			    return anything.</td>
-		</tr>
-		<tr>
-		<td>reconcile(boolean, IProgressMonitor)</td>
-		<td>reconcile(boolean, IProgressMonitor)</td>
-		<td>&nbsp;</td>
-		</tr>
-		<tr>
-		<td>restore()</td>
-		<td>restore()</td>
-		<td>&nbsp;</td>
-		</tr>
-		</table>
-		</p>
-	</li>
+  <li>IWorkingCopy (package org.eclipse.jdt.core)
+    <ul>
+      <li>public void commit(boolean, IProgressMonitor) has been deprecated.
+        <ul>
+          <li>The equivalent functionality is now provided on ICompilationUnit
+            directly:
+            <ul>
+              <li>public void commitWorkingCopy(boolean, IProgressMonitor)</li>
+            </ul>
+          </li>
+          <li>Replace wc.commit(b,monitor) with ((ICompilationUnit)
+            wc).commitWorkingCopy(b,monitor)</li>
+        </ul>
+      </li>
+      <li>public void destroy() has been deprecated.
+        <ul>
+          <li>The equivalent functionality is now provided on ICompilationUnit
+            directly:
+            <ul>
+              <li>public void discardWorkingCopy(boolean, IProgressMonitor)</li>
+            </ul>
+          </li>
+          <li>Replace wc.destroy() with ((ICompilationUnit)
+            wc).discardWorkingCopy()</li>
+        </ul>
+      </li>
+      <li>public IJavaElement findSharedWorkingCopy(IBufferFactory) has been
+        deprecated.
+        <ul>
+          <li>The equivalent functionality is now provided on ICompilationUnit
+            directly:
+            <ul>
+              <li>public ICompilationUnit findWorkingCopy(WorkingCopyOwner)</li>
+            </ul>
+          </li>
+        </ul>
+      </li>
+      <li>public IJavaElement getOriginal(IJavaElement) has been deprecated.
+        <ul>
+          <li>The equivalent functionality is now provided on IJavaElement:
+            <ul>
+              <li>public IJavaElement getPrimaryElement()</li>
+            </ul>
+          </li>
+        </ul>
+        <ul>
+          <li>Replace wc.getOriginal(elt) with elt.getPrimaryElement()</li>
+          <li>Note: Unlike IWorkingCopy.getOriginal,
+            IJavaElement.getPrimaryElement does not return <code>null</code> if
+            the receiver is not a working copy.</li>
+        </ul>
+      </li>
+      <li>public IJavaElement getOriginalElement() has been deprecated.
+        <ul>
+          <li>The equivalent functionality is now provided on ICompilationUnit
+            directly:
+            <ul>
+              <li>public ICompilationUnit getPrimary()</li>
+            </ul>
+          </li>
+          <li>Replace wc.getOriginalElement() with ((ICompilationUnit)
+            wc).getPrimary()</li>
+          <li>Note: Unlike IWorkingCopy.getOriginalElement,
+            IWorkingCopy.getPrimary does not return <code>null</code> if the
+            receiver is not a working copy.</li>
+        </ul>
+      </li>
+      <li>public IJavaElement[] findElements(IJavaElement) has been deprecated.
+        <ul>
+          <li>The method is now declared on ICompilationUnit directly.</li>
+          <li>Replace wc.findElements(elts) with ((ICompilationUnit)
+            wc).findElements(elts)</li>
+        </ul>
+      </li>
+      <li>public IType findPrimaryType() has been deprecated.
+        <ul>
+          <li>The method is now declared on ICompilationUnit directly.</li>
+          <li>Replace wc.findPrimaryType() with ((ICompilationUnit)
+            wc).findPrimaryType()</li>
+        </ul>
+      </li>
+      <li>public IJavaElement getSharedWorkingCopy(IProgressMonitor,
+        IBufferFactory, IProblemRequestor) has been deprecated.
+        <ul>
+          <li>The equivalent functionality is now provided on ICompilationUnit
+            directly:
+            <ul>
+              <li>public ICompilationUnit getWorkingCopy(WorkingCopyOwner,
+                IProblemRequestor, IProgressMonitor)</li>
+            </ul>
+          </li>
+          <li>[parameter order scrambling]</li>
+        </ul>
+      </li>
+      <li>public IJavaElement getWorkingCopy() has been deprecated.
+        <ul>
+          <li>The equivalent functionality is now provided on ICompilationUnit
+            directly:
+            <ul>
+              <li>public ICompilationUnit getWorkingCopy(IProgressMonitor)</li>
+            </ul>
+          </li>
+          <li>Replace wc.getWorkingCopy() with ((ICompilationUnit)
+            wc).getWorkingCopy(null)</li>
+        </ul>
+      </li>
+      <li>public IJavaElement getWorkingCopy(IProgressMonitor, IBufferFactory,
+        IProblemRequestor) has been deprecated.
+        <ul>
+          <li>The equivalent functionality is now provided on ICompilationUnit
+            directly:
+            <ul>
+              <li>public ICompilationUnit getWorkingCopy(WorkingCopyOwner,
+                IProblemRequestor, IProgressMonitor)</li>
+            </ul>
+          </li>
+          <li>[parameter order scrambling]</li>
+        </ul>
+      </li>
+      <li>public boolean isBasedOn(IResource) has been deprecated.
+        <ul>
+          <li>The equivalent functionality is now provided on ICompilationUnit
+            directly:
+            <ul>
+              <li>public boolean hasResourceChanged()</li>
+            </ul>
+          </li>
+          <li>Replace wc.isBasesOn(res) with ((ICompilationUnit)
+            wc).hasResourceChanged()</li>
+        </ul>
+      </li>
+      <li>public boolean isWorkingCopy() has been deprecated.
+        <ul>
+          <li>The method is now declared on ICompilationUnit directly.</li>
+          <li>Replace wc.isWorkingCopy() with ((ICompilationUnit)
+            wc).isWorkingCopy()</li>
+        </ul>
+      </li>
+      <li>public IMarker[]&nbsp; reconcile() has been deprecated.
+        <ul>
+          <li>The equivalent functionality is now provided on ICompilationUnit
+            directly:
+            <ul>
+              <li>public void reconcile(boolean,boolean,WorkingCopyOwner,IProgressMonitor)</li>
+            </ul>
+          </li>
+          <li>Replace wc.reconcile() with ((ICompilationUnit)
+            wc).reconcile(false,false,null,null)</li>
+          <li>Note: The former method always returned null; the replacement
+            method does not return a result.</li>
+        </ul>
+      </li>
+      <li>public void reconcile(boolean, IProgressMonitor) has been deprecated.
+        <ul>
+          <li>The method is now declared on ICompilationUnit directly.</li>
+          <li>Replace wc.reconcile(b,monitor) with ((ICompilationUnit)
+            wc).reconcile(false,b,null,monitor)</li>
+        </ul>
+      </li>
+      <li>public void restore() has been deprecated.
+        <ul>
+          <li>The method is now declared on ICompilationUnit directly.</li>
+          <li>Replace wc.restore() with ((ICompilationUnit) wc).restore()</li>
+        </ul>
+      </li>
+    </ul>
+  </li>
+  <li>IType (package org.eclipse.jdt.core)
+    <ul>
+      <li>public ITypeHierarchy newSupertypeHierarchy(IWorkingCopy[],
+        IProgressMonitor) has been deprecated.
+        <ul>
+          <li>The replacement method is provided on the same class:
+            <ul>
+              <li>public ITypeHierarchy newSupertypeHierarchy(ICompilationUnit[],
+                IProgressMonitor)</li>
+            </ul>
+          </li>
+        </ul>
+      </li>
+      <li>public ITypeHierarchy newTypeHierarchy(IWorkingCopy[],
+        IProgressMonitor) has been deprecated.
+        <ul>
+          <li>The replacement method is provided on the same class:
+            <ul>
+              <li>public ITypeHierarchy newTypeHierarchy(ICompilationUnit[],
+                IProgressMonitor)</li>
+            </ul>
+          </li>
+        </ul>
+      </li>
+    </ul>
+  </li>
+  <li>IClassFile (package org.eclipse.jdt.core)
+    <ul>
+      <li>public IJavaElement getWorkingCopy(IProgressMonitor, IBufferFactory)
+        has been deprecated.
+        <ul>
+          <li>The replacement method is provided on the same class:
+            <ul>
+              <li>public ICompilationUnit getWorkingCopy(WorkingCopyOwner,
+                IProgressMonitor)</li>
+            </ul>
+          </li>
+          <li>[parameter order scrambling]</li>
+        </ul>
+      </li>
+    </ul>
+  </li>
+  <li>JavaCore (package org.eclipse.jdt.core)
+    <ul>
+      <li>public IWorkingCopy[] getSharedWorkingCopies(IBufferFactory) has been
+        deprecated.
+        <ul>
+          <li>The replacement method is provided on the same class:
+            <ul>
+              <li>public ICompilationUnit[] getWorkingCopies(WorkingCopyOwner)</li>
+            </ul>
+          </li>
+        </ul>
+      </li>
+    </ul>
+  </li>
+  <li>SearchEngine (package org.eclipse.jdt.core.search)
+    <ul>
+      <li>public SearchEngine(IWorkingCopy[]) has been deprecated.
+        <ul>
+          <li>The replacement constructor is provided on the same class:
+            <ul>
+              <li>public SearchEngine(ICompilationUnit[])</li>
+            </ul>
+          </li>
+        </ul>
+      </li>
+    </ul>
+  </li>
 </ul>
 
-<a name="bug_36888"></a>
-<h4>Interface IBufferFactory is replaced with class WorkingCopyOwner (package org.eclipse.jdt.core; plug-in org.eclipse.jdt.core)<br>
-        (closing the gap between resource based compilation units and working copies)</h4>
+<b><font face="Times New Roman">
+<p>[JDT only] Java search participants (package org.eclipse.jdt.core.search)</p>
+</font></b>
+<p>Languages close to Java (such as JSP, SQLJ, JWS, etc.) should be able to participate in Java searching. 
+In particular implementors of such languages should be able to:
 <ul>
-	<li>Prior to 3.0, going from a resource based compilation unit (i.e. a compilation unit representing a file on disk) to the corresponding 
-		 shared working copy was tedious. For example, the Package Explorer had to fiirst find the children of a package fragment, then for 
-		 each compilation unit it had to find if a shared working copy had been created.
-	</li>
-	<li>Also doing a Java model operation in the context of a set of shared working copies was not possible. For example a refactoring 
-		operation had to save all editors prior to doing any change so as to have a consistent model.
-	</li>
-	<li>The notion of working copy owner got introduced to define a set of shared working copies to work on. This replaces the
-		 notion of buffer factory that was used to share working copies. The name 'owner' being more explicit.
-	</li>
-	<li>A working copy is now created for a given working copy owner. Java model operations that need to work on a set of working 
-		 copies can now be passed a working copy owner and this operation will consider the working copies before the compilation units.
-	</li>
-	<li>A class is used instead of an interface so that a default implementation for <code>createBuffer(...)</code> can be
-		 provided.
-	</li>
-	<li>Clients that used <code>IBufferFactory</code> should now subclass <code>WorkingCopyOwner</code> and pass this working
-		  copy owner to the Java model operation in lieu of the buffer factory. The simplest implementation being: 
-		  <code>new WorkingCopyOwner() {}</code>
-	</li>
-	<li>A Package Explorer like client that used to have such code:
-	<pre>
-	IBufferFactory factory = ...
-	
-	// Create a shared working copy for this buffer factory (to show it in an editor)
-	ICompilationUnit cu = ...
-	IWorkingCopy copy = cu.getSharedWorkingCopy(null/*no progress monitor*/, factory, null/*no problem reporter*/);
-	
-	// Find out the children of a package
-	IPackageFragment pkg = ...
-	ICompilationUnit[] cus = pkg.getCompilationUnits();
-	for (int i = 0; i < cus.length; i++) {
-		ICompilationUnit copy = (ICompilationUnit) cus[i].findSharedWorkingCopy(factory);
-		if (copy != null) {
-			cus[i] = copy;
-		}
-	}
-	</pre>
-	would now convert this code to:
-	<pre>
-	WorkingCopyOwner owner = ...
-	
-	// Create a shared working copy for this working copy owner (to show it in an editor)
-	ICompilationUnit cu = ...
-	ICompilationUnit copy = cu.getWorkingCopy(owner, null/*no problem reporter*/, null/*no progress monitor*/);
-	
-	// Find out the children of a package
-	IPackageFragment pkg = ...
-	ICompilationUnit[] cus = pkg.getCompilationUnits(owner);
-	</pre>
-	</li>
-	<li>A refactoring like client that used to have to save all editors before proceding can now work with working copies:
-	<pre>
-	WorkingCopyOwner owner = ...
-	
-	// Search for references to a method in the working copies of the given owner
-	IMethod method = ....
-	IJavaSearchScope scope = ...
-	IJavaSearchResultCollector resultCollector = ...
-	SearchEngine searchEngine = new SearchEngine(owner);
-	searchEngine.search(ResourcesPlugin.getWorkspace(), method, REFERENCES, scope, resultCollector);
-	
-	// Build AST for a compilation unit that contains a reference to the method
-	// and build its bindings in the context of the working copies of the given owner
-	ICompilationUnit cu = ...;
-	CompilationUnit ast = AST.parseCompilationUnit(cu, true /*resolve bindings*/, owner) ;
-	</pre>
-	</li>
-	<li>[TODO: add a table for conversion of IBufferFactory usage to WorkingCopyOwner usage]
-	</li>
+<li>index their source by converting it into Java equivalent, and feeding it to the Java indexer</li>
+<li>index their source by parsing it themselves, but record Java index entries</li>
+<li>locate matches in their source by converting it into Java equivalent, and feeding it to the Java match locator</li>
+<li>locate matches in their source by matching themselves, and return Java matches</li>
 </ul>
+</p>
+<p>Such an implementor is called a search participant. It extends the SearchParticipant 
+class. Search participants are passed to search queries 
+(see SearchEngine.search(SearchPattern, SearchParticipant[], IJavaSearchScope, SearchRequestor, IProgressMonitor).</p>
+<p>For either indexing or locating matches, a search participant needs to define a subclass of 
+SearchDocument that can retrieve the contents of a document by overriding either 
+getByteContents() or getCharContents(). An instance of such class is
+returned in SearchParticipant.getDocument(IFile) or getDocument(String).</p>
+<p>A search participant whishing to index some document will use 
+SearchParticipant.scheduleDocumentIndexing(SearchDocument, IPath) to schedule the indexing
+of the given document in the given index. Once the document is ready to be indexed, the underlying framework
+calls SearchParticipant.indexDocument(SearchDocument, IPath). The search participant is then
+supposed to get the document's content, parse it and add index entries using 
+SearchParticipant.addIndexEntry(char[], char[], SearchDocument).</p>
+<p>Once indexing is done, one can then query the indexes and locate matches using 
+SearchEngine.search(SearchPattern, SearchParticipant[], IJavaSearchScope, SearchRequestor, IProgressMonitor).
+This first asks each search participant for the indexes needed by this query using 
+SearchParticipant.selectIndexes(SearchPattern, IJavaSearchScope). For each index entry that matches
+the given pattern, a search document is created by asking the search participant (see getDocument(String)).
+All these documents are passed to the search participant so that it can locate matches using 
+locateMatches(SearchDocument[], SearchPattern, IJavaSearchScope, SearchRequestor, IProgressMonitor).
+The search participant notifies the SearchRequestor of search matches using acceptSearchMatch(SearchMatch)
+and passing an instance of a subclass of SearchMatch.</p>
+<p>A search participant can delegate part of its work to the default Java search participant. An instance of
+this default participant is obtained using SearchEngine.getDefaultSearchParticipant(). For example when asked to
+locate matches, an SQLJ participant can create documents .java documents from its .sqlj documents and
+delegate the work to the default participant passing it the .java documents.</p>
 
 </body>
 
diff --git a/org.eclipse.jdt.core/plugin.properties b/org.eclipse.jdt.core/plugin.properties
index 61f9ac7..cee64cb 100644
--- a/org.eclipse.jdt.core/plugin.properties
+++ b/org.eclipse.jdt.core/plugin.properties
@@ -1,5 +1,5 @@
 ###############################################################################
-# Copyright (c) 2000, 2003 IBM Corporation and others.
+# 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
@@ -18,4 +18,7 @@
 classpathVariableInitializersName=Classpath Variable Initializers
 classpathContainerInitializersName=Classpath Container Initializers
 codeFormattersName=Source Code Formatters
-javaTaskName=Java Task
\ No newline at end of file
+javaTaskName=Java Task
+javaPropertiesName=Java Properties File
+javaSourceName=Java Source File
+jarManifestName=JAR Manifest File
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/plugin.xml b/org.eclipse.jdt.core/plugin.xml
index 4a3369a..9b7c1b5 100644
--- a/org.eclipse.jdt.core/plugin.xml
+++ b/org.eclipse.jdt.core/plugin.xml
@@ -16,9 +16,9 @@
 
 <requires>
     <import plugin="org.eclipse.core.resources"/>
-    <import plugin="org.eclipse.core.runtime.compatibility" optional="true"/>    
+    <import plugin="org.eclipse.core.runtime"/>    
     <import plugin="org.eclipse.text"/>
-    <import plugin="org.eclipse.ant.core" optional="true"/>
+    <import plugin="org.apache.ant" optional="true"/>
     <import plugin="org.eclipse.team.core" optional="true"/>
 </requires>
 	
@@ -29,7 +29,6 @@
 <runtime>
   <library name="jdtcore.jar">  
      <export name="*"/>
-     <packages prefixes="org.eclipse.jdt.core,org.eclipse.jdt.internal"/>
   </library> 
 </runtime>
 
@@ -87,13 +86,9 @@
 	</builder>
 </extension>
 
-
 <!-- =================================================================================== -->
-<!-- Extension: Java Markers                                                             -->
+<!-- Extension: Java Problem                                                             -->
 <!-- =================================================================================== -->
-
-<!-- Java problems -->
-
 <extension id="problem" point="org.eclipse.core.resources.markers" name="%javaProblemName">
 	<super type="org.eclipse.core.resources.problemmarker"/>
 	<super type="org.eclipse.core.resources.textmarker"/>
@@ -103,8 +98,9 @@
 	<attribute name="arguments"/>
 </extension>   
 
-<!-- Java buildpath problems -->
-
+<!-- =================================================================================== -->
+<!-- Extension: Java Buildpath Problem                                                   -->
+<!-- =================================================================================== -->
 <extension id="buildpath_problem" point="org.eclipse.core.resources.markers" name="%buildPathProblemName">
 	<super type="org.eclipse.core.resources.problemmarker"/>
 	<super type="org.eclipse.core.resources.textmarker"/>
@@ -114,8 +110,9 @@
 	<attribute name="arguments"/>
 </extension>   
 
-<!-- Java transient problems -->
-
+<!-- =================================================================================== -->
+<!-- Extension: Java Transient Problem                                                   -->
+<!-- =================================================================================== -->
 <extension id="transient_problem" point="org.eclipse.core.resources.markers" name="%transientJavaProblemName">
 	<super type="org.eclipse.core.resources.textmarker"/>
 	<persistent value="false"/>
@@ -124,8 +121,9 @@
 	<attribute name="arguments"/>
 </extension>
 
-<!-- Java tasks -->
-
+<!-- =================================================================================== -->
+<!-- Extension: Java Task                                                                -->
+<!-- =================================================================================== -->
 <extension id="task" name="%javaTaskName" point="org.eclipse.core.resources.markers">
     <super type="org.eclipse.core.resources.taskmarker"/> 
     <persistent value="true"/>
@@ -141,25 +139,66 @@
 	</extraClasspathEntry>
 </extension> 
 
-<!-- Tasks -->
+<!-- =================================================================================== -->
+<!-- Extension: Javac Ant Task                                                           -->
+<!-- =================================================================================== -->
 <extension point="org.eclipse.ant.core.antTasks">
-  <antTask
-  	name="eclipse.checkDebugAttributes"
-	class="org.eclipse.jdt.core.CheckDebugAttributes"
-	library="jdtCompilerAdapter.jar">
-  </antTask>
+	<antTask
+		name="eclipse.checkDebugAttributes"
+		class="org.eclipse.jdt.core.CheckDebugAttributes"
+		library="jdtCompilerAdapter.jar">
+	</antTask>
 </extension>
       
 <!-- =================================================================================== -->
-<!-- Extension: Java file types                                                        -->
+<!-- Extension: User Library Container                                                   -->
+<!-- =================================================================================== -->
+<extension
+      point="org.eclipse.jdt.core.classpathContainerInitializer">
+      <classpathContainerInitializer
+            class="org.eclipse.jdt.internal.core.UserLibraryClasspathContainerInitializer"
+            id="org.eclipse.jdt.USER_LIBRARY">
+      </classpathContainerInitializer>
+   </extension>
+
+<!-- =================================================================================== -->
+<!-- Extension: Java File Types                                                          -->
 <!-- =================================================================================== -->
 <extension point="org.eclipse.team.core.fileTypes">
-  <fileTypes extension="java" type="text"/>
-  <fileTypes extension="classpath" type="text"/>
-  <fileTypes extension="properties" type="text"/>
-  <fileTypes extension="class" type="binary"/>
-  <fileTypes extension="jar" type="binary"/>
-  <fileTypes extension="zip" type="binary"/>
+	<fileTypes extension="java" type="text"/>
+	<fileTypes extension="classpath" type="text"/>
+	<fileTypes extension="properties" type="text"/>
+	<fileTypes extension="class" type="binary"/>
+	<fileTypes extension="jar" type="binary"/>
+	<fileTypes extension="jardesc" type="text"/>
+	<fileTypes extension="zip" type="binary"/>
+</extension>
+      
+<!-- =================================================================================== -->
+<!-- Extension: Java Content Types                                                       -->
+<!-- =================================================================================== -->
+<extension point="org.eclipse.core.runtime.contentTypes">
+	<!-- declares a content type for Java Properties files -->
+	<content-type id="javaProperties" name="%javaPropertiesName" 
+		base-type="org.eclipse.core.runtime.text"
+		priority="high"				
+		file-extensions="properties"
+		default-charset="ISO-8859-1"/>
+	<!-- Associates .classpath to the XML content type -->
+	<file-association 
+		content-type="org.eclipse.core.runtime.xml" 
+		file-names=".classpath"/>  
+	<!-- declares a content type for Java Source files -->
+	<content-type id="javaSource" name="%javaSourceName" 
+		base-type="org.eclipse.core.runtime.text"
+		priority="high"				
+		file-extensions="java"/>
+	<!-- declares a content type for JAR manifest files -->
+    <content-type id="JARManifest" name="%jarManifestName" 
+        base-type="org.eclipse.core.runtime.text"
+        priority="high"				
+        file-names="MANIFEST.MF"
+        default-charset="UTF-8"/>
 </extension>
 
 </plugin>
diff --git a/org.eclipse.jdt.core/schema/classpathContainerInitializer.exsd b/org.eclipse.jdt.core/schema/classpathContainerInitializer.exsd
index 719b929..96a64b0 100644
--- a/org.eclipse.jdt.core/schema/classpathContainerInitializer.exsd
+++ b/org.eclipse.jdt.core/schema/classpathContainerInitializer.exsd
@@ -2,14 +2,14 @@
 <!-- Schema file written by PDE -->

 <schema targetNamespace="org.eclipse.jdt.core">

 <annotation>

-   <appInfo>

-      <meta.schema plugin="org.eclipse.jdt.core" id="classpathContainerInitializer" name="Classpath Container Initializers"/>

-   </appInfo>

-   <documentation>

-      This extension point allows clients to contribute custom classpath container initializers, 

+      <appInfo>

+         <meta.schema plugin="org.eclipse.jdt.core" id="classpathContainerInitializer" name="Classpath Container Initializers"/>

+      </appInfo>

+      <documentation>

+         This extension point allows clients to contribute custom classpath container initializers, 

       which are used to lazily bind classpath containers to instances of org.eclipse.jdt.core.IClasspathContainer.

-   </documentation>

-</annotation>

+      </documentation>

+   </annotation>

 

    <element name="extension">

       <complexType>

@@ -74,11 +74,11 @@
          <meta.section type="examples"/>

       </appInfo>

       <documentation>

-         Example of a declaration of a &lt;code&gt;ClasspathContainerInitializer&lt;/code&gt; for a classpath container named "JDK/1.2":  &lt;pre&gt;                                                                       

-&lt;extension point="org.eclipse.jdt.core.classpathContainerInitializer"&gt;            

+         Example of a declaration of a &lt;code&gt;ClasspathContainerInitializer&lt;/code&gt; for a classpath container named &quot;JDK&quot;:  &lt;pre&gt;                                                                       

+&lt;extension point=&quot;org.eclipse.jdt.core.classpathContainerInitializer&quot;&gt;            

    &lt;classpathContainerInitializer                                          

-      id="JDK"                                                        

-      class="com.example.MyInitializer"/&gt;                           

+      id=&quot;JDK&quot;                                                        

+      class=&quot;com.example.MyInitializer&quot;/&gt;                           

 &lt;/extension&gt;

 &lt;/pre&gt;

       </documentation>

@@ -107,13 +107,12 @@
          <meta.section type="copyright"/>

       </appInfo>

       <documentation>

-         &lt;p&gt;

-&lt;a href="hglegal.htm"&gt;

- &lt;img SRC="ngibmcpy.gif"

-   ALT="Copyright IBM Corp. 2000, 2003. All Rights Reserved."

-   BORDER=0 height=14 width=324&gt;&lt;/a&gt;

-&lt;/p&gt;

+         Copyright (c) 2000, 2004 IBM Corporation and others.&lt;br&gt;

+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 &lt;a 

+href=&quot;http://www.eclipse.org/legal/cpl-v10.html&quot;&gt;http://www.eclipse.org/legal/cpl-v10.html&lt;/a&gt;

       </documentation>

    </annotation>

-

+   

 </schema>

diff --git a/org.eclipse.jdt.core/schema/classpathVariableInitializer.exsd b/org.eclipse.jdt.core/schema/classpathVariableInitializer.exsd
index 94a83ff..e803ebc 100644
--- a/org.eclipse.jdt.core/schema/classpathVariableInitializer.exsd
+++ b/org.eclipse.jdt.core/schema/classpathVariableInitializer.exsd
@@ -107,12 +107,11 @@
          <meta.section type="copyright"/>

       </appInfo>

       <documentation>

-         &lt;p&gt;

-&lt;a href="hglegal.htm"&gt;

- &lt;img SRC="ngibmcpy.gif"

-   ALT="Copyright IBM Corp. 2000, 2003. All Rights Reserved."

-   BORDER=0 height=14 width=324&gt;&lt;/a&gt;

-&lt;/p&gt;

+         Copyright (c) 2000, 2004 IBM Corporation and others.&lt;br&gt;

+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 &lt;a 

+href=&quot;http://www.eclipse.org/legal/cpl-v10.html&quot;&gt;http://www.eclipse.org/legal/cpl-v10.html&lt;/a&gt;

       </documentation>

    </annotation>

 

diff --git a/org.eclipse.jdt.core/schema/codeFormatter.exsd b/org.eclipse.jdt.core/schema/codeFormatter.exsd
index b51b15d..a14d9b6 100644
--- a/org.eclipse.jdt.core/schema/codeFormatter.exsd
+++ b/org.eclipse.jdt.core/schema/codeFormatter.exsd
@@ -1,109 +1,109 @@
-<?xml version='1.0' encoding='UTF-8'?>

-<!-- Schema file written by PDE -->

-<schema targetNamespace="org.eclipse.jdt.core">

-<annotation>

-   <appInfo>

-      <meta.schema plugin="org.eclipse.jdt.core" id="codeFormatter" name="Code Formatters"/>

-   </appInfo>

-   <documentation>

-      This extension point allows clients to contribute new source code formatter implementations.

-   </documentation>

-</annotation>

-

-   <element name="extension">

-      <complexType>

-         <sequence>

-            <element ref="codeFormatter" minOccurs="0" maxOccurs="unbounded"/>

-         </sequence>

-         <attribute name="point" type="string" use="required">

-            <annotation>

-               <documentation>

-                  a fully qualified identifier of the target extension point

-               </documentation>

-            </annotation>

-         </attribute>

-         <attribute name="id" type="string">

-            <annotation>

-               <documentation>

-                  an optional identifier of the extension instance

-               </documentation>

-            </annotation>

-         </attribute>

-         <attribute name="name" type="string">

-            <annotation>

-               <documentation>

-                  an optional name of the extension instance

-               </documentation>

-            </annotation>

-         </attribute>

-      </complexType>

-   </element>

-

-   <element name="codeFormatter">

-      <complexType>

-         <attribute name="class" type="string" use="required">

-            <annotation>

-               <documentation>

-                  the class that defines the code formatter implementation. This class must be a public implementation of &lt;code&gt;org.eclipse.jdt.core.ICodeFormatter&lt;/code&gt; with a public 0-argument constructor.

-               </documentation>

-            </annotation>

-         </attribute>

-      </complexType>

-   </element>

-

-   <annotation>

-      <appInfo>

-         <meta.section type="since"/>

-      </appInfo>

-      <documentation>

-         2.0

-      </documentation>

-   </annotation>

-

-   <annotation>

-      <appInfo>

-         <meta.section type="examples"/>

-      </appInfo>

-      <documentation>

-         Example of an implementation of &lt;code&gt;ICodeFormatter&lt;/code&gt;:  &lt;pre&gt;                                                                       

-&lt;extension point="org.eclipse.jdt.core.codeFormatter"&gt;            

-   &lt;codeFormatter                                                                                              

-      class="com.example.MyCodeFormatter"/&gt;                           

-&lt;/extension&gt;

-&lt;/pre&gt;

-      </documentation>

-   </annotation>

-

-   <annotation>

-      <appInfo>

-         <meta.section type="apiInfo"/>

-      </appInfo>

-      <documentation>

-         

-      </documentation>

-   </annotation>

-

-   <annotation>

-      <appInfo>

-         <meta.section type="implementation"/>

-      </appInfo>

-      <documentation>

-         

-      </documentation>

-   </annotation>

-

-   <annotation>

-      <appInfo>

-         <meta.section type="copyright"/>

-      </appInfo>

-      <documentation>

-         &lt;p&gt;

-&lt;a href="hglegal.htm"&gt;

- &lt;img SRC="ngibmcpy.gif"

-   ALT="Copyright IBM Corp. 2000, 2003. All Rights Reserved."

-   BORDER=0 height=14 width=324&gt;&lt;/a&gt;

-&lt;/p&gt;

-      </documentation>

-   </annotation>

-

-</schema>

+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.jdt.core">
+<annotation>
+   <appInfo>
+      <meta.schema plugin="org.eclipse.jdt.core" id="codeFormatter" name="Code Formatters"/>
+   </appInfo>
+   <documentation>
+      This extension point allows clients to contribute new source code formatter implementations.
+   </documentation>
+</annotation>
+
+   <element name="extension">
+      <complexType>
+         <sequence>
+            <element ref="codeFormatter" minOccurs="0" maxOccurs="unbounded"/>
+         </sequence>
+         <attribute name="point" type="string" use="required">
+            <annotation>
+               <documentation>
+                  a fully qualified identifier of the target extension point
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="id" type="string">
+            <annotation>
+               <documentation>
+                  an optional identifier of the extension instance
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="name" type="string">
+            <annotation>
+               <documentation>
+                  an optional name of the extension instance
+               </documentation>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <element name="codeFormatter">
+      <complexType>
+         <attribute name="class" type="string" use="required">
+            <annotation>
+               <documentation>
+                  the class that defines the code formatter implementation. This class must be a public implementation of &lt;code&gt;org.eclipse.jdt.core.ICodeFormatter&lt;/code&gt; with a public 0-argument constructor.
+               </documentation>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="since"/>
+      </appInfo>
+      <documentation>
+         2.0
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="examples"/>
+      </appInfo>
+      <documentation>
+         Example of an implementation of &lt;code&gt;ICodeFormatter&lt;/code&gt;:  &lt;pre&gt;                                                                       
+&lt;extension point="org.eclipse.jdt.core.codeFormatter"&gt;            
+   &lt;codeFormatter                                                                                              
+      class="com.example.MyCodeFormatter"/&gt;                           
+&lt;/extension&gt;
+&lt;/pre&gt;
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="apiInfo"/>
+      </appInfo>
+      <documentation>
+         
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="implementation"/>
+      </appInfo>
+      <documentation>
+         
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="copyright"/>
+      </appInfo>
+      <documentation>
+         Copyright (c) 2000, 2004 IBM Corporation and others.&lt;br&gt;
+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 &lt;a 
+href=&quot;http://www.eclipse.org/legal/cpl-v10.html&quot;&gt;http://www.eclipse.org/legal/cpl-v10.html&lt;/a&gt;
+      </documentation>
+   </annotation>
+
+
+</schema>
diff --git a/org.eclipse.jdt.core/scripts/export-batch-jdtcom.xml b/org.eclipse.jdt.core/scripts/export-batch-jdtcom.xml
index 78768a0..4435924 100644
--- a/org.eclipse.jdt.core/scripts/export-batch-jdtcom.xml
+++ b/org.eclipse.jdt.core/scripts/export-batch-jdtcom.xml
@@ -19,7 +19,7 @@
 		<jar 
 			jarfile="${dest}/jdtcom.jar"
 			basedir="bin"
-			includes="org/eclipse/jdt/internal/compiler/**,org/eclipse/jdt/core/compiler/*" />
+			includes="org/eclipse/jdt/internal/compiler/**,org/eclipse/jdt/core/compiler/**" />
 		
 		<echo message="UPDATE jdtcomsrc.zip" />
 		<zip zipfile="${dest}/jdtcomsrc.zip">
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/FieldDeclarationMatch.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/FieldDeclarationMatch.java
new file mode 100644
index 0000000..a44a317
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/FieldDeclarationMatch.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.search;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.jdt.core.IJavaElement;
+
+/**
+ * A Java search match that represents a field declaration.
+ * The element is an <code>IField</code>.
+ * <p>
+ * This class is intended to be instantiated and subclassed by clients.
+ * </p>
+ * 
+ * @since 3.0
+ */
+public class FieldDeclarationMatch extends SearchMatch {
+
+	/**
+	 * Creates a new field declaration match.
+	 * 
+	 * @param element the field declaration
+	 * @param accuracy one of A_ACCURATE or A_INACCURATE
+	 * @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 offset, int length, SearchParticipant participant, IResource resource) {
+		super(element, accuracy, offset, length, participant, resource);
+	}
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/FieldReferenceMatch.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/FieldReferenceMatch.java
new file mode 100644
index 0000000..9c28b74
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/FieldReferenceMatch.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.search;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.jdt.core.IJavaElement;
+
+/**
+ * A Java search match that represents a field reference.
+ * The element is the inner-most enclosing member that references this field.
+ * <p>
+ * This class is intended to be instantiated and subclassed by clients.
+ * </p>
+ * 
+ * @since 3.0
+ */
+public class FieldReferenceMatch extends SearchMatch {
+
+	private boolean isReadAccess;
+	private boolean isWriteAccess;
+
+	/**
+	 * Creates a new field reference match.
+	 * 
+	 * @param enclosingElement the inner-most enclosing member that references this field
+	 * @param accuracy one of {@link #A_ACCURATE} or {@link #A_INACCURATE}
+	 * @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 <code>true</code> if this search match is inside a doc
+	 * comment, and <code>false</code> otherwise
+	 * @param participant the search participant that created the match
+	 * @param resource the resource of the element
+	 */
+	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;
+		setInsideDocComment(insideDocComment);
+	}
+	
+	/**
+	 * Returns whether the field reference is a read access to the field.
+	 * Note that a field reference can be read and written at once in case of compound assignments (e.g. i += 0;)
+	 * 
+	 * @return whether the field reference is a read access to the field.
+	 */
+	public final boolean isReadAccess() {
+		return this.isReadAccess;
+	}
+
+	/**
+	 * Returns whether the field reference is a write access to the field.
+	 * Note that a field reference can be read and written at once in case of compound assignments (e.g. i += 0;)
+	 * 
+	 * @return whether the field reference is a write access to the field.
+	 */
+	public final boolean isWriteAccess() {
+		return this.isWriteAccess;
+	}
+	
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/IJavaSearchConstants.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/IJavaSearchConstants.java
index bb12194..9897d79 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/IJavaSearchConstants.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/IJavaSearchConstants.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -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,14 @@
 	/**
 	 * The search pattern matches the search result only
 	 * if cases are the same.
+	 * @deprecated Use the methods that take the matchMode
+	 *   with {@link SearchPattern#R_CASE_SENSITIVE} as a matchRule instead.
 	 */
 	boolean CASE_SENSITIVE = true;
 	/**
 	 * The search pattern ignores cases in the search result.
+	 * @deprecated Use the methods that take the matchMode
+	 *   without {@link SearchPattern#R_CASE_SENSITIVE} as a matchRule instead.
 	 */
 	boolean CASE_INSENSITIVE = false;
 	
@@ -159,7 +166,7 @@
 	 * has not finished indexing the workspace. Results will more likely
 	 * not contain all the matches.
 	 */
-	int FORCE_IMMEDIATE_SEARCH = IJob.ForceImmediate; // TODO may discard for 3.0, since it isn't used anyway
+	int FORCE_IMMEDIATE_SEARCH = IJob.ForceImmediate;
 	/**
 	 * The search operation throws an <code>org.eclipse.core.runtime.OperationCanceledException</code>
 	 * if the underlying indexer has not finished indexing the workspace.
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/IJavaSearchResultCollector.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/IJavaSearchResultCollector.java
index ad8d7fb..8035883 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/IJavaSearchResultCollector.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/IJavaSearchResultCollector.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -38,12 +38,15 @@
  * Clients may implement this interface.
  * </p>
  *
- * @see SearchEngine#search
- * TODO (jerome) deprecate - should use SearchRequestor instead
+ * @see SearchEngine
+ * @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/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/IJavaSearchScope.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/IJavaSearchScope.java
index 475a4ee..5aa54a7 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/IJavaSearchScope.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/IJavaSearchScope.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -29,6 +29,26 @@
  */
 String JAR_FILE_ENTRY_SEPARATOR = "|"; //$NON-NLS-1$
 /**
+ * Include type constant (bit mask) indicating that source folders should be considered in the search scope.
+ * @since 3.0
+ */
+int SOURCES = 1;
+/**
+ * Include type constant (bit mask) indicating that application libraries should be considered in the search scope.
+ * @since 3.0
+ */
+int APPLICATION_LIBRARIES = 2;
+/**
+ * Include type constant (bit mask) indicating that system libraries should be considered in the search scope.
+ * @since 3.0
+ */
+int SYSTEM_LIBRARIES = 4;
+/**
+ * Include type constant (bit mask) indicating that referenced projects should be considered in the search scope.
+ * @since 3.0
+ */
+int REFERENCED_PROJECTS = 8;
+/**
  * Checks whether the resource at the given path is enclosed by this scope.
  *
  * @param resourcePath if the resource is contained in
@@ -72,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();
 /**
@@ -81,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();
 /**
@@ -90,17 +112,19 @@
  * 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);
 /**
  * Sets whether this scope includes the classpaths defined by 
  * the projects of the resources of this search scope.
  * 
- * @return includesClasspaths whether this scope includes classpaths
- * @deprecated Use SearchEngine.createJavaSearchScope(IJavaElement[]) 
- * 				with a java project instead
+ * @param includesClasspaths whether this scope includes classpaths
+ * @deprecated Use
+ * {@link org.eclipse.jdt.core.search.SearchEngine#createJavaSearchScope(IJavaElement[])}
+ * with a Java project instead.
  */
 public void setIncludesClasspaths(boolean includesClasspaths);
 }
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/ISearchPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/ISearchPattern.java
index 2314df9..a893aa6 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/ISearchPattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/ISearchPattern.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -14,9 +14,10 @@
  * A search pattern defines how search results are found. Use <code>SearchEngine.createSearchPattern</code>
  * to create a search pattern.
  *
- * @see SearchEngine#createSearchPattern(IJavaElement, int)
+ * @see SearchEngine#createSearchPattern(org.eclipse.jdt.core.IJavaElement, int)
  * @see SearchEngine#createSearchPattern(String, int, int, boolean)
- * TODO (jerome) deprecate this interface - should 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/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/ITypeNameRequestor.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/ITypeNameRequestor.java
index 8ac9f4f..218f797 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/ITypeNameRequestor.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/ITypeNameRequestor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/LocalVariableDeclarationMatch.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/LocalVariableDeclarationMatch.java
new file mode 100644
index 0000000..ea42f42
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/LocalVariableDeclarationMatch.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.search;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.jdt.core.IJavaElement;
+
+/**
+ * A Java search match that represents a local variable declaration.
+ * The element is an <code>ILocalVariable</code>.
+ * <p>
+ * This class is intended to be instantiated and subclassed by clients.
+ * </p>
+ * 
+ * @since 3.0
+ */
+public class LocalVariableDeclarationMatch extends SearchMatch {
+
+	/**
+	 * Creates a new local variable declaration match.
+	 * 
+	 * @param element the local variable declaration
+	 * @param accuracy one of A_ACCURATE or A_INACCURATE
+	 * @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 offset, int length, SearchParticipant participant, IResource resource) {
+		super(element, accuracy, offset, length, participant, resource);
+	}
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/LocalVariableReferenceMatch.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/LocalVariableReferenceMatch.java
new file mode 100644
index 0000000..f42bcdb
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/LocalVariableReferenceMatch.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.search;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.jdt.core.IJavaElement;
+
+/**
+ * A Java search match that represents a local variable reference.
+ * The element is the inner-most enclosing member that references this local variable.
+ * <p>
+ * This class is intended to be instantiated and subclassed by clients.
+ * </p>
+ * 
+ * @since 3.0
+ */
+public class LocalVariableReferenceMatch extends SearchMatch {
+
+	private boolean isReadAccess;
+	private boolean isWriteAccess;
+
+	/**
+	 * Creates a new local variable reference match.
+	 * 
+	 * @param enclosingElement the inner-most enclosing member that references this local variable
+	 * @param accuracy one of {@link #A_ACCURATE} or {@link #A_INACCURATE}
+	 * @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 <code>true</code> if this search match is inside a doc
+	 * comment, and <code>false</code> otherwise
+	 * @param participant the search participant that created the match
+	 * @param resource the resource of the element
+	 */
+	public LocalVariableReferenceMatch(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;
+		setInsideDocComment(insideDocComment);
+	}
+
+	/**
+	 * Returns whether the local variable reference is a read access to the variable.
+	 * Note that a local variable reference can be read and written at once in case of compound assignments (e.g. i += 0;)
+	 * 
+	 * @return whether the local variable reference is a read access to the variable.
+	 */
+	public final boolean isReadAccess() {
+		return this.isReadAccess;
+	}
+
+	/**
+	 * Returns whether the local variable reference is a write access to the variable.
+	 * Note that a local variable reference can be read and written at once in case of compound assignments (e.g. i += 0;)
+	 * 
+	 * @return whether the local variable reference is a write access to the variable.
+	 */
+	public final boolean isWriteAccess() {
+		return this.isWriteAccess;
+	}
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/MethodDeclarationMatch.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/MethodDeclarationMatch.java
new file mode 100644
index 0000000..2bb5438
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/MethodDeclarationMatch.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.search;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.jdt.core.IJavaElement;
+
+/**
+ * A Java search match that represents a method declaration.
+ * The element is an <code>IMethod</code>.
+ * <p>
+ * This class is intended to be instantiated and subclassed by clients.
+ * </p>
+ * 
+ * @since 3.0
+ */
+public class MethodDeclarationMatch extends SearchMatch {
+
+	/**
+	 * Creates a new method declaration match.
+	 * 
+	 * @param element the method declaration
+	 * @param accuracy one of A_ACCURATE or A_INACCURATE
+	 * @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 offset, int length, SearchParticipant participant, IResource resource) {
+		super(element, accuracy, offset, length, participant, resource);
+	}
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/MethodReferenceMatch.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/MethodReferenceMatch.java
new file mode 100644
index 0000000..9a58c28
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/MethodReferenceMatch.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.search;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.jdt.core.IJavaElement;
+
+/**
+ * A Java search match that represents a method reference.
+ * The element is the inner-most enclosing member that references this method.
+ * <p>
+ * This class is intended to be instantiated and subclassed by clients.
+ * </p>
+ * 
+ * @since 3.0
+ */
+public class MethodReferenceMatch extends SearchMatch {
+
+	/**
+	 * Creates a new method reference match.
+	 * 
+	 * @param enclosingElement the inner-most enclosing member that references this method
+	 * @param accuracy one of {@link #A_ACCURATE} or {@link #A_INACCURATE}
+	 * @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 <code>true</code> if this search match is inside a doc
+	 * comment, and <code>false</code> otherwise
+	 * @param participant the search participant that created the match
+	 * @param resource the resource of the element
+	 */
+	public MethodReferenceMatch(IJavaElement enclosingElement, int accuracy, int offset, int length, boolean insideDocComment, SearchParticipant participant, IResource resource) {
+		super(enclosingElement, accuracy, offset, length, participant, resource);
+		setInsideDocComment(insideDocComment);
+	}
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/PackageDeclarationMatch.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/PackageDeclarationMatch.java
new file mode 100644
index 0000000..d94cfca
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/PackageDeclarationMatch.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.search;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.jdt.core.IJavaElement;
+
+/**
+ * A Java search match that represents a package declaration.
+ * The element is an <code>IPackageFragment</code>.
+ * <p>
+ * This class is intended to be instantiated and subclassed by clients.
+ * </p>
+ * 
+ * @since 3.0
+ */
+public class PackageDeclarationMatch extends SearchMatch {
+
+	/**
+	 * Creates a new package declaration match.
+	 * 
+	 * @param element the package declaration
+	 * @param accuracy one of A_ACCURATE or A_INACCURATE
+	 * @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 offset, int length, SearchParticipant participant, IResource resource) {
+		super(element, accuracy, offset, length, participant, resource);
+	}
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/PackageReferenceMatch.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/PackageReferenceMatch.java
new file mode 100644
index 0000000..802ece0
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/PackageReferenceMatch.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.search;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.jdt.core.IJavaElement;
+
+/**
+ * A Java search match that represents a package reference.
+ * The element is the inner-most enclosing member that references this package.
+ * <p>
+ * This class is intended to be instantiated and subclassed by clients.
+ * </p>
+ * 
+ * @since 3.0
+ */
+public class PackageReferenceMatch extends SearchMatch {
+
+	/**
+	 * Creates a new package reference match.
+	 * 
+	 * @param enclosingElement the inner-most enclosing member that references this package
+	 * @param accuracy one of {@link #A_ACCURATE} or {@link #A_INACCURATE}
+	 * @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 <code>true</code> if this search match is inside a doc
+	 * comment, and <code>false</code> otherwise
+	 * @param participant the search participant that created the match
+	 * @param resource the resource of the element
+	 */
+	public PackageReferenceMatch(IJavaElement enclosingElement, int accuracy, int offset, int length, boolean insideDocComment, SearchParticipant participant, IResource resource) {
+		super(enclosingElement, accuracy, offset, length, participant, resource);
+		setInsideDocComment(insideDocComment);
+	}
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchDocument.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchDocument.java
index 0ec14d7..7f06e61 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchDocument.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchDocument.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -10,53 +10,121 @@
  *******************************************************************************/
 package org.eclipse.jdt.core.search;
 
+import org.eclipse.jdt.internal.core.search.indexing.InternalSearchDocument;
+
 /**
- * TODO (jerome) spec
+ * A search document encapsulates a content to be either indexed or searched in.
+ * A search particpant creates a search document.
+ * <p>
+ * This class is intended to be subclassed by clients.
+ * </p>
+ * 
  * @since 3.0
  */
-public class SearchDocument {
-	protected String documentPath;
-	protected SearchParticipant participant;
-
-	public SearchDocument(String documentPath, SearchParticipant participant) {
+public abstract class SearchDocument extends InternalSearchDocument {
+	private String documentPath;
+	private SearchParticipant participant;
+	
+	/**
+	 * Creates a new search document. The given document path is a string that uniquely identifies the document.
+	 * Most of the time it is a workspace-relative path, but it can also be a file system path, or a path inside a zip file.
+	 * 
+	 * @param documentPath the path to the document,
+	 * or <code>null</code> if none
+	 * @param participant the participant that creates the search document
+	 */
+	protected SearchDocument(String documentPath, SearchParticipant participant) {
 		this.documentPath = documentPath;
 		this.participant = participant;
 	}
 
 	/**
+	 * Adds the given index entry (category and key) coming from this
+	 * document to the index. This method must be called from
+	 * {@link SearchParticipant#indexDocument(SearchDocument document, org.eclipse.core.runtime.IPath indexPath)}.
+	 * 
+	 * @param category the category of the index entry
+	 * @param key the key of the index entry
+	 */
+	public void addIndexEntry(char[] category, char[] key) {
+		super.addIndexEntry(category, key);
+	}
+	
+	/**
+	 * Returns the contents of this document.
 	 * Contents may be different from actual resource at corresponding document path,
 	 * in case of preprocessing.
+	 * <p>
+	 * This method must be implemented in subclasses.
+	 * </p><p>
+	 * Note: some implementation may choose to cache the contents directly on the
+	 * document for performance reason. However, this could induce scalability issues due
+	 * to the fact that collections of documents are manipulated throughout the search
+	 * operation, and cached contents would then consume lots of memory until they are 
+	 * all released at once in the end.
+	 * </p>
+	 * 
+	 * @return the contents of this document,
+	 * or <code>null</code> if none
 	 */
-	public byte[] getByteContents() {
-		return null;
-	}
+	public abstract byte[] getByteContents();
 
 	/**
-	 * Contents may be different from actual resource at corresponding document path,
-	 * in case of preprocessing.
+	 * Returns the contents of this document.
+	 * Contents may be different from actual resource at corresponding document
+	 * path due to preprocessing.
+	 * <p>
+	 * This method must be implemented in subclasses.
+	 * </p><p>
+	 * Note: some implementation may choose to cache the contents directly on the
+	 * document for performance reason. However, this could induce scalability issues due
+	 * to the fact that collections of documents are manipulated throughout the search
+	 * operation, and cached contents would then consume lots of memory until they are 
+	 * all released at once in the end.
+	 * </p>
+	 * 
+	 * @return the contents of this document,
+	 * or <code>null</code> if none
 	 */
-	public char[] getCharContents() {
-		return null;
-	}
+	public abstract char[] getCharContents();
 
 	/**
-	 * Returns the encoding for this document
+	 * Returns the encoding for this document.
+	 * <p>
+	 * This method must be implemented in subclasses.
+	 * </p>
+	 * 
+	 * @return the encoding for this document,
+	 * or <code>null</code> if none
 	 */
-	public String getEncoding() {
-		return null;
-	}
+	public abstract String getEncoding();
 
 	/**
-	 * Returns the participant that created this document
+	 * Returns the participant that created this document.
+	 * 
+	 * @return the participant that created this document
 	 */
-	public SearchParticipant getParticipant() {
+	public final SearchParticipant getParticipant() {
 		return this.participant;
 	}
 	
 	/**
-	 * Path to the original document to publicly mention in index or search results.
+	 * Returns the path to the original document to publicly mention in index
+	 * or search results. This path is a string that uniquely identifies the document.
+	 * Most of the time it is a workspace-relative path, but it can also be a file system path, 
+	 * or a path inside a zip file.
+	 * 
+	 * @return the path to the document
 	 */	
-	public String getPath() {
+	public final String getPath() {
 		return this.documentPath;
 	}
+	/**
+	 * Removes all index entries from the index for the given document.
+	 * This method must be called from 
+	 * {@link SearchParticipant#indexDocument(SearchDocument document, org.eclipse.core.runtime.IPath indexPath)}.
+	 */
+	public void removeAllIndexEntries() {
+		super.removeAllIndexEntries();
+	}
 }
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchEngine.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchEngine.java
index 923a2e0..7426d74 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchEngine.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchEngine.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -10,37 +10,28 @@
  *******************************************************************************/
 package org.eclipse.jdt.core.search;
 
+import java.util.*;
+
 import org.eclipse.core.resources.*;
 import org.eclipse.core.runtime.*;
 
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.internal.compiler.ASTVisitor;
-import org.eclipse.jdt.internal.compiler.CompilationResult;
-import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
+import org.eclipse.jdt.internal.compiler.*;
 import org.eclipse.jdt.internal.compiler.ast.*;
-import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
-import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
-import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
-import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
+import org.eclipse.jdt.internal.compiler.lookup.*;
 import org.eclipse.jdt.internal.compiler.parser.Parser;
 import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
 import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
 import org.eclipse.jdt.internal.core.*;
 import org.eclipse.jdt.internal.core.search.*;
-import org.eclipse.jdt.internal.core.search.HierarchyScope;
-import org.eclipse.jdt.internal.core.search.JavaSearchScope;
-import org.eclipse.jdt.internal.core.search.JavaWorkspaceScope;
-import org.eclipse.jdt.internal.core.search.PatternSearchJob;
 import org.eclipse.jdt.internal.core.search.indexing.*;
 import org.eclipse.jdt.internal.core.search.matching.*;
 import org.eclipse.jdt.internal.core.util.Util;
 
-import java.util.*;
-
 /**
- * A <code>SearchEngine</code> searches for java elements following a search pattern.
+ * A <code>SearchEngine</code> searches for Java elements following a search pattern.
  * The search can be limited to a search scope.
  * <p>
  * Various search patterns can be created using the factory methods 
@@ -53,38 +44,52 @@
  * <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 {
+		SearchPattern pattern;
+		SearchPatternAdapter(SearchPattern pattern) {
+			this.pattern = pattern;
+		}
+	}
+	/**
+	 * Internal adapter class.
+	 * @deprecated marking deprecated as it uses deprecated IJavaSearchResultCollector
+	 */
 	class ResultCollectorAdapter extends SearchRequestor {
 		IJavaSearchResultCollector resultCollector;
 		ResultCollectorAdapter(IJavaSearchResultCollector resultCollector) {
 			this.resultCollector = resultCollector;
 		}
-		public boolean acceptSearchMatch(SearchMatch match) throws CoreException {
-			JavaSearchMatch javaSearchMatch = (JavaSearchMatch) match;
+		/**
+		 * @see org.eclipse.jdt.core.search.SearchRequestor#acceptSearchMatch(org.eclipse.jdt.core.search.SearchMatch)
+		 */
+		public void acceptSearchMatch(SearchMatch match) throws CoreException {
 			this.resultCollector.accept(
-				javaSearchMatch.resource,
-				javaSearchMatch.getSourceStart(),
-				javaSearchMatch.getSourceEnd(),
-				javaSearchMatch.element,
-				javaSearchMatch.getAccuracy()
+				match.getResource(),
+				match.getOffset(),
+				match.getOffset() + match.getLength(),
+				(IJavaElement) match.getElement(),
+				match.getAccuracy()
 			);
-			return true;
 		}
+		/**
+		 * @see org.eclipse.jdt.core.search.SearchRequestor#beginReporting()
+		 */
 		public void beginReporting() {
 			this.resultCollector.aboutToStart();
 		}
+		/**
+		 * @see org.eclipse.jdt.core.search.SearchRequestor#endReporting()
+		 */
 		public void endReporting() {
 			this.resultCollector.done();
 		}
-		public void enterParticipant(SearchParticipant participant) {
-			// Nothing to do since only one Java search participant
-		}
-		public void exitParticipant(SearchParticipant participant) {
-			// Nothing to do since only one Java search participant
-		}
 	}
 		
 	/*
@@ -143,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;
@@ -163,8 +168,8 @@
 	}
 	
 	/**
-	 * Returns a java search scope limited to the hierarchy of the given type.
-	 * The java elements resulting from a search with this scope will
+	 * Returns a Java search scope limited to the hierarchy of the given type.
+	 * The Java elements resulting from a search with this scope will
 	 * be types in this hierarchy, or members of the types in this hierarchy.
 	 *
 	 * @param type the focus of the hierarchy scope
@@ -176,10 +181,10 @@
 	}
 	
 	/**
-	 * Returns a java search scope limited to the hierarchy of the given type.
+	 * Returns a Java search scope limited to the hierarchy of the given type.
 	 * When the hierarchy is computed, the types defined in the working copies owned
 	 * by the given owner take precedence over the original compilation units.
-	 * The java elements resulting from a search with this scope will
+	 * The Java elements resulting from a search with this scope will
 	 * be types in this hierarchy, or members of the types in this hierarchy.
 	 *
 	 * @param type the focus of the hierarchy scope
@@ -193,8 +198,8 @@
 	}
 
 	/**
-	 * Returns a java search scope limited to the given resources.
-	 * The java elements resulting from a search with this scope will
+	 * Returns a Java search scope limited to the given resources.
+	 * The Java elements resulting from a search with this scope will
 	 * have their underlying resource included in or equals to one of the given
 	 * resources.
 	 * <p>
@@ -202,8 +207,8 @@
 	 * </p>
 	 *
 	 * @param resources the resources the scope is limited to
-	 * @return a new java search scope
-	 * @deprecated Use createJavaSearchScope(IJavaElement[]) instead
+	 * @return a new Java search scope
+	 * @deprecated Use {@link #createJavaSearchScope(IJavaElement[])} instead.
 	 */
 	public static IJavaSearchScope createJavaSearchScope(IResource[] resources) {
 		int length = resources.length;
@@ -215,8 +220,8 @@
 	}
 
 	/**
-	 * Returns a java search scope limited to the given java elements.
-	 * The java elements resulting from a search with this scope will
+	 * Returns a Java search scope limited to the given Java elements.
+	 * The Java elements resulting from a search with this scope will
 	 * be children of the given elements.
 	 * <p>
 	 * If an element is an IJavaProject, then the project's source folders, 
@@ -230,8 +235,8 @@
 	 * <p>
 	 * In other words, this is equivalent to using SearchEngine.createJavaSearchScope(elements, true).</p>
 	 *
-	 * @param elements the java elements the scope is limited to
-	 * @return a new java search scope
+	 * @param elements the Java elements the scope is limited to
+	 * @return a new Java search scope
 	 * @since 2.0
 	 */
 	public static IJavaSearchScope createJavaSearchScope(IJavaElement[] elements) {
@@ -239,8 +244,8 @@
 	}
 
 	/**
-	 * Returns a java search scope limited to the given java elements.
-	 * The java elements resulting from a search with this scope will
+	 * Returns a Java search scope limited to the given Java elements.
+	 * The Java elements resulting from a search with this scope will
 	 * be children of the given elements.
 	 * 
 	 * If an element is an IJavaProject, then the project's source folders, 
@@ -252,21 +257,60 @@
 	 * files of this package fragment will be included. Subpackages will NOT be 
 	 * included.
 	 *
-	 * @param elements the java elements the scope is limited to
+	 * @param elements the Java elements the scope is limited to
 	 * @param includeReferencedProjects a flag indicating if referenced projects must be 
 	 * 									 recursively included
-	 * @return a new java search scope
+	 * @return a new Java search scope
 	 * @since 2.0
 	 */
 	public static IJavaSearchScope createJavaSearchScope(IJavaElement[] elements, boolean includeReferencedProjects) {
+		int includeMask = IJavaSearchScope.SOURCES | IJavaSearchScope.APPLICATION_LIBRARIES | IJavaSearchScope.SYSTEM_LIBRARIES;
+		if (includeReferencedProjects) {
+			includeMask |= IJavaSearchScope.REFERENCED_PROJECTS;
+		}
+		return createJavaSearchScope(elements, includeMask);
+	}
+
+	/**
+	 * Returns a Java search scope limited to the given Java elements.
+	 * The Java elements resulting from a search with this scope will
+	 * be children of the given elements.
+	 * 
+	 * If an element is an IJavaProject, then it includes:
+	 * - its source folders if IJavaSearchScope.SOURCES is specified, 
+	 * - its application libraries (internal and external jars, class folders that are on the raw classpath, 
+	 *   or the ones that are coming from a classpath path variable,
+	 *   or the ones that are coming from a classpath container with the K_APPLICATION kind)
+	 *   if IJavaSearchScope.APPLICATION_LIBRARIES is specified
+	 * - its system libraries (internal and external jars, class folders that are coming from an 
+	 *   IClasspathContainer with the K_SYSTEM kind) 
+	 *   if IJavaSearchScope.APPLICATION_LIBRARIES is specified
+	 * - its referenced projects (with their source folders and jars, recursively) 
+	 *   if IJavaSearchScope.REFERENCED_PROJECTS is specified.
+	 * If an element is an IPackageFragmentRoot, then only the package fragments of 
+	 * this package fragment root will be included.
+	 * If an element is an IPackageFragment, then only the compilation unit and class 
+	 * files of this package fragment will be included. Subpackages will NOT be 
+	 * included.
+	 *
+	 * @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
+	 * @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();
 		HashSet visitedProjects = new HashSet(2);
 		for (int i = 0, length = elements.length; i < length; i++) {
 			IJavaElement element = elements[i];
 			if (element != null) {
 				try {
-					if (element instanceof IJavaProject) {
-						scope.add((IJavaProject)element, includeReferencedProjects, visitedProjects);
+					if (element instanceof JavaProject) {
+						scope.add((JavaProject)element, includeMask, visitedProjects);
 					} else {
 						scope.add(element);
 					}
@@ -277,50 +321,6 @@
 		}
 		return scope;
 	}
-
-	/**
-	 * Returns a search pattern that combines the given two patterns into a "and" pattern.
-	 * The search result will match both the left pattern and the right pattern.
-	 *
-	 * @param leftPattern the left pattern
-	 * @param rightPattern the right pattern
-	 * @return a "and" pattern
-     * @since 3.0
-	 */
-	public static SearchPattern createAndSearchPattern(final SearchPattern leftPattern, final SearchPattern rightPattern) {
-		return new AndPattern(0/*no kind*/, 0/*no rule*/){
-			SearchPattern current = leftPattern;
-			public void decodeIndexKey(char[] key) {
-				current.decodeIndexKey(key);
-
-			}
-			public char[] encodeIndexKey() {
-				return current.encodeIndexKey();
-			}
-			public SearchPattern getIndexRecord() {
-				return current.getIndexRecord();
-			}
-			public char[][] getMatchCategories() {
-				return current.getMatchCategories();
-			}
-			public int getMatchRule() {
-				return current.getMatchRule();
-			}
-			protected boolean hasNextQuery() {
-				if (current == leftPattern) {
-					current = rightPattern;
-					return true;
-				}
-				return false; 
-			}
-			public boolean isMatchingIndexRecord() {
-				return current.isMatchingIndexRecord();
-			}
-			protected void resetQuery() {
-				current = leftPattern;
-			}
-		};
-	}
 	
 	/**
 	 * Returns a search pattern that combines the given two patterns into a "or" pattern.
@@ -329,9 +329,13 @@
 	 * @param leftPattern the left pattern
 	 * @param rightPattern the right pattern
 	 * @return a "or" pattern
+	 * @deprecated Use {@link SearchPattern#createOrPattern(SearchPattern, SearchPattern)} instead.
 	 */
 	public static ISearchPattern createOrSearchPattern(ISearchPattern leftPattern, ISearchPattern rightPattern) {
-		return new OrPattern((SearchPattern)leftPattern, (SearchPattern)rightPattern);
+		SearchPattern left = ((SearchPatternAdapter) leftPattern).pattern;
+		SearchPattern right = ((SearchPatternAdapter) rightPattern).pattern;
+		SearchPattern pattern = SearchPattern.createOrPattern(left, right);
+		return new SearchPatternAdapter(pattern);
 	}
 	
 	/**
@@ -375,22 +379,21 @@
 	 *
 	 * @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 {@link SearchPattern#createPattern(String, int, int, int)} instead.
 	 */
 	public static ISearchPattern createSearchPattern(String stringPattern, int searchFor, int limitTo, boolean isCaseSensitive) {
-		int matchMode;
-		if (stringPattern.indexOf('*') != -1 || stringPattern.indexOf('?') != -1) {
-			matchMode = IJavaSearchConstants.PATTERN_MATCH;
-		} else {
-			matchMode = IJavaSearchConstants.EXACT_MATCH;
-		}
-		return SearchPattern.createPattern(stringPattern, searchFor, limitTo, matchMode, isCaseSensitive);
+		int matchMode = stringPattern.indexOf('*') != -1 || stringPattern.indexOf('?') != -1
+			? SearchPattern.R_PATTERN_MATCH
+			: SearchPattern.R_EXACT_MATCH;
+		int matchRule = isCaseSensitive ? matchMode | SearchPattern.R_CASE_SENSITIVE : matchMode;
+		return  new SearchPatternAdapter(SearchPattern.createPattern(stringPattern, searchFor, limitTo, matchRule));
 	}
 	
 	/**
 	 * Returns a search pattern based on a given Java element. 
 	 * The pattern is used to trigger the appropriate search, and can be parameterized as follows:
 	 *
-	 * @param element the java element the search pattern is based on
+	 * @param element the Java element the search pattern is based on
 	 * @param limitTo determines the nature of the expected matches
 	 * 	<ul>
 	 * 		<li><code>IJavaSearchConstants.DECLARATIONS</code>: will search declarations matching with the corresponding
@@ -404,15 +407,15 @@
 	 *
 	 *		 <li><code>IJavaSearchConstants.IMPLEMENTORS</code>: for interface, will find all types which implements a given interface.</li>
 	 *	</ul>
-	 * @return a search pattern for a java element or <code>null</code> if the given element is ill-formed
+	 * @return a search pattern for a Java element or <code>null</code> if the given element is ill-formed
+	 * @deprecated Use {@link SearchPattern#createPattern(IJavaElement, int)} instead.
 	 */
 	public static ISearchPattern createSearchPattern(IJavaElement element, int limitTo) {
-	
-		return SearchPattern.createPattern(element, limitTo);
+		return new SearchPatternAdapter(SearchPattern.createPattern(element, limitTo));
 	}
 	
 	/**
-	 * Returns a java search scope with the workspace as the only limit.
+	 * Returns a Java search scope with the workspace as the only limit.
 	 *
 	 * @return a new workspace scope
 	 */
@@ -421,58 +424,67 @@
 	}
 	
 	/**
-	 * Returns default Java search participant
-	 * TODO add spec
+	 * 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 requestor 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
 	 */
 	public static SearchParticipant getDefaultSearchParticipant() {
-		
-		return new JavaSearchParticipant(null);
-	}
-
-	/**
-	 * Returns all registered search participants
-	 * TODO add spec
-	 * @since 3.0
-	 */
-	public static SearchParticipant[] getSearchParticipants() {
-		
-		Plugin plugin = JavaCore.getPlugin();
-		if (plugin == null) return SearchParticipant.NO_PARTICIPANT;
-	
-		IExtensionPoint extension = plugin.getDescriptor().getExtensionPoint(JavaModelManager.SEARCH_PARTICIPANT_EXTPOINT_ID);
-		if (extension != null) {
-			IExtension[] extensions =  extension.getExtensions();
-			int length = extensions.length;
-			SearchParticipant[] participants = new SearchParticipant[length+1];
-			// insert first the default Java participant (implicitly registered)
-			participants[0] = getDefaultSearchParticipant();
-			int found = 1;
-			for(int i = 0; i < extensions.length; i++){
-				IConfigurationElement [] configElements = extensions[i].getConfigurationElements();
-				for(int j = 0, configLength = configElements.length; j < configLength; j++){
-					try {
-						Object execExt = configElements[j].createExecutableExtension("class"); //$NON-NLS-1$
-						if (execExt != null && execExt instanceof SearchParticipant){
-							participants[found++] = (SearchParticipant)execExt;
-						}
-					} catch(CoreException e) {
-						// executable extension could not be created: ignore this participant
-						if (SearchEngine.VERBOSE) {
-							System.out.println("Search - failed to instanciate participant: "+ configElements[j].getAttribute("class"));//$NON-NLS-2$//$NON-NLS-1$
-							e.printStackTrace();
-						}						
-					}
-				}
-			}	
-			if (found == 0) return SearchParticipant.NO_PARTICIPANT;
-			if (found < length) {
-				System.arraycopy(participants, 0, participants = new SearchParticipant[found], 0, found);
-			}
-			return participants;
-		}
-		// return default participant (implicitely registered)
-		return new SearchParticipant[] {getDefaultSearchParticipant()};
+		return new JavaSearchParticipant();
 	}
 
 	private Parser getParser() {
@@ -564,7 +576,7 @@
 	}
 	
 	/**
-	 * Returns the list of working copies used to do the search on the given java element.
+	 * Returns the list of working copies used to do the search on the given Java element.
 	 * @param element an IJavaElement
 	 * @return an array of ICompilationUnit
 	 */
@@ -579,15 +591,14 @@
 					System.arraycopy(copies, 0, newWorkingCopies, 0, length);
 					newWorkingCopies[length] = cu;
 					return newWorkingCopies;
-				} else {
-					return new ICompilationUnit[] {cu};
-				}
+				} 
+				return new ICompilationUnit[] {cu};
 			}
 		}
 		return getWorkingCopies();
 	}
 
-	boolean match(char classOrInterface, char[] patternPkg, char[] patternTypeName, int matchMode, boolean isCaseSensitive, boolean isClass, char[] pkg, char[] typeName) {
+	boolean match(char classOrInterface, char[] patternPkg, char[] patternTypeName, int matchRule, boolean isClass, char[] pkg, char[] typeName) {
 		switch(classOrInterface) {
 			case IIndexConstants.CLASS_SUFFIX :
 				if (!isClass) return false;
@@ -596,16 +607,18 @@
 			case IIndexConstants.TYPE_SUFFIX : // nothing
 		}
 	
+		boolean isCaseSensitive = (matchRule & SearchPattern.R_CASE_SENSITIVE) != 0;
 		if (patternPkg != null && !CharOperation.equals(patternPkg, pkg, isCaseSensitive))
-			return false;
-	
+				return false;
+		
 		if (patternTypeName != null) {
+			int matchMode = matchRule - (isCaseSensitive ? SearchPattern.R_CASE_SENSITIVE : 0);
 			switch(matchMode) {
-				case IJavaSearchConstants.EXACT_MATCH :
+				case SearchPattern.R_EXACT_MATCH :
 					return CharOperation.equals(patternTypeName, typeName, isCaseSensitive);
-				case IJavaSearchConstants.PREFIX_MATCH :
+				case SearchPattern.R_PREFIX_MATCH :
 					return CharOperation.prefixEquals(patternTypeName, typeName, isCaseSensitive);
-				case IJavaSearchConstants.PATTERN_MATCH :
+				case SearchPattern.R_PATTERN_MATCH :
 					return CharOperation.match(patternTypeName, typeName, isCaseSensitive);
 			}
 		}
@@ -644,9 +657,24 @@
 	 *	<ul>
 	 *		<li>the classpath is incorrectly set</li>
 	 *	</ul>
+	 * @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 {
-		search(workspace, createSearchPattern(patternString, searchFor, limitTo, true), scope, resultCollector);
+		try {
+			int matchMode = patternString.indexOf('*') != -1 || patternString.indexOf('?') != -1
+				? SearchPattern.R_PATTERN_MATCH
+				: SearchPattern.R_EXACT_MATCH;
+			search(
+				SearchPattern.createPattern(patternString, searchFor, limitTo, matchMode | SearchPattern.R_CASE_SENSITIVE), 
+				new SearchParticipant[] {getDefaultSearchParticipant()}, 
+				scope, 
+				new ResultCollectorAdapter(resultCollector), 
+				resultCollector.getProgressMonitor());
+		} catch (CoreException e) {
+			if (e instanceof JavaModelException)
+				throw (JavaModelException) e;
+			throw new JavaModelException(e);
+		}
 	}
 
 	/**
@@ -673,6 +701,7 @@
 	 *		<li>the element doesn't exist</li>
 	 *		<li>the classpath is incorrectly set</li>
 	 *	</ul>
+	 * @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);
@@ -691,21 +720,20 @@
 	 *	<ul>
 	 *		<li>the classpath is incorrectly set</li>
 	 *	</ul>
+	 * @deprecated Use {@link  #search(SearchPattern, SearchParticipant[], IJavaSearchScope, SearchRequestor, IProgressMonitor)} instead.
 	 */
 	public void search(IWorkspace workspace, ISearchPattern searchPattern, IJavaSearchScope scope, IJavaSearchResultCollector resultCollector) throws JavaModelException {
 		try {
 			search(
-				(SearchPattern)searchPattern, 
-				new SearchParticipant[] {new JavaSearchParticipant(getWorkingCopies())}, 
+				((SearchPatternAdapter)searchPattern).pattern, 
+				new SearchParticipant[] {getDefaultSearchParticipant()}, 
 				scope, 
 				new ResultCollectorAdapter(resultCollector), 
 				resultCollector.getProgressMonitor());
 		} catch (CoreException e) {
-			if (e instanceof JavaModelException) {
+			if (e instanceof JavaModelException)
 				throw (JavaModelException) e;
-			} else {
-				throw new JavaModelException(e);
-			}
+			throw new JavaModelException(e);
 		}
 	}
 	
@@ -714,19 +742,19 @@
 	 * 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 workspace the workspace
-	 * @param searchPattern the pattern to be searched for
-	 * @param scope the search result has to be limited to the given scope
-	 * @param resultCollector a callback object to which each match is reported
-	 * @exception JavaModelException if the search failed. Reasons include:
+	 * @param pattern the pattern to search
+	 * @param participants the particpants in the search
+	 * @param scope the search scope
+	 * @param requestor the requestor to report the matches to
+	 * @param monitor the progress monitor used to report progress
+	 * @exception CoreException if the search failed. Reasons include:
 	 *	<ul>
 	 *		<li>the classpath is incorrectly set</li>
 	 *	</ul>
 	 *@since 3.0
-	 *TODO add spec
 	 */
 	public void search(SearchPattern pattern, SearchParticipant[] participants, IJavaSearchScope scope, SearchRequestor requestor, IProgressMonitor monitor) throws CoreException {
-		pattern.findMatches(participants, scope, requestor, monitor);
+		findMatches(pattern, participants, scope, requestor, monitor);
 	}
 
 	/**
@@ -734,6 +762,218 @@
 	 * The search can be selecting specific types (given a package or a type name
 	 * prefix and match modes). 
 	 * 
+	 * @param packageName the full name of the package of the searched types, or a prefix for this
+	 *						package, or a wild-carded string for this package.
+	 * @param typeName the dot-separated qualified name of the searched type (the qualification include
+	 *					the enclosing types if the searched type is a member type), or a prefix
+	 *					for this type, or a wild-carded string for this type.
+	 * @param matchRule one of
+	 * <ul>
+	 *		<li><code>SearchPattern.R_EXACT_MATCH</code> if the package name and type name are the full names
+	 *			of the searched types.</li>
+	 *		<li><code>SearchPattern.R_PREFIX_MATCH</code> if the package name and type name are prefixes of the names
+	 *			of the searched types.</li>
+	 *		<li><code>SearchPattern.R_PATTERN_MATCH</code> if the package name and type name contain wild-cards.</li>
+	 * </ul>
+	 * combined with <code>SearchPattern.R_CASE_SENSITIVE</code>,
+	 *   e.g. <code>R_EXACT_MATCH | R_CASE_SENSITIVE</code> if an exact and case sensitive match is requested, 
+	 *   or <code>R_PREFIX_MATCH</code> if a prefix non case sensitive match is requested.
+	 * @param searchFor one of
+	 * <ul>
+	 * 		<li><code>IJavaSearchConstants.CLASS</code> if searching for classes only</li>
+	 * 		<li><code>IJavaSearchConstants.INTERFACE</code> if searching for interfaces only</li>
+	 * 		<li><code>IJavaSearchConstants.TYPE</code> if searching for both classes and interfaces</li>
+	 * </ul>
+	 * @param scope the scope to search in
+	 * @param nameRequestor the requestor that collects the results of the search
+	 * @param waitingPolicy one of
+	 * <ul>
+	 *		<li><code>IJavaSearchConstants.FORCE_IMMEDIATE_SEARCH</code> if the search should start immediately</li>
+	 *		<li><code>IJavaSearchConstants.CANCEL_IF_NOT_READY_TO_SEARCH</code> if the search should be cancelled if the
+	 *			underlying indexer has not finished indexing the workspace</li>
+	 *		<li><code>IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH</code> if the search should wait for the
+	 *			underlying indexer to finish indexing the workspace</li>
+	 * </ul>
+	 * @param progressMonitor the progress monitor to report progress to, or <code>null</code> if no progress
+	 *							monitor is provided
+	 * @exception JavaModelException if the search failed. Reasons include:
+	 *	<ul>
+	 *		<li>the classpath is incorrectly set</li>
+	 *	</ul>
+	 * @since 3.0
+	 */
+	public void searchAllTypeNames(
+		final char[] packageName, 
+		final char[] typeName,
+		final int matchRule, 
+		int searchFor, 
+		IJavaSearchScope scope, 
+		final ITypeNameRequestor nameRequestor,
+		int waitingPolicy,
+		IProgressMonitor progressMonitor)  throws JavaModelException {
+	
+		IndexManager indexManager = JavaModelManager.getJavaModelManager().getIndexManager();
+			
+		final char classOrInterface;
+		switch(searchFor){
+			case IJavaSearchConstants.CLASS :
+				classOrInterface = IIndexConstants.CLASS_SUFFIX;
+				break;
+			case IJavaSearchConstants.INTERFACE :
+				classOrInterface = IIndexConstants.INTERFACE_SUFFIX;
+				break;
+			default : 
+				classOrInterface = IIndexConstants.TYPE_SUFFIX;
+				break;
+		}
+		final TypeDeclarationPattern pattern = new TypeDeclarationPattern(
+			packageName,
+			null, // do find member types
+			typeName,
+			classOrInterface,
+			matchRule);
+		
+		final HashSet workingCopyPaths = new HashSet();
+		ICompilationUnit[] copies = getWorkingCopies();
+		if (copies != null) {
+			for (int i = 0, length = copies.length; i < length; i++) {
+				ICompilationUnit workingCopy = copies[i];
+				workingCopyPaths.add(workingCopy.getPath().toString());
+			}
+		}
+	
+		IndexQueryRequestor searchRequestor = new IndexQueryRequestor(){
+			public boolean acceptIndexMatch(String documentPath, SearchPattern indexRecord, SearchParticipant participant) {
+				TypeDeclarationPattern record = (TypeDeclarationPattern)indexRecord;
+				if (record.enclosingTypeNames != IIndexConstants.ONE_ZERO_CHAR  // filter out local and anonymous classes
+						&& !workingCopyPaths.contains(documentPath)) { // filter out working copies
+					boolean isClass = record.classOrInterface != IIndexConstants.INTERFACE_SUFFIX;
+					if (isClass) {
+						nameRequestor.acceptClass(record.pkg, record.simpleName, record.enclosingTypeNames, documentPath);
+					} else {
+						nameRequestor.acceptInterface(record.pkg, record.simpleName, record.enclosingTypeNames, documentPath);
+					}
+				}
+				return true;
+			}
+		};
+	
+		try {
+			if (progressMonitor != null) {
+				progressMonitor.beginTask(Util.bind("engine.searching"), 100); //$NON-NLS-1$
+			}
+			// add type names from indexes
+			indexManager.performConcurrentJob(
+				new PatternSearchJob(
+					pattern, 
+					getDefaultSearchParticipant(), // Java search only
+					scope, 
+					searchRequestor),
+				waitingPolicy,
+				progressMonitor == null ? null : new SubProgressMonitor(progressMonitor, 100));	
+				
+			// add type names from working copies
+			if (copies != null) {
+				for (int i = 0, length = copies.length; i < length; i++) {
+					ICompilationUnit workingCopy = copies[i];
+					final String path = workingCopy.getPath().toString();
+					if (workingCopy.isConsistent()) {
+						IPackageDeclaration[] packageDeclarations = workingCopy.getPackageDeclarations();
+						char[] packageDeclaration = packageDeclarations.length == 0 ? CharOperation.NO_CHAR : packageDeclarations[0].getElementName().toCharArray();
+						IType[] allTypes = workingCopy.getAllTypes();
+						for (int j = 0, allTypesLength = allTypes.length; j < allTypesLength; j++) {
+							IType type = allTypes[j];
+							IJavaElement parent = type.getParent();
+							char[][] enclosingTypeNames;
+							if (parent instanceof IType) {
+								char[] parentQualifiedName = ((IType)parent).getTypeQualifiedName('.').toCharArray();
+								enclosingTypeNames = CharOperation.splitOn('.', parentQualifiedName);
+							} else {
+								enclosingTypeNames = CharOperation.NO_CHAR_CHAR;
+							}
+							char[] simpleName = type.getElementName().toCharArray();
+							if (match(classOrInterface, packageName, typeName, matchRule, type.isClass(), packageDeclaration, simpleName)) {
+								if (type.isClass()) {
+									nameRequestor.acceptClass(packageDeclaration, simpleName, enclosingTypeNames, path);
+								} else {
+									nameRequestor.acceptInterface(packageDeclaration, simpleName, enclosingTypeNames, path);
+								}
+							}
+						}
+					} else {
+						Parser basicParser = getParser();
+						final char[] contents = workingCopy.getBuffer().getCharacters();
+						org.eclipse.jdt.internal.compiler.env.ICompilationUnit unit = new org.eclipse.jdt.internal.compiler.env.ICompilationUnit() {
+							public char[] getContents() {
+								return contents;
+							}
+							public char[] getMainTypeName() {
+								return null;
+							}
+							public char[][] getPackageName() {
+								return null;
+							}
+							public char[] getFileName() {
+								return null;
+							}
+						};
+						CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0, this.compilerOptions.maxProblemsPerUnit);
+						CompilationUnitDeclaration parsedUnit = basicParser.dietParse(unit, compilationUnitResult);
+						if (parsedUnit != null) {
+							final char[] packageDeclaration = parsedUnit.currentPackage == null ? CharOperation.NO_CHAR : CharOperation.concatWith(parsedUnit.currentPackage.getImportName(), '.');
+							class AllTypeDeclarationsVisitor extends ASTVisitor {
+								public boolean visit(TypeDeclaration typeDeclaration, BlockScope blockScope) {
+									return false; // no local/anonymous type
+								}
+								public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope compilationUnitScope) {
+									if (match(classOrInterface, packageName, typeName, matchRule, !typeDeclaration.isInterface(), packageDeclaration, typeDeclaration.name)) {
+										if (!typeDeclaration.isInterface()) {
+											nameRequestor.acceptClass(packageDeclaration, typeDeclaration.name, CharOperation.NO_CHAR_CHAR, path);
+										} else {
+											nameRequestor.acceptInterface(packageDeclaration, typeDeclaration.name, CharOperation.NO_CHAR_CHAR, path);
+										}
+									}
+									return true;
+								}
+								public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope classScope) {
+									if (match(classOrInterface, packageName, typeName, matchRule, !memberTypeDeclaration.isInterface(), packageDeclaration, memberTypeDeclaration.name)) {
+										// compute encloising type names
+										TypeDeclaration enclosing = memberTypeDeclaration.enclosingType;
+										char[][] enclosingTypeNames = CharOperation.NO_CHAR_CHAR;
+										while (enclosing != null) {
+											enclosingTypeNames = CharOperation.arrayConcat(new char[][] {enclosing.name}, enclosingTypeNames);
+											if ((enclosing.bits & ASTNode.IsMemberTypeMASK) != 0) {
+												enclosing = enclosing.enclosingType;
+											} else {
+												enclosing = null;
+											}
+										}
+										// report
+										if (!memberTypeDeclaration.isInterface()) {
+											nameRequestor.acceptClass(packageDeclaration, memberTypeDeclaration.name, enclosingTypeNames, path);
+										} else {
+											nameRequestor.acceptInterface(packageDeclaration, memberTypeDeclaration.name, enclosingTypeNames, path);
+										}
+									}
+									return true;
+								}
+							}
+							parsedUnit.traverse(new AllTypeDeclarationsVisitor(), parsedUnit.scope);
+						}
+					}
+				}
+			}	
+		} finally {
+			if (progressMonitor != null) {
+				progressMonitor.done();
+			}
+		}
+	}
+	/**
+	 * Searches for all top-level types and member types in the given scope.
+	 * The search can be selecting specific types (given a package or a type name
+	 * prefix and match modes). 
+	 * 
 	 * @param workspace the workspace to search in
 	 * @param packageName the full name of the package of the searched types, or a prefix for this
 	 *						package, or a wild-carded string for this package.
@@ -771,6 +1011,7 @@
 	 *	<ul>
 	 *		<li>the classpath is incorrectly set</li>
 	 *	</ul>
+	 *@deprecated Use {@link #searchAllTypeNames(char[], char[], int, int, IJavaSearchScope, ITypeNameRequestor, int, IProgressMonitor)} instead
 	 */
 	public void searchAllTypeNames(
 		IWorkspace workspace,
@@ -783,195 +1024,105 @@
 		final ITypeNameRequestor nameRequestor,
 		int waitingPolicy,
 		IProgressMonitor progressMonitor)  throws JavaModelException {
-	
-		IndexManager indexManager = JavaModelManager.getJavaModelManager().getIndexManager();
-			
-		final char classOrInterface;
-		switch(searchFor){
-			case IJavaSearchConstants.CLASS :
-				classOrInterface = IIndexConstants.CLASS_SUFFIX;
-				break;
-			case IJavaSearchConstants.INTERFACE :
-				classOrInterface = IIndexConstants.INTERFACE_SUFFIX;
-				break;
-			default : 
-				classOrInterface = IIndexConstants.TYPE_SUFFIX;
-				break;
-		}
-		final TypeDeclarationPattern pattern = new TypeDeclarationPattern(
-			packageName,
-			null, // do find member types
-			typeName,
-			classOrInterface,
-			isCaseSensitive ? matchMode | SearchPattern.R_CASE_SENSITIVE : matchMode);
 		
-		final HashSet workingCopyPaths = new HashSet();
-		ICompilationUnit[] copies = getWorkingCopies();
-		if (copies != null) {
-			for (int i = 0, length = copies.length; i < length; i++) {
-				ICompilationUnit workingCopy = copies[i];
-				workingCopyPaths.add(workingCopy.getPath().toString());
-			}
-		}
-	
-		IndexQueryRequestor searchRequestor = new IndexQueryRequestor(){
-			public boolean acceptIndexMatch(String documentPath, SearchPattern indexRecord, SearchParticipant participant) {
-				TypeDeclarationPattern record = (TypeDeclarationPattern)indexRecord;
-				if (record.enclosingTypeNames != IIndexConstants.ONE_ZERO_CHAR  // filter out local and anonymous classes
-						&& !workingCopyPaths.contains(documentPath)) { // filter out working copies
-					boolean isClass = record.classOrInterface != IIndexConstants.INTERFACE_SUFFIX;
-					if (isClass) {
-						nameRequestor.acceptClass(record.pkg, record.simpleName, record.enclosingTypeNames, documentPath);
-					} else {
-						nameRequestor.acceptInterface(record.pkg, record.simpleName, record.enclosingTypeNames, documentPath);
-					}
-				}
-				return true;
-			}
-		};
-	
-		try {
-			if (progressMonitor != null) {
-				progressMonitor.beginTask(Util.bind("engine.searching"), 100); //$NON-NLS-1$
-			}
-			// add type names from indexes
-			indexManager.performConcurrentJob(
-				new PatternSearchJob(
-					pattern, 
-					new JavaSearchParticipant(getWorkingCopies()), // java search only
-					scope, 
-					searchRequestor),
-				waitingPolicy,
-				progressMonitor == null ? null : new SubProgressMonitor(progressMonitor, 100));	
-				
-			// add type names from working copies
-			if (copies != null) {
-				for (int i = 0, length = copies.length; i < length; i++) {
-					ICompilationUnit workingCopy = copies[i];
-					final String path = workingCopy.getPath().toString();
-					if (workingCopy.isConsistent()) {
-						IPackageDeclaration[] packageDeclarations = workingCopy.getPackageDeclarations();
-						char[] packageDeclaration = packageDeclarations.length == 0 ? CharOperation.NO_CHAR : packageDeclarations[0].getElementName().toCharArray();
-						IType[] allTypes = workingCopy.getAllTypes();
-						for (int j = 0, allTypesLength = allTypes.length; j < allTypesLength; j++) {
-							IType type = allTypes[j];
-							IJavaElement parent = type.getParent();
-							char[][] enclosingTypeNames;
-							if (parent instanceof IType) {
-								char[] parentQualifiedName = ((IType)parent).getTypeQualifiedName('.').toCharArray();
-								enclosingTypeNames = CharOperation.splitOn('.', parentQualifiedName);
-							} else {
-								enclosingTypeNames = CharOperation.NO_CHAR_CHAR;
-							}
-							char[] simpleName = type.getElementName().toCharArray();
-							if (match(classOrInterface, packageName, typeName, matchMode, isCaseSensitive, type.isClass(), packageDeclaration, simpleName)) {
-								if (type.isClass()) {
-									nameRequestor.acceptClass(packageDeclaration, simpleName, enclosingTypeNames, path);
-								} else {
-									nameRequestor.acceptInterface(packageDeclaration, simpleName, enclosingTypeNames, path);
-								}
-							}
-						}
-					} else {
-						Parser basicParser = getParser();
-						final char[] contents = workingCopy.getBuffer().getCharacters();
-						org.eclipse.jdt.internal.compiler.env.ICompilationUnit unit = new org.eclipse.jdt.internal.compiler.env.ICompilationUnit() {
-							public char[] getContents() {
-								return contents;
-							}
-							public char[] getMainTypeName() {
-								return null;
-							}
-							public char[][] getPackageName() {
-								return null;
-							}
-							public char[] getFileName() {
-								return null;
-							}
-						};
-						CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0, this.compilerOptions.maxProblemsPerUnit);
-						CompilationUnitDeclaration parsedUnit = basicParser.dietParse(unit, compilationUnitResult);
-						if (parsedUnit != null) {
-							final char[] packageDeclaration = parsedUnit.currentPackage == null ? CharOperation.NO_CHAR : CharOperation.concatWith(parsedUnit.currentPackage.getImportName(), '.');
-							class AllTypeDeclarationsVisitor extends ASTVisitor {
-								public boolean visit(TypeDeclaration typeDeclaration, BlockScope blockScope) {
-									return false; // no local/anonymous type
-								}
-								public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope compilationUnitScope) {
-									if (match(classOrInterface, packageName, typeName, matchMode, isCaseSensitive, !typeDeclaration.isInterface(), packageDeclaration, typeDeclaration.name)) {
-										if (!typeDeclaration.isInterface()) {
-											nameRequestor.acceptClass(packageDeclaration, typeDeclaration.name, CharOperation.NO_CHAR_CHAR, path);
-										} else {
-											nameRequestor.acceptInterface(packageDeclaration, typeDeclaration.name, CharOperation.NO_CHAR_CHAR, path);
-										}
-									}
-									return true;
-								}
-								public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope classScope) {
-									if (match(classOrInterface, packageName, typeName, matchMode, isCaseSensitive, !memberTypeDeclaration.isInterface(), packageDeclaration, memberTypeDeclaration.name)) {
-										// compute encloising type names
-										TypeDeclaration enclosing = memberTypeDeclaration.enclosingType;
-										char[][] enclosingTypeNames = CharOperation.NO_CHAR_CHAR;
-										while (enclosing != null) {
-											enclosingTypeNames = CharOperation.arrayConcat(new char[][] {enclosing.name}, enclosingTypeNames);
-											if ((enclosing.bits & ASTNode.IsMemberTypeMASK) != 0) {
-												enclosing = enclosing.enclosingType;
-											} else {
-												enclosing = null;
-											}
-										}
-										// report
-										if (!memberTypeDeclaration.isInterface()) {
-											nameRequestor.acceptClass(packageDeclaration, memberTypeDeclaration.name, enclosingTypeNames, path);
-										} else {
-											nameRequestor.acceptInterface(packageDeclaration, memberTypeDeclaration.name, enclosingTypeNames, path);
-										}
-									}
-									return true;
-								}
-							}
-							parsedUnit.traverse(new AllTypeDeclarationsVisitor(), parsedUnit.scope);
-						}
-					}
-				}
-			}	
-		} finally {
-			if (progressMonitor != null) {
-				progressMonitor.done();
-			}
-		}
+		searchAllTypeNames(
+			packageName, 
+			typeName, 
+			isCaseSensitive ? matchMode | SearchPattern.R_CASE_SENSITIVE : matchMode, 
+			searchFor, 
+			scope, 
+			nameRequestor, 
+			waitingPolicy, 
+			progressMonitor);
 	}	
 	
-	private void searchDeclarations(IWorkspace workspace, IJavaElement enclosingElement, IJavaSearchResultCollector resultCollector, SearchPattern pattern) throws JavaModelException {
+	/**
+	 * @deprecated mark deprecated as it uses deprecated code
+	 */
+	private void searchDeclarations(IJavaElement enclosingElement, IJavaSearchResultCollector resultCollector, SearchPattern pattern) throws JavaModelException {
+		searchDeclarations(enclosingElement, new ResultCollectorAdapter(resultCollector), pattern, resultCollector.getProgressMonitor());
+	}
+	
+	private void searchDeclarations(IJavaElement enclosingElement, SearchRequestor requestor, SearchPattern pattern, IProgressMonitor monitor) throws JavaModelException {
 		IJavaSearchScope scope = createJavaSearchScope(new IJavaElement[] {enclosingElement});
 		IResource resource = this.getResource(enclosingElement);
-		if (resource instanceof IFile) {
-			if (VERBOSE) {
-				System.out.println("Searching for " + pattern + " in " + resource.getFullPath()); //$NON-NLS-1$//$NON-NLS-2$
-			}
-			try {
-				SearchParticipant participant = new JavaSearchParticipant(getWorkingCopies(enclosingElement));
+		try {
+			if (resource instanceof IFile) {
+				if (VERBOSE) {
+					System.out.println("Searching for " + pattern + " in " + resource.getFullPath()); //$NON-NLS-1$//$NON-NLS-2$
+				}
+				SearchParticipant participant = getDefaultSearchParticipant();
+				SearchDocument[] documents = MatchLocator.addWorkingCopies(
+					pattern,
+					new SearchDocument[] {new JavaSearchDocument(enclosingElement.getPath().toString(), participant)},
+					getWorkingCopies(enclosingElement),
+					participant);
 				participant.locateMatches(
-					new SearchDocument[] {new JavaSearchDocument(enclosingElement.getPath().toString(), participant)}, 
+					documents, 
 					pattern, 
 					scope, 
-					new ResultCollectorAdapter(resultCollector), 
-					resultCollector.getProgressMonitor());
-			} catch (CoreException e) {
-				if (e instanceof JavaModelException) {
-					throw (JavaModelException) e;
-				} else {
-					throw new JavaModelException(e);
-				}
+					requestor, 
+					monitor);
+			} else {
+				search(
+					pattern, 
+					new SearchParticipant[] {getDefaultSearchParticipant()}, 
+					scope, 
+					requestor, 
+					monitor);
 			}
-		} else {
-			search(workspace, pattern, scope, resultCollector);
+		} catch (CoreException e) {
+			if (e instanceof JavaModelException)
+				throw (JavaModelException) e;
+			throw new JavaModelException(e);
 		}
 	}
 
 	/**
 	 * Searches for all declarations of the fields accessed in the given element.
 	 * The element can be a compilation unit, a source type, or a source method.
+	 * Reports the field declarations using the given requestor.
+	 * <p>
+	 * Consider the following code:
+	 * <code>
+	 * <pre>
+	 *		class A {
+	 *			int field1;
+	 *		}
+	 *		class B extends A {
+	 *			String value;
+	 *		}
+	 *		class X {
+	 *			void test() {
+	 *				B b = new B();
+	 *				System.out.println(b.value + b.field1);
+	 *			};
+	 *		}
+	 * </pre>
+	 * </code>
+	 * then searching for declarations of accessed fields in method 
+	 * <code>X.test()</code> would collect the fields
+	 * <code>B.value</code> and <code>A.field1</code>.
+	 * </p>
+	 *
+	 * @param enclosingElement the method, type, or compilation unit to be searched in
+	 * @param requestor a callback object to which each match is reported
+	 * @param monitor the progress monitor used to report progress
+	 * @exception JavaModelException if the search failed. Reasons include:
+	 *	<ul>
+	 *		<li>the element doesn't exist</li>
+	 *		<li>the classpath is incorrectly set</li>
+	 *	</ul>
+	 * @since 3.0
+	 */	
+	public void searchDeclarationsOfAccessedFields(IJavaElement enclosingElement, SearchRequestor requestor, IProgressMonitor monitor) throws JavaModelException {
+		SearchPattern pattern = new DeclarationOfAccessedFieldsPattern(enclosingElement);
+		searchDeclarations(enclosingElement, requestor, pattern, monitor);
+	}
+	
+	/**
+	 * Searches for all declarations of the fields accessed in the given element.
+	 * The element can be a compilation unit, a source type, or a source method.
 	 * Reports the field declarations using the given collector.
 	 * <p>
 	 * Consider the following code:
@@ -1004,10 +1155,53 @@
 	 *		<li>the element doesn't exist</li>
 	 *		<li>the classpath is incorrectly set</li>
 	 *	</ul>
+	 * @deprecated Use {@link  #searchDeclarationsOfAccessedFields(IJavaElement, SearchRequestor, IProgressMonitor)} instead.
 	 */	
 	public void searchDeclarationsOfAccessedFields(IWorkspace workspace, IJavaElement enclosingElement, IJavaSearchResultCollector resultCollector) throws JavaModelException {
 		SearchPattern pattern = new DeclarationOfAccessedFieldsPattern(enclosingElement);
-		searchDeclarations(workspace, enclosingElement, resultCollector, pattern);
+		searchDeclarations(enclosingElement, resultCollector, pattern);
+	}
+	
+	/**
+	 * Searches for all declarations of the types referenced in the given element.
+	 * The element can be a compilation unit, a source type, or a source method.
+	 * Reports the type declarations using the given requestor.
+	 * <p>
+	 * Consider the following code:
+	 * <code>
+	 * <pre>
+	 *		class A {
+	 *		}
+	 *		class B extends A {
+	 *		}
+	 *		interface I {
+	 *		  int VALUE = 0;
+	 *		}
+	 *		class X {
+	 *			void test() {
+	 *				B b = new B();
+	 *				this.foo(b, I.VALUE);
+	 *			};
+	 *		}
+	 * </pre>
+	 * </code>
+	 * then searching for declarations of referenced types in method <code>X.test()</code>
+	 * would collect the class <code>B</code> and the interface <code>I</code>.
+	 * </p>
+	 *
+	 * @param enclosingElement the method, type, or compilation unit to be searched in
+	 * @param requestor a callback object to which each match is reported
+	 * @param monitor the progress monitor used to report progress
+	 * @exception JavaModelException if the search failed. Reasons include:
+	 *	<ul>
+	 *		<li>the element doesn't exist</li>
+	 *		<li>the classpath is incorrectly set</li>
+	 *	</ul>
+	 * @since 3.0
+	 */	
+	public void searchDeclarationsOfReferencedTypes(IJavaElement enclosingElement, SearchRequestor requestor, IProgressMonitor monitor) throws JavaModelException {
+		SearchPattern pattern = new DeclarationOfReferencedTypesPattern(enclosingElement);
+		searchDeclarations(enclosingElement, requestor, pattern, monitor);
 	}
 	
 	/**
@@ -1045,15 +1239,61 @@
 	 *		<li>the element doesn't exist</li>
 	 *		<li>the classpath is incorrectly set</li>
 	 *	</ul>
+	 * @deprecated Use {@link #searchDeclarationsOfReferencedTypes(IJavaElement, SearchRequestor, IProgressMonitor)} instead.
 	 */	
 	public void searchDeclarationsOfReferencedTypes(IWorkspace workspace, IJavaElement enclosingElement, IJavaSearchResultCollector resultCollector) throws JavaModelException {
 		SearchPattern pattern = new DeclarationOfReferencedTypesPattern(enclosingElement);
-		searchDeclarations(workspace, enclosingElement, resultCollector, pattern);
+		searchDeclarations(enclosingElement, resultCollector, pattern);
 	}
 	
 	/**
 	 * Searches for all declarations of the methods invoked in the given element.
 	 * The element can be a compilation unit, a source type, or a source method.
+	 * Reports the method declarations using the given requestor.
+	 * <p>
+	 * Consider the following code:
+	 * <code>
+	 * <pre>
+	 *		class A {
+	 *			void foo() {};
+	 *			void bar() {};
+	 *		}
+	 *		class B extends A {
+	 *			void foo() {};
+	 *		}
+	 *		class X {
+	 *			void test() {
+	 *				A a = new B();
+	 *				a.foo();
+	 *				B b = (B)a;
+	 *				b.bar();
+	 *			};
+	 *		}
+	 * </pre>
+	 * </code>
+	 * then searching for declarations of sent messages in method 
+	 * <code>X.test()</code> would collect the methods
+	 * <code>A.foo()</code>, <code>B.foo()</code>, and <code>A.bar()</code>.
+	 * </p>
+	 *
+	 * @param enclosingElement the method, type, or compilation unit to be searched in
+	 * @param requestor a callback object to which each match is reported
+	 * @param monitor the progress monitor used to report progress
+	 * @exception JavaModelException if the search failed. Reasons include:
+	 *	<ul>
+	 *		<li>the element doesn't exist</li>
+	 *		<li>the classpath is incorrectly set</li>
+	 *	</ul>
+	 * @since 3.0
+	 */	
+	public void searchDeclarationsOfSentMessages(IJavaElement enclosingElement, SearchRequestor requestor, IProgressMonitor monitor) throws JavaModelException {
+		SearchPattern pattern = new DeclarationOfReferencedMethodsPattern(enclosingElement);
+		searchDeclarations(enclosingElement, requestor, pattern, monitor);
+	}
+
+	/**
+	 * Searches for all declarations of the methods invoked in the given element.
+	 * The element can be a compilation unit, a source type, or a source method.
 	 * Reports the method declarations using the given collector.
 	 * <p>
 	 * Consider the following code:
@@ -1089,9 +1329,10 @@
 	 *		<li>the element doesn't exist</li>
 	 *		<li>the classpath is incorrectly set</li>
 	 *	</ul>
+	 * @deprecated Use {@link #searchDeclarationsOfSentMessages(IJavaElement, SearchRequestor, IProgressMonitor)} instead.
 	 */	
 	public void searchDeclarationsOfSentMessages(IWorkspace workspace, IJavaElement enclosingElement, IJavaSearchResultCollector resultCollector) throws JavaModelException {
 		SearchPattern pattern = new DeclarationOfReferencedMethodsPattern(enclosingElement);
-		searchDeclarations(workspace, enclosingElement, resultCollector, pattern);
+		searchDeclarations(enclosingElement, resultCollector, pattern);
 	}
 }
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchMatch.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchMatch.java
index 8666269..a7a5c27 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchMatch.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchMatch.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -10,79 +10,228 @@
  *******************************************************************************/
 package org.eclipse.jdt.core.search;
 
+import org.eclipse.core.resources.IResource;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.internal.core.JavaElement;
+
 /**
- * generic result. hierarchy can be extended
- * TODO add spec
+ * 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>
+ * <p>
+ * This class is intended to be instantiated and subclassed by clients.
+ * </p>
+ * 
+ * @see SearchEngine#search(SearchPattern, SearchParticipant[], IJavaSearchScope, SearchRequestor, org.eclipse.core.runtime.IProgressMonitor)
  * @since 3.0
  */
 public class SearchMatch {
 	
-	/* match accuracy */
-	public static final int A_ACCURATE = 1;
-	public static final int A_INACCURATE = 2;
+	/**
+	 * 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 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;
 	
-	/* generic information */
-	private final int accuracy;
-	private final  String descriptiveLocation;
-	private final String documentPath;
-	private final String name;
-	private final SearchParticipant participant;	
-	private final int sourceEnd;
-	private final int sourceLineNumber;
-	private final int sourceStart;
+	private Object element;
+	private int length;
+	private int offset;
 
+	private int accuracy;
+	private SearchParticipant participant;	
+	private IResource resource;
+
+	private boolean insideDocComment = false;
+
+	/**
+	 * Creates a new search match.
+	 * <p>
+	 * Note that <code>isInsideDocComment()</code> defaults to false.
+	 * </p>
+	 * 
+	 * @param element the element that encloses or corresponds to the match,
+	 * or <code>null</code> if none
+	 * @param accuracy one of {@link #A_ACCURATE} or {@link #A_INACCURATE}
+	 * @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, or <code>null</code> if none
+	 */
 	public SearchMatch(
-			String name, 
-			String documentPath, 
-			int accuracy,  
+			IJavaElement element,
+			int accuracy,
+			int offset,  
+			int length,
 			SearchParticipant participant, 
-			int sourceStart, 
-			int sourceEnd, 
-			int sourceLineNumber, 
-			String descriptiveLocation) {
-
-		this.name = name;
-		this.documentPath = documentPath;
+			IResource resource) {
+		this.element = element;
+		this.offset = offset;
+		this.length = length;
 		this.accuracy = accuracy;
 		this.participant = participant;
-		this.sourceStart = sourceStart;
-		this.sourceEnd = sourceEnd;
-		this.sourceLineNumber = sourceLineNumber;
-		this.descriptiveLocation = descriptiveLocation;
-	}
-	
-	public int getAccuracy() {
-		return this.accuracy;
-	}
-
-	public String getDescriptiveLocation() {
-		return this.descriptiveLocation;
-	}
-
-	public String getDocumentPath() {
-		return this.documentPath;
-	}
-
-	public String getName() {
-		return this.name;
+		this.resource = resource;
 	}
 
 	/**
-	 * Returns the participant which issued this match
+	 * Returns the accuracy of this search match.
+	 * 
+	 * @return one of {@link #A_ACCURATE} or {@link #A_INACCURATE}
 	 */
-	public SearchParticipant getParticipant() {
+	public final int getAccuracy() {
+		return this.accuracy;
+	}
+
+	/**
+	 * Returns the element of this search match.
+	 * In case of a reference match, this is the inner-most enclosing element of the reference.
+	 * In case of a declaration match, this is the declaration.
+	 * 
+	 * @return the element of the search match, or <code>null</code> if none
+	 */
+	public final Object getElement() {
+		return this.element;
+	}
+
+	/**
+	 * Returns the length of this search match.
+	 * 
+	 * @return the length of this search match, or -1 if unknown
+	 */
+	public final int getLength() {
+		return this.length;
+	}
+	
+	/**
+	 * Returns the offset of this search match.
+	 * 
+	 * @return the offset of this search match, or -1 if unknown
+	 */
+	public final int getOffset() {
+		return this.offset;
+	}
+	
+	/**
+	 * Returns the search participant which issued this search match.
+	 * 
+	 * @return the participant which issued this search match
+	 */
+	public final SearchParticipant getParticipant() {
 		return this.participant;
 	}
 	
-	public int getSourceEnd() {
-		return this.sourceEnd;
+	/**
+	 * Returns the resource containing this search match.
+	 * 
+	 * @return the resource of the match, or <code>null</code> if none
+	 */
+	public final IResource getResource() {
+		return this.resource;
 	}
 
-	public int getSourceLineNumber() {
-		return this.sourceLineNumber;
+	/**
+	 * 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 doc
+	 * comment, and <code>false</code> otherwise
+	 */
+	public final boolean isInsideDocComment() {
+		// default is outside a doc comment
+		return this.insideDocComment;
 	}
 
-	public int getSourceStart() {
-		return this.sourceStart;
+	/**
+	 * Sets the accuracy of this match.
+	 * 
+	 * @param accuracy one of {@link #A_ACCURATE} or {@link #A_INACCURATE}
+	 */
+	public final void setAccuracy (int accuracy) {
+		this.accuracy = accuracy;
+	}
+
+	/**
+	 * Sets the element of this search match.
+	 * 
+	 * @param element the element that encloses or corresponds to the match,
+	 * or <code>null</code> if none
+	 */
+	public final void setElement (Object element) {
+		this.element = element;
+	}
+	/**
+	 * Sets the length of this search match.
+	 * 
+	 * @param length the length of the match, or -1 if unknown
+	 */
+	public final void setLength(int length) {
+		this.length = length;
+	}
+	
+	/**
+	 * Sets the offset of this search match.
+	 * 
+	 * @param offset the offset the match starts at, or -1 if unknown
+	 */
+	public final void setOffset(int offset) {
+		this.offset = offset;
+	}
+
+	/**
+	 * Sets the participant of this match.
+	 * 
+	 * @param participant the search participant that created this match
+	 */
+	public final void setParticipant (SearchParticipant participant) {
+		this.participant = participant;
+	}
+
+	/**
+	 * Sets the resource of this match.
+	 * 
+	 * @param resource the resource of the match, or <code>null</code> if none
+	 */
+	public final void setResource (IResource resource) {
+		this.resource = resource;
+	}
+
+	/**
+	 * Sets whether this search match is inside a doc comment of a Java
+	 * source file.
+	 * 
+	 * @param insideDoc <code>true</code> if this search match is inside a doc
+	 * comment, and <code>false</code> otherwise
+	 */
+	public final void setInsideDocComment (boolean insideDoc) {
+		this.insideDocComment = insideDoc;
+	}
+
+	/* (non-javadoc)
+	 * @see java.lang.Object#toString()
+	 */
+	public String toString() {
+		StringBuffer buffer = new StringBuffer();
+		buffer.append("Search match"); //$NON-NLS-1$
+		buffer.append("\n  accuracy="); //$NON-NLS-1$
+		buffer.append(this.accuracy == A_ACCURATE ? "ACCURATE" : "INACCURATE"); //$NON-NLS-1$ //$NON-NLS-2$
+		buffer.append("\n  offset="); //$NON-NLS-1$
+		buffer.append(this.offset);
+		buffer.append("\n  length="); //$NON-NLS-1$
+		buffer.append(this.length);
+		if (this.element != null) {
+			buffer.append("\n  element="); //$NON-NLS-1$
+			buffer.append(((JavaElement)getElement()).toStringWithAncestors());
+		}
+		buffer.append("\n"); //$NON-NLS-1$
+		return buffer.toString();
 	}
 }
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchParticipant.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchParticipant.java
index 24693ab..015958b 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchParticipant.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchParticipant.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -10,81 +10,191 @@
  *******************************************************************************/
 package org.eclipse.jdt.core.search;
 
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IPath;
-import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.*;
 import org.eclipse.jdt.internal.core.JavaModelManager;
+import org.eclipse.jdt.internal.core.search.indexing.IndexManager;
 
 /**
- * A search participant describes a particular extension to a generic search mechanism, permitting 
- * combined search actions which will involve all required participants.
+ * A search participant describes a particular extension to a generic search
+ * mechanism, permitting combined search actions which will involve all required
+ * participants.
+ * <p>
+ * A search participant is involved in the indexing phase and in the search phase. 
+ * The indexing phase consists in taking one or more search documents, parse them, and
+ * add index entries in an index chosen by the participant. An index is identified by a
+ * path on disk.
+ * The search phase consists in selecting the indexes corresponding to a search pattern
+ * and a search scope, from these indexes the search infrastructure extracts the document paths
+ * that match the search pattern asking the search participant for the corresponding document,
+ * finally the search participant is asked to locate the matches precisely in these search documents.
+ * </p>
+ * <p>
+ * This class is intended to be subclassed by clients. During the indexing phase, 
+ * a subclass will be called with the following requests in order:
+ * <ul>
+ * <li>{@link #scheduleDocumentIndexing(SearchDocument, IPath)}</li>
+ * <li>{@link #indexDocument(SearchDocument, IPath)}</li>
+ * </ul>
+ * During the search phase, a subclass will be called with the following requests in order:
+ * <ul>
+ * <li>{@link #selectIndexes(SearchPattern, IJavaSearchScope)}</li>
+ * <li>one or more {@link #getDocument(String)}</li>
+ * <li>{@link #locateMatches(SearchDocument[], SearchPattern, IJavaSearchScope, SearchRequestor, IProgressMonitor)}</li>
+ * </ul>
+ * </p>
  * 
- * A search scope defines which participants are involved. 
- * 
- * A search participant is responsible for holding index files, and selecting the appropriate ones to feed to
- * index queries. It also can map a document path to an actual document (note that documents could live outside
- * the workspace or not exist yet, and thus aren't just resources).
  * @since 3.0
  */
 public abstract class SearchParticipant {
 
-	public static final SearchParticipant[] NO_PARTICIPANT = {};
-
-	// A service provided for participants so that they can delegate between themselves.
-	public static void addIndexEntry(char[] category, char[] key, SearchDocument document, String indexPath) {
-		JavaModelManager.getJavaModelManager().getIndexManager().addIndexEntry(category, key, document, indexPath);
-	}
-
-	public static void removeAllIndexEntries(String documentPath, String indexPath) {
-		// TODO (jerome) implement
-	}
-
 	/**
-	 * Intermediate notification sent when a given participant is getting involved.
+	 * Creates a new search participant.
 	 */
-	public abstract void beginSearching();
-
-	/**
-	 * Intermediate notification sent when a given participant is finished to be involved.
-	 */
-	public abstract void doneSearching();
+	protected SearchParticipant() {
+		// do nothing
+	}
 	
 	/**
-	 * Returns a displayable name of this search participant. e.g. "Java".
+	 * Notification that this participant's help is needed in a search.
+	 * <p>
+	 * This method should be re-implemented in subclasses that need to do something
+	 * when the participant is needed in a search.
+	 * </p>
 	 */
-	public abstract String getDescription();
+	public void beginSearching() {
+		// do nothing
+	}
 
 	/**
-	 * Bind a document path to an actual document. A document path is interpreted by a participant.
+	 * Notification that this participant's help is no longer needed.
+	 * <p>
+	 * This method should be re-implemented in subclasses that need to do something
+	 * when the participant is no longer needed in a search.
+	 * </p>
+	 */
+	public void doneSearching() {
+		// do nothing
+	}
+
+	/**
+	 * Returns a displayable name of this search participant.
+	 * <p>
+	 * This method should be re-implemented in subclasses that need to 
+	 * display a meaningfull name.
+	 * </p>
+	 * 
+	 * @return the displayable name of this search participant
+	 */
+	public String getDescription() {
+		return "Search participant"; //$NON-NLS-1$
+	}
+
+	/**
+	 * Returns a search document for the given path.
+	 * The given document path is a string that uniquely identifies the document.
+	 * Most of the time it is a workspace-relative path, but it can also be a file system path, or a path inside a zip file.
+	 * <p>
+	 * Implementors of this method can either create an instance of their own subclass of 
+	 * {@link SearchDocument} or return an existing instance of such a subclass.
+	 * </p>
+	 * 
+	 * @param documentPath the path of the document.
+	 * @return a search document
 	 */
 	public abstract SearchDocument getDocument(String documentPath);
 
 	/**
-	 * Index the given document.
-	 * Implementation should call addIndexEntry(...)
-	 * TODO (jerome) improve spec
+	 * Indexes the given document in the given index. A search participant
+	 * asked to index a document should parse it and call 
+	 * {@link SearchDocument#addIndexEntry(char[], char[])} as many times as
+	 * needed to add index entries to the index. If delegating to another
+	 * participant, it should use the original index location (and not the
+	 * delegatee's one). In the particular case of delegating to the default
+	 * search participant (see {@link SearchEngine#getDefaultSearchParticipant()}),
+	 * the provided document's path must be a path ending with '.java' or a '.class'.
+	 * <p>
+	 * The given index location must represent a path in the file system to a file that
+	 * either already exists or is going to be created. If it exists, it must be an index file,
+	 * otherwise its data might be overwritten.
+	 * </p><p>
+	 * Clients are not expected to call this method.
+	 * </p>
+	 * 
+	 * @param document the document to index
+	 * @param indexLocation the location in the file system to the index
 	 */
-	public abstract void indexDocument(SearchDocument document, String indexPath);
+	public abstract void indexDocument(SearchDocument document, IPath indexLocation);
 
 	/**
-	 * Locate the matches in the given documents and report them using the search requestor. 
-	 * Note: allows to combine match locators (e.g. jsp match locator can preprocess jsp unit contents and feed it to Java match locator asking for virtual matches
-	 * by contributing document implementations which do the conversion). It is assumed that virtual matches are rearranged by requestor for adapting line/source 
-	 * positions before submitting final results so the provided searchRequestor should intercept virtual matches and do appropriate conversions.
+	 * Locates the matches in the given documents using the given search pattern
+	 * and search scope, and reports them to the givenn search requestor. This
+	 * method is called by the search engine once it has search documents
+	 * matching the given pattern in the given search scope.
+	 * <p>
+	 * Note that a participant (e.g. a JSP participant) can pre-process the contents of the given documents, 
+	 * create its own documents whose contents are Java compilation units and delegate the match location 
+	 * to the default participant (see {@link SearchEngine#getDefaultSearchParticipant()}). Passing its own
+	 * {@link SearchRequestor} this particpant can then map the match positions back to the original
+	 * contents, create its own matches and report them to the original requestor.
+	 * </p><p>
+	 * Implementors of this method should check the progress monitor
+	 * for cancelation when it is safe and appropriate to do so.  The cancelation
+	 * request should be propagated to the caller by throwing 
+	 * <code>OperationCanceledException</code>.
+	 * </p>
+	 * 
+	 * @param documents the documents to locate matches in
+	 * @param pattern the search pattern to use when locating matches
+	 * @param scope the scope to limit the search to
+	 * @param requestor the requestor to report matches to
+	 * @param monitor the progress monitor to report progress to,
+	 * or <code>null</code> if no progress should be reported
+	 * @throws CoreException if the requestor had problem accepting one of the matches
 	 */
-	public abstract void locateMatches(SearchDocument[] indexMatches, SearchPattern pattern, IJavaSearchScope scope, SearchRequestor requestor, IProgressMonitor monitor) throws CoreException;
+	public abstract void locateMatches(SearchDocument[] documents, SearchPattern pattern, IJavaSearchScope scope, SearchRequestor requestor, IProgressMonitor monitor) throws CoreException;
 
 	/**
 	 * Schedules the indexing of the given document.
-	 * Once the document is ready to be indexed, indexDocument(SearchDocument) is called.
+	 * Once the document is ready to be indexed, 
+	 * {@link #indexDocument(SearchDocument, IPath) indexDocument(document, indexPath)}
+	 * will be called in a different thread than the caller's thread.
+	 * <p>
+	 * The given index location must represent a path in the file system to a file that
+	 * either already exists or is going to be created. If it exists, it must be an index file,
+	 * otherwise its data might be overwritten.
+	 * </p>
+	 * 
+	 * @param document the document to index
+	 * @param indexLocation the location on the file system of the index
 	 */
-	public void scheduleDocumentIndexing(SearchDocument document, String containerPath, String indexPath) {
-		JavaModelManager.getJavaModelManager().getIndexManager().scheduleDocumentIndexing(document, containerPath, indexPath, this);
+	public final void scheduleDocumentIndexing(SearchDocument document, IPath indexLocation) {
+		IPath documentPath = new Path(document.getPath());
+		IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+		IResource resource = root.findMember(documentPath);
+		IPath containerPath = resource == null ? documentPath : resource.getProject().getFullPath();
+		IndexManager manager = JavaModelManager.getJavaModelManager().getIndexManager();
+		String osIndexLocation = indexLocation.toOSString();
+		// TODO (jerome) should not have to create index manually, should expose API that recreates index instead
+		manager.ensureIndexExists(osIndexLocation, containerPath);
+		manager.scheduleDocumentIndexing(document, containerPath, osIndexLocation, this);
 	}
-	
+
 	/**
-	 * Returns the collection of index paths to consider when performing a given search query in a given scope.
+	 * Returns the collection of index locations to consider when performing the
+	 * given search query in the given scope. The search engine calls this
+	 * method before locating matches.
+	 * <p>
+	 * An index location represents a path in the file system to a file that holds index information. 
+	 * </p><p>
+	 * Clients are not expected to call this method.
+	 * </p>
+	 * 
+	 * @param query the search pattern to consider
+	 * @param scope the given search scope
+	 * @return the collection of index paths to consider
 	 */
 	public abstract IPath[] selectIndexes(SearchPattern query, IJavaSearchScope scope);
-
 }
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchPattern.java
index 81877cf..34e607c 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchPattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchPattern.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -18,17 +18,32 @@
 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;
 
 /**
- * TODO (jerome) spec
+ * A search pattern defines how search results are found. Use <code>SearchPattern.createPattern</code>
+ * to create a search pattern.
+ * <p>
+ * Search patterns are used during the search phase to decode index entries that were added during the indexing phase
+ * (see {@link SearchDocument#addIndexEntry(char[], char[])}). When an index is queried, the 
+ * index categories and keys to consider are retrieved from the search pattern using {@link #getIndexCategories()} and
+ * {@link #getIndexKey()}, as well as the match rule (see {@link #getMatchRule()}). A blank pattern is
+ * then created (see {@link #getBlankPattern()}). This blank pattern is used as a record as follows.
+ * For each index entry in the given index categories and that starts with the given key, the blank pattern is fed using 
+ * {@link #decodeIndexKey(char[])}. The original pattern is then asked if it matches the decoded key using
+ * {@link #matchesDecodedKey(SearchPattern)}. If it matches, a search doument is created for this index entry
+ * using {@link SearchParticipant#getDocument(String)}.
+ * 
+ * </p><p>
+ * This class is intended to be subclassed by clients. A default behavior is provided for each of the methods above, that
+ * clients can ovveride if they wish.
+ * </p>
+ * @see #createPattern(org.eclipse.jdt.core.IJavaElement, int)
+ * @see #createPattern(String, int, int, int)
  * @since 3.0
  */
-public abstract class SearchPattern extends InternalSearchPattern implements ISearchPattern, IIndexConstants, IJavaSearchConstants {
+public abstract class SearchPattern extends InternalSearchPattern {
 
-	/**
-	 * Rules for pattern matching: (exact, prefix, pattern) [ | case sensitive]
-	 */
+	// Rules for pattern matching: (exact, prefix, pattern) [ | case sensitive]
 	/**
 	 * Match rule: The search pattern matches exactly the search result,
 	 * that is, the source of the search result equals the search pattern.
@@ -46,18 +61,39 @@
 	/**
 	 * Match rule: The search pattern contains a regular expression.
 	 */
-	public static final int R_REGEXP_MATCH = 3;
+	public static final int R_REGEXP_MATCH = 4;
 	/**
 	 * Match rule: The search pattern matches the search result only if cases are the same.
 	 * Can be combined to previous rules, e.g. R_EXACT_MATCH | R_CASE_SENSITIVE
 	 */
-	public static final int R_CASE_SENSITIVE = 4;
-
-
-	public boolean mustResolve = true;
+	public static final int R_CASE_SENSITIVE = 8;
 	
-	public SearchPattern(int patternKind, int matchRule) {
-		super(patternKind, matchRule);
+	private int matchRule;
+
+	/**
+	 * Creates a search pattern with the rule to apply for matching index keys. 
+	 * It can be exact match, prefix match, pattern match or regexp match.
+	 * Rule can also be combined with a case sensitivity flag.
+	 * 
+	 * @param matchRule one of R_EXACT_MATCH, R_PREFIX_MATCH, R_PATTERN_MATCH, R_REGEXP_MATCH combined with R_CASE_SENSITIVE,
+	 *   e.g. R_EXACT_MATCH | R_CASE_SENSITIVE if an exact and case sensitive match is requested, 
+	 *   or R_PREFIX_MATCH if a prefix non case sensitive match is requested.
+	 */
+	public SearchPattern(int matchRule) {
+		this.matchRule = matchRule;
+	}
+
+	/**
+	 * Returns a search pattern that combines the given two patterns into an
+	 * "and" pattern. The search result will match both the left pattern and
+	 * the right pattern.
+	 *
+	 * @param leftPattern the left pattern
+	 * @param rightPattern the right pattern
+	 * @return an "and" pattern
+	 */
+	public static SearchPattern createAndPattern(SearchPattern leftPattern, SearchPattern rightPattern) {
+		return MatchLocator.createAndPattern(leftPattern, rightPattern);
 	}
 	
 	/**
@@ -65,11 +101,9 @@
 	 * e.g. java.lang.Object()
 	 *		Main(*)
 	 */
-	private static SearchPattern createConstructorPattern(String patternString, int limitTo, int matchMode, boolean isCaseSensitive) {
+	private static SearchPattern createConstructorPattern(String patternString, int limitTo, int matchRule) {
 	
-		int matchRule = isCaseSensitive ? matchMode | R_CASE_SENSITIVE : matchMode;
-		
-		Scanner scanner = new Scanner(false /*comment*/, true /*whitespace*/, false /*nls*/, ClassFileConstants.JDK1_3/*sourceLevel*/, null /*taskTags*/, null/*taskPriorities*/);
+		Scanner scanner = new Scanner(false /*comment*/, true /*whitespace*/, false /*nls*/, ClassFileConstants.JDK1_3/*sourceLevel*/, null /*taskTags*/, null/*taskPriorities*/, true/*taskCaseSensitive*/);
 		scanner.setSource(patternString.toCharArray());
 		final int InsideName = 1;
 		final int InsideParameter = 2;
@@ -172,7 +206,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 {
@@ -219,11 +253,9 @@
 	 * e.g. java.lang.String.serialVersionUID long
 	 *		field*
 	 */
-	private static SearchPattern createFieldPattern(String patternString, int limitTo, int matchMode, boolean isCaseSensitive) {
+	private static SearchPattern createFieldPattern(String patternString, int limitTo, int matchRule) {
 		
-		int matchRule = isCaseSensitive ? matchMode | R_CASE_SENSITIVE : matchMode;
-	
-		Scanner scanner = new Scanner(false /*comment*/, true /*whitespace*/, false /*nls*/, ClassFileConstants.JDK1_3/*sourceLevel*/, null /*taskTags*/, null/*taskPriorities*/); 
+		Scanner scanner = new Scanner(false /*comment*/, true /*whitespace*/, false /*nls*/, ClassFileConstants.JDK1_3/*sourceLevel*/, null /*taskTags*/, null/*taskPriorities*/, true/*taskCaseSensitive*/); 
 		scanner.setSource(patternString.toCharArray());
 		final int InsideDeclaringPart = 1;
 		final int InsideType = 2;
@@ -318,7 +350,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 {
@@ -392,11 +424,9 @@
 	 * e.g. java.lang.Runnable.run() void
 	 *		main(*)
 	 */
-	private static SearchPattern createMethodPattern(String patternString, int limitTo, int matchMode, boolean isCaseSensitive) {
+	private static SearchPattern createMethodPattern(String patternString, int limitTo, int matchRule) {
 		
-		int matchRule = isCaseSensitive ? matchMode | R_CASE_SENSITIVE : matchMode;
-	
-		Scanner scanner = new Scanner(false /*comment*/, true /*whitespace*/, false /*nls*/, ClassFileConstants.JDK1_3/*sourceLevel*/, null /*taskTags*/, null/*taskPriorities*/); 
+		Scanner scanner = new Scanner(false /*comment*/, true /*whitespace*/, false /*nls*/, ClassFileConstants.JDK1_3/*sourceLevel*/, null /*taskTags*/, null/*taskPriorities*/, true/*taskCaseSensitive*/); 
 		scanner.setSource(patternString.toCharArray());
 		final int InsideSelector = 1;
 		final int InsideParameter = 2;
@@ -536,7 +566,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 {
@@ -557,7 +587,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 {
@@ -610,8 +640,20 @@
 		}
 		return null;
 	}
-	private static SearchPattern createPackagePattern(String patternString, int limitTo, int matchMode, boolean isCaseSensitive) {
-		int matchRule = isCaseSensitive ? matchMode | R_CASE_SENSITIVE : matchMode;
+	/**
+	 * Returns a search pattern that combines the given two patterns into an
+	 * "or" pattern. The search result will match either the left pattern or the
+	 * right pattern.
+	 *
+	 * @param leftPattern the left pattern
+	 * @param rightPattern the right pattern
+	 * @return an "or" pattern
+	 */
+	public static SearchPattern createOrPattern(SearchPattern leftPattern, SearchPattern rightPattern) {
+		return new OrPattern(leftPattern, rightPattern);
+	}
+	
+	private static SearchPattern createPackagePattern(String patternString, int limitTo, int matchRule) {
 		switch (limitTo) {
 			case IJavaSearchConstants.DECLARATIONS :
 				return new PackageDeclarationPattern(patternString.toCharArray(), matchRule);
@@ -625,23 +667,86 @@
 		}
 		return null;
 	}
-	public static SearchPattern createPattern(String patternString, int searchFor, int limitTo, int matchMode, boolean isCaseSensitive) {
-		if (patternString == null || patternString.length() == 0) return null;
+	/**
+	 * Returns a search pattern based on a given string pattern. The string patterns support '*' wild-cards.
+	 * The remaining parameters are used to narrow down the type of expected results.
+	 *
+	 * <br>
+	 *	Examples:
+	 *	<ul>
+	 * 		<li>search for case insensitive references to <code>Object</code>:
+	 *			<code>createSearchPattern("Object", TYPE, REFERENCES, false);</code></li>
+	 *  	<li>search for case sensitive references to exact <code>Object()</code> constructor:
+	 *			<code>createSearchPattern("java.lang.Object()", CONSTRUCTOR, REFERENCES, true);</code></li>
+	 *  	<li>search for implementers of <code>java.lang.Runnable</code>:
+	 *			<code>createSearchPattern("java.lang.Runnable", TYPE, IMPLEMENTORS, true);</code></li>
+	 *  </ul>
+	 * @param stringPattern the given pattern
+	 * @param searchFor determines the nature of the searched elements
+	 *	<ul>
+	 * 	<li><code>IJavaSearchConstants.CLASS</code>: only look for classes</li>
+	 *		<li><code>IJavaSearchConstants.INTERFACE</code>: only look for interfaces</li>
+	 * 	<li><code>IJavaSearchConstants.TYPE</code>: look for both classes and interfaces</li>
+	 *		<li><code>IJavaSearchConstants.FIELD</code>: look for fields</li>
+	 *		<li><code>IJavaSearchConstants.METHOD</code>: look for methods</li>
+	 *		<li><code>IJavaSearchConstants.CONSTRUCTOR</code>: look for constructors</li>
+	 *		<li><code>IJavaSearchConstants.PACKAGE</code>: look for packages</li>
+	 *	</ul>
+	 * @param limitTo determines the nature of the expected matches
+	 *	<ul>
+	 * 		<li><code>IJavaSearchConstants.DECLARATIONS</code>: will search declarations matching with the corresponding
+	 * 			element. In case the element is a method, declarations of matching methods in subtypes will also
+	 *  		be found, allowing to find declarations of abstract methods, etc.</li>
+	 *
+	 *		 <li><code>IJavaSearchConstants.REFERENCES</code>: will search references to the given element.</li>
+	 *
+	 *		 <li><code>IJavaSearchConstants.ALL_OCCURRENCES</code>: will search for either declarations or references as specified
+	 *  		above.</li>
+	 *
+	 *		 <li><code>IJavaSearchConstants.IMPLEMENTORS</code>: for interface, will find all types which implements a given interface.</li>
+	 *	</ul>
+	 * @param matchRule one of R_EXACT_MATCH, R_PREFIX_MATCH, R_PATTERN_MATCH, R_REGEXP_MATCH combined with R_CASE_SENSITIVE,
+	 *   e.g. R_EXACT_MATCH | R_CASE_SENSITIVE if an exact and case sensitive match is requested, 
+	 *   or R_PREFIX_MATCH if a prefix non case sensitive match is requested.
+	 * @return a search pattern on the given string pattern, or <code>null</code> if the string pattern is ill-formed
+	 */
+	public static SearchPattern createPattern(String stringPattern, int searchFor, int limitTo, int matchRule) {
+		if (stringPattern == null || stringPattern.length() == 0) return null;
 	
 		switch (searchFor) {
 			case IJavaSearchConstants.TYPE:
-				return createTypePattern(patternString, limitTo, matchMode, isCaseSensitive);
+				return createTypePattern(stringPattern, limitTo, matchRule);
 			case IJavaSearchConstants.METHOD:
-				return createMethodPattern(patternString, limitTo, matchMode, isCaseSensitive);
+				return createMethodPattern(stringPattern, limitTo, matchRule);
 			case IJavaSearchConstants.CONSTRUCTOR:
-				return createConstructorPattern(patternString, limitTo, matchMode, isCaseSensitive);
+				return createConstructorPattern(stringPattern, limitTo, matchRule);
 			case IJavaSearchConstants.FIELD:
-				return createFieldPattern(patternString, limitTo, matchMode, isCaseSensitive);
+				return createFieldPattern(stringPattern, limitTo, matchRule);
 			case IJavaSearchConstants.PACKAGE:
-				return createPackagePattern(patternString, limitTo, matchMode, isCaseSensitive);
+				return createPackagePattern(stringPattern, limitTo, matchRule);
 		}
 		return null;
 	}
+	/**
+	 * Returns a search pattern based on a given Java element. 
+	 * The pattern is used to trigger the appropriate search, and can be parameterized as follows:
+	 *
+	 * @param element the Java element the search pattern is based on
+	 * @param limitTo determines the nature of the expected matches
+	 * 	<ul>
+	 * 		<li><code>IJavaSearchConstants.DECLARATIONS</code>: will search declarations matching with the corresponding
+	 * 			element. In case the element is a method, declarations of matching methods in subtypes will also
+	 *  		be found, allowing to find declarations of abstract methods, etc.</li>
+	 *
+	 *		 <li><code>IJavaSearchConstants.REFERENCES</code>: will search references to the given element.</li>
+	 *
+	 *		 <li><code>IJavaSearchConstants.ALL_OCCURRENCES</code>: will search for either declarations or references as specified
+	 *  		above.</li>
+	 *
+	 *		 <li><code>IJavaSearchConstants.IMPLEMENTORS</code>: for interface, will find all types which implements a given interface.</li>
+	 *	</ul>
+	 * @return a search pattern for a Java element or <code>null</code> if the given element is ill-formed
+	 */
 	public static SearchPattern createPattern(IJavaElement element, int limitTo) {
 		SearchPattern searchPattern = null;
 		int lastDot;
@@ -667,7 +772,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;
@@ -746,7 +851,7 @@
 				if (lastDot == -1) return null; // invalid import declaration
 				IImportDeclaration importDecl = (IImportDeclaration)element;
 				if (importDecl.isOnDemand()) {
-					searchPattern = createPackagePattern(elementName.substring(0, lastDot), limitTo, EXACT_MATCH, CASE_SENSITIVE);
+					searchPattern = createPackagePattern(elementName.substring(0, lastDot), limitTo, R_EXACT_MATCH | R_CASE_SENSITIVE);
 				} else {
 					searchPattern = 
 						createTypePattern(
@@ -833,7 +938,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;
@@ -852,7 +957,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) {
@@ -950,11 +1055,11 @@
 				break;
 			case IJavaElement.PACKAGE_DECLARATION :
 			case IJavaElement.PACKAGE_FRAGMENT :
-				searchPattern = createPackagePattern(element.getElementName(), limitTo, EXACT_MATCH, CASE_SENSITIVE);
+				searchPattern = createPackagePattern(element.getElementName(), limitTo, R_EXACT_MATCH | R_CASE_SENSITIVE);
 				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) {
@@ -964,7 +1069,7 @@
 					packageName, 
 					enclosingTypeNames, 
 					simpleName, 
-					TYPE_SUFFIX,
+					IIndexConstants.TYPE_SUFFIX,
 					R_EXACT_MATCH | R_CASE_SENSITIVE);
 			case IJavaSearchConstants.REFERENCES :
 				return new TypeReferencePattern(
@@ -983,7 +1088,7 @@
 						packageName, 
 						enclosingTypeNames, 
 						simpleName, 
-						TYPE_SUFFIX,
+						IIndexConstants.TYPE_SUFFIX,
 						R_EXACT_MATCH | R_CASE_SENSITIVE), 
 					new TypeReferencePattern(
 						CharOperation.concatWith(packageName, enclosingTypeNames, '.'), 
@@ -998,11 +1103,9 @@
 	 *		Runnable
 	 *
 	 */
-	private static SearchPattern createTypePattern(String patternString, int limitTo, int matchMode, boolean isCaseSensitive) {
+	private static SearchPattern createTypePattern(String patternString, int limitTo, int matchRule) {
 		
-		int matchRule = isCaseSensitive ? matchMode | R_CASE_SENSITIVE : matchMode;
-	
-		Scanner scanner = new Scanner(false /*comment*/, true /*whitespace*/, false /*nls*/, ClassFileConstants.JDK1_3/*sourceLevel*/, null /*taskTags*/, null/*taskPriorities*/); 
+		Scanner scanner = new Scanner(false /*comment*/, true /*whitespace*/, false /*nls*/, ClassFileConstants.JDK1_3/*sourceLevel*/, null /*taskTags*/, null/*taskPriorities*/, true/*taskCaseSensitive*/); 
 		scanner.setSource(patternString.toCharArray());
 		String type = null;
 		int token;
@@ -1049,14 +1152,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;
@@ -1083,7 +1186,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), 
@@ -1092,58 +1195,109 @@
 				return null;
 		}
 	}
-	
 	/**
-	 * Decoded the given index key into the given record.
+	 * Decode the given index key in this pattern. The decoded index key is used by 
+	 * {@link #matchesDecodedKey(SearchPattern)} to find out if the corresponding index entry 
+	 * should be considered.
+	 * <p>
+	 * This method should be re-implemented in subclasses that need to decode an index key.
+	 * </p>
+	 * 
+	 * @param key the given index key
 	 */
-	public abstract void decodeIndexKey(char[] key);
-
+	public void decodeIndexKey(char[] key) {
+		// called from findIndexMatches(), override as necessary
+	}
 	/**
-	 * Returns a key to find in relevant index categories. The key will be matched according to some match rule.
-	 * These potential matches will be further narrowed by the match locator, but precise
-	 * match locating can be expensive, and index query should be as accurate as possible
-	 * so as to eliminate obvious false hits.
+	 * Returns a blank pattern that can be used as a record to decode an index key.
+	 * <p>
+	 * Implementors of this method should return a new search pattern that is going to be used
+	 * to decode index keys.
+	 * </p>
+	 * 
+	 * @return a new blank pattern
+	 * @see #decodeIndexKey(char[])
 	 */
-	public abstract char[] encodeIndexKey();
-	
-	public abstract SearchPattern getIndexRecord();
-	
+	public abstract SearchPattern getBlankPattern();
+	/**
+	 * Returns a key to find in relevant index categories, if null then all index entries are matched.
+	 * The key will be matched according to some match rule. These potential matches
+	 * will be further narrowed by the match locator, but precise match locating can be expensive,
+	 * and index query should be as accurate as possible so as to eliminate obvious false hits.
+	 * <p>
+	 * This method should be re-implemented in subclasses that need to narrow down the
+	 * index query.
+	 * </p>
+	 * 
+	 * @return an index key from this pattern, or <code>null</code> if all index entries are matched.
+	 */
+	public char[] getIndexKey() {
+		return null; // called from queryIn(), override as necessary
+	}
 	/**
 	 * Returns an array of index categories to consider for this index query.
 	 * These potential matches will be further narrowed by the match locator, but precise
 	 * match locating can be expensive, and index query should be as accurate as possible
 	 * so as to eliminate obvious false hits.
+	 * <p>
+	 * This method should be re-implemented in subclasses that need to narrow down the
+	 * index query.
+	 * </p>
+	 * 
+	 * @return an array of index categories
 	 */
-	public abstract char[][] getMatchCategories();
-	
+	public char[][] getIndexCategories() {
+		return CharOperation.NO_CHAR_CHAR; // called from queryIn(), override as necessary
+	}
 	/**
 	 * Returns the rule to apply for matching index keys. Can be exact match, prefix match, pattern match or regexp match.
 	 * Rule can also be combined with a case sensitivity flag.
+	 * 
+	 * @return one of R_EXACT_MATCH, R_PREFIX_MATCH, R_PATTERN_MATCH, R_REGEXP_MATCH combined with R_CASE_SENSITIVE,
+	 *   e.g. R_EXACT_MATCH | R_CASE_SENSITIVE if an exact and case sensitive match is requested, 
+	 *   or R_PREFIX_MATCH if a prefix non case sensitive match is requested.
 	 */	
-	public int getMatchRule() {
+	public final int getMatchRule() {
 		return this.matchRule;
 	}
-	
 	/**
-	 * TODO (jerome) spec
+	 * Returns whether this pattern matches the given pattern (representing a decoded index key).
+	 * <p>
+	 * This method should be re-implemented in subclasses that need to narrow down the
+	 * index query.
+	 * </p>
+	 * 
+	 * @param decodedPattern a pattern representing a decoded index key
+	 * @return whether this pattern matches the given pattern
 	 */
-	public abstract boolean isMatchingIndexRecord();
-		
+	public boolean matchesDecodedKey(SearchPattern decodedPattern) {
+		return true; // called from findIndexMatches(), override as necessary if index key is encoded
+	}
 	/**
 	 * Returns whether the given name matches the given pattern.
+	 * <p>
+	 * This method should be re-implemented in subclasses that need to define how
+	 * a name matches a pattern.
+	 * </p>
+	 * 
+	 * @param pattern the given pattern, or <code>null</code> to represent "*"
+	 * @param name the given name
+	 * @return whether the given name matches the given pattern
 	 */
 	public boolean matchesName(char[] pattern, char[] name) {
 		if (pattern == null) return true; // null is as if it was "*"
 		if (name != null) {
-			switch (matchMode()) {
+			boolean isCaseSensitive = (this.matchRule & R_CASE_SENSITIVE) != 0;
+			int matchMode = this.matchRule - (isCaseSensitive ? R_CASE_SENSITIVE : 0);
+			switch (matchMode) {
 				case R_EXACT_MATCH :
-					return CharOperation.equals(pattern, name, isCaseSensitive());
+					return CharOperation.equals(pattern, name, isCaseSensitive);
 				case R_PREFIX_MATCH :
-					return CharOperation.prefixEquals(pattern, name, isCaseSensitive());
+					return CharOperation.prefixEquals(pattern, name, isCaseSensitive);
 				case R_PATTERN_MATCH :
-					if (!isCaseSensitive())
+					if (!isCaseSensitive)
 						pattern = CharOperation.toLowerCase(pattern);
-					return CharOperation.match(pattern, name, isCaseSensitive());
+					return CharOperation.match(pattern, name, isCaseSensitive);
 				case R_REGEXP_MATCH :
 					// TODO (jerome) implement regular expression match
 					return true;
@@ -1151,8 +1305,10 @@
 		}
 		return false;
 	}
-	
-	public String toString(){
+	/**
+	 * @see java.lang.Object#toString()
+	 */
+	public String toString() {
 		return "SearchPattern"; //$NON-NLS-1$
 	}
 }
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchRequestor.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchRequestor.java
index df71d22..aa4d3b2 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchRequestor.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchRequestor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -13,72 +13,84 @@
 import org.eclipse.core.runtime.CoreException;
 
 /**
- * TODO add spec
- */
-/**
- * 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>aboutToStart()</code>
- * method is called, then 0 or more call to <code>accept(...)</code> are done, finally the
- * <code>done()</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>EXACT_MATCH</code> accuracy -
- * or they might be potential matches only - they have a <code>POTENTIAL_MATCH</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>
- * The <code>SearchRequestor</code> is also used to provide a progress monitor to the 
- * <code>SearchEngine</code>.
- * </p>
- * <p>
- * Clients may implement this interface.
+ * 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#search
+ * @see SearchEngine
  * @since 3.0
  */
 public abstract class SearchRequestor {
 
-	/**expected detail level */
-	public static final int D_LOCATION = 8;
-	public static final int D_NAME = 1;
-	public static final int D_PATH = 2;
-	public static final int D_POSITION = 4;
-
-	// answer false if requesting to cancel
-	public abstract boolean acceptSearchMatch(SearchMatch match) throws CoreException;
+	/**
+	 * Accepts the given search match.
+	 *
+	 * @param match the found match
+	 * @throws CoreException
+	 */
+	// 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.
+	 * Typically, this would tell a search requestor collector that no more
+	 * results will be forthcomping in this search.
+	 * <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 the given participant starts 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 the 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);
-
-//	/**
-//	 * Client can indicate how much detail is expected
-//	 */
-//	public int getRequestedDetailLevel() {
-//		// by default, request all details
-//		return D_NAME | D_PATH | D_POSITION | D_LOCATION;
-//	}
+	public void exitParticipant(SearchParticipant participant) {
+		// do nothing
+	}
 }
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/TypeDeclarationMatch.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/TypeDeclarationMatch.java
new file mode 100644
index 0000000..0b69db4
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/TypeDeclarationMatch.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.search;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.jdt.core.IJavaElement;
+
+/**
+ * A Java search match that represents a type declaration.
+ * The element is an <code>IType</code>.
+ * <p>
+ * This class is intended to be instantiated and subclassed by clients.
+ * </p>
+ * 
+ * @since 3.0
+ */
+public class TypeDeclarationMatch extends SearchMatch {
+
+	/**
+	 * Creates a new type declaration match.
+	 * 
+	 * @param element the type declaration
+	 * @param accuracy one of A_ACCURATE or A_INACCURATE
+	 * @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 offset, int length, SearchParticipant participant, IResource resource) {
+		super(element, accuracy, offset, length, participant, resource);
+	}
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/TypeReferenceMatch.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/TypeReferenceMatch.java
new file mode 100644
index 0000000..82a7f56
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/TypeReferenceMatch.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.search;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.jdt.core.IJavaElement;
+
+/**
+ * A Java search match that represents a type reference.
+ * The element is the inner-most enclosing member that references this type.
+ * <p>
+ * This class is intended to be instantiated and subclassed by clients.
+ * </p>
+ * 
+ * @since 3.0
+ */
+public class TypeReferenceMatch extends SearchMatch {
+
+	/**
+	 * Creates a new type reference match.
+	 * 
+	 * @param enclosingElement the inner-most enclosing member that references this type
+	 * @param accuracy one of {@link #A_ACCURATE} or {@link #A_INACCURATE}
+	 * @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 <code>true</code> if this search match is inside a doc
+	 * comment, and <code>false</code> otherwise
+	 * @param participant the search participant that created the match
+	 * @param resource the resource of the element
+	 */
+	public TypeReferenceMatch(IJavaElement enclosingElement, int accuracy,	int offset, int length, boolean insideDocComment, SearchParticipant participant, IResource resource) {
+		super(enclosingElement, accuracy, offset, length, participant, resource);
+		setInsideDocComment(insideDocComment);
+	}
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/DiskIndex.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/DiskIndex.java
new file mode 100644
index 0000000..a9f684e
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/DiskIndex.java
@@ -0,0 +1,800 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core.index;
+
+import java.io.*;
+
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.internal.core.util.*;
+import org.eclipse.jdt.internal.compiler.util.HashtableOfIntValues;
+import org.eclipse.jdt.internal.compiler.util.HashtableOfObject;
+
+public class DiskIndex {
+
+String fileName;
+
+private int headerInfoOffset;
+private int numberOfChunks;
+private int sizeOfLastChunk;
+private int[] chunkOffsets;
+private int documentReferenceSize; // 1, 2 or more bytes... depends on # of document names
+private HashtableOfIntValues categoryOffsets;
+
+private int cacheUserCount;
+private String[][] cachedChunks; // decompressed chunks of document names
+private HashtableOfObject categoryTables; // category name -> HashtableOfObject(words -> int[] of document #'s) or offset if not read yet
+
+public static final String SIGNATURE= "INDEX VERSION 1.001"; //$NON-NLS-1$
+public static boolean DEBUG = false;
+
+private static final int RE_INDEXED = -1;
+private static final int DELETED = -2;
+
+private static final int CHUNK_SIZE = 100;
+
+class IntList {
+
+int size;
+int[] elements;
+
+IntList(int[] elements) {
+	this.elements = elements;
+	this.size = elements.length;
+}
+void add(int newElement) {
+	if (this.size == this.elements.length) {
+		int newSize = this.size * 3;
+		if (newSize < 7) newSize = 7;
+		System.arraycopy(this.elements, 0, this.elements = new int[newSize], 0, this.size);
+	}
+	this.elements[this.size++] = newElement;
+}
+int[] asArray() {
+	int[] result = new int[this.size];
+	System.arraycopy(this.elements, 0, result, 0, this.size);
+	return result;
+}	
+}
+
+
+DiskIndex(String fileName) {
+	this.fileName = fileName;
+
+	// clear cached items
+	this.headerInfoOffset = -1;
+	this.numberOfChunks = -1;
+	this.sizeOfLastChunk = -1;
+	this.chunkOffsets = null;
+	this.documentReferenceSize = -1;
+	this.cacheUserCount = -1;
+	this.cachedChunks = null;
+	this.categoryTables = null;
+	this.categoryOffsets = null;
+}
+SimpleSet addDocumentNames(String substring, MemoryIndex memoryIndex) throws IOException {
+	// must skip over documents which have been added/changed/deleted in the memory index
+	String[] docNames = readAllDocumentNames();
+	SimpleSet results = new SimpleSet(docNames.length);
+	if (substring == null) {
+		if (memoryIndex == null) {
+			for (int i = 0, l = docNames.length; i < l; i++)
+				results.add(docNames[i]);
+		} else {
+			SimpleLookupTable docsToRefs = memoryIndex.docsToReferences;
+			for (int i = 0, l = docNames.length; i < l; i++) {
+				String docName = docNames[i];
+				if (!docsToRefs.containsKey(docName))
+					results.add(docName);
+			}
+		}
+	} else {
+		if (memoryIndex == null) {
+			for (int i = 0, l = docNames.length; i < l; i++)
+				if (docNames[i].startsWith(substring, 0))
+					results.add(docNames[i]);
+		} else {
+			SimpleLookupTable docsToRefs = memoryIndex.docsToReferences;
+			for (int i = 0, l = docNames.length; i < l; i++) {
+				String docName = docNames[i];
+				if (docName.startsWith(substring, 0) && !docsToRefs.containsKey(docName))
+					results.add(docName);
+			}
+		}
+	}
+	return results;
+}
+private void addQueryResult(HashtableOfObject results, char[] word, HashtableOfObject wordsToDocNumbers, MemoryIndex memoryIndex) throws IOException {
+	// must skip over documents which have been added/changed/deleted in the memory index
+	EntryResult result = (EntryResult) results.get(word);
+	if (memoryIndex == null) {
+		if (result == null)
+			results.put(word, new EntryResult(word, wordsToDocNumbers));
+		else
+			result.addDocumentTable(wordsToDocNumbers);
+	} else {
+		SimpleLookupTable docsToRefs = memoryIndex.docsToReferences;
+		if (result == null)
+			result = new EntryResult(word, null);
+		int[] docNumbers = readDocumentNumbers(wordsToDocNumbers.get(word));
+		for (int i = 0, l = docNumbers.length; i < l; i++) {
+			String docName = readDocumentName(docNumbers[i]);
+			if (!docsToRefs.containsKey(docName))
+				result.addDocumentName(docName);
+		}
+		if (!result.isEmpty())
+			results.put(word, result);
+	}
+}
+HashtableOfObject addQueryResults(char[][] categories, char[] key, int matchRule, MemoryIndex memoryIndex) throws IOException {
+	// assumes sender has called startQuery() & will call stopQuery() when finished
+	HashtableOfObject results = new HashtableOfObject(13);
+	if (this.categoryOffsets == null)
+		return results; // file is empty
+
+	if (matchRule == SearchPattern.R_EXACT_MATCH + SearchPattern.R_CASE_SENSITIVE) {
+		for (int i = 0, l = categories.length; i < l; i++) {
+			HashtableOfObject wordsToDocNumbers = readCategoryTable(categories[i], false);
+			if (wordsToDocNumbers != null && wordsToDocNumbers.containsKey(key))
+				addQueryResult(results, key, wordsToDocNumbers, memoryIndex);
+		}
+	} else {
+		for (int i = 0, l = categories.length; i < l; i++) {
+			HashtableOfObject wordsToDocNumbers = readCategoryTable(categories[i], false);
+			if (wordsToDocNumbers != null) {
+				char[][] words = wordsToDocNumbers.keyTable;
+				for (int j = 0, m = words.length; j < m; j++) {
+					char[] word = words[j];
+					if (word != null && Index.isMatch(key, word, matchRule))
+						addQueryResult(results, word, wordsToDocNumbers, memoryIndex);
+				}
+			}
+		}
+	}
+	return results;
+}
+private String[] computeDocumentNames(String[] onDiskNames, int[] positions, SimpleLookupTable indexedDocuments, MemoryIndex memoryIndex) {
+	int onDiskLength = onDiskNames.length;
+	Object[] docNames = memoryIndex.docsToReferences.keyTable;
+	Object[] referenceTables = memoryIndex.docsToReferences.valueTable;
+	if (onDiskLength == 0) {
+		// disk index was empty, so add every indexed document
+		for (int i = 0, l = referenceTables.length; i < l; i++)
+			if (referenceTables[i] != null)
+				indexedDocuments.put(docNames[i], null); // remember each new document
+
+		String[] newDocNames = new String[indexedDocuments.elementSize];
+		int count = 0;
+		Object[] added = indexedDocuments.keyTable;
+		for (int i = 0, l = added.length; i < l; i++)
+			if (added[i] != null)
+				newDocNames[count++] = (String) added[i];
+		Util.sort(newDocNames);
+		for (int i = 0, l = newDocNames.length; i < l; i++)
+			indexedDocuments.put(newDocNames[i], new Integer(i));
+		return newDocNames;
+	}
+
+	// initialize positions as if each document will remain in the same position
+	for (int i = 0; i < onDiskLength; i++)
+		positions[i] = i;
+
+	// find out if the memory index has any new or deleted documents, if not then the names & positions are the same
+	int numDeletedDocNames = 0;
+	int numReindexedDocNames = 0;
+	nextPath : for (int i = 0, l = docNames.length; i < l; i++) {
+		String docName = (String) docNames[i];
+		if (docName != null) {
+			for (int j = 0; j < onDiskLength; j++) {
+				if (docName.equals(onDiskNames[j])) {
+					if (referenceTables[i] == null) {
+						positions[j] = DELETED;
+						numDeletedDocNames++;
+					} else {
+						positions[j] = RE_INDEXED;
+						numReindexedDocNames++;
+					}
+					continue nextPath;
+				}
+			}
+			if (referenceTables[i] != null)
+				indexedDocuments.put(docName, null); // remember each new document, skip deleted documents which were never saved
+		}
+	}
+
+	String[] newDocNames = onDiskNames;
+	if (numDeletedDocNames > 0 || indexedDocuments.elementSize > 0) {
+		// some new documents have been added or some old ones deleted
+		newDocNames = new String[onDiskLength + indexedDocuments.elementSize - numDeletedDocNames];
+		int count = 0;
+		for (int i = 0; i < onDiskLength; i++)
+			if (positions[i] >= RE_INDEXED)
+				newDocNames[count++] = onDiskNames[i]; // keep each unchanged document
+		Object[] added = indexedDocuments.keyTable;
+		for (int i = 0, l = added.length; i < l; i++)
+			if (added[i] != null)
+				newDocNames[count++] = (String) added[i]; // add each new document
+		Util.sort(newDocNames);
+		for (int i = 0, l = newDocNames.length; i < l; i++)
+			if (indexedDocuments.containsKey(newDocNames[i]))
+				indexedDocuments.put(newDocNames[i], new Integer(i)); // remember the position for each new document
+	}
+
+	// need to be able to look up an old position (ref# from a ref[]) and map it to its new position
+	// if its old position == DELETED then its forgotton
+	// if its old position == ReINDEXED then its also forgotten but its new position is needed to map references
+	int count = -1;
+	for (int i = 0; i < onDiskLength;) {
+		switch(positions[i]) {
+			case DELETED :
+				i++; // skip over deleted... references are forgotten
+				break;
+			case RE_INDEXED :
+				String newName = newDocNames[++count];
+				if (newName.equals(onDiskNames[i])) {
+					indexedDocuments.put(newName, new Integer(count)); // the reindexed docName that was at position i is now at position count
+					i++;
+				}
+				break;
+			default :
+				if (newDocNames[++count].equals(onDiskNames[i]))
+					positions[i++] = count; // the unchanged docName that was at position i is now at position count
+		}
+	}
+	return newDocNames;
+}
+private void copyQueryResults(HashtableOfObject categoryToWords, int newPosition) throws IOException {
+	char[][] categoryNames = categoryToWords.keyTable;
+	Object[] wordSets = categoryToWords.valueTable;
+	for (int i = 0, l = categoryNames.length; i < l; i++) {
+		char[] categoryName = categoryNames[i];
+		if (categoryName != null) {
+			SimpleWordSet wordSet = (SimpleWordSet) wordSets[i];
+			HashtableOfObject wordsToDocs = (HashtableOfObject) this.categoryTables.get(categoryName);
+			if (wordsToDocs == null)
+				this.categoryTables.put(categoryName, wordsToDocs = new HashtableOfObject(wordSet.elementSize));
+
+			char[][] words = wordSet.words;
+			for (int j = 0, m = words.length; j < m; j++) {
+				char[] word = words[j];
+				if (word != null) {
+					Object o = wordsToDocs.get(word);
+					if (o == null) {
+						wordsToDocs.put(word, new int[] {newPosition});
+					} else if (o instanceof IntList) {
+						((IntList) o).add(newPosition);
+					} else {
+						IntList list = new IntList((int[]) o);
+						list.add(newPosition);
+						wordsToDocs.put(word, list);
+					}
+				}
+			}
+		}
+	}
+}
+File getIndexFile() {
+	if (this.fileName == null) return null;
+
+	return new File(this.fileName);
+}
+void initialize(boolean reuseExistingFile) throws IOException {
+	File indexFile = getIndexFile();
+	if (indexFile.exists()) {
+		if (reuseExistingFile) {
+			RandomAccessFile file = new RandomAccessFile(this.fileName, "r"); //$NON-NLS-1$
+			try {
+				String signature = file.readUTF();
+				if (!signature.equals(SIGNATURE))
+					throw new IOException(Util.bind("exception.wrongFormat")); //$NON-NLS-1$
+
+				this.headerInfoOffset = file.readInt();
+				if (this.headerInfoOffset > 0) // file is empty if its not set
+					readHeaderInfo(file);
+			} finally {
+				file.close();
+			}
+			return;
+		}
+		if (!indexFile.delete()) {
+			if (DEBUG)
+				System.out.println("initialize - Failed to delete index " + this.fileName); //$NON-NLS-1$
+			throw new IOException("Failed to delete index " + this.fileName); //$NON-NLS-1$
+		}
+	}
+	if (indexFile.createNewFile()) {
+		RandomAccessFile file = new RandomAccessFile(this.fileName, "rw"); //$NON-NLS-1$
+		try {
+			file.writeUTF(SIGNATURE);
+			file.writeInt(-1); // file is empty
+		} finally {
+			file.close();
+		}
+	} else {
+		if (DEBUG)
+			System.out.println("initialize - Failed to create new index " + this.fileName); //$NON-NLS-1$
+		throw new IOException("Failed to create new index " + this.fileName); //$NON-NLS-1$
+	}
+}
+private void initializeFrom(DiskIndex diskIndex, File newIndexFile) throws IOException {
+	if (newIndexFile.exists() && !newIndexFile.delete()) { // delete the temporary index file
+		if (DEBUG)
+			System.out.println("initializeFrom - Failed to delete temp index " + this.fileName); //$NON-NLS-1$
+	} else if (!newIndexFile.createNewFile()) {
+		if (DEBUG)
+			System.out.println("initializeFrom - Failed to create temp index " + this.fileName); //$NON-NLS-1$
+		throw new IOException("Failed to create temp index " + this.fileName); //$NON-NLS-1$
+	}
+
+	int size = diskIndex.categoryOffsets == null ? 8 : diskIndex.categoryOffsets.elementSize;
+	this.categoryOffsets = new HashtableOfIntValues(size);
+	this.categoryTables = new HashtableOfObject(size);
+}
+private void mergeCategories(DiskIndex onDisk, int[] positions, DataOutputStream stream) throws IOException {
+	// at this point, this.categoryTables contains the names -> wordsToDocs added in copyQueryResults()
+	char[][] oldNames = onDisk.categoryOffsets.keyTable;
+	for (int i = 0, l = oldNames.length; i < l; i++) {
+		char[] oldName = oldNames[i];
+		if (oldName != null && !this.categoryTables.containsKey(oldName))
+			this.categoryTables.put(oldName, null);
+	}
+
+	char[][] categoryNames = this.categoryTables.keyTable;
+	for (int i = 0, l = categoryNames.length; i < l; i++)
+		if (categoryNames[i] != null)
+			mergeCategory(categoryNames[i], onDisk, positions, stream);
+	this.categoryTables = null;
+}
+private void mergeCategory(char[] categoryName, DiskIndex onDisk, int[] positions, DataOutputStream stream) throws IOException {
+	HashtableOfObject wordsToDocs = (HashtableOfObject) this.categoryTables.get(categoryName);
+	if (wordsToDocs == null)
+		wordsToDocs = new HashtableOfObject(3);
+
+	HashtableOfObject oldWordsToDocs = onDisk.readCategoryTable(categoryName, true);
+	if (oldWordsToDocs != null) {
+		char[][] oldWords = oldWordsToDocs.keyTable;
+		Object[] oldArrayOffsets = oldWordsToDocs.valueTable;
+		nextWord: for (int i = 0, l = oldWords.length; i < l; i++) {
+			char[] oldWord = oldWords[i];
+			if (oldWord != null) {
+				int[] oldDocNumbers = (int[]) oldArrayOffsets[i];
+				int length = oldDocNumbers.length;
+				int[] mappedNumbers = new int[length];
+				int count = 0;
+				for (int j = 0; j < length; j++) {
+					int pos = positions[oldDocNumbers[j]];
+					if (pos > RE_INDEXED) // forget any reference to a document which was deleted or re_indexed
+						mappedNumbers[count++] = pos;
+				}
+				if (count < length) {
+					if (count == 0) continue nextWord; // skip words which no longer have any references
+					System.arraycopy(mappedNumbers, 0, mappedNumbers = new int[count], 0, count);
+				}
+
+				Object o = wordsToDocs.get(oldWord);
+				if (o == null) {
+					wordsToDocs.put(oldWord, mappedNumbers);
+				} else {
+					IntList list = null;
+					if (o instanceof IntList) {
+						list = (IntList) o;
+					} else {
+						list = new IntList((int[]) o);
+						wordsToDocs.put(oldWord, list);
+					}
+					for (int j = 0; j < count; j++)
+						list.add(mappedNumbers[j]);
+				}
+			}
+		}
+		onDisk.categoryTables.put(categoryName, null); // flush cached table
+	}
+	writeCategoryTable(categoryName, wordsToDocs, stream);
+}
+DiskIndex mergeWith(MemoryIndex memoryIndex) throws IOException {
+ 	// assume write lock is held
+	// compute & write out new docNames
+	String[] docNames = readAllDocumentNames();
+	int previousLength = docNames.length;
+	int[] positions = new int[previousLength]; // keeps track of the position of each document in the new sorted docNames
+	SimpleLookupTable indexedDocuments = new SimpleLookupTable(3); // for each new/changed document in the memoryIndex
+	docNames = computeDocumentNames(docNames, positions, indexedDocuments, memoryIndex);
+	if (docNames.length == 0) {
+		if (previousLength == 0) return this; // nothing to do... memory index contained deleted documents that had never been saved
+
+		// index is now empty since all the saved documents were removed
+		DiskIndex newDiskIndex = new DiskIndex(this.fileName);
+		newDiskIndex.initialize(false);
+		return newDiskIndex;
+	}
+
+	DiskIndex newDiskIndex = new DiskIndex(this.fileName + ".tmp"); //$NON-NLS-1$
+	File newIndexFile = newDiskIndex.getIndexFile();
+	try {
+		newDiskIndex.initializeFrom(this, newIndexFile);
+		DataOutputStream stream = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(newIndexFile, false), 2048));
+		int offsetToHeader = -1;
+		try {
+			newDiskIndex.writeAllDocumentNames(docNames, stream);
+			docNames = null; // free up the space
+
+			// add each new/changed doc to empty category tables using its new position #
+			if (indexedDocuments.elementSize > 0) {
+				Object[] names = indexedDocuments.keyTable;
+				Object[] integerPositions = indexedDocuments.valueTable;
+				for (int i = 0, l = names.length; i < l; i++)
+					if (names[i] != null)
+						newDiskIndex.copyQueryResults(
+							(HashtableOfObject) memoryIndex.docsToReferences.get(names[i]),
+							((Integer) integerPositions[i]).intValue());
+			}
+			indexedDocuments = null; // free up the space
+
+			// merge each category table with the new ones & write them out
+			if (previousLength == 0)
+				newDiskIndex.writeCategories(stream);
+			else
+				newDiskIndex.mergeCategories(this, positions, stream);
+			offsetToHeader = stream.size();
+			newDiskIndex.writeHeaderInfo(stream);
+			positions = null; // free up the space
+		} finally {
+			stream.close();
+		}
+		newDiskIndex.writeOffsetToHeader(offsetToHeader);
+
+		// rename file by deleting previous index file & renaming temp one
+		File old = getIndexFile();
+		if (!old.delete()) {
+			if (DEBUG)
+				System.out.println("mergeWith - Failed to delete " + this.fileName); //$NON-NLS-1$
+			throw new IOException("Failed to delete index file " + this.fileName); //$NON-NLS-1$
+		}
+		if (!newIndexFile.renameTo(old)) {
+			if (DEBUG)
+				System.out.println("mergeWith - Failed to rename " + this.fileName); //$NON-NLS-1$
+			throw new IOException("Failed to rename index file " + this.fileName); //$NON-NLS-1$
+		}
+	} catch (IOException e) {
+		if (newIndexFile.exists() && !newIndexFile.delete())
+			if (DEBUG)
+				System.out.println("mergeWith - Failed to delete temp index " + newDiskIndex.fileName); //$NON-NLS-1$
+		throw e;
+	}
+
+	newDiskIndex.fileName = this.fileName;
+	return newDiskIndex;
+}
+private synchronized String[] readAllDocumentNames() throws IOException {
+	if (this.numberOfChunks <= 0)
+		return new String[0];
+
+	DataInputStream stream = new DataInputStream(new BufferedInputStream(new FileInputStream(getIndexFile()), 2048));
+	try {
+		stream.skip(this.chunkOffsets[0]);
+		int lastIndex = this.numberOfChunks - 1;
+		String[] docNames = new String[lastIndex * CHUNK_SIZE + sizeOfLastChunk];
+		for (int i = 0; i < this.numberOfChunks; i++)
+			readChunk(docNames, stream, i * CHUNK_SIZE, i < lastIndex ? CHUNK_SIZE : sizeOfLastChunk);
+		return docNames;
+	} finally {
+		stream.close();
+	}
+}
+private synchronized HashtableOfObject readCategoryTable(char[] categoryName, boolean cacheDocNumbers) throws IOException {
+	// result will be null if categoryName is unknown
+	int offset = this.categoryOffsets.get(categoryName);
+	if (offset == HashtableOfIntValues.NO_VALUE)
+		return null;
+
+	if (this.categoryTables == null) {
+		this.categoryTables = new HashtableOfObject(this.categoryOffsets.elementSize);
+	} else {
+		HashtableOfObject cachedTable = (HashtableOfObject) this.categoryTables.get(categoryName);
+		if (cachedTable != null)
+			return cachedTable;
+	}
+
+	DataInputStream stream = new DataInputStream(new BufferedInputStream(new FileInputStream(getIndexFile()), 2048));
+	HashtableOfObject categoryTable = null;
+	char[][] matchingWords = null;
+	int count = 0;
+	int firstOffset = -1;
+	try {
+		stream.skip(offset);
+		int size = stream.readInt();
+		categoryTable = new HashtableOfObject(size);
+		if (cacheDocNumbers)
+			matchingWords = new char[size][];
+		for (int i = 0; i < size; i++) {
+			char[] word = Util.readUTF(stream);
+			int arrayOffset = stream.readInt();
+			if (arrayOffset > 0) {
+				if (matchingWords != null) {
+					if (count == 0)
+						firstOffset = arrayOffset;
+					matchingWords[count++] = word;
+				}
+				categoryTable.put(word, new Integer(arrayOffset)); // offset to array in the file
+			} else {
+				categoryTable.put(word, new int[] {-arrayOffset}); // stored a 1 element array by negating the documentNumber
+			}
+		}
+		this.categoryTables.put(categoryName, categoryTable);
+	} finally {
+		stream.close();
+	}
+
+	if (count > 0) {
+		stream = new DataInputStream(new BufferedInputStream(new FileInputStream(getIndexFile()), 2048));
+		try {
+			stream.skip(firstOffset);
+			for (int i = 0; i < count; i++) // each array follows the previous one
+				categoryTable.put(matchingWords[i], readDocumentArray(stream));
+		} finally {
+			stream.close();
+		}
+	}
+	return categoryTable;
+}
+private void readChunk(String[] docNames, DataInputStream stream, int index, int size) throws IOException {
+	String current = stream.readUTF();
+	docNames[index++] = current;
+	for (int i = 1; i < size; i++) {
+		int start = stream.readUnsignedByte(); // number of identical characters at the beginning
+		int end = stream.readUnsignedByte(); // number of identical characters at the end
+		String next = stream.readUTF();
+		if (start > 0) {
+			if (end > 0) {
+				int length = current.length();
+				next = current.substring(0, start) + next + current.substring(length - end, length);
+			} else {
+				next = current.substring(0, start) + next;
+			}
+		} else if (end > 0) {
+			int length = current.length();
+			next = next + current.substring(length - end, length);
+		}
+		docNames[index++] = next;
+		current = next;
+	}
+}
+private int[] readDocumentArray(DataInputStream stream) throws IOException {
+	int arraySize = stream.readShort();
+	if (arraySize == 0x7FFF)
+		arraySize = stream.readInt();
+	int[] result = new int[arraySize];
+	for (int i = 0; i < arraySize; i++) {
+		switch (this.documentReferenceSize) {
+			case 1 :
+				result[i] = stream.readUnsignedByte();
+				break;
+			case 2 :
+				result[i] = stream.readUnsignedShort();
+				break;
+			default :
+				result[i] = stream.readInt();
+				break;
+		}
+	}
+	return result;
+}
+synchronized String readDocumentName(int docNumber) throws IOException {
+	if (this.cachedChunks == null)
+		this.cachedChunks = new String[this.numberOfChunks][];
+
+	int chunkNumber = docNumber / CHUNK_SIZE;
+	String[] chunk = this.cachedChunks[chunkNumber];
+	if (chunk == null) {
+		DataInputStream stream = new DataInputStream(new BufferedInputStream(new FileInputStream(getIndexFile()), 2048));
+		try {
+			stream.skip(this.chunkOffsets[chunkNumber]);
+			int size = chunkNumber == this.numberOfChunks - 1 ? this.sizeOfLastChunk : CHUNK_SIZE;
+			chunk = new String[size];
+			readChunk(chunk, stream, 0, size);
+		} finally {
+			stream.close();
+		}
+		this.cachedChunks[chunkNumber] = chunk;
+	}
+	return chunk[docNumber - (chunkNumber * CHUNK_SIZE)];
+}
+synchronized int[] readDocumentNumbers(Object arrayOffset) throws IOException {
+	// arrayOffset is either a cached array of docNumbers or an Integer offset in the file
+	if (arrayOffset instanceof int[])
+		return (int[]) arrayOffset;
+
+	DataInputStream stream = new DataInputStream(new BufferedInputStream(new FileInputStream(getIndexFile()), 2048));
+	try {
+		stream.skip(((Integer) arrayOffset).intValue());
+		return readDocumentArray(stream);
+	} finally {
+		stream.close();
+	}
+}
+private void readHeaderInfo(RandomAccessFile file) throws IOException {
+	file.seek(this.headerInfoOffset);
+
+	// must be same order as writeHeaderInfo()
+	this.numberOfChunks = file.readInt();
+	this.sizeOfLastChunk = file.readUnsignedByte();
+	this.documentReferenceSize = file.readUnsignedByte();
+
+	this.chunkOffsets = new int[this.numberOfChunks];
+	for (int i = 0; i < this.numberOfChunks; i++)
+		this.chunkOffsets[i] = file.readInt();
+
+	int size = file.readInt();
+	this.categoryOffsets = new HashtableOfIntValues(size);
+	for (int i = 0; i < size; i++)
+		this.categoryOffsets.put(Util.readUTF(file), file.readInt()); // cache offset to category table
+	this.categoryTables = new HashtableOfObject(size);
+}
+synchronized void startQuery() {
+	this.cacheUserCount++;
+}
+synchronized void stopQuery() {
+	if (--this.cacheUserCount < 0) {
+		// clear cached items
+		this.cacheUserCount = -1;
+		this.cachedChunks = null;
+		this.categoryTables = null;
+	}
+}
+private void writeAllDocumentNames(String[] sortedDocNames, DataOutputStream stream) throws IOException {
+	if (sortedDocNames.length == 0)
+		throw new IllegalArgumentException();
+
+	// assume the file was just created by initializeFrom()
+	// in order, write: SIGNATURE & headerInfoOffset place holder, then each compressed chunk of document names
+	stream.writeUTF(SIGNATURE);
+	this.headerInfoOffset = stream.size();
+	stream.writeInt(-1); // will overwrite with correct value later
+
+	int size = sortedDocNames.length;
+	this.numberOfChunks = (size / CHUNK_SIZE) + 1;
+	this.sizeOfLastChunk = size % CHUNK_SIZE;
+	if (this.sizeOfLastChunk == 0) {
+		this.numberOfChunks--;
+		this.sizeOfLastChunk = CHUNK_SIZE;
+	}
+	this.documentReferenceSize = size <= 0x7F ? 1 : (size <= 0x7FFF ? 2 : 4); // number of bytes used to encode a reference
+
+	this.chunkOffsets = new int[this.numberOfChunks];
+	int lastIndex = this.numberOfChunks - 1;
+	for (int i = 0; i < this.numberOfChunks; i++) {
+		this.chunkOffsets[i] = stream.size();
+
+		int chunkSize = i == lastIndex ? this.sizeOfLastChunk : CHUNK_SIZE;
+		int chunkIndex = i * CHUNK_SIZE;
+		String current = sortedDocNames[chunkIndex];
+		stream.writeUTF(current);
+		for (int j = 1; j < chunkSize; j++) {
+			String next = sortedDocNames[chunkIndex + j];
+			int len1 = current.length();
+			int len2 = next.length();
+			int max = len1 < len2 ? len1 : len2;
+			int start = 0; // number of identical characters at the beginning (also the index of first character that is different)
+			while (current.charAt(start) == next.charAt(start)) {
+				start++;
+				if (max == start) break; // current is 'abba', next is 'abbab'
+			}
+			if (start > 255) start = 255;
+
+			int end = 0; // number of identical characters at the end
+			while (current.charAt(--len1) == next.charAt(--len2)) {
+				end++;
+				if (len2 == start) break; // current is 'abbba', next is 'abba'
+			}
+			if (end > 255) end = 255;
+			stream.writeByte(start);
+			stream.writeByte(end);
+
+			int last = next.length() - end;
+			stream.writeUTF(start < last ? next.substring(start, last) : ""); //$NON-NLS-1$
+			current = next;
+		}
+	}
+}
+private void writeCategories(DataOutputStream stream) throws IOException {
+	char[][] categoryNames = this.categoryTables.keyTable;
+	Object[] tables = this.categoryTables.valueTable;
+	for (int i = 0, l = categoryNames.length; i < l; i++)
+		if (categoryNames[i] != null)
+			writeCategoryTable(categoryNames[i], (HashtableOfObject) tables[i], stream);
+	this.categoryTables = null;
+}
+private void writeCategoryTable(char[] categoryName, HashtableOfObject wordsToDocs, DataOutputStream stream) throws IOException {
+	// append the file with the document number arrays & remember the offsets
+	Object[] values = wordsToDocs.valueTable;
+	for (int i = 0, l = values.length; i < l; i++) {
+		Object o = values[i];
+		if (o != null) {
+			int[] documentNumbers = o instanceof int[] ? (int[]) o : ((IntList) o).asArray();
+			int length = documentNumbers.length;
+			if (length == 1) {
+				values[i] = new Integer(-documentNumbers[0]); // store an array of 1 element by negating the documentNumber (can be zero)
+			} else {
+				values[i] = new Integer(stream.size());
+				writeDocumentNumbers(documentNumbers, stream);
+			}
+		}
+	}
+
+	// append the file with the arrays followed by the words & offsets
+	this.categoryOffsets.put(categoryName, stream.size()); // remember the offset to the start of the table
+	this.categoryTables.put(categoryName, null); // flush cached table
+	stream.writeInt(wordsToDocs.elementSize);
+	char[][] words = wordsToDocs.keyTable;
+	for (int i = 0, l = words.length; i < l; i++) {
+		if (words[i] != null) {
+			Util.writeUTF(stream, words[i]);
+			stream.writeInt(((Integer) values[i]).intValue()); // offset in the file of the array of document numbers
+		}
+	}
+}
+private void writeDocumentNumbers(int[] documentNumbers, DataOutputStream stream) throws IOException {
+	int length = documentNumbers.length;
+	if (length < 0x7FFF) {
+		if (length == 0)
+			throw new IllegalArgumentException();
+		stream.writeShort(length);
+	} else {
+		stream.writeShort(0x7FFF);
+		stream.writeInt(length);
+	}
+	Util.sort(documentNumbers);
+	for (int i = 0; i < length; i++) {
+		switch (this.documentReferenceSize) {
+			case 1 :
+				stream.writeByte(documentNumbers[i]);
+				break;
+			case 2 :
+				stream.writeShort(documentNumbers[i]);
+				break;
+			default :
+				stream.writeInt(documentNumbers[i]);
+				break;
+		}
+	}
+}
+private void writeHeaderInfo(DataOutputStream stream) throws IOException {
+	stream.writeInt(this.numberOfChunks);
+	stream.writeByte(this.sizeOfLastChunk);
+	stream.writeByte(this.documentReferenceSize);
+
+	// apend the file with chunk offsets
+	for (int i = 0; i < this.numberOfChunks; i++)
+		stream.writeInt(this.chunkOffsets[i]);
+
+	// append the file with the category offsets... # of name -> offset pairs, followed by each name & an offset to its word->doc# table
+	stream.writeInt(this.categoryOffsets.elementSize);
+	char[][] categoryNames = this.categoryOffsets.keyTable;
+	int[] offsets = this.categoryOffsets.valueTable;
+	for (int i = 0, l = categoryNames.length; i < l; i++) {
+		if (categoryNames[i] != null) {
+			Util.writeUTF(stream, categoryNames[i]);
+			stream.writeInt(offsets[i]);
+		}
+	}
+}
+private void writeOffsetToHeader(int offsetToHeader) throws IOException {
+	if (offsetToHeader > 0) {
+		RandomAccessFile file = new RandomAccessFile(this.fileName, "rw"); //$NON-NLS-1$
+		try {
+			file.seek(this.headerInfoOffset); // offset to position in header
+			file.writeInt(offsetToHeader);
+			this.headerInfoOffset = offsetToHeader; // update to reflect the correct offset
+		} finally {
+			file.close();
+		}
+	}
+}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/EntryResult.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/EntryResult.java
new file mode 100644
index 0000000..2d271f7
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/EntryResult.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core.index;
+
+import org.eclipse.jdt.internal.compiler.util.HashtableOfObject;
+import org.eclipse.jdt.internal.core.util.SimpleSet;
+
+public class EntryResult {
+
+private char[] word;
+private HashtableOfObject[] documentTables;
+private SimpleSet documentNames;
+
+public EntryResult(char[] word, HashtableOfObject table) {
+	this.word = word;
+	if (table != null)
+		this.documentTables = new HashtableOfObject[] {table};
+}
+public void addDocumentName(String documentName) {
+	if (this.documentNames == null)
+		this.documentNames = new SimpleSet(3);
+	this.documentNames.add(documentName);
+}
+public void addDocumentTable(HashtableOfObject table) {
+	if (this.documentTables == null) {
+		this.documentTables = new HashtableOfObject[] {table};
+		return;
+	}
+
+	int length = this.documentTables.length;
+	System.arraycopy(this.documentTables, 0, this.documentTables = new HashtableOfObject[length + 1], 0, length);
+	this.documentTables[length] = table;
+}
+public char[] getWord() {
+	return this.word;
+}
+public String[] getDocumentNames(Index index) throws java.io.IOException {
+	if (this.documentTables != null) {
+		for (int i = 0, l = this.documentTables.length; i < l; i++) {
+			Object offset = this.documentTables[i].get(word);
+			int[] numbers = index.diskIndex.readDocumentNumbers(offset);
+			for (int j = 0, k = numbers.length; j < k; j++)
+				addDocumentName(index.diskIndex.readDocumentName(numbers[j]));
+		}
+	}
+
+	if (this.documentNames == null)
+		return new String[0];
+
+	String[] names = new String[this.documentNames.elementSize];
+	int count = 0;
+	Object[] values = this.documentNames.values;
+	for (int i = 0, l = values.length; i < l; i++)
+		if (values[i] != null)
+			names[count++] = (String) values[i];
+	return names;
+}
+public boolean isEmpty() {
+	return this.documentTables == null && this.documentNames == null;
+}
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IIndex.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IIndex.java
deleted file mode 100644
index b512716..0000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IIndex.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index;
-
-import java.io.File;
-import java.io.IOException;
-
-import org.eclipse.jdt.core.search.SearchDocument;
-import org.eclipse.jdt.internal.core.index.impl.EntryResult;
-
-/**
- * An IIndex is the interface used to generate an index file, and to make queries on
- * this index.
- */
-
-public interface IIndex {
-	/**
-	 * Adds the given document to the index.
-	 */
-	void add(SearchDocument document, IIndexer indexer) throws IOException;
-	/**
-	 * Returns the index file on the disk.
-	 */
-	File getIndexFile();
-	/**
-	 * Returns the path corresponding to a given document number
-	 */
-	String getPath(int documentNumber) throws IOException;
-	/**
-	 * Ansers true if has some changes to save.
-	 */
-	boolean hasChanged();
-	/**
-	 * Returns the paths of the documents containing the given word.
-	 */
-	String[] query(String word) throws IOException;
-	/**
-	 * Returns all entries for a given word.
-	 */
-	EntryResult[] queryEntries(char[] pattern) throws IOException;
-	/**
-	 * Returns the paths of the documents whose names contain the given word.
-	 */
-	String[] queryInDocumentNames(String word) throws IOException;
-	/**
-	 * Returns the paths of the documents containing the given word prefix.
-	 */
-	String[] queryPrefix(char[] prefix) throws IOException;
-	/**
-	 * Removes the corresponding document from the index.
-	 */
-	void remove(String documentName) throws IOException;
-	/**
-	 * Saves the index on the disk.
-	 */
-	void save() throws IOException;
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IIndexer.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IIndexer.java
deleted file mode 100644
index d724b7c..0000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IIndexer.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index;
-
-import org.eclipse.jdt.core.search.SearchDocument;
-
-/**
- * An <code>IIndexer</code> indexes ONE document at each time. It adds the document names and
- * the words references to an IIndex. Each IIndexer can index certain types of document, and should
- * not index the other files. 
- */
-public interface IIndexer {
-	/**
-	 * Indexes the given document, adding the document name and the word references 
-	 * to this document to the given <code>IIndex</code>.The caller should use 
-	 * <code>shouldIndex()</code> first to determine whether this indexer handles 
-	 * the given type of file, and only call this method if so. 
-	 */
-
-	void index(SearchDocument document, IIndexerOutput output) throws java.io.IOException;
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IIndexerOutput.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IIndexerOutput.java
deleted file mode 100644
index 5121273..0000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IIndexerOutput.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index;
-
-import org.eclipse.jdt.core.search.SearchDocument;
-
-/**
- * This class represents the output from an indexer to an index 
- * for a single document.
- */
-
-public interface IIndexerOutput {
-	public void addDocument(SearchDocument document);
-	public void addRef(char[] word);
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/Index.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/Index.java
new file mode 100644
index 0000000..44a4f5b
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/Index.java
@@ -0,0 +1,188 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core.index;
+
+import java.io.*;
+
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.internal.compiler.util.HashtableOfObject;
+import org.eclipse.jdt.internal.core.util.*;
+import org.eclipse.jdt.internal.core.search.indexing.InternalSearchDocument;
+import org.eclipse.jdt.internal.core.search.indexing.ReadWriteMonitor;
+
+/**
+ * An <code>Index</code> maps document names to their referenced words in various categories.
+ * 
+ * Queries can search a single category or several at the same time.
+ * 
+ * Indexes are not synchronized structures and should only be queried/updated one at a time.
+ */
+
+public class Index {
+
+public String printableName;
+public ReadWriteMonitor monitor;
+
+protected DiskIndex diskIndex;
+protected MemoryIndex memoryIndex;
+
+/**
+ * Returns the path represented by pathString converted back to a path relative to the local file system.
+ *
+ * @param pathString the path to convert:
+ * <ul>
+ *		<li>an absolute IPath (relative to the workspace root) if the path represents a resource in the 
+ *			workspace
+ *		<li>a relative IPath (relative to the workspace root) followed by JAR_FILE_ENTRY_SEPARATOR
+ *			followed by an absolute path (relative to the jar) if the path represents a .class file in
+ *			an internal jar
+ *		<li>an absolute path (relative to the file system) followed by JAR_FILE_ENTRY_SEPARATOR
+ *			followed by an absolute path (relative to the jar) if the path represents a .class file in
+ *			an external jar
+ * </ul>
+ * @return the converted path:
+ * <ul>
+ *		<li>the original pathString if the path represents a resource in the workspace
+ *		<li>an absolute path (relative to the file system) followed by JAR_FILE_ENTRY_SEPARATOR
+ *			followed by an absolute path (relative to the jar) if the path represents a .class file in
+ *			an external or internal jar
+ * </ul>
+ */
+public static String convertPath(String pathString) {
+	int index = pathString.indexOf(IJavaSearchScope.JAR_FILE_ENTRY_SEPARATOR);
+	if (index == -1) return pathString;
+	
+	Path jarPath = new Path(pathString.substring(0, index));
+	return (jarPath.isAbsolute() ? jarPath.toOSString() : jarPath.makeAbsolute().toString())
+		+ pathString.substring(index, pathString.length());
+}
+public static boolean isMatch(char[] pattern, char[] word, int matchRule) {
+	if (pattern == null) return true;
+
+	switch(matchRule) {
+		case SearchPattern.R_EXACT_MATCH :
+			return CharOperation.equals(pattern, word, false);
+		case SearchPattern.R_PREFIX_MATCH :
+			return CharOperation.prefixEquals(pattern, word, false);
+		case SearchPattern.R_PATTERN_MATCH :
+			return CharOperation.match(pattern, word, false);
+		case SearchPattern.R_EXACT_MATCH + SearchPattern.R_CASE_SENSITIVE :
+			return CharOperation.equals(pattern, word);
+		case SearchPattern.R_PREFIX_MATCH + SearchPattern.R_CASE_SENSITIVE :
+			return CharOperation.prefixEquals(pattern, word);
+		case SearchPattern.R_PATTERN_MATCH + SearchPattern.R_CASE_SENSITIVE :
+			return CharOperation.match(pattern, word, true);
+	}
+	return false;
+}
+
+
+public Index(String fileName, String printableName, boolean reuseExistingFile) throws IOException {
+	this.printableName = printableName;
+	this.monitor = new ReadWriteMonitor();
+
+	this.memoryIndex = new MemoryIndex();
+	this.diskIndex = new DiskIndex(fileName);
+	this.diskIndex.initialize(reuseExistingFile);
+}
+public void addIndexEntry(char[] category, char[] key, InternalSearchDocument document) {
+	this.memoryIndex.addIndexEntry(category, key, document);
+}
+public File getIndexFile() {
+	if (this.diskIndex == null) return null;
+
+	return this.diskIndex.getIndexFile();
+}
+public boolean hasChanged() {
+	return this.memoryIndex.hasChanged();
+}
+/**
+ * Returns the entries containing the given key in a group of categories, or null if no matches are found.
+ * The matchRule dictates whether its an exact, prefix or pattern match, as well as case sensitive or insensitive.
+ * If the key is null then all entries in specified categories are returned.
+ */
+public EntryResult[] query(char[][] categories, char[] key, int matchRule) throws IOException {
+	if (this.memoryIndex.shouldMerge() && monitor.exitReadEnterWrite()) {
+		try {
+			save();
+		} finally {
+			monitor.exitWriteEnterRead();
+		}
+	}
+
+	HashtableOfObject results;
+	if (this.memoryIndex.hasChanged()) {
+		results = this.diskIndex.addQueryResults(categories, key, matchRule, this.memoryIndex);
+		this.memoryIndex.addQueryResults(categories, key, matchRule, results);
+	} else {
+		results = this.diskIndex.addQueryResults(categories, key, matchRule, null);
+	}
+	if (results.elementSize == 0) return null;
+
+	EntryResult[] entryResults = new EntryResult[results.elementSize];
+	int count = 0;
+	Object[] values = results.valueTable;
+	for (int i = 0, l = values.length; i < l; i++) {
+		EntryResult result = (EntryResult) values[i];
+		if (result != null)
+			entryResults[count++] = result;
+	}
+	return entryResults;
+}
+/**
+ * Returns the document names that contain the given substring, if null then returns all of them.
+ */
+public String[] queryDocumentNames(String substring) throws IOException {
+	SimpleSet results;
+	if (this.memoryIndex.hasChanged()) {
+		results = this.diskIndex.addDocumentNames(substring, this.memoryIndex);
+		this.memoryIndex.addDocumentNames(substring, results);
+	} else {
+		results = this.diskIndex.addDocumentNames(substring, null);
+	}
+	if (results.elementSize == 0) return null;
+
+	String[] documentNames = new String[results.elementSize];
+	int count = 0;
+	Object[] paths = results.values;
+	for (int i = 0, l = paths.length; i < l; i++)
+		if (paths[i] != null)
+			documentNames[count++] = (String) paths[i];
+	return documentNames;
+}
+public void remove(String documentName) {
+	this.memoryIndex.remove(documentName);
+}
+public void save() throws IOException {
+	// must own the write lock of the monitor
+	if (!hasChanged()) return;
+
+	int numberOfChanges = this.memoryIndex.docsToReferences.elementSize;
+	this.diskIndex = this.diskIndex.mergeWith(this.memoryIndex);
+	this.memoryIndex = new MemoryIndex();
+	if (numberOfChanges > 1000)
+		System.gc(); // reclaim space if the MemoryIndex was very BIG
+}
+public void startQuery() throws IOException {
+	if (this.diskIndex != null)
+		this.diskIndex.startQuery();
+}
+public void stopQuery() throws IOException {
+	if (this.diskIndex != null)
+		this.diskIndex.stopQuery();
+}
+public String toString() {
+	if (this.printableName != null) return this.printableName;
+	return super.toString();
+}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/MemoryIndex.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/MemoryIndex.java
new file mode 100644
index 0000000..ca44041
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/MemoryIndex.java
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core.index;
+
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.internal.core.search.indexing.InternalSearchDocument;
+import org.eclipse.jdt.internal.core.util.*;
+import org.eclipse.jdt.internal.compiler.util.HashtableOfObject;
+
+public class MemoryIndex {
+
+public int NUM_CHANGES = 100; // number of separate document changes... used to decide when to merge
+
+SimpleLookupTable docsToReferences; // document paths -> HashtableOfObject(category names -> set of words)
+SimpleWordSet allWords; // save space by locally interning the referenced words, since an indexer can generate numerous duplicates
+
+MemoryIndex() {
+	this.docsToReferences = new SimpleLookupTable(7);
+	this.allWords = new SimpleWordSet(7);
+}
+void addDocumentNames(String substring, SimpleSet results) {
+	// assumed the disk index already skipped over documents which have been added/changed/deleted
+	Object[] paths = this.docsToReferences.keyTable;
+	Object[] referenceTables = this.docsToReferences.valueTable;
+	if (substring == null) { // add all new/changed documents
+		for (int i = 0, l = referenceTables.length; i < l; i++)
+			if (referenceTables[i] != null)
+				results.add(paths[i]);
+	} else {
+		for (int i = 0, l = referenceTables.length; i < l; i++)
+			if (referenceTables[i] != null && ((String) paths[i]).startsWith(substring, 0))
+				results.add(paths[i]);
+	}
+}
+void addIndexEntry(char[] category, char[] key, InternalSearchDocument document) {
+	// assumed a document was removed before its reindexed
+	String documentName = document.getPath();
+	HashtableOfObject referenceTable = (HashtableOfObject) this.docsToReferences.get(documentName);
+	if (referenceTable == null)
+		this.docsToReferences.put(documentName, referenceTable = new HashtableOfObject(3));
+
+	SimpleWordSet existingWords = (SimpleWordSet) referenceTable.get(category);
+	if (existingWords == null)
+		referenceTable.put(category, existingWords = new SimpleWordSet(1));
+
+	existingWords.add(this.allWords.add(key));
+}
+void addQueryResults(char[][] categories, char[] key, int matchRule, HashtableOfObject results) {
+	// assumed the disk index already skipped over documents which have been added/changed/deleted
+	// results maps a word -> EntryResult
+	Object[] paths = this.docsToReferences.keyTable;
+	Object[] referenceTables = this.docsToReferences.valueTable;
+	if (matchRule == (SearchPattern.R_EXACT_MATCH + SearchPattern.R_CASE_SENSITIVE) && key != null) {
+		nextPath : for (int i = 0, l = referenceTables.length; i < l; i++) {
+			HashtableOfObject categoryToWords = (HashtableOfObject) referenceTables[i];
+			if (categoryToWords != null) {
+				for (int j = 0, m = categories.length; j < m; j++) {
+					SimpleWordSet wordSet = (SimpleWordSet) categoryToWords.get(categories[j]);
+					if (wordSet != null && wordSet.includes(key)) {
+						EntryResult result = (EntryResult) results.get(key);
+						if (result == null)
+							results.put(key, result = new EntryResult(key, null));
+						result.addDocumentName((String) paths[i]);
+						continue nextPath;
+					}
+				}
+			}
+		}
+	} else {
+		for (int i = 0, l = referenceTables.length; i < l; i++) {
+			HashtableOfObject categoryToWords = (HashtableOfObject) referenceTables[i];
+			if (categoryToWords != null) {
+				for (int j = 0, m = categories.length; j < m; j++) {
+					SimpleWordSet wordSet = (SimpleWordSet) categoryToWords.get(categories[j]);
+					if (wordSet != null) {
+						char[][] words = wordSet.words;
+						for (int k = 0, n = words.length; k < n; k++) {
+							char[] word = words[k];
+							if (word != null && Index.isMatch(key, word, matchRule)) {
+								EntryResult result = (EntryResult) results.get(word);
+								if (result == null)
+									results.put(word, result = new EntryResult(word, null));
+								result.addDocumentName((String) paths[i]);
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+}
+boolean hasChanged() {
+	return this.docsToReferences.elementSize > 0;
+}
+void remove(String documentName) {
+	this.docsToReferences.put(documentName, null);
+}
+boolean shouldMerge() {
+	return this.docsToReferences.elementSize >= NUM_CHANGES;
+}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/Block.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/Block.java
deleted file mode 100644
index 7718b6c..0000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/Block.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.io.IOException;
-import java.io.RandomAccessFile;
-
-/**
- * A block is a container that can hold information (a list of file names, a list of
- * words, ...), be saved on the disk and loaded in memory.
- */
-
-public abstract class Block {
-	/**
-	 * Size of the block
-	 */
-	protected int blockSize;
-
-	/**
-	 * Field in which the information is stored
-	 */
-	protected Field field;
-
-	public Block(int blockSize) {
-		this.blockSize= blockSize;
-		field= new Field(blockSize);
-	}
-	/**
-	 * Empties the block.
-	 */
-	public void clear() {
-		field.clear();
-	}
-	/**
-	 * Flushes the block
-	 */
-	public void flush() {
-		// ignore
-	}
-	/**
-	 * Loads the block with the given number in memory, reading it from a RandomAccessFile.
-	 */
-	public void read(RandomAccessFile raf, int blockNum) throws IOException {
-		raf.seek(blockNum * (long) blockSize);
-		raf.readFully(field.buffer());
-	}
-	/**
-	 * Writes the block in a RandomAccessFile, giving it a block number.
-	 */
-	public void write(RandomAccessFile raf, int blockNum) throws IOException {
-		raf.seek(blockNum * (long) blockSize);
-		raf.write(field.buffer());
-	}
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/BlocksIndexInput.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/BlocksIndexInput.java
deleted file mode 100644
index e05c4e0..0000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/BlocksIndexInput.java
+++ /dev/null
@@ -1,393 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.util.ArrayList;
-
-import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.core.search.SearchDocument;
-import org.eclipse.jdt.internal.core.util.Util;
-
-/**
- * This input is used for reading indexes saved using a BlocksIndexOutput.
- */
-public class BlocksIndexInput extends IndexInput {
-	public static final int CACHE_SIZE= 16; // Cache 16 blocks of 8K each, for a cache size of 128K
-	protected FileListBlock currentFileListBlock;
-	protected int currentFileListBlockNum;
-	protected int currentIndexBlockNum;
-	protected IndexBlock currentIndexBlock;
-	private RandomAccessFile raf;
-	protected File indexFile;
-	protected LRUCache blockCache;
-	protected boolean opened= false;
-	protected IndexSummary summary;
-
-	public BlocksIndexInput(File inputFile) {
-		this.indexFile= inputFile;
-		blockCache= new LRUCache(CACHE_SIZE);
-	}
-	/**
-	 * @see IndexInput#clearCache()
-	 */
-	public void clearCache() {
-		blockCache= new LRUCache(CACHE_SIZE);
-	}
-	/**
-	 * @see IndexInput#close()
-	 */
-	public void close() throws IOException {
-		if (opened) {
-			summary= null;
-			opened= false;
-			if (raf != null)
-				raf.close();
-		}
-	}
-	/**
-	 * @see IndexInput#getCurrentFile()
-	 */
-	public IndexedFile getCurrentFile() throws IOException {
-		if (!hasMoreFiles())
-			return null;
-		IndexedFile file= null;
-		if ((file= currentFileListBlock.getFile(filePosition)) == null) {
-			currentFileListBlockNum= summary.getBlockNumForFileNum(filePosition);
-			currentFileListBlock= getFileListBlock(currentFileListBlockNum);
-			file= currentFileListBlock.getFile(filePosition);
-		}
-		return file;
-	}
-	/**
-	 * Returns the entry corresponding to the given word.
-	 */
-	protected WordEntry getEntry(char[] word) throws IOException {
-		int blockNum= summary.getBlockNumForWord(word);
-		if (blockNum == -1) return null;
-		IndexBlock block= getIndexBlock(blockNum);
-		return block.findExactEntry(word);
-	}
-	/**
-	 * Returns the FileListBlock with the given number.
-	 */
-	protected FileListBlock getFileListBlock(int blockNum) throws IOException {
-		Integer key= new Integer(blockNum);
-		Block block= (Block) blockCache.get(key);
-		if (block != null && block instanceof FileListBlock)
-			return (FileListBlock) block;
-		FileListBlock fileListBlock= new FileListBlock(IIndexConstants.BLOCK_SIZE);
-		fileListBlock.read(raf, blockNum);
-		blockCache.put(key, fileListBlock);
-		return fileListBlock;
-	}
-	/**
-	 * Returns the IndexBlock (containing words) with the given number.
-	 */
-	protected IndexBlock getIndexBlock(int blockNum) throws IOException {
-		Integer key= new Integer(blockNum);
-		Block block= (Block) blockCache.get(key);
-		if (block != null && block instanceof IndexBlock)
-			return (IndexBlock) block;
-		IndexBlock indexBlock= new GammaCompressedIndexBlock(IIndexConstants.BLOCK_SIZE);
-		indexBlock.read(raf, blockNum);
-		blockCache.put(key, indexBlock);
-		return indexBlock;
-	}
-	/**
-	 * @see IndexInput#getIndexedFile(int)
-	 */
-	public IndexedFile getIndexedFile(int fileNum) throws IOException {
-		int blockNum= summary.getBlockNumForFileNum(fileNum);
-		if (blockNum == -1)
-			return null;
-		FileListBlock block= getFileListBlock(blockNum);
-		return block.getFile(fileNum);
-	}
-	/**
-	 * @see IndexInput#getIndexedFile(IDocument)
-	 */
-	public IndexedFile getIndexedFile(SearchDocument document) throws java.io.IOException {
-		setFirstFile();
-		String name= document.getPath();
-		while (hasMoreFiles()) {
-			IndexedFile file= getCurrentFile();
-			String path= file.getPath();
-			if (path.equals(name))
-				return file;
-			moveToNextFile();
-		}
-		return null;
-	}
-	/**
-	 * Returns the list of numbers of files containing the given word.
-	 */
-
-	protected int[] getMatchingFileNumbers(char[] word) throws IOException {
-		int blockNum= summary.getBlockNumForWord(word);
-		if (blockNum == -1)
-			return new int[0];
-		IndexBlock block= getIndexBlock(blockNum);
-		WordEntry entry= block.findExactEntry(word);
-		return entry == null ? new int[0] : entry.getRefs();
-	}
-	/**
-	 * @see IndexInput#getNumFiles()
-	 */
-	public int getNumFiles() {
-		return summary.getNumFiles();
-	}
-	/**
-	 * @see IndexInput#getNumWords()
-	 */
-	public int getNumWords() {
-		return summary.getNumWords();
-	}
-	/**
-	 * @see IndexInput#getSource()
-	 */
-	public Object getSource() {
-		return indexFile;
-	}
-	/**
-	 * Initialises the blocksIndexInput
-	 */
-	protected void init() throws IOException {
-		clearCache();
-		setFirstFile();
-		setFirstWord();
-	}
-	/**
-	 * @see IndexInput#moveToNextFile()
-	 */
-	public void moveToNextFile() {
-		filePosition++;
-	}
-	/**
-	 * @see IndexInput#moveToNextWordEntry()
-	 */
-	public void moveToNextWordEntry() throws IOException {
-		wordPosition++;
-		if (!hasMoreWords()) {
-			return;
-		}
-		//if end of the current block, we load the next one.
-		boolean endOfBlock= !currentIndexBlock.nextEntry(currentWordEntry);
-		if (endOfBlock) {
-			currentIndexBlock= getIndexBlock(++currentIndexBlockNum);
-			currentIndexBlock.nextEntry(currentWordEntry);
-		}
-	}
-	/**
-	 * @see IndexInput#open()
-	 */
-
-	public void open() throws IOException {
-		if (!opened) {
-			raf= new SafeRandomAccessFile(indexFile, "r"); //$NON-NLS-1$
-			String sig= raf.readUTF();
-			if (!sig.equals(IIndexConstants.SIGNATURE))
-				throw new IOException(Util.bind("exception.wrongFormat")); //$NON-NLS-1$
-			int summaryBlockNum= raf.readInt();
-			raf.seek(summaryBlockNum * (long) IIndexConstants.BLOCK_SIZE);
-			summary= new IndexSummary();
-			summary.read(raf);
-			init();
-			opened= true;
-		}
-	}
-	/**
-	 * @see IndexInput#query(String)
-	 */
-	public String[] query(String word) throws IOException {
-		open();
-		int[] fileNums= getMatchingFileNumbers(word.toCharArray());
-		int size= fileNums.length;
-		String[] paths= new String[size];
-		for (int i= 0; i < size; ++i) {
-			paths[i]= getIndexedFile(fileNums[i]).getPath();
-		}
-		return paths;
-	}
-	/**
-	 * If no prefix is provided in the pattern, then this operation will have to walk
-	 * all the entries of the whole index.
-	 */
-	public EntryResult[] queryEntriesMatching(char[] pattern/*, boolean isCaseSensitive*/) throws IOException {
-		open();
-	
-		if (pattern == null || pattern.length == 0) return null;
-		int[] blockNums = null;
-		int firstStar = CharOperation.indexOf('*', pattern);
-		switch (firstStar){
-			case -1 :
-				WordEntry entry = getEntry(pattern);
-				if (entry == null) return null;
-				return new EntryResult[]{ new EntryResult(entry.getWord(), entry.getRefs()) };
-			case 0 :
-				blockNums = summary.getAllBlockNums();
-				break;
-			default :
-				char[] prefix = CharOperation.subarray(pattern, 0, firstStar);
-				blockNums = summary.getBlockNumsForPrefix(prefix);
-		}
-		if (blockNums == null || blockNums.length == 0)	return null;
-				
-		EntryResult[] entries = new EntryResult[5];
-		int count = 0;
-		for (int i = 0, max = blockNums.length; i < max; i++) {
-			IndexBlock block = getIndexBlock(blockNums[i]);
-			block.reset();
-			boolean found = false;
-			WordEntry entry = new WordEntry();
-			while (block.nextEntry(entry)) {
-				if (CharOperation.match(entry.getWord(), pattern, true)) {
-					if (count == entries.length)
-						System.arraycopy(entries, 0, entries = new EntryResult[count*2], 0, count);
-					entries[count++] = new EntryResult(entry.getWord(), entry.getRefs());
-					found = true;
-				} else {
-					if (found) break;
-				}
-			}
-		}
-		if (count != entries.length)
-			System.arraycopy(entries, 0, entries = new EntryResult[count], 0, count);
-		return entries;
-	}
-	/* (non-Javadoc)
-	 * @see org.eclipse.jdt.internal.core.index.impl.IndexInput#queryEntries(char[], int)
-	 */
-	public EntryResult[] queryEntries(char[] pattern, int matchRule) throws IOException {
-		// TODO should evolve to provide different flavors of matching
-		return queryEntriesPrefixedBy(pattern);
-	}
-	public EntryResult[] queryEntriesPrefixedBy(char[] prefix) throws IOException {
-		open();
-		
-		int blockLoc = summary.getFirstBlockLocationForPrefix(prefix);
-		if (blockLoc < 0) return null;
-			
-		EntryResult[] entries = new EntryResult[5];
-		int count = 0;
-		while(blockLoc >= 0){
-			IndexBlock block = getIndexBlock(summary.getBlockNum(blockLoc));
-			block.reset();
-			boolean found = false;
-			WordEntry entry = new WordEntry();
-			while (block.nextEntry(entry)) {
-				if (CharOperation.prefixEquals(prefix, entry.getWord())) {
-					if (count == entries.length){
-						System.arraycopy(entries, 0, entries = new EntryResult[count*2], 0, count);
-					}
-					entries[count++] = new EntryResult(entry.getWord(), entry.getRefs());
-					found = true;
-				} else {
-					if (found) break;
-				}
-			}
-			/* consider next block ? */
-			blockLoc = summary.getNextBlockLocationForPrefix(prefix, blockLoc);				
-		}
-		if (count == 0) return null;
-		if (count != entries.length){
-			System.arraycopy(entries, 0, entries = new EntryResult[count], 0, count);
-		}
-		return entries;
-	}
-	public String[] queryFilesReferringToPrefix(char[] prefix) throws IOException {
-		open();
-		
-		int blockLoc = summary.getFirstBlockLocationForPrefix(prefix);
-		if (blockLoc < 0) return null;
-			
-		// each filename must be returned already once
-		org.eclipse.jdt.internal.compiler.util.HashtableOfInt fileMatches = new org.eclipse.jdt.internal.compiler.util.HashtableOfInt(20);
-		int count = 0; 
-		while(blockLoc >= 0){
-			IndexBlock block = getIndexBlock(summary.getBlockNum(blockLoc));
-			block.reset();
-			boolean found = false;
-			WordEntry entry = new WordEntry();
-			while (block.nextEntry(entry)) {
-				if (CharOperation.prefixEquals(prefix, entry.getWord()/*, isCaseSensitive*/)) {
-					int [] refs = entry.getRefs();
-					for (int i = 0, max = refs.length; i < max; i++){
-						int ref = refs[i];
-						if (!fileMatches.containsKey(ref)){
-							count++;
-							fileMatches.put(ref, getIndexedFile(ref));
-						}
-					}
-					found = true;
-				} else {
-					if (found) break;
-				}
-			}
-			/* consider next block ? */
-			blockLoc = summary.getNextBlockLocationForPrefix(prefix, blockLoc);				
-		}
-		/* extract indexed files */
-		String[] paths = new String[count];
-		Object[] indexedFiles = fileMatches.valueTable;
-		for (int i = 0, index = 0, max = indexedFiles.length; i < max; i++){
-			IndexedFile indexedFile = (IndexedFile) indexedFiles[i];
-			if (indexedFile != null){
-				paths[index++] = indexedFile.getPath();
-			}
-		}	
-		return paths;
-	}
-	/**
-	 * @see IndexInput#queryInDocumentNames(String)
-	 */
-	public String[] queryInDocumentNames(String word) throws IOException {
-		open();
-		ArrayList matches= new ArrayList();
-		setFirstFile();
-		while (hasMoreFiles()) {
-			IndexedFile file= getCurrentFile();
-			if (file.getPath().indexOf(word) != -1)
-				matches.add(file.getPath());
-			moveToNextFile();
-		}
-		String[] match= new String[matches.size()];
-		matches.toArray(match);
-		return match;
-	}
-	/**
-	 * @see IndexInput#setFirstFile()
-	 */
-
-	protected void setFirstFile() throws IOException {
-		filePosition= 1;
-		if (getNumFiles() > 0) {
-			currentFileListBlockNum= summary.getBlockNumForFileNum(1);
-			currentFileListBlock= getFileListBlock(currentFileListBlockNum);
-		}
-	}
-	/**
-	 * @see IndexInput#setFirstWord()
-	 */
-
-	protected void setFirstWord() throws IOException {
-		wordPosition= 1;
-		if (getNumWords() > 0) {
-			currentIndexBlockNum= summary.getFirstWordBlockNum();
-			currentIndexBlock= getIndexBlock(currentIndexBlockNum);
-			currentWordEntry= new WordEntry();
-			currentIndexBlock.reset();
-			currentIndexBlock.nextEntry(currentWordEntry);
-		}
-	}
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/BlocksIndexOutput.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/BlocksIndexOutput.java
deleted file mode 100644
index 501955f..0000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/BlocksIndexOutput.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-
-/**
- * A blocksIndexOutput is used to save an index in a file with the given structure:<br>
- *  - Signature of the file;<br>
- *  - FileListBlocks;<br>
- *  - IndexBlocks;<br>
- *  - Summary of the index.
- */
-
-public class BlocksIndexOutput extends IndexOutput {
-	protected RandomAccessFile indexOut;
-	protected int blockNum;
-	protected boolean opened= false;
-	protected File indexFile;
-	protected FileListBlock fileListBlock;
-	protected IndexBlock indexBlock;
-	protected int numWords= 0;
-	protected IndexSummary summary;
-	protected int numFiles= 0;
-	protected boolean firstInBlock;
-	protected boolean firstIndexBlock;
-	protected boolean firstFileListBlock;
-
-	public BlocksIndexOutput(File indexFile) {
-		this.indexFile= indexFile;
-		summary= new IndexSummary();
-		blockNum= 1;
-		firstInBlock= true;
-		firstIndexBlock= true;
-		firstFileListBlock= true;
-	}
-	/**
-	 * @see IndexOutput#addFile
-	 */
-	public void addFile(IndexedFile indexedFile) throws IOException {
-		if (firstFileListBlock) {
-			firstInBlock= true;
-			fileListBlock= new FileListBlock(IIndexConstants.BLOCK_SIZE);
-			firstFileListBlock= false;
-		}
-		if (fileListBlock.addFile(indexedFile)) {
-			if (firstInBlock) {
-				summary.addFirstFileInBlock(indexedFile, blockNum);
-				firstInBlock= false;
-			}
-			numFiles++;
-		} else {
-			if (fileListBlock.isEmpty()) {
-				return;
-			}
-			flushFiles();
-			addFile(indexedFile);
-		}
-	}
-	/**
-	 * @see IndexOutput#addWord
-	 */
-	public void addWord(WordEntry entry) throws IOException {
-		if (firstIndexBlock) {
-			indexBlock= new GammaCompressedIndexBlock(IIndexConstants.BLOCK_SIZE);
-			firstInBlock= true;
-			firstIndexBlock= false;
-		}
-		if (entry.getNumRefs() == 0)
-			return;
-		if (indexBlock.addEntry(entry)) {
-			if (firstInBlock) {
-				summary.addFirstWordInBlock(entry.getWord(), blockNum);
-				firstInBlock= false;
-			}
-			numWords++;
-		} else {
-			if (indexBlock.isEmpty()) {
-				return;
-			}
-			flushWords();
-			addWord(entry);
-		}
-	}
-	/**
-	 * @see IndexOutput#close
-	 */
-	public void close() throws IOException {
-		if (opened) {
-			indexOut.close();
-			summary= null;
-			numFiles= 0;
-			opened= false;
-		}
-	}
-	/**
-	 * @see IndexOutput#flush
-	 */
-	public void flush() throws IOException {
-		
-		summary.setNumFiles(numFiles);
-		summary.setNumWords(numWords);
-		indexOut.seek(blockNum * (long) IIndexConstants.BLOCK_SIZE);
-		summary.write(indexOut);
-		indexOut.seek(0);
-		indexOut.writeUTF(IIndexConstants.SIGNATURE);
-		indexOut.writeInt(blockNum);
-	}
-	/**
-	 * Writes the current fileListBlock on the disk and initialises it
-	 * (when it's full or it's the end of the index).
-	 */
-	protected void flushFiles() throws IOException {
-		if (!firstFileListBlock
-				&& fileListBlock != null) {
-			fileListBlock.flush();
-			fileListBlock.write(indexOut, blockNum++);
-			fileListBlock.clear();
-			firstInBlock= true;
-		}
-	}
-	/**
-	 * Writes the current indexBlock on the disk and initialises it
-	 * (when it's full or it's the end of the index).
-	 */
-	protected void flushWords() throws IOException {
-		if (!firstInBlock 
-				&& indexBlock != null) { // could have added a document without any indexed word, no block created yet
-			indexBlock.flush();
-			indexBlock.write(indexOut, blockNum++);
-			indexBlock.clear();
-			firstInBlock= true;
-		}
-	}
-	/**
-	 * @see IndexOutput#getDestination
-	 */
-	public Object getDestination() {
-		return indexFile;
-	}
-	/**
-	 * @see IndexOutput#open
-	 */
-	public void open() throws IOException {
-		if (!opened) {
-			summary= new IndexSummary();
-			numFiles= 0;
-			numWords= 0;
-			blockNum= 1;
-			firstInBlock= true;
-			firstIndexBlock= true;
-			firstFileListBlock= true;
-			indexOut= new SafeRandomAccessFile(this.indexFile, "rw"); //$NON-NLS-1$
-			opened= true;
-		}
-	}
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/CodeByteStream.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/CodeByteStream.java
deleted file mode 100644
index c6a1d7a..0000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/CodeByteStream.java
+++ /dev/null
@@ -1,342 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.io.UTFDataFormatException;
-
-public class CodeByteStream {
-	protected byte[] bytes;
-	protected int byteOffset= 0;
-	protected int bitOffset= 0;
-	protected int markByteOffset= -1;
-	protected int markBitOffset= -1;
-
-	public CodeByteStream() {
-		this(16);
-	}
-	public CodeByteStream(byte[] bytes) {
-		this.bytes= bytes;
-	}
-	public CodeByteStream(int initialByteLength) {
-		bytes= new byte[initialByteLength];
-	}
-	public int byteLength() {
-		return (bitOffset + 7) / 8 + byteOffset;
-	}
-	public byte[] getBytes(int startOffset, int endOffset) {
-		int byteLength= byteLength();
-		if (startOffset > byteLength || endOffset > byteLength || startOffset > endOffset)
-			throw new IndexOutOfBoundsException();
-		int length= endOffset - startOffset;
-		byte[] result= new byte[length];
-		System.arraycopy(bytes, startOffset, result, 0, length);
-		if (endOffset == byteLength && bitOffset != 0) {
-			int mask= (1 << bitOffset) - 1;
-			result[length - 1] &= (mask << 8 - bitOffset);
-		}
-		return result;
-	}
-	protected void grow() {
-		byte[] newBytes= new byte[bytes.length * 2 + 1];
-		System.arraycopy(bytes, 0, newBytes, 0, bytes.length);
-		bytes= newBytes;
-	}
-	public void mark() {
-		markByteOffset= byteOffset;
-		markBitOffset= bitOffset;
-	}
-	/**
-	 * Reads a single bit (value == 0 or == 1).
-	 */
-	public int readBit() {
-		int value= (bytes[byteOffset] >> (7 - bitOffset)) & 1;
-		if (++bitOffset >= 8) {
-			bitOffset= 0;
-			++byteOffset;
-		}
-		return value;
-	}
-	/**
-	 * Read up to 32 bits from the stream.
-	 */
-	public int readBits(int numBits) {
-		int value= 0;
-		while (numBits > 0) {
-			int bitsToRead= 8 - bitOffset;
-			if (bitsToRead > numBits)
-				bitsToRead= numBits;
-			int mask= (1 << bitsToRead) - 1;
-			value |= ((bytes[byteOffset] >> (8 - bitOffset - bitsToRead)) & mask) << (numBits - bitsToRead);
-			numBits -= bitsToRead;
-			bitOffset += bitsToRead;
-			if (bitOffset >= 8) {
-				bitOffset -= 8;
-				byteOffset += 1;
-			}
-		}
-		return value;
-	}
-	public final int readByte() {
-
-		// no need to rebuild byte value from bit sequences
-		if (bitOffset == 0) return bytes[byteOffset++] & 255;
-	
-		int value= 0;
-		int numBits = 8;
-		while (numBits > 0) {
-			int bitsToRead= 8 - bitOffset;
-			if (bitsToRead > numBits)
-				bitsToRead= numBits;
-			int mask= (1 << bitsToRead) - 1;
-			value |= ((bytes[byteOffset] >> (8 - bitOffset - bitsToRead)) & mask) << (numBits - bitsToRead);
-			numBits -= bitsToRead;
-			bitOffset += bitsToRead;
-			if (bitOffset >= 8) {
-				bitOffset -= 8;
-				byteOffset += 1;
-			}
-		}
-		return value;
-	}
-	/**
-	 * Reads a value using Gamma coding.
-	 */
-	public int readGamma() {
-		int numBits= readUnary();
-		return readBits(numBits - 1) | (1 << (numBits - 1));
-	}
-	public char[] readUTF() throws UTFDataFormatException {
-		int utflen= readByte();
-		if (utflen == 255) {
-			// long UTF
-			int high = readByte();
-			int low = readByte();
-			utflen = (high << 8) + low;
-		}
-		char str[]= new char[utflen];
-		int count= 0;
-		int strlen= 0;
-		while (count < utflen) {
-			int c= readByte();
-			int char2, char3;
-			switch (c >> 4) {
-				case 0 :
-				case 1 :
-				case 2 :
-				case 3 :
-				case 4 :
-				case 5 :
-				case 6 :
-				case 7 :
-					// 0xxxxxxx
-					count++;
-					str[strlen++]= (char) c;
-					break;
-				case 12 :
-				case 13 :
-					// 110x xxxx   10xx xxxx
-					count += 2;
-					if (count > utflen)
-						throw new UTFDataFormatException();
-					char2= readByte();
-					if ((char2 & 0xC0) != 0x80)
-						throw new UTFDataFormatException();
-					str[strlen++]= (char) (((c & 0x1F) << 6) | (char2 & 0x3F));
-					break;
-				case 14 :
-					// 1110 xxxx  10xx xxxx  10xx xxxx
-					count += 3;
-					if (count > utflen)
-						throw new UTFDataFormatException();
-					char2= readByte();
-					char3= readByte();
-					if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
-						throw new UTFDataFormatException();
-					str[strlen++]= (char) (((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0));
-					break;
-				default :
-					// 10xx xxxx,  1111 xxxx
-					throw new UTFDataFormatException();
-			}
-		}
-		if (strlen < utflen)
-			System.arraycopy(str, 0, str= new char[strlen], 0, strlen);
-		return str;
-	}
-	/**
-	 *  Reads a value in unary.
-	 */
-	public int readUnary() {
-		int value= 1;
-		int mask= 1 << (7 - bitOffset);
-		while ((bytes[byteOffset] & mask) != 0) {
-			++value;
-			if (++bitOffset >= 8) {
-				bitOffset= 0;
-				++byteOffset;
-				mask= 0x80;
-			} else {
-				mask >>>= 1;
-			}
-		}
-		// skip the 0 bit
-		if (++bitOffset >= 8) {
-			bitOffset= 0;
-			++byteOffset;
-		}
-		return value;
-	}
-	public void reset() {
-		byteOffset= bitOffset= 0;
-		markByteOffset= markBitOffset= -1;
-	}
-	public void reset(byte[] bytesValue) {
-		this.bytes= bytesValue;
-		reset();
-	}
-	public void reset(byte[] bytesValue, int byteOffsetValue) {
-		reset(bytesValue);
-		this.byteOffset= byteOffsetValue;
-	}
-	public boolean resetToMark() {
-		if (markByteOffset == -1)
-			return false;
-		byteOffset= markByteOffset;
-		bitOffset= markBitOffset;
-		markByteOffset= markBitOffset= -1;
-		return true;
-	}
-	public void skipBits(int numBits) {
-		int newOffset= byteOffset * 8 + bitOffset + numBits;
-		if (newOffset < 0 || (newOffset + 7) / 8 >= bytes.length)
-			throw new IllegalArgumentException();
-		byteOffset= newOffset / 8;
-		bitOffset= newOffset % 8;
-	}
-	public byte[] toByteArray() {
-		return getBytes(0, byteLength());
-	}
-	/**
-	 * Writes a single bit (value == 0 or == 1).
-	 */
-	public void writeBit(int value) {
-		bytes[byteOffset] |= (value & 1) << (7 - bitOffset);
-		if (++bitOffset >= 8) {
-			bitOffset= 0;
-			if (++byteOffset >= bytes.length)
-				grow();
-		}
-	}
-	/**
-	 * Write up to 32 bits to the stream.
-	 * The least significant numBits bits of value are written.
-	 */
-	public void writeBits(int value, int numBits) {
-		while (numBits > 0) {
-			int bitsToWrite= 8 - bitOffset;
-			if (bitsToWrite > numBits)
-				bitsToWrite= numBits;
-			int shift= 8 - bitOffset - bitsToWrite;
-			int mask= ((1 << bitsToWrite) - 1) << shift;
-			bytes[byteOffset]= (byte) ((bytes[byteOffset] & ~mask) | (((value >>> (numBits - bitsToWrite)) << shift) & mask));
-			numBits -= bitsToWrite;
-			bitOffset += bitsToWrite;
-			if (bitOffset >= 8) {
-				bitOffset -= 8;
-				if (++byteOffset >= bytes.length)
-					grow();
-			}
-		}
-	}
-	public void writeByte(int value) {
-		writeBits(value, 8);
-	}
-	/**
-	 * Writes the given value using Gamma coding, in which positive integer x
-	 * is represented by coding floor(log2(x) in unary followed by the value 
-	 * of x - 2**floor(log2(x)) in binary.
-	 * The value must be >= 1.
-	 */
-	public void writeGamma(int value) {
-		if (value < 1)
-			throw new IllegalArgumentException();
-		int temp= value;
-		int numBits= 0;
-		while (temp != 0) {
-			temp >>>= 1;
-			++numBits;
-		}
-		writeUnary(numBits);
-		writeBits(value, numBits - 1);
-	}
-	public void writeUTF(char[] str, int start, int end) {
-		int utflen= 0;
-		for (int i= start; i < end; i++) {
-			int c= str[i];
-			if ((c >= 0x0001) && (c <= 0x007F)) {
-				utflen++;
-			} else if (c > 0x07FF) {
-				utflen += 3;
-			} else {
-				utflen += 2;
-			}
-		}
-		if (utflen < 255) {
-			writeByte(utflen & 0xFF);
-		} else if (utflen > 65535) {
-			throw new IllegalArgumentException();
-		} else {
-			writeByte(255); // marker for long UTF
-			writeByte((utflen >>> 8) & 0xFF); // high byte
-			writeByte((utflen >>> 0) & 0xFF); // low byte
-		}
-		for (int i= start; i < end; i++) {
-			int c= str[i];
-			if ((c >= 0x0001) && (c <= 0x007F)) {
-				writeByte(c);
-			} else if (c > 0x07FF) {
-				writeByte(0xE0 | ((c >> 12) & 0x0F));
-				writeByte(0x80 | ((c >> 6) & 0x3F));
-				writeByte(0x80 | ((c >> 0) & 0x3F));
-			} else {
-				writeByte(0xC0 | ((c >> 6) & 0x1F));
-				writeByte(0x80 | ((c >> 0) & 0x3F));
-			}
-		}
-	}
-	/**
-	 * Write the given value in unary.  The value must be >= 1.
-	 */
-	public void writeUnary(int value) {
-		if (value < 1)
-			throw new IllegalArgumentException();
-		int mask= 1 << (7 - bitOffset);
-		// write N-1 1-bits
-		while (--value > 0) {
-			bytes[byteOffset] |= mask;
-			if (++bitOffset >= 8) {
-				bitOffset= 0;
-				if (++byteOffset >= bytes.length)
-					grow();
-				mask= 0x80;
-			} else {
-				mask >>>= 1;
-			}
-		}
-		// write a 0-bit
-		bytes[byteOffset] &= ~mask;
-		if (++bitOffset >= 8) {
-			bitOffset= 0;
-			if (++byteOffset >= bytes.length)
-				grow();
-		}
-	}
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/EntryResult.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/EntryResult.java
deleted file mode 100644
index 9435f34..0000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/EntryResult.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import org.eclipse.jdt.core.compiler.CharOperation;
-
-public class EntryResult {
-	private char[] word;
-	private int[]  fileRefs;
-	
-public EntryResult(char[] word, int[] refs) {
-	this.word = word;
-	this.fileRefs = refs;
-}
-public boolean equals(Object anObject){
-	
-	if (this == anObject) {
-	    return true;
-	}
-	if ((anObject != null) && (anObject instanceof EntryResult)) {
-		EntryResult anEntryResult = (EntryResult) anObject;
-		if (!CharOperation.equals(this.word, anEntryResult.word)) return false;
-
-		int length;
-		int[] refs, otherRefs;
-		if ((length = (refs = this.fileRefs).length) != (otherRefs = anEntryResult.fileRefs).length) return false;
-		for (int i =  0; i < length; i++){
-			if (refs[i] != otherRefs[i]) return false;
-		}
-		return true;
-	}
-	return false;
-	
-}
-public int[] getFileReferences() {
-	return fileRefs;
-}
-public char[] getWord() {
-	return word;
-}
-public int hashCode(){
-	return CharOperation.hashCode(word);
-}
-public String toString(){
-	StringBuffer buffer = new StringBuffer(word.length * 2);
-	buffer.append("EntryResult: word="); //$NON-NLS-1$
-	buffer.append(word);
-	buffer.append(", refs={"); //$NON-NLS-1$
-	for (int i = 0; i < fileRefs.length; i++){
-		if (i > 0) buffer.append(',');
-		buffer.append(' ');
-		buffer.append(fileRefs[i]);
-	}
-	buffer.append(" }"); //$NON-NLS-1$
-	return buffer.toString();
-}
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/Field.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/Field.java
deleted file mode 100644
index 96111ff..0000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/Field.java
+++ /dev/null
@@ -1,380 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.io.UTFDataFormatException;
-
-public class Field {
-	protected byte[] buffer; // contents
-	protected int offset; // offset of the field within the byte array
-	protected int length; // length of the field
-
-	/**
-	 * ByteSegment constructor comment.
-	 */
-	public Field(byte[] bytes) {
-		this.buffer= bytes;
-		this.offset= 0;
-		this.length= bytes.length;
-	}
-	/**
-	 * ByteSegment constructor comment.
-	 */
-	public Field(byte[] bytes, int length) {
-		this.buffer= bytes;
-		this.offset= 0;
-		this.length= length;
-	}
-	/**
-	 * ByteSegment constructor comment.
-	 */
-	public Field(byte[] bytes, int offset, int length) {
-		this.buffer= bytes;
-		this.offset= offset;
-		this.length= length;
-	}
-	/**
-	 * Creates a new field containing an empty buffer of the given length.
-	 */
-	public Field(int length) {
-		this.buffer= new byte[length];
-		this.offset= 0;
-		this.length= length;
-	}
-	public byte[] buffer() {
-		return buffer;
-	}
-	public Field buffer(byte[] someBuffer) {
-		this.buffer= someBuffer;
-		return this;
-	}
-	public Field clear() {
-		clear(buffer, offset, length);
-		return this;
-	}
-	protected static void clear(byte[] buffer, int offset, int length) {
-		int n= offset;
-		for (int i= 0; i < length; i++) {
-			buffer[n]= 0;
-			n++;
-		}
-	}
-	public Field clear(int someLength) {
-		clear(buffer, offset, someLength);
-		return this;
-	}
-	public Field clear(int someOffset, int someLength) {
-		clear(buffer, this.offset + someOffset, someLength);
-		return this;
-	}
-	protected static int compare(byte[] buffer1, int offset1, int length1, byte[] buffer2, int offset2, int length2) {
-		int n= Math.min(length1, length2);
-		for (int i= 0; i < n; i++) {
-			int j1= buffer1[offset1 + i] & 255;
-			int j2= buffer2[offset2 + i] & 255;
-			if (j1 > j2)
-				return 1;
-			if (j1 < j2)
-				return -1;
-		}
-		if (length1 > n) {
-			for (int i= n; i < length1; i++)
-				if (buffer1[offset1 + i] != 0)
-					return 1;
-			return 0;
-		}
-		for (int i= n; i < length2; i++)
-			if (buffer2[offset2 + i] != 0)
-				return -1;
-		return 0;
-	}
-	public static int compare(Field f1, Field f2) {
-		return compare(f1.buffer, f1.offset, f1.length, f2.buffer, f2.offset, f2.length);
-	}
-	// copy bytes from one offset to another within the field
-	public Field copy(int fromOffset, int toOffset, int someLength) {
-		System.arraycopy(buffer, offset + fromOffset, buffer, offset + toOffset, someLength);
-		return this;
-	}
-	public Field dec(int n) {
-		offset -= n;
-		return this;
-	}
-	public byte[] get() {
-		byte[] result= new byte[length];
-		System.arraycopy(buffer, offset, result, 0, length);
-		return result;
-	}
-	public byte[] get(int someOffset, int someLength) {
-		byte[] result= new byte[someLength];
-		System.arraycopy(buffer, this.offset + someOffset, result, 0, someLength);
-		return result;
-	}
-	public Field getField(int someOffset, int someLength) {
-		return new Field(buffer, this.offset + someOffset, someLength);
-	}
-	public int getInt1() {
-		return buffer[this.offset];
-	}
-	public int getInt1(int someOffset) {
-		return buffer[this.offset + someOffset];
-	}
-	public int getInt2() {
-		int i= this.offset;
-		int v= buffer[i++];
-		v= (v << 8) | (buffer[i++] & 255);
-		return v;
-	}
-	public int getInt2(int someOffset) {
-		int i= this.offset + someOffset;
-		int v= buffer[i++];
-		v= (v << 8) | (buffer[i++] & 255);
-		return v;
-	}
-	public int getInt3() {
-		int i= this.offset;
-		int v= buffer[i++];
-		v= (v << 8) | (buffer[i++] & 255);
-		v= (v << 8) | (buffer[i++] & 255);
-		return v;
-	}
-	public int getInt3(int someOffset) {
-		int i= this.offset + someOffset;
-		int v= buffer[i++];
-		v= (v << 8) | (buffer[i++] & 255);
-		v= (v << 8) | (buffer[i++] & 255);
-		return v;
-	}
-	public int getInt4() {
-		int i= this.offset;
-		int v= buffer[i++];
-		v= (v << 8) | (buffer[i++] & 255);
-		v= (v << 8) | (buffer[i++] & 255);
-		v= (v << 8) | (buffer[i++] & 255);
-		return v;
-	}
-	public int getInt4(int someOffset) {
-		int i= this.offset + someOffset;
-		int v= buffer[i++];
-		v= (v << 8) | (buffer[i++] & 255);
-		v= (v << 8) | (buffer[i++] & 255);
-		v= (v << 8) | (buffer[i++] & 255);
-		return v;
-	}
-	public int getUInt1() {
-		return buffer[this.offset] & 255;
-	}
-	public int getUInt1(int someOffset) {
-		return buffer[this.offset + someOffset] & 255;
-	}
-	public int getUInt2() {
-		int i= this.offset;
-		int v= (buffer[i++] & 255);
-		v= (v << 8) | (buffer[i++] & 255);
-		return v;
-	}
-	public int getUInt2(int someOffset) {
-		int i= this.offset + someOffset;
-		int v= (buffer[i++] & 255);
-		v= (v << 8) | (buffer[i++] & 255);
-		return v;
-	}
-	public int getUInt3() {
-		int i= this.offset;
-		int v= (buffer[i++] & 255);
-		v= (v << 8) | (buffer[i++] & 255);
-		v= (v << 8) | (buffer[i++] & 255);
-		return v;
-	}
-	public int getUInt3(int someOffset) {
-		int i= this.offset + someOffset;
-		int v= (buffer[i++] & 255);
-		v= (v << 8) | (buffer[i++] & 255);
-		v= (v << 8) | (buffer[i++] & 255);
-		return v;
-	}
-	public char[] getUTF(int someOffset) throws UTFDataFormatException {
-		int pos= this.offset + someOffset;
-		int utflen= getUInt2(pos);
-		pos += 2;
-		char str[]= new char[utflen];
-		int count= 0;
-		int strlen= 0;
-		while (count < utflen) {
-			int c= buffer[pos++] & 0xFF;
-			int char2, char3;
-			switch (c >> 4) {
-				case 0 :
-				case 1 :
-				case 2 :
-				case 3 :
-				case 4 :
-				case 5 :
-				case 6 :
-				case 7 :
-					// 0xxxxxxx
-					count++;
-					str[strlen++]= (char) c;
-					break;
-				case 12 :
-				case 13 :
-					// 110x xxxx   10xx xxxx
-					count += 2;
-					if (count > utflen)
-						throw new UTFDataFormatException();
-					char2= buffer[pos++] & 0xFF;
-					if ((char2 & 0xC0) != 0x80)
-						throw new UTFDataFormatException();
-					str[strlen++]= (char) (((c & 0x1F) << 6) | (char2 & 0x3F));
-					break;
-				case 14 :
-					// 1110 xxxx  10xx xxxx  10xx xxxx
-					count += 3;
-					if (count > utflen)
-						throw new UTFDataFormatException();
-					char2= buffer[pos++] & 0xFF;
-					char3= buffer[pos++] & 0xFF;
-					if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
-						throw new UTFDataFormatException();
-					str[strlen++]= (char) (((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0));
-					break;
-				default :
-					// 10xx xxxx,  1111 xxxx
-					throw new UTFDataFormatException();
-			}
-		}
-		if (strlen < utflen)
-			System.arraycopy(str, 0, str= new char[strlen], 0, strlen);
-		return str;
-	}
-	public Field inc(int n) {
-		offset += n;
-		return this;
-	}
-	public int length() {
-		return length;
-	}
-	public Field length(int someLength) {
-		this.length= someLength;
-		return this;
-	}
-	/**
-	Returns the offset into the underlying byte array that this field is defined over.
-	*/
-	public int offset() {
-		return offset;
-	}
-	public Field offset(int someOffset) {
-		this.offset= someOffset;
-		return this;
-	}
-	public Field pointTo(int someOffset) {
-		return new Field(buffer, this.offset + someOffset, 0);
-	}
-	public Field put(byte[] b) {
-		return put(0, b);
-	}
-	public Field put(int someOffset, byte[] b) {
-		System.arraycopy(b, 0, buffer, this.offset + someOffset, b.length);
-		return this;
-	}
-	public Field put(int someOffset, Field f) {
-		System.arraycopy(f.buffer, f.offset, buffer, this.offset + someOffset, f.length);
-		return this;
-	}
-	public Field put(Field f) {
-		System.arraycopy(f.buffer, f.offset, buffer, offset, f.length);
-		return this;
-	}
-	public Field putInt1(int n) {
-		buffer[offset]= (byte) (n);
-		return this;
-	}
-	public Field putInt1(int someOffset, int n) {
-		buffer[this.offset + someOffset]= (byte) (n);
-		return this;
-	}
-	public Field putInt2(int n) {
-		int i= offset;
-		buffer[i++]= (byte) (n >> 8);
-		buffer[i++]= (byte) (n >> 0);
-		return this;
-	}
-	public Field putInt2(int someOffset, int n) {
-		int i= this.offset + someOffset;
-		buffer[i++]= (byte) (n >> 8);
-		buffer[i++]= (byte) (n >> 0);
-		return this;
-	}
-	public Field putInt3(int n) {
-		int i= offset;
-		buffer[i++]= (byte) (n >> 16);
-		buffer[i++]= (byte) (n >> 8);
-		buffer[i++]= (byte) (n >> 0);
-		return this;
-	}
-	public Field putInt3(int someOffset, int n) {
-		int i= this.offset + someOffset;
-		buffer[i++]= (byte) (n >> 16);
-		buffer[i++]= (byte) (n >> 8);
-		buffer[i++]= (byte) (n >> 0);
-		return this;
-	}
-	public Field putInt4(int n) {
-		int i= offset;
-		buffer[i++]= (byte) (n >> 24);
-		buffer[i++]= (byte) (n >> 16);
-		buffer[i++]= (byte) (n >> 8);
-		buffer[i++]= (byte) (n >> 0);
-		return this;
-	}
-	public Field putInt4(int someOffset, int n) {
-		int i= this.offset + someOffset;
-		buffer[i++]= (byte) (n >> 24);
-		buffer[i++]= (byte) (n >> 16);
-		buffer[i++]= (byte) (n >> 8);
-		buffer[i++]= (byte) (n >> 0);
-		return this;
-	}
-	public int putUTF(int someOffset, char[] str) {
-		int strlen= str.length;
-		int utflen= 0;
-		for (int i= 0; i < strlen; i++) {
-			int c= str[i];
-			if ((c >= 0x0001) && (c <= 0x007F)) {
-				utflen++;
-			} else if (c > 0x07FF) {
-				utflen += 3;
-			} else {
-				utflen += 2;
-			}
-		}
-		if (utflen > 65535)
-			throw new IllegalArgumentException();
-		int pos= this.offset + someOffset;
-		buffer[pos++]= (byte) ((utflen >>> 8) & 0xFF);
-		buffer[pos++]= (byte) ((utflen >>> 0) & 0xFF);
-		for (int i= 0; i < strlen; i++) {
-			int c= str[i];
-			if ((c >= 0x0001) && (c <= 0x007F)) {
-				buffer[pos++]= ((byte) c);
-			} else if (c > 0x07FF) {
-				buffer[pos++]= ((byte) (0xE0 | ((c >> 12) & 0x0F)));
-				buffer[pos++]= ((byte) (0x80 | ((c >> 6) & 0x3F)));
-				buffer[pos++]= ((byte) (0x80 | ((c >> 0) & 0x3F)));
-			} else {
-				buffer[pos++]= ((byte) (0xC0 | ((c >> 6) & 0x1F)));
-				buffer[pos++]= ((byte) (0x80 | ((c >> 0) & 0x3F)));
-			}
-		}
-		return 2 + utflen;
-	}
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/FileListBlock.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/FileListBlock.java
deleted file mode 100644
index cf31639..0000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/FileListBlock.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.io.IOException;
-import java.util.ArrayList;
-
-import org.eclipse.jdt.internal.core.util.Util;
-
-public class FileListBlock extends Block {
-
-	protected int offset= 0;
-	protected String prevPath= null;
-	protected String[] paths= null;
-
-	public FileListBlock(int blockSize) {
-		super(blockSize);
-	}
-	/**
-	 * add the name of the indexedfile to the buffr of the field. 
-	 * The name is not the entire name of the indexedfile, but the 
-	 * difference between its name and the name of the previous indexedfile ...	
-	 */
-	public boolean addFile(IndexedFile indexedFile) {
-		int currentOffset= this.offset;
-		if (isEmpty()) {
-			field.putInt4(currentOffset, indexedFile.getFileNumber());
-			currentOffset += 4;
-		}
-		String path= indexedFile.getPath();
-		int prefixLen= prevPath == null ? 0 : Util.prefixLength(prevPath, path);
-		int sizeEstimate= 2 + 2 + (path.length() - prefixLen) * 3;
-		if (currentOffset + sizeEstimate > blockSize - 2)
-			return false;
-		field.putInt2(currentOffset, prefixLen);
-		currentOffset += 2;
-		char[] chars= new char[path.length() - prefixLen];
-		path.getChars(prefixLen, path.length(), chars, 0);
-		currentOffset += field.putUTF(currentOffset, chars);
-		this.offset= currentOffset;
-		prevPath= path;
-		return true;
-	}
-	public void clear() {
-		reset();
-		super.clear();
-	}
-	public void flush() {
-		if (offset > 0) {
-			field.putInt2(offset, 0);
-			field.putInt2(offset + 2, 0);
-			offset= 0;
-		}
-	}
-	public IndexedFile getFile(int fileNum) {
-		IndexedFile resp= null;
-		try {
-			String[] currentPaths = getPaths();
-			int i= fileNum - field.getInt4(0);
-			resp= new IndexedFile(currentPaths[i], fileNum);
-		} catch (Exception e) {
-			//fileNum too big
-		}
-		return resp;
-	}
-	/**
-	 * Creates a vector of paths reading the buffer of the field.
-	 */
-	protected String[] getPaths() throws IOException {
-		if (paths == null) {
-			ArrayList v= new ArrayList();
-			int currentOffset = 4;
-			char[] previousPath = null;
-			for (;;) {
-				int prefixLen= field.getUInt2(currentOffset);
-				currentOffset += 2;
-				int utfLen= field.getUInt2(currentOffset);
-				char[] path= field.getUTF(currentOffset);
-				currentOffset += 2 + utfLen;
-				if (prefixLen != 0) {
-					char[] temp= new char[prefixLen + path.length];
-					System.arraycopy(previousPath, 0, temp, 0, prefixLen);
-					System.arraycopy(path, 0, temp, prefixLen, path.length);
-					path= temp;
-				}
-				if (path.length == 0)
-					break;
-				v.add(new String(path));
-				previousPath= path;
-			}
-			paths= new String[v.size()];
-			v.toArray(paths);
-		}
-		return paths;
-	}
-	public boolean isEmpty() {
-		return offset == 0;
-	}
-	public void reset() {
-		offset= 0;
-		prevPath= null;
-	}
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/GammaCompressedIndexBlock.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/GammaCompressedIndexBlock.java
deleted file mode 100644
index d2d1183..0000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/GammaCompressedIndexBlock.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.io.UTFDataFormatException;
-
-import org.eclipse.jdt.internal.core.util.Util;
-
-/**
- * Uses prefix coding on words, and gamma coding of document numbers differences.
- */
-public class GammaCompressedIndexBlock extends IndexBlock {
-	CodeByteStream writeCodeStream= new CodeByteStream();
-	CodeByteStream readCodeStream;
-	char[] prevWord= null;
-	int offset= 0;
-
-	public GammaCompressedIndexBlock(int blockSize) {
-		super(blockSize);
-		readCodeStream= new CodeByteStream(field.buffer());
-	}
-	/**
-	 * @see IndexBlock#addEntry
-	 */
-	public boolean addEntry(WordEntry entry) {
-		writeCodeStream.reset();
-		encodeEntry(entry);
-		if (offset + writeCodeStream.byteLength() > this.blockSize - 2) {
-			return false;
-		}
-		byte[] bytes= writeCodeStream.toByteArray();
-		field.put(offset, bytes);
-		offset += bytes.length;
-		prevWord= entry.getWord();
-		return true;
-	}
-	private void encodeEntry(WordEntry entry) {
-		char[] word= entry.getWord();
-		int prefixLen= prevWord == null ? 0 : Util.prefixLength(prevWord, word);
-		writeCodeStream.writeByte(prefixLen);
-		writeCodeStream.writeUTF(word, prefixLen, word.length);
-		int n= entry.getNumRefs();
-		writeCodeStream.writeGamma(n);
-		int prevRef= 0;
-		for (int i= 0; i < n; ++i) {
-			int ref= entry.getRef(i);
-			if (ref <= prevRef)
-				throw new IllegalArgumentException();
-			writeCodeStream.writeGamma(ref - prevRef);
-			prevRef= ref;
-		}
-	}
-	/**
-	 * @see IndexBlock#flush
-	 */
-	public void flush() {
-		if (offset > 0) {
-			field.putInt2(offset, 0);
-			offset= 0;
-			prevWord= null;
-		}
-	}
-	/**
-	 * @see IndexBlock#isEmpty
-	 */
-	public boolean isEmpty() {
-		return offset == 0;
-	}
-	/**
-	 * @see IndexBlock#nextEntry
-	 */
-	public boolean nextEntry(WordEntry entry) {
-		try {
-			readCodeStream.reset(field.buffer(), offset);
-			int prefixLength= readCodeStream.readByte();
-			char[] word= readCodeStream.readUTF();
-			if (prevWord != null && prefixLength > 0) {
-				char[] temp= new char[prefixLength + word.length];
-				System.arraycopy(prevWord, 0, temp, 0, prefixLength);
-				System.arraycopy(word, 0, temp, prefixLength, word.length);
-				word= temp;
-			}
-			if (word.length == 0) {
-				return false;
-			}
-			entry.reset(word);
-			int n= readCodeStream.readGamma();
-			int prevRef= 0;
-			for (int i= 0; i < n; ++i) {
-				int ref= prevRef + readCodeStream.readGamma();
-				if (ref < prevRef)
-					throw new InternalError();
-				entry.addRef(ref);
-				prevRef= ref;
-			}
-			offset= readCodeStream.byteLength();
-			prevWord= word;
-			return true;
-		} catch (UTFDataFormatException e) {
-			return false;
-		}
-	}
-	/**
-	 * @see IndexBlock#reset
-	 */
-	public void reset() {
-		super.reset();
-		offset= 0;
-		prevWord= null;
-	}
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/ICacheEnumeration.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/ICacheEnumeration.java
deleted file mode 100644
index 7e2eeb5..0000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/ICacheEnumeration.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.util.Enumeration;
-
-/**
- * The <code>ICacheEnumeration</code> is used to iterate over both the keys 
- * and values in an LRUCache.  The <code>getValue()</code> method returns the 
- * value of the last key to be retrieved using <code>nextElement()</code>.  
- * The <code>nextElement()</code> method must be called before the 
- * <code>getValue()</code> method.
- *
- * <p>The iteration can be made efficient by making use of the fact that values in 
- * the cache (instances of <code>LRUCacheEntry</code>), know their key.  For this reason,
- * Hashtable lookups don't have to be made at each step of the iteration.
- *
- * <p>Modifications to the cache must not be performed while using the
- * enumeration.  Doing so will lead to an illegal state.
- *
- * @see LRUCache
- */
-public interface ICacheEnumeration extends Enumeration {
-	/**
-	 * Returns the value of the previously accessed key in the enumeration.
-	 * Must be called after a call to nextElement().
-	 *
-	 * @return Value of current cache entry
-	 */
-	public Object getValue();
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IIndexConstants.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IIndexConstants.java
deleted file mode 100644
index 182c847..0000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IIndexConstants.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-/**
- * This interface provides constants used by the search engine.
- */
-public interface IIndexConstants {
-	/**
-	 * The signature of the index file.
-	 */
-	public static final String SIGNATURE= "INDEX FILE 0.016"; //$NON-NLS-1$
-	/**
-	 * The separator for files in the index file.
-	 */
-	public static final char FILE_SEPARATOR= '/';
-	/**
-	 * The size of a block for a <code>Block</code>.
-	 */
-	public static final int BLOCK_SIZE= 8192;
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/ILRUCacheable.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/ILRUCacheable.java
deleted file mode 100644
index f5eb42b..0000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/ILRUCacheable.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-/**
- * Types implementing this interface can occupy a variable amount of space
- * in an LRUCache.  Cached items that do not implement this interface are
- * considered to occupy one unit of space.
- *
- * @see LRUCache
- */
-public interface ILRUCacheable {
-	/**
-	 * Returns the space the receiver consumes in an LRU Cache.  The default space
-	 * value is 1.
-	 *
-	 * @return int Amount of cache space taken by the receiver
-	 */
-	public int getCacheFootprint();
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/InMemoryIndex.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/InMemoryIndex.java
deleted file mode 100644
index 7b6ee0d..0000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/InMemoryIndex.java
+++ /dev/null
@@ -1,206 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.io.File;
-import java.io.IOException;
-
-import org.eclipse.jdt.core.search.SearchDocument;
-import org.eclipse.jdt.internal.core.util.Util;
-
-/**
- * This index stores the document names in an <code>ObjectVector</code>, and the words in
- * an <code>HashtableOfObjects</code>.
- */
-
-public class InMemoryIndex {
-
-	/**
-	 * hashtable of WordEntrys = words+numbers of the files they appear in.
-	 */
-	protected WordEntryHashedArray words;
-
-	/**
-	 * List of IndexedFiles = file name + a unique number.
-	 */
-	protected IndexedFileHashedArray files;
-
-	/**
-	 * Size of the index.
-	 */
-	protected long footprint;
-
-	private WordEntry[] sortedWordEntries;
-	private IndexedFile[] sortedFiles;
-	public InMemoryIndex() {
-		init();
-	}
-
-	public IndexedFile addDocument(SearchDocument document) {
-		IndexedFile indexedFile= this.files.add(document);
-		this.footprint += indexedFile.footprint() + 4;
-		this.sortedFiles = null;
-		return indexedFile;
-	}
-	/**
-	 * Adds the references of the word to the index (reference = number of the file the word belongs to).
-	 */
-	protected void addRef(char[] word, int[] references) {
-		int size= references.length;
-		int i= 0;
-		while (i < size) {
-			if (references[i] != 0)
-				addRef(word, references[i]);
-			i++;
-		}
-	}
-	/**
-	 * Looks if the word already exists in the index and add the fileNum to this word.
-	 * If the word does not exist, it adds it in the index.
-	 */
-	protected void addRef(char[] word, int fileNum) {
-		WordEntry entry= this.words.get(word);
-		if (entry == null) {
-			entry= new WordEntry(word);
-			entry.addRef(fileNum);
-			this.words.add(entry);
-			this.sortedWordEntries= null;
-			this.footprint += entry.footprint();
-		} else {
-			this.footprint += entry.addRef(fileNum);
-		}
-	}
-
-	public void addRef(IndexedFile indexedFile, char[] word) {
-		addRef(word, indexedFile.getFileNumber());
-	}
-
-	public void addRef(IndexedFile indexedFile, String word) {
-		addRef(word.toCharArray(), indexedFile.getFileNumber());
-	}
-
-	/**
-	 * Returns the footprint of the index.
-	 */
-	public long getFootprint() {
-		return this.footprint;
-	}
-
-	/**
-	 * Returns the indexed file with the given path, or null if such file does not exist.
-	 */
-	public IndexedFile getIndexedFile(String path) {
-		return files.get(path);
-	}
-
-	/**
-	 * @see IIndex#getNumDocuments()
-	 */
-	public int getNumFiles() {
-		return files.size();
-	}
-
-	/**
-	 * @see IIndex#getNumWords()
-	 */
-	public int getNumWords() {
-		return words.elementSize;
-	}
-	
-	/**
-	 * Returns the words contained in the hashtable of words, sorted by alphabetical order.
-	 */
-	protected IndexedFile[] getSortedFiles() {
-		if (this.sortedFiles == null) {
-			IndexedFile[] indexedFiles= files.asArray();
-			Util.sort(indexedFiles);
-			this.sortedFiles= indexedFiles;
-		}
-		return this.sortedFiles;
-	}
-	/**
-	 * Returns the word entries contained in the hashtable of words, sorted by alphabetical order.
-	 */
-	protected WordEntry[] getSortedWordEntries() {
-		if (this.sortedWordEntries == null) {
-			WordEntry[] wordEntries= this.words.asArray();
-			Util.sort(wordEntries);
-			this.sortedWordEntries= wordEntries;
-		}
-		return this.sortedWordEntries;
-	}
-	/**
-	 * Returns the word entry corresponding to the given word.
-	 */
-	protected WordEntry getWordEntry(char[] word) {
-		return words.get(word);
-	}
-	/**
-	 * Initialises the fields of the index
-	 */
-	public void init() {
-		words= new WordEntryHashedArray(501);
-		files= new IndexedFileHashedArray(101);
-		footprint= 0;
-		sortedWordEntries= null;
-		sortedFiles= null;
-	}
-	/**
-	 * Saves the index in the given file.
-	 * Structure of the saved Index :
-	 *   - IndexedFiles in sorted order.
-	 *		+ example: 
-	 *			"c:/com/Test.java 1"
-	 *			"c:/com/UI.java 2"
-	 *   - References with the words in sorted order
-	 *		+ example: 
-	 *			"classDecl/Test 1"
-	 *			"classDecl/UI 2"
-	 *			"ref/String 1 2"
-	 */
-
-	public void save(File file) throws IOException {
-		BlocksIndexOutput output= new BlocksIndexOutput(file);
-		save(output);
-	}
-	/**
-	 * Saves the index in the given IndexOutput.
-	 * Structure of the saved Index :
-	 *   - IndexedFiles in sorted order.
-	 *		+ example: 
-	 *			"c:/com/Test.java 1"
-	 *			"c:/com/UI.java 2"
-	 *   - References with the words in sorted order
-	 *		+ example: 
-	 *			"classDecl/Test 1"
-	 *			"classDecl/UI 2"
-	 *			"ref/String 1 2"
-	 */
-
-	protected void save(IndexOutput output) throws IOException {
-		boolean ok= false;
-		try {
-			output.open();
-			IndexedFile[] indexedFiles= files.asArray();
-			for (int i= 0, length = indexedFiles.length; i < length; ++i)
-				output.addFile(indexedFiles[i]); // written out in order BUT not alphabetical
-			getSortedWordEntries(); // init the slot
-			for (int i= 0, numWords= sortedWordEntries.length; i < numWords; ++i)
-				output.addWord(sortedWordEntries[i]);
-			output.flush();
-			output.close();
-			ok= true;
-		} finally {
-			if (!ok && output != null)
-				output.close();
-		}
-	}
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/Index.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/Index.java
deleted file mode 100644
index bf653c5..0000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/Index.java
+++ /dev/null
@@ -1,335 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.eclipse.jdt.core.search.SearchDocument;
-import org.eclipse.jdt.internal.core.index.IIndex;
-import org.eclipse.jdt.internal.core.index.IIndexer;
-
-/**
- * An Index is used to create an index on the disk, and to make queries. It uses a set of 
- * indexers and a mergeFactory. The index fills an inMemoryIndex up 
- * to it reaches a certain size, and then merges it with a main index on the disk.
- * <br> <br>
- * The changes are only taken into account by the queries after a merge.
- */
-
-public class Index implements IIndex {
-	/**
-	 * Maximum size of the index in memory.
-	 */
-	public static final int MAX_FOOTPRINT= 10000000;
-
-	/**
-	 * Index in memory, who is merged with mainIndex each times it 
-	 * reaches a certain size.
-	 */
-	protected InMemoryIndex addsIndex;
-	protected IndexInput addsIndexInput;
-
-	/**
-	 * State of the indexGenerator: addsIndex empty <=> MERGED, or
-	 * addsIndex not empty <=> CAN_MERGE
-	 */
-	protected int state;
-
-	/**
-	 * Files removed form the addsIndex.
-	 */
-	protected Map removedInAdds;
-
-	/**
-	 * Files removed form the oldIndex.
-	 */
-	protected Map removedInOld;
-	protected static final int CAN_MERGE= 0;
-	protected static final int MERGED= 1;
-	private File indexFile;
-
-	/**
-	 * String representation of this index.
-	 */
-	public String toString;
-	public Index(File indexDirectory, boolean reuseExistingFile) throws IOException {
-		this(indexDirectory,".index", reuseExistingFile); //$NON-NLS-1$
-	}
-	public Index(File indexDirectory, String indexName, boolean reuseExistingFile) throws IOException {
-		super();
-		state= MERGED;
-		indexFile= new File(indexDirectory, indexName);
-		initialize(reuseExistingFile);
-	}
-	public Index(String indexName, boolean reuseExistingFile) throws IOException {
-		this(indexName, null, reuseExistingFile);
-	}
-	public Index(String indexName, String toString, boolean reuseExistingFile) throws IOException {
-		super();
-		state= MERGED;
-		indexFile= new File(indexName);
-		this.toString = toString;
-		initialize(reuseExistingFile);
-	}
-	/**
-	 * Indexes the given document, using the appropriate indexer registered in the indexerRegistry.
-	 * If the document already exists in the index, it overrides the previous one. The changes will be 
-	 * taken into account after a merge.
-	 */
-	public void add(SearchDocument document, IIndexer indexer) throws IOException {
-		if (timeToMerge()) {
-			merge();
-		}
-		IndexedFile indexedFile= addsIndex.getIndexedFile(document.getPath());
-		if (indexedFile != null /*&& removedInAdds.get(document.getName()) == null*/
-			)
-			remove(indexedFile, MergeFactory.ADDS_INDEX);
-		IndexerOutput output= new IndexerOutput(addsIndex);
-		indexer.index(document, output);
-		state= CAN_MERGE;
-	}
-	/**
-	 * Returns true if the index in memory is not empty, so 
-	 * merge() can be called to fill the mainIndex with the files and words
-	 * contained in the addsIndex. 
-	 */
-	protected boolean canMerge() {
-		return state == CAN_MERGE;
-	}
-	/**
-	 * Initialises the indexGenerator.
-	 */
-//	public void empty() throws IOException {
-//
-//		if (indexFile.exists()){
-//			indexFile.delete();
-//			//initialisation of mainIndex
-//			InMemoryIndex mainIndex= new InMemoryIndex();
-//			IndexOutput mainIndexOutput= new BlocksIndexOutput(indexFile);
-//			if (!indexFile.exists())
-//				mainIndex.save(mainIndexOutput);
-//		}
-//
-//		//initialisation of addsIndex
-//		addsIndex= new InMemoryIndex();
-//		addsIndexInput= new SimpleIndexInput(addsIndex);
-//
-//		//vectors who keep track of the removed Files
-//		removedInAdds= new HashMap(11);
-//		removedInOld= new HashMap(11);
-//	}
-	/**
-	 * @see IIndex#getIndexFile
-	 */
-	public File getIndexFile() {
-		return indexFile;
-	}
-	/**
-	 * Returns the path corresponding to a given document number
-	 */
-	public String getPath(int documentNumber) throws IOException {
-		//save();
-		IndexInput input= new BlocksIndexInput(indexFile);
-		try {
-			input.open();
-			IndexedFile file = input.getIndexedFile(documentNumber);
-			if (file == null) return null;
-			return file.getPath();
-		} finally {
-			input.close();
-		}		
-	}
-	/**
-	 * see IIndex.hasChanged
-	 */
-	public boolean hasChanged() {
-		return canMerge();
-	}
-	/**
-	 * Initialises the indexGenerator.
-	 */
-	public void initialize(boolean reuseExistingFile) throws IOException {
-		
-		//initialisation of addsIndex
-		addsIndex= new InMemoryIndex();
-		addsIndexInput= new SimpleIndexInput(addsIndex);
-
-		//vectors who keep track of the removed Files
-		removedInAdds= new HashMap(11);
-		removedInOld= new HashMap(11);
-
-		// check whether existing index file can be read
-		if (reuseExistingFile && indexFile.exists()) {
-			IndexInput mainIndexInput= new BlocksIndexInput(indexFile);
-			try {
-				mainIndexInput.open();
-			} catch(IOException e) {
-				BlocksIndexInput input = (BlocksIndexInput)mainIndexInput;
-				try {
-					input.opened = true;
-					input.close();
-				} finally {
-					input.opened = false;
-				}
-				indexFile.delete();
-				mainIndexInput = null;
-				throw e;
-			}
-			mainIndexInput.close();
-		} else {
-			InMemoryIndex mainIndex= new InMemoryIndex();			
-			IndexOutput mainIndexOutput= new BlocksIndexOutput(indexFile);
-			mainIndex.save(mainIndexOutput);
-		}
-	}
-	/**
-	 * Merges the in memory index and the index on the disk, and saves the results on the disk.
-	 */
-	protected void merge() throws IOException {
-		//System.out.println("merge");
-
-		//initialisation of tempIndex
-		File tempFile= new File(indexFile.getAbsolutePath() + "TempVA"); //$NON-NLS-1$
-
-		IndexInput mainIndexInput= new BlocksIndexInput(indexFile);
-		BlocksIndexOutput tempIndexOutput= new BlocksIndexOutput(tempFile);
-
-		try {
-			//invoke a mergeFactory
-			new MergeFactory(
-				mainIndexInput, 
-				addsIndexInput, 
-				tempIndexOutput, 
-				removedInOld, 
-				removedInAdds).merge();
-			
-			//rename the file created to become the main index
-			File mainIndexFile= (File) mainIndexInput.getSource();
-			File tempIndexFile= (File) tempIndexOutput.getDestination();
-			mainIndexFile.delete();
-			tempIndexFile.renameTo(mainIndexFile);
-		} finally {		
-			//initialise remove vectors and addsindex, and change the state
-			removedInAdds.clear();
-			removedInOld.clear();
-			addsIndex.init();
-			addsIndexInput= new SimpleIndexInput(addsIndex);
-			state= MERGED;
-		}
-	}
-	/**
-	 * @see IIndex#query
-	 */
-	public String[] query(String word) throws IOException {
-		//save();
-		IndexInput input= new BlocksIndexInput(indexFile);
-		try {
-			return input.query(word);
-		} finally {
-			input.close();
-		}
-	}
-	public EntryResult[] queryEntries(char[] prefix) throws IOException {
-		//save();
-		IndexInput input= new BlocksIndexInput(indexFile);
-		try {
-			return input.queryEntriesPrefixedBy(prefix);
-		} finally {
-			input.close();
-		}
-	}
-	/**
-	 * @see IIndex#queryInDocumentNames
-	 */
-	public String[] queryInDocumentNames(String word) throws IOException {
-		//save();
-		IndexInput input= new BlocksIndexInput(indexFile);
-		try {
-			return input.queryInDocumentNames(word);
-		} finally {
-			input.close();
-		}
-	}
-	/**
-	 * @see IIndex#queryPrefix
-	 */
-	public String[] queryPrefix(char[] prefix) throws IOException {
-		//save();
-		IndexInput input= new BlocksIndexInput(indexFile);
-		try {
-			return input.queryFilesReferringToPrefix(prefix);
-		} finally {
-			input.close();
-		}
-	}
-	/**
-	 * @see IIndex#remove
-	 */
-	public void remove(String documentName) {
-		IndexedFile file= addsIndex.getIndexedFile(documentName);
-		if (file != null) {
-			//the file is in the adds Index, we remove it from this one
-			Int lastRemoved= (Int) removedInAdds.get(documentName);
-			if (lastRemoved != null) {
-				int fileNum= file.getFileNumber();
-				if (lastRemoved.value < fileNum)
-					lastRemoved.value= fileNum;
-			} else
-				removedInAdds.put(documentName, new Int(file.getFileNumber()));
-		} else {
-			//we remove the file from the old index
-			removedInOld.put(documentName, new Int(1));
-		}
-		state= CAN_MERGE;
-	}
-	/**
-	 * Removes the given document from the given index (MergeFactory.ADDS_INDEX for the
-	 * in memory index, MergeFactory.OLD_INDEX for the index on the disk).
-	 */
-	protected void remove(IndexedFile file, int index) {
-		String name= file.getPath();
-		if (index == MergeFactory.ADDS_INDEX) {
-			Int lastRemoved= (Int) removedInAdds.get(name);
-			if (lastRemoved != null) {
-				if (lastRemoved.value < file.getFileNumber())
-					lastRemoved.value= file.getFileNumber();
-			} else
-				removedInAdds.put(name, new Int(file.getFileNumber()));
-		} else if (index == MergeFactory.OLD_INDEX)
-			removedInOld.put(name, new Int(1));
-		else
-			throw new Error();
-		state= CAN_MERGE;
-	}
-	/**
-	 * @see IIndex#save
-	 */
-	public void save() throws IOException {
-		if (canMerge())
-			merge();
-	}
-	/**
-	 * Returns true if the in memory index reaches a critical size, 
-	 * to merge it with the index on the disk.
-	 */
-	protected boolean timeToMerge() {
-		return (addsIndex.getFootprint() >= MAX_FOOTPRINT);
-	}
-public String toString() {
-	String str = this.toString;
-	if (str == null) str = super.toString();
-	str += "(length: "+ getIndexFile().length() +")"; //$NON-NLS-1$ //$NON-NLS-2$
-	return str;
-}
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexBlock.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexBlock.java
deleted file mode 100644
index a6665db..0000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexBlock.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import org.eclipse.jdt.core.compiler.CharOperation;
-
-/**
- * An indexBlock stores wordEntries.
- */
-
-public abstract class IndexBlock extends Block {
-
-	public IndexBlock(int blockSize) {
-		super(blockSize);
-	}
-	/**
-	 * Adds the given wordEntry to the indexBlock.
-	 */
-
-	public abstract boolean addEntry(WordEntry entry);
-	/**
-	 * @see Block#clear()
-	 */
-	public void clear() {
-		reset();
-		super.clear();
-	}
-	public WordEntry findEntryMatching(char[] pattern, boolean isCaseSensitive) {
-		reset();
-		WordEntry entry= new WordEntry();
-		while (nextEntry(entry)) {
-			if (CharOperation.match(pattern, entry.getWord(), isCaseSensitive)) {
-				return entry;
-			}
-		}
-		return null;
-	}
-	public WordEntry findEntryPrefixedBy(char[] word, boolean isCaseSensitive) {
-		reset();
-		WordEntry entry= new WordEntry();
-		while (nextEntry(entry)) {
-			if (CharOperation.prefixEquals(entry.getWord(), word, isCaseSensitive)) {
-				return entry;
-			}
-		}
-		return null;
-	}
-	public WordEntry findExactEntry(char[] word) {
-		reset();
-		WordEntry entry= new WordEntry();
-		while (nextEntry(entry)) {
-			if (CharOperation.equals(entry.getWord(), word)) {
-				return entry;
-			}
-		}
-		return null;
-	}
-	/**
-	 * Returns whether the block is empty or not (if it doesn't contain any wordEntry).
-	 */
-	public abstract boolean isEmpty();
-
-	/**
-	 * Finds the next wordEntry and stores it in the given entry.
-	 */
-	public abstract boolean nextEntry(WordEntry entry);
-
-	public void reset() {
-		// do nothing
-	}
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexInput.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexInput.java
deleted file mode 100644
index bae3eda..0000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexInput.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.io.IOException;
-
-import org.eclipse.jdt.core.search.SearchDocument;
-
-
-/**
- * This class provides an input on an index, after it has been generated.
- * You can access all the files of an index via getNextFile(), getCurrentFile() 
- * and moveToNextFile() (idem for the word entries). 
- * The usage is the same for every subclass: creation (constructor), opening
- * (the open() method), usage, and closing (the close() method), to release the
- * data source used by this input.
- */
-public abstract class IndexInput {
-	protected int filePosition;
-	protected WordEntry currentWordEntry;
-	protected int wordPosition;
-
-
-	public IndexInput() {
-		super();
-		wordPosition= 1;
-		filePosition= 1;
-	}
-	/**
-	 * clears the cache of this indexInput, if it keeps track of the information already read.
-	 */
-	public abstract void clearCache();
-	/**
-	 * Closes the IndexInput. For example, if the input is on a RandomAccessFile,
-	 * it calls the close() method of RandomAccessFile. 
-	 */
-	public abstract void close() throws IOException;
-	/**
-	 * Returns the current file the indexInput is pointing to in the index.
-	 */
-	public abstract IndexedFile getCurrentFile() throws IOException;
-	/**
-	 * Returns the current file the indexInput is pointing to in the index.
-	 */
-	public WordEntry getCurrentWordEntry() {
-		if (!hasMoreWords())
-			return null;
-		return currentWordEntry;
-	}
-	/**
-	 * Returns the position of the current file the input is pointing to in the index.
-	 */
-	public int getFilePosition() {
-		return filePosition;
-	}
-	/**
-	 * Returns the indexedFile corresponding to the given document number in the index the input
-	 * reads in, or null if such indexedFile does not exist.
-	 */
-	public abstract IndexedFile getIndexedFile(int fileNum) throws IOException;
-	/**
-	 * Returns the indexedFile corresponding to the given document in the index the input
-	 * reads in (e.g. the indexedFile with the same path in this index), or null if such 
-	 * indexedFile does not exist.
-	 */
-	public abstract IndexedFile getIndexedFile(SearchDocument document) throws IOException;
-	/**
-	 * Returns the number of files in the index.
-	 */
-	public abstract int getNumFiles();
-	/**
-	 * Returns the number of unique words in the index.
-	 */
-	public abstract int getNumWords();
-	/**
-	 * Returns the Object the input is reading from. It can be an IIndex,
-	 * a File, ...
-	 */
-	public abstract Object getSource();
-	/**
-	 * Returns true if the input has not reached the end of the index for the files.
-	 */
-	public boolean hasMoreFiles() {
-		return getFilePosition() <= getNumFiles();
-	}
-	/**
-	 * Returns true if the input has not reached the end of the index for the files.
-	 */
-	public boolean hasMoreWords() {
-		return wordPosition <= getNumWords();
-	}
-	/**
-	 * Moves the pointer on the current file to the next file in the index.
-	 */
-	public abstract void moveToNextFile();
-	/**
-	 * Moves the pointer on the current word to the next file in the index.
-	 */
-	public abstract void moveToNextWordEntry() throws IOException;
-	/**
-	 * Open the Source where the input gets the information from.
-	 */
-	public abstract void open() throws IOException;
-	/**
-	 * Returns the list of the files containing the given word in the index.
-	 */
-	public abstract String[] query(String word) throws IOException;
-	public abstract EntryResult[] queryEntries(char[] pattern, int matchRule) throws IOException;
-	public abstract EntryResult[] queryEntriesPrefixedBy(char[] prefix) throws IOException;
-	public abstract String[] queryFilesReferringToPrefix(char[] prefix) throws IOException;
-	/**
-	 * Returns the list of the files whose name contain the given word in the index.
-	 */
-	public abstract String[] queryInDocumentNames(String word) throws IOException;
-	/**
-	 * Set the pointer on the current file to the first file of the index.
-	 */
-	protected abstract void setFirstFile() throws IOException;
-	/**
-	 * Set the pointer on the current word to the first word of the index.
-	 */
-	protected abstract void setFirstWord() throws IOException;
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexOutput.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexOutput.java
deleted file mode 100644
index 4b9e94f..0000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexOutput.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.io.IOException;
-
-/**
- * An indexOutput is used to write an index into a different object (a File, ...). 
- */
-public abstract class IndexOutput {
-	/**
-	 * Adds a File to the destination.
-	 */
-	public abstract void addFile(IndexedFile file) throws IOException;
-	/**
-	 * Adds a word to the destination.
-	 */
-	public abstract void addWord(WordEntry word) throws IOException;
-	/**
-	 * Closes the output, releasing the resources it was using.
-	 */
-	public abstract void close() throws IOException;
-	/**
-	 * Flushes the output.
-	 */
-	public abstract void flush() throws IOException;
-	/**
-	 * Returns the Object the output is writing to. It can be a file, another type of index, ... 
-	 */
-	public abstract Object getDestination();
-	/**
-	 * Opens the output, before writing any information.
-	 */
-	public abstract void open() throws IOException;
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexSummary.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexSummary.java
deleted file mode 100644
index 27c4a02..0000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexSummary.java
+++ /dev/null
@@ -1,318 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.util.ArrayList;
-
-import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.internal.core.util.Util;
-
-/**
- * An indexSummary is used when saving an index into a BlocksIndexOuput or 
- * reading it from a BlocksIndexInput. It contains basic informations about 
- * an index: first files/words in each block, number of files/words.
- */
-
-public class IndexSummary {
-	/**
-	 * First file for each block.
-	 */
-	protected ArrayList firstFilesInBlocks= new ArrayList();
-
-	/**
-	 * First word for each block.
-	 */
-	protected ArrayList firstWordsInBlocks= new ArrayList();
-
-	/**
-	 * Number of files in the index.
-	 */
-	protected int numFiles;
-
-	/**
-	 * Number of words in the index.
-	 */
-	protected int numWords;
-
-	static class FirstFileInBlock {
-		IndexedFile indexedFile;
-		int blockNum;
-	}
-
-	static class FirstWordInBlock {
-		char[] word;
-		int blockNum;
-		public String toString(){
-			return "FirstWordInBlock: " + new String(word) + ", blockNum: " + blockNum; //$NON-NLS-1$ //$NON-NLS-2$
-		}
-	}
-
-	protected int firstWordBlockNum;
-	protected boolean firstWordAdded= true;
-	/**
-	 * Adds the given file as the first file for the given Block number. 
-	 */
-	public void addFirstFileInBlock(IndexedFile indexedFile, int blockNum) {
-		FirstFileInBlock entry= new FirstFileInBlock();
-		entry.indexedFile= indexedFile;
-		entry.blockNum= blockNum;
-		firstFilesInBlocks.add(entry);
-	}
-	/**
-	 * Adds the given word as the first word for the given Block number. 
-	 */
-	public void addFirstWordInBlock(char[] word, int blockNum) {
-		if (firstWordAdded) {
-			firstWordBlockNum= blockNum;
-			firstWordAdded= false;
-		}
-		FirstWordInBlock entry= new FirstWordInBlock();
-		entry.word= word;
-		entry.blockNum= blockNum;
-		firstWordsInBlocks.add(entry);
-	}
-	/**
-	 * Returns the numbers of all the blocks
-	 */
-	public int[] getAllBlockNums() {
-
-		int max = firstWordsInBlocks.size();
-		int[] blockNums = new int[max];
-		for (int i = 0; i < max; i++){
-			blockNums[i] = ((FirstWordInBlock)firstWordsInBlocks.get(i)).blockNum;
-		}
-		return blockNums;
-	}
-public int getBlockNum(int blockLocation) {
-	return ((FirstWordInBlock) firstWordsInBlocks.get(blockLocation)).blockNum;
-}
-	/**
-	 * Returns the number of the Block containing the file with the given number. 
-	 */
-	public int getBlockNumForFileNum(int fileNum) {
-		int min= 0;
-		int max= firstFilesInBlocks.size() - 1;
-		while (min <= max) {
-			int mid= (min + max) / 2;
-			FirstFileInBlock entry= (FirstFileInBlock) firstFilesInBlocks.get(mid);
-			int compare= fileNum - entry.indexedFile.getFileNumber();
-			if (compare == 0)
-				return entry.blockNum;
-			if (compare < 0)
-				max= mid - 1;
-			else
-				min= mid + 1;
-		}
-		if (max < 0)
-			return -1;
-		FirstFileInBlock entry= (FirstFileInBlock) firstFilesInBlocks.get(max);
-		return entry.blockNum;
-	}
-	/**
-	 * Returns the number of the Block containing the given word. 
-	 */
-	public int getBlockNumForWord(char[] word) {
-		int min= 0;
-		int max= firstWordsInBlocks.size() - 1;
-		while (min <= max) {
-			int mid= (min + max) / 2;
-			FirstWordInBlock entry= (FirstWordInBlock) firstWordsInBlocks.get(mid);
-			int compare= Util.compare(word, entry.word);
-			if (compare == 0)
-				return entry.blockNum;
-			if (compare < 0)
-				max= mid - 1;
-			else
-				min= mid + 1;
-		}
-		if (max < 0)
-			return -1;
-		FirstWordInBlock entry= (FirstWordInBlock) firstWordsInBlocks.get(max);
-		return entry.blockNum;
-	}
-	public int[] getBlockNumsForPrefix(char[] prefix) {
-		int min= 0;
-		int size= firstWordsInBlocks.size();
-		int max=  size - 1;
-		int match= -1;
-		while (min <= max && match < 0) {
-			int mid= (min + max) / 2;
-			FirstWordInBlock entry= (FirstWordInBlock) firstWordsInBlocks.get(mid);
-			int compare= CharOperation.compareWith(entry.word, prefix);
-			if (compare == 0) {
-				match= mid;
-				break;
-			}	
-			if (compare >= 0)
-				max= mid - 1;
-			else
-				min= mid + 1;
-		}
-		if (max < 0)
-			return new int[0];
-			
-		if (match < 0)
-			match= max;
-		
-		int firstBlock= match - 1;
-		// Look if previous blocks are affected
-		for (; firstBlock >= 0; firstBlock--) {
-			FirstWordInBlock entry= (FirstWordInBlock) firstWordsInBlocks.get(firstBlock);
-			if (!CharOperation.prefixEquals(prefix, entry.word))
-				break;
-		}
-		if (firstBlock < 0)
-			firstBlock= 0;	
-		
-		// Look if next blocks are affected
-		int firstNotIncludedBlock= match + 1;
-		for (; firstNotIncludedBlock < size; firstNotIncludedBlock++) {
-			FirstWordInBlock entry= (FirstWordInBlock) firstWordsInBlocks.get(firstNotIncludedBlock);
-			if (!CharOperation.prefixEquals(prefix, entry.word))
-				break;
-		}
-		
-		int numberOfBlocks= firstNotIncludedBlock - firstBlock;
-		int[] result= new int[numberOfBlocks];
-		int pos= firstBlock;
-		for (int i= 0; i < numberOfBlocks; i++, pos++) {
-			FirstWordInBlock entry= (FirstWordInBlock) firstWordsInBlocks.get(pos);
-			result[i]= entry.blockNum;
-		}
-		return result;
-	}
-public int getFirstBlockLocationForPrefix(char[] prefix) {
-	int min = 0;
-	int size = firstWordsInBlocks.size();
-	int max = size - 1;
-	int match = -1;
-	while (min <= max) {
-		int mid = (min + max) / 2;
-		FirstWordInBlock entry = (FirstWordInBlock) firstWordsInBlocks.get(mid);
-		int compare = CharOperation.compareWith(entry.word, prefix);
-		if (compare == 0) {
-			match = mid;
-			break;
-		}
-		if (compare >= 0) {
-			max = mid - 1;
-		} else {
-			match = mid; // not perfect match, but could be inside
-			min = mid + 1;
-		}
-	}
-	if (max < 0) return -1;
-
-	// no match at all, might be some matching entries inside max block
-	if (match < 0){
-		match = max;
-	} else {
-		// look for possible matches inside previous blocks
-		while (match > 0){
-			FirstWordInBlock entry = (FirstWordInBlock) firstWordsInBlocks.get(match);
-			if (!CharOperation.prefixEquals(prefix, entry.word))
-				break;
-			match--;
-		}
-	}
-	return match;
-}
-	/**
-	 * Returns the number of the first IndexBlock (containing words).
-	 */
-	public int getFirstWordBlockNum() {
-		return firstWordBlockNum;
-	}
-/** 
- * Blocks are contiguous, so the next one is a potential candidate if its first word starts with
- * the given prefix
- */
-public int getNextBlockLocationForPrefix(char[] prefix, int blockLoc) {
-	if (++blockLoc < firstWordsInBlocks.size()){
-		FirstWordInBlock entry= (FirstWordInBlock) firstWordsInBlocks.get(blockLoc);
-		if (CharOperation.prefixEquals(prefix, entry.word)) return blockLoc;
-	}
-	return -1;
-}
-	/**
-	 * Returns the number of files contained in the index.
-	 */
-	public int getNumFiles() {
-		return numFiles;
-	}
-	/**
-	 * Returns the number of words contained in the index.
-	 */
-	public int getNumWords() {
-		return numWords;
-	}
-	/**
-	 * Loads the summary in memory.
-	 */
-	public void read(RandomAccessFile raf) throws IOException {
-		numFiles= raf.readInt();
-		numWords= raf.readInt();
-		firstWordBlockNum= raf.readInt();
-		int numFirstFiles= raf.readInt();
-		for (int i= 0; i < numFirstFiles; ++i) {
-			FirstFileInBlock entry= new FirstFileInBlock();
-			String path= raf.readUTF();
-			int fileNum= raf.readInt();
-			entry.indexedFile= new IndexedFile(path, fileNum);
-			entry.blockNum= raf.readInt();
-			firstFilesInBlocks.add(entry);
-		}
-		int numFirstWords= raf.readInt();
-		for (int i= 0; i < numFirstWords; ++i) {
-			FirstWordInBlock entry= new FirstWordInBlock();
-			entry.word= raf.readUTF().toCharArray();
-			entry.blockNum= raf.readInt();
-			firstWordsInBlocks.add(entry);
-		}
-	}
-	/**
-	 * Sets the number of files of the index.
-	 */
-
-	public void setNumFiles(int numFiles) {
-		this.numFiles= numFiles;
-	}
-	/**
-	 * Sets the number of words of the index.
-	 */
-
-	public void setNumWords(int numWords) {
-		this.numWords= numWords;
-	}
-	/**
-	 * Saves the summary on the disk.
-	 */
-	public void write(RandomAccessFile raf) throws IOException {
-		raf.writeInt(numFiles);
-		raf.writeInt(numWords);
-		raf.writeInt(firstWordBlockNum);
-		raf.writeInt(firstFilesInBlocks.size());
-		for (int i= 0, size= firstFilesInBlocks.size(); i < size; ++i) {
-			FirstFileInBlock entry= (FirstFileInBlock) firstFilesInBlocks.get(i);
-			raf.writeUTF(entry.indexedFile.getPath());
-			raf.writeInt(entry.indexedFile.getFileNumber());
-			raf.writeInt(entry.blockNum);
-		}
-		raf.writeInt(firstWordsInBlocks.size());
-		for (int i= 0, size= firstWordsInBlocks.size(); i < size; ++i) {
-			FirstWordInBlock entry= (FirstWordInBlock) firstWordsInBlocks.get(i);
-			raf.writeUTF(new String(entry.word));
-			raf.writeInt(entry.blockNum);
-		}
-	}
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexedFile.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexedFile.java
deleted file mode 100644
index 7a8b3ab..0000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexedFile.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import org.eclipse.core.runtime.Path;
-import org.eclipse.jdt.core.search.IJavaSearchScope;
-import org.eclipse.jdt.core.search.SearchDocument;
-
-/**
- * An indexedFile associates a number to a document path, and document properties. 
- * It is what we add into an index, and the result of a query.
- */
-
-public class IndexedFile {
-	public String path;
-	protected int fileNumber;
-
-	public IndexedFile(String path, int fileNum) {
-		if (fileNum < 1)
-			throw new IllegalArgumentException();
-		this.fileNumber= fileNum;
-		this.path= path;
-	}
-	public IndexedFile(SearchDocument document, int fileNum) {
-		if (fileNum < 1)
-			throw new IllegalArgumentException();
-		this.path= document.getPath();
-		this.fileNumber= fileNum;
-	}
-	/**
-	 * Returns the path represented by pathString converted back to a path relative to the local file system.
-	 *
-	 * @param pathString the path to convert:
-	 * <ul>
-	 *		<li>an absolute IPath (relative to the workspace root) if the path represents a resource in the 
-	 *			workspace
-	 *		<li>a relative IPath (relative to the workspace root) followed by JAR_FILE_ENTRY_SEPARATOR
-	 *			followed by an absolute path (relative to the jar) if the path represents a .class file in
-	 *			an internal jar
-	 *		<li>an absolute path (relative to the file system) followed by JAR_FILE_ENTRY_SEPARATOR
-	 *			followed by an absolute path (relative to the jar) if the path represents a .class file in
-	 *			an external jar
-	 * </ul>
-	 * @return the converted path:
-	 * <ul>
-	 *		<li>the original pathString if the path represents a resource in the workspace
-	 *		<li>an absolute path (relative to the file system) followed by JAR_FILE_ENTRY_SEPARATOR
-	 *			followed by an absolute path (relative to the jar) if the path represents a .class file in
-	 *			an external or internal jar
-	 * </ul>
-	 */
-	public static String convertPath(String pathString) {
-		int index = pathString.indexOf(IJavaSearchScope.JAR_FILE_ENTRY_SEPARATOR);
-		if (index == -1)
-			return pathString;
-			
-		Path jarPath = new Path(pathString.substring(0, index));
-		if (!jarPath.isAbsolute()) {
-			return jarPath.makeAbsolute().toString() + pathString.substring(index, pathString.length());
-		} else {
-			return jarPath.toOSString() + pathString.substring(index, pathString.length());
-		}
-	}
-	/**
-	 * Returns the size of the indexedFile.
-	 */
-	public int footprint() {
-		//object+ 2 slots + size of the string (header + 4 slots + char[])
-		return 8 + (2 * 4) + (8 + (4 * 4) + 8 + path.length() * 2);
-	}
-	/**
-	 * Returns the file number.
-	 */
-	public int getFileNumber() {
-		return fileNumber;
-	}
-	/**
-	 * Returns the path.
-	 */
-	public String getPath() {
-		return path;
-	}
-	/**
-	 * Sets the file number.
-	 */
-	public void setFileNumber(int fileNumber) {
-		this.fileNumber= fileNumber;
-	}
-	public String toString() {
-		return "IndexedFile(" + fileNumber + ": " + path + ")"; //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-3$
-	}
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexedFileHashedArray.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexedFileHashedArray.java
deleted file mode 100644
index 6db5bd9..0000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexedFileHashedArray.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.util.ArrayList;
-
-import org.eclipse.jdt.core.search.SearchDocument;
-
-public final class IndexedFileHashedArray {
-
-private IndexedFile elements[];
-private int elementSize; // number of elements in the table
-private int threshold;
-private int lastId;
-private ArrayList replacedElements;
-
-public IndexedFileHashedArray(int size) {
-	if (size < 7) size = 7;
-	this.elements = new IndexedFile[2 * size + 1];
-	this.elementSize = 0;
-	this.threshold = size + 1; // size is the expected number of elements
-	this.lastId = 0;
-	this.replacedElements = null;
-}
-
-public IndexedFile add(SearchDocument document) {
-	return add(new IndexedFile(document, ++lastId));
-}
-
-private IndexedFile add(IndexedFile file) {
-	int length = elements.length;
-	String path = file.getPath();
-	int index = (path.hashCode() & 0x7FFFFFFF) % length;
-	IndexedFile current;
-	while ((current = elements[index]) != null) {
-		if (current.getPath().equals(path)) {
-			if (replacedElements == null) replacedElements = new ArrayList(5);
-			replacedElements.add(current);
-			return elements[index] = file;
-		}
-		if (++index == length) index = 0;
-	}
-	elements[index] = file;
-
-	// assumes the threshold is never equal to the size of the table
-	if (++elementSize > threshold) grow();
-	return file;
-}
-
-public IndexedFile[] asArray() {
-	IndexedFile[] array = new IndexedFile[lastId];
-	for (int i = 0, length = elements.length; i < length; i++) {
-		IndexedFile current = elements[i];
-		if (current != null)
-			array[current.fileNumber - 1] = current;
-	}
-	if (replacedElements != null) {
-		for (int i = 0, length = replacedElements.size(); i < length; i++) {
-			IndexedFile current = (IndexedFile) replacedElements.get(i);
-			array[current.fileNumber - 1] = current;
-		}
-	}
-	return array;
-}
-
-public IndexedFile get(String path) {
-	int length = elements.length;
-	int index = (path.hashCode() & 0x7FFFFFFF) % length;
-	IndexedFile current;
-	while ((current = elements[index]) != null) {
-		if (current.getPath().equals(path)) return current;
-		if (++index == length) index = 0;
-	}
-	return null;
-}
-
-private void grow() {
-	IndexedFileHashedArray newArray = new IndexedFileHashedArray(elementSize * 2); // double the number of expected elements
-	for (int i = 0, length = elements.length; i < length; i++)
-		if (elements[i] != null)
-			newArray.add(elements[i]);
-
-	// leave replacedElements as is
-	this.elements = newArray.elements;
-	this.elementSize = newArray.elementSize;
-	this.threshold = newArray.threshold;
-}
-
-public int size() {
-	return elementSize + (replacedElements == null ? 0 : replacedElements.size());
-}
-
-public String toString() {
-	String s = ""; //$NON-NLS-1$
-	IndexedFile[] files = asArray();
-	for (int i = 0, length = files.length; i < length; i++)
-		s += files[i].toString() + "\n"; 	//$NON-NLS-1$
-	return s;
-}
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexerOutput.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexerOutput.java
deleted file mode 100644
index 91150f0..0000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/IndexerOutput.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import org.eclipse.jdt.core.search.SearchDocument;
-import org.eclipse.jdt.internal.core.index.IIndexerOutput;
-
-/**
- * An indexerOutput is used by an indexer to add documents and word references to
- * an inMemoryIndex. It keeps track of the document being indexed and add the
- * word references to this document (so you do not need to precise the document
- * each time you add a word).
- */
-
-public class IndexerOutput implements IIndexerOutput {
-	protected InMemoryIndex index;
-	protected IndexedFile indexedFile;
-	/**
-	 * IndexerOutput constructor comment.
-	 */
-	public IndexerOutput(InMemoryIndex index) {
-		this.index= index;
-	}
-	/**
-	 * Adds the given document to the inMemoryIndex.
-	 */
-
-	public void addDocument(SearchDocument document) {
-		if (indexedFile == null) {
-			indexedFile= index.addDocument(document);
-		} else {
-			throw new IllegalStateException();
-		}
-	}
-	/**
-	 * Adds a reference to the given word to the inMemoryIndex.
-	 */
-	public void addRef(char[] word) {
-		if (indexedFile == null) {
-			throw new IllegalStateException();
-		}
-		index.addRef(indexedFile, word);
-	}
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/LRUCache.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/LRUCache.java
deleted file mode 100644
index 9823815..0000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/LRUCache.java
+++ /dev/null
@@ -1,473 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.util.Hashtable;
-import java.util.Enumeration;
-
-/**
- * The <code>LRUCache</code> is a hashtable that stores a finite number of elements.  
- * When an attempt is made to add values to a full cache, the least recently used values
- * in the cache are discarded to make room for the new values as necessary.
- * 
- * <p>The data structure is based on the LRU virtual memory paging scheme.
- * 
- * <p>Objects can take up a variable amount of cache space by implementing
- * the <code>ILRUCacheable</code> interface.
- *
- * <p>This implementation is NOT thread-safe.  Synchronization wrappers would
- * have to be added to ensure atomic insertions and deletions from the cache.
- *
- * @see org.eclipse.jdt.internal.core.index.impl.ILRUCacheable
- */
-public class LRUCache implements Cloneable {
-
-	/**
-	 * This type is used internally by the LRUCache to represent entries 
-	 * stored in the cache.
-	 * It is static because it does not require a pointer to the cache
-	 * which contains it.
-	 *
-	 * @see LRUCache
-	 */
-	protected static class LRUCacheEntry {
-
-		/**
-		 * Hash table key
-		 */
-		/* package */
-		Object _fKey;
-
-		/**
-		 * Hash table value (an LRUCacheEntry object)
-		 */
-		/* package */
-		Object _fValue;
-
-		/**
-		 * Time value for queue sorting
-		 */
-		/* package */
-		int _fTimestamp;
-
-		/**
-		 * Cache footprint of this entry
-		 */
-		int _fSpace;
-
-		/**
-		 * Previous entry in queue
-		 */
-		/* package */
-		LRUCacheEntry _fPrevious;
-
-		/**
-		 * Next entry in queue
-		 */
-		/* package */
-		LRUCacheEntry _fNext;
-
-		/**
-		 * Creates a new instance of the receiver with the provided values
-		 * for key, value, and space.
-		 */
-		public LRUCacheEntry(Object key, Object value, int space) {
-			_fKey= key;
-			_fValue= value;
-			_fSpace= space;
-		}
-
-		/**
-		 * Returns a String that represents the value of this object.
-		 */
-		public String toString() {
-
-			return "LRUCacheEntry [" + _fKey + "-->" + _fValue + "]"; //$NON-NLS-3$ //$NON-NLS-1$ //$NON-NLS-2$
-		}
-	}
-
-	/**
-	 * Amount of cache space used so far
-	 */
-	protected int fCurrentSpace;
-
-	/**
-	 * Maximum space allowed in cache
-	 */
-	protected int fSpaceLimit;
-
-	/**
-	 * Counter for handing out sequential timestamps
-	 */
-	protected int fTimestampCounter;
-
-	/**
-	 * Hash table for fast random access to cache entries
-	 */
-	protected Hashtable fEntryTable;
-
-	/**
-	 * Start of queue (most recently used entry) 
-	 */
-	protected LRUCacheEntry fEntryQueue;
-
-	/**
-	 * End of queue (least recently used entry)
-	 */
-	protected LRUCacheEntry fEntryQueueTail;
-
-	/**
-	 * Default amount of space in the cache
-	 */
-	protected static final int DEFAULT_SPACELIMIT= 100;
-	/**
-	 * Creates a new cache.  Size of cache is defined by 
-	 * <code>DEFAULT_SPACELIMIT</code>.
-	 */
-	public LRUCache() {
-
-		this(DEFAULT_SPACELIMIT);
-	}
-	/**
-	 * Creates a new cache.
-	 * @param size Size of Cache
-	 */
-	public LRUCache(int size) {
-
-		fTimestampCounter= fCurrentSpace= 0;
-		fEntryQueue= fEntryQueueTail= null;
-		fEntryTable= new Hashtable(size);
-		fSpaceLimit= size;
-	}
-	/**
-	 * Returns a new cache containing the same contents.
-	 *
-	 * @return New copy of object.
-	 */
-	public Object clone() {
-
-		LRUCache newCache= newInstance(fSpaceLimit);
-		LRUCacheEntry qEntry;
-
-		/* Preserve order of entries by copying from oldest to newest */
-		qEntry= this.fEntryQueueTail;
-		while (qEntry != null) {
-			newCache.privateAdd(qEntry._fKey, qEntry._fValue, qEntry._fSpace);
-			qEntry= qEntry._fPrevious;
-		}
-		return newCache;
-	}
-	/**
-	 * Flushes all entries from the cache.
-	 */
-	public void flush() {
-
-		fCurrentSpace= 0;
-		LRUCacheEntry entry= fEntryQueueTail; // Remember last entry
-		fEntryTable= new Hashtable(); // Clear it out
-		fEntryQueue= fEntryQueueTail= null;
-		while (entry != null) { // send deletion notifications in LRU order
-			privateNotifyDeletionFromCache(entry);
-			entry= entry._fPrevious;
-		}
-	}
-	/**
-	 * Flushes the given entry from the cache.  Does nothing if entry does not
-	 * exist in cache.
-	 *
-	 * @param key Key of object to flush
-	 */
-	public void flush(Object key) {
-
-		LRUCacheEntry entry;
-
-		entry= (LRUCacheEntry) fEntryTable.get(key);
-
-		/* If entry does not exist, return */
-		if (entry == null)
-			return;
-
-		this.privateRemoveEntry(entry, false);
-	}
-	/**
-	 * Answers the value in the cache at the given key.
-	 * If the value is not in the cache, returns null
-	 *
-	 * @param key Hash table key of object to retrieve
-	 * @return Retreived object, or null if object does not exist
-	 */
-	public Object get(Object key) {
-
-		LRUCacheEntry entry= (LRUCacheEntry) fEntryTable.get(key);
-		if (entry == null) {
-			return null;
-		}
-
-		this.updateTimestamp(entry);
-		return entry._fValue;
-	}
-	/**
-	 * Returns the amount of space that is current used in the cache.
-	 */
-	public int getCurrentSpace() {
-		return fCurrentSpace;
-	}
-	/**
-	 * Returns the maximum amount of space available in the cache.
-	 */
-	public int getSpaceLimit() {
-		return fSpaceLimit;
-	}
-	/**
-	 * Returns an Enumeration of the keys currently in the cache.
-	 */
-	public Enumeration keys() {
-
-		return fEntryTable.keys();
-	}
-	/**
-	 * Returns an enumeration that iterates over all the keys and values 
-	 * currently in the cache.
-	 */
-	public ICacheEnumeration keysAndValues() {
-		return new ICacheEnumeration() {
-
-			Enumeration fValues= fEntryTable.elements();
-			LRUCacheEntry fEntry;
-
-			public boolean hasMoreElements() {
-				return fValues.hasMoreElements();
-			}
-
-			public Object nextElement() {
-				fEntry= (LRUCacheEntry) fValues.nextElement();
-				return fEntry._fKey;
-			}
-
-			public Object getValue() {
-				if (fEntry == null) {
-					throw new java.util.NoSuchElementException();
-				}
-				return fEntry._fValue;
-			}
-		};
-	}
-	/**
-	 * Ensures there is the specified amount of free space in the receiver,
-	 * by removing old entries if necessary.  Returns true if the requested space was
-	 * made available, false otherwise.
-	 *
-	 * @param space Amount of space to free up
-	 */
-	protected boolean makeSpace(int space) {
-
-		int limit;
-
-		limit= this.getSpaceLimit();
-
-		/* if space is already available */
-		if (fCurrentSpace + space <= limit) {
-			return true;
-		}
-
-		/* if entry is too big for cache */
-		if (space > limit) {
-			return false;
-		}
-
-		/* Free up space by removing oldest entries */
-		while (fCurrentSpace + space > limit && fEntryQueueTail != null) {
-			this.privateRemoveEntry(fEntryQueueTail, false);
-		}
-		return true;
-	}
-	/**
-	 * Returns a new LRUCache instance
-	 */
-	protected LRUCache newInstance(int size) {
-		return new LRUCache(size);
-	}
-	/**
-	 * Adds an entry for the given key/value/space.
-	 */
-	protected void privateAdd(Object key, Object value, int space) {
-
-		LRUCacheEntry entry;
-
-		entry= new LRUCacheEntry(key, value, space);
-		this.privateAddEntry(entry, false);
-	}
-	/**
-	 * Adds the given entry from the receiver.
-	 * @param shuffle Indicates whether we are just shuffling the queue 
-	 * (in which case, the entry table is not modified).
-	 */
-	protected void privateAddEntry(LRUCacheEntry entry, boolean shuffle) {
-
-		if (!shuffle) {
-			fEntryTable.put(entry._fKey, entry);
-			fCurrentSpace += entry._fSpace;
-		}
-
-		entry._fTimestamp= fTimestampCounter++;
-		entry._fNext= this.fEntryQueue;
-		entry._fPrevious= null;
-
-		if (fEntryQueue == null) {
-			/* this is the first and last entry */
-			fEntryQueueTail= entry;
-		} else {
-			fEntryQueue._fPrevious= entry;
-		}
-
-		fEntryQueue= entry;
-	}
-	/**
-	 * An entry has been removed from the cache, for example because it has 
-	 * fallen off the bottom of the LRU queue.  
-	 * Subclasses could over-ride this to implement a persistent cache below the LRU cache.
-	 */
-	protected void privateNotifyDeletionFromCache(LRUCacheEntry entry) {
-		// Default is NOP.
-	}
-	/**
-	 * Removes the entry from the entry queue.  
-	 * @param shuffle indicates whether we are just shuffling the queue 
-	 * (in which case, the entry table is not modified).
-	 */
-	protected void privateRemoveEntry(LRUCacheEntry entry, boolean shuffle) {
-
-		LRUCacheEntry previous, next;
-
-		previous= entry._fPrevious;
-		next= entry._fNext;
-
-		if (!shuffle) {
-			fEntryTable.remove(entry._fKey);
-			fCurrentSpace -= entry._fSpace;
-			privateNotifyDeletionFromCache(entry);
-		}
-
-		/* if this was the first entry */
-		if (previous == null) {
-			fEntryQueue= next;
-		} else {
-			previous._fNext= next;
-		}
-
-		/* if this was the last entry */
-		if (next == null) {
-			fEntryQueueTail= previous;
-		} else {
-			next._fPrevious= previous;
-		}
-	}
-	/**
-	 * Sets the value in the cache at the given key. Returns the value.
-	 *
-	 * @param key Key of object to add.
-	 * @param value Value of object to add.
-	 * @return added value.
-	 */
-	public Object put(Object key, Object value) {
-
-		int newSpace, oldSpace, newTotal;
-		LRUCacheEntry entry;
-
-		/* Check whether there's an entry in the cache */
-		newSpace= spaceFor(value);
-		entry= (LRUCacheEntry) fEntryTable.get(key);
-
-		if (entry != null) {
-
-			/**
-			 * Replace the entry in the cache if it would not overflow
-			 * the cache.  Otherwise flush the entry and re-add it so as 
-			 * to keep cache within budget
-			 */
-			oldSpace= entry._fSpace;
-			newTotal= getCurrentSpace() - oldSpace + newSpace;
-			if (newTotal <= getSpaceLimit()) {
-				updateTimestamp(entry);
-				entry._fValue= value;
-				entry._fSpace= newSpace;
-				this.fCurrentSpace= newTotal;
-				return value;
-			} else {
-				privateRemoveEntry(entry, false);
-			}
-		}
-		if (makeSpace(newSpace)) {
-			privateAdd(key, value, newSpace);
-		}
-		return value;
-	}
-	/**
-	 * Removes and returns the value in the cache for the given key.
-	 * If the key is not in the cache, returns null.
-	 *
-	 * @param key Key of object to remove from cache.
-	 * @return Value removed from cache.
-	 */
-	public Object removeKey(Object key) {
-
-		LRUCacheEntry entry= (LRUCacheEntry) fEntryTable.get(key);
-		if (entry == null) {
-			return null;
-		}
-		Object value= entry._fValue;
-		this.privateRemoveEntry(entry, false);
-		return value;
-	}
-	/**
-	 * Sets the maximum amount of space that the cache can store
-	 *
-	 * @param limit Number of units of cache space
-	 */
-	public void setSpaceLimit(int limit) {
-		if (limit < fSpaceLimit) {
-			makeSpace(fSpaceLimit - limit);
-		}
-		fSpaceLimit= limit;
-	}
-	/**
-	 * Returns the space taken by the given value.
-	 */
-	protected int spaceFor(Object value) {
-
-		if (value instanceof ILRUCacheable) {
-			return ((ILRUCacheable) value).getCacheFootprint();
-		} else {
-			return 1;
-		}
-	}
-	/**
-	 * Returns a String that represents the value of this object.  This method
-	 * is for debugging purposes only.
-	 */
-	public String toString() {
-
-		return "LRUCache " + (getCurrentSpace() * 100.0 / getSpaceLimit()) + "% full"; //$NON-NLS-1$ //$NON-NLS-2$
-	}
-	/**
-	 * Updates the timestamp for the given entry, ensuring that the queue is 
-	 * kept in correct order.  The entry must exist
-	 */
-	protected void updateTimestamp(LRUCacheEntry entry) {
-
-		entry._fTimestamp= fTimestampCounter++;
-		if (fEntryQueue != entry) {
-			this.privateRemoveEntry(entry, true);
-			this.privateAddEntry(entry, true);
-		}
-		return;
-	}
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/MergeFactory.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/MergeFactory.java
deleted file mode 100644
index 3d0b6ab..0000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/MergeFactory.java
+++ /dev/null
@@ -1,230 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.io.IOException;
-import java.util.Map;
-
-import org.eclipse.jdt.internal.core.util.Util;
-
-/**
- * A mergeFactory is used to merge 2 indexes into one. One of the indexes 
- * (oldIndex) is on the disk and the other(addsIndex) is in memory.
- * The merge respects the following rules: <br>
- *   - The files are sorted in alphabetical order;<br>
- *   - if a file is in oldIndex and addsIndex, the one which is added 
- * is the one in the addsIndex.<br>
- */
-public class MergeFactory {
-	/**
-	 * Input on the addsIndex.
-	 */
-	protected IndexInput addsInput;
-
-	/**
-	 * Input on the oldIndex. 
-	 */
-	protected IndexInput oldInput;
-
-	/**
-	 * Output to write the result of the merge in.
-	 */
-	protected BlocksIndexOutput mergeOutput;
-
-	/**
-	 * Files removed from oldIndex. 
-	 */
-	protected Map removedInOld;
-
-	/**
-	 * Files removed from addsIndex. 
-	 */
-	protected Map removedInAdds;
-	protected int[] mappingOld;
-	protected int[] mappingAdds;
-	public static final int ADDS_INDEX= 0;
-	public static final int OLD_INDEX= 1;
-	/**
-	 * MergeFactory constructor comment.
-	 * @param directory java.io.File
-	 */
-	public MergeFactory(IndexInput oldIndexInput, IndexInput addsIndexInput, BlocksIndexOutput mergeIndexOutput, Map removedInOld, Map removedInAdds) {
-		oldInput= oldIndexInput;
-		addsInput= addsIndexInput;
-		mergeOutput= mergeIndexOutput;
-		this.removedInOld= removedInOld;
-		this.removedInAdds= removedInAdds;
-	}
-	/**
-	 * Initialise the merge.
-	 */
-	protected void init() {
-		mappingOld= new int[oldInput.getNumFiles() + 1];
-		mappingAdds= new int[addsInput.getNumFiles() + 1];
-
-	}
-	/**
-	 * Merges the 2 indexes into a new one on the disk.
-	 */
-	public void merge() throws IOException {
-		try {
-			//init
-			addsInput.open();
-			oldInput.open();
-			mergeOutput.open();
-			init();
-			//merge
-			//findChanges();
-			mergeFiles();
-			mergeReferences();
-			mergeOutput.flush();
-		} finally {
-			//closes everything
-			oldInput.close();
-			addsInput.close();
-			mergeOutput.close();
-		}
-	}
-	/**
-	 * Merges the files of the 2 indexes in the new index, removes the files
-	 * to be removed, and records the changes made to propagate them to the 
-	 * word references.
-	 */
-
-	protected void mergeFiles() throws IOException {
-		int positionInMerge= 1;
-		int compare;
-		while (oldInput.hasMoreFiles() || addsInput.hasMoreFiles()) {
-			IndexedFile file1= oldInput.getCurrentFile();
-			IndexedFile file2= addsInput.getCurrentFile();
-
-			//if the file has been removed we don't take it into account
-			while (file1 != null && wasRemoved(file1, OLD_INDEX)) {
-				oldInput.moveToNextFile();
-				file1= oldInput.getCurrentFile();
-			}
-			while (file2 != null && wasRemoved(file2, ADDS_INDEX)) {
-				addsInput.moveToNextFile();
-				file2= addsInput.getCurrentFile();
-			}
-
-			//the addsIndex was empty, we just removed files from the oldIndex
-			if (file1 == null && file2 == null)
-				break;
-
-			//test if we reached the end of one the 2 index
-			if (file1 == null)
-				compare= 1;
-			else if (file2 == null)
-				compare= -1;
-			else
-				compare= file1.getPath().compareTo(file2.getPath());
-
-			//records the changes to Make
-			if (compare == 0) {
-				//the file has been modified: 
-				//we remove it from the oldIndex and add it to the addsIndex
-				removeFile(file1, OLD_INDEX);
-				mappingAdds[file2.getFileNumber()]= positionInMerge;
-				file1.setFileNumber(positionInMerge);
-				mergeOutput.addFile(file1);
-				oldInput.moveToNextFile();
-				addsInput.moveToNextFile();
-			} else if (compare < 0) {
-				mappingOld[file1.getFileNumber()]= positionInMerge;
-				file1.setFileNumber(positionInMerge);
-				mergeOutput.addFile(file1);
-				oldInput.moveToNextFile();
-			} else {
-				mappingAdds[file2.getFileNumber()]= positionInMerge;
-				file2.setFileNumber(positionInMerge);
-				mergeOutput.addFile(file2);
-				addsInput.moveToNextFile();
-			}
-			positionInMerge++;
-		}
-		mergeOutput.flushFiles();		
-	}
-	/**
-	 * Merges the files of the 2 indexes in the new index, according to the changes
-	 * recorded during mergeFiles().
-	 */
-	protected void mergeReferences() throws IOException {
-		int compare;
-		while (oldInput.hasMoreWords() || addsInput.hasMoreWords()) {
-			WordEntry word1= oldInput.getCurrentWordEntry();
-			WordEntry word2= addsInput.getCurrentWordEntry();
-
-			if (word1 == null && word2 == null)
-				break;
-			
-			if (word1 == null)
-				compare= 1;
-			else if (word2 == null)
-				compare= -1;
-			else
-				compare= Util.compare(word1.getWord(), word2.getWord());
-			if (compare < 0) {
-				word1.mapRefs(mappingOld);
-				mergeOutput.addWord(word1);
-				oldInput.moveToNextWordEntry();
-			} else if (compare > 0) {
-				word2.mapRefs(mappingAdds);
-				mergeOutput.addWord(word2);
-				addsInput.moveToNextWordEntry();
-			} else {
-				word1.mapRefs(mappingOld);
-				word2.mapRefs(mappingAdds);
-				word1.addRefs(word2.getRefs());
-				mergeOutput.addWord(word1);
-				addsInput.moveToNextWordEntry();
-				oldInput.moveToNextWordEntry();
-			}
-		}
-		mergeOutput.flushWords();
-	}
-	/**
-	 * Records the deletion of one file.
-	 */
-	protected void removeFile(IndexedFile file, int index) {
-		if (index == OLD_INDEX)
-			mappingOld[file.getFileNumber()]= -1;
-		else
-			mappingAdds[file.getFileNumber()]= -1;
-	}
-	/**
-	 * Returns whether the given file has to be removed from the given index
-	 * (ADDS_INDEX or OLD_INDEX). If it has to be removed, the mergeFactory 
-	 * deletes it and records the changes. 
-	 */
-
-	protected boolean wasRemoved(IndexedFile indexedFile, int index) {
-		String path= indexedFile.getPath();
-		if (index == OLD_INDEX) {
-			if (removedInOld.remove(path) != null) {
-				mappingOld[indexedFile.getFileNumber()]= -1;
-				return true;
-			}
-		} else if (index == ADDS_INDEX) {
-			Int lastRemoved= (Int) removedInAdds.get(path);
-			if (lastRemoved != null) {
-				int fileNum= indexedFile.getFileNumber();
-				if (lastRemoved.value >= fileNum) {
-					mappingAdds[fileNum]= -1;
-					//if (lastRemoved.value == fileNum) // ONLY if files in sorted order for names AND fileNums
-					//removedInAdds.remove(path);
-					return true;
-				}
-			}
-		}
-		return false;
-	}
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/SafeRandomAccessFile.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/SafeRandomAccessFile.java
deleted file mode 100644
index bf8d4b1..0000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/SafeRandomAccessFile.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.io.IOException;
-import java.io.RandomAccessFile;
-
-/**
- * A safe subclass of RandomAccessFile, which ensure that it's closed
- * on finalize.
- */
-public class SafeRandomAccessFile extends RandomAccessFile {
-	public SafeRandomAccessFile(java.io.File file, String mode) throws java.io.IOException {
-		super(file, mode);
-	}
-	public SafeRandomAccessFile(String name, String mode) throws java.io.IOException {
-		super(name, mode);
-	}
-	protected void finalize() throws IOException {
-		close();
-	}
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/SimpleIndexBlock.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/SimpleIndexBlock.java
deleted file mode 100644
index b1e9b15..0000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/SimpleIndexBlock.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.io.UTFDataFormatException;
-
-import org.eclipse.jdt.core.compiler.CharOperation;
-
-/**
- * Does no compression of words, and uses 4-byte ints for file numbers and number of files.
- */
-public class SimpleIndexBlock extends IndexBlock {
-	protected int offset= 0;
-
-	public SimpleIndexBlock(int blockSize) {
-		super(blockSize);
-	}
-	/**
-	 * @see IndexBlock#addEntry
-	 */
-	public boolean addEntry(WordEntry entry) {
-		char[] word= entry.getWord();
-		int n= entry.getNumRefs();
-		int sizeEstimate= 2 + word.length * 3 + 4 + n * 4;
-		int off= this.offset;
-		if (off + sizeEstimate > this.blockSize - 2)
-			return false;
-		off += field.putUTF(off, word);
-		field.putInt4(off, n);
-		off += 4;
-		for (int i= 0; i < n; ++i) {
-			field.putInt4(off, entry.getRef(i));
-			off += 4;
-		}
-		this.offset= off;
-		return true;
-	}
-	public WordEntry findEntry(char[] word) {
-		try {
-			int off= 0;
-			int byteLen;
-			while ((byteLen= field.getUInt2(off)) != 0) {
-				char[] tempWord= field.getUTF(off);
-				off += byteLen + 2;
-				if (CharOperation.equals(tempWord, word)) {
-					WordEntry entry= new WordEntry(word);
-					int n= field.getInt4(off);
-					off += 4;
-					for (int i= 0; i < n; ++i) {
-						int ref= field.getInt4(off);
-						off += 4;
-						entry.addRef(ref);
-					}
-					return entry;
-				} else {
-					int n= field.getInt4(off);
-					off += 4 + 4 * n;
-				}
-			}
-			return null;
-		} catch (UTFDataFormatException e) {
-			return null;
-		}
-	}
-	/**
-	 * @see IndexBlock#flush
-	 */
-	public void flush() {
-		if (offset > 0) {
-			field.putInt2(offset, 0);
-			offset= 0;
-		}
-	}
-	/**
-	 * @see IndexBlock#isEmpty
-	 */
-	public boolean isEmpty() {
-		return offset == 0;
-	}
-	/**
-	 * @see IndexBlock#nextEntry
-	 */
-	public boolean nextEntry(WordEntry entry) {
-		try {
-			int off= this.offset;
-			int byteLen= field.getUInt2(off);
-			if (byteLen == 0)
-				return false;
-			char[] word= field.getUTF(off);
-			off += byteLen + 2;
-			entry.reset(word);
-			int n= field.getInt4(off);
-			off += 4;
-			for (int i= 0; i < n; ++i) {
-				int ref= field.getInt4(off);
-				off += 4;
-				entry.addRef(ref);
-			}
-			this.offset= off;
-			return true;
-		} catch (UTFDataFormatException e) {
-			return false;
-		}
-	}
-	/**
-	 * @see IndexBlock#reset
-	 */
-	public void reset() {
-		super.reset();
-		this.offset= 0;
-	}
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/SimpleIndexInput.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/SimpleIndexInput.java
deleted file mode 100644
index ea0d2c6..0000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/SimpleIndexInput.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import java.util.ArrayList;
-
-import org.eclipse.jdt.core.search.SearchDocument;
-
-/**
- * A simpleIndexInput is an input on an in memory Index. 
- */
-
-public class SimpleIndexInput extends IndexInput {
-	protected WordEntry[] sortedWordEntries;
-	protected IndexedFile currentFile;
-	protected IndexedFile[] sortedFiles;
-	protected InMemoryIndex index;
-
-	public SimpleIndexInput(InMemoryIndex index) {
-		super();
-		this.index= index;
-	}
-	/**
-	 * @see IndexInput#clearCache()
-	 */
-	public void clearCache() {
-		// implements abstract method
-	}
-	/**
-	 * @see IndexInput#close()
-	 */
-	public void close() {
-		sortedFiles= null;
-	}
-	/**
-	 * @see IndexInput#getCurrentFile()
-	 */
-	public IndexedFile getCurrentFile() {
-		if (!hasMoreFiles())
-			return null;
-		return currentFile;
-	}
-	/**
-	 * @see IndexInput#getIndexedFile(int)
-	 */
-	public IndexedFile getIndexedFile(int fileNum) {
-		for (int i= 0; i < sortedFiles.length; i++)
-			if (sortedFiles[i].getFileNumber() == fileNum)
-				return sortedFiles[i];
-		return null;
-	}
-	/**
-	 * @see IndexInput#getIndexedFile(IDocument)
-	 */
-	public IndexedFile getIndexedFile(SearchDocument document) {
-		String name= document.getPath();
-		for (int i= index.getNumFiles(); i >= 1; i--) {
-			IndexedFile file= getIndexedFile(i);
-			if (name.equals(file.getPath()))
-				return file;
-		}
-		return null;
-	}
-	/**
-	 * @see IndexInput#getNumFiles()
-	 */
-	public int getNumFiles() {
-		return index.getNumFiles();
-	}
-	/**
-	 * @see IndexInput#getNumWords()
-	 */
-	public int getNumWords() {
-		return sortedWordEntries.length;
-	}
-	/**
-	 * @see IndexInput#getSource()
-	 */
-	public Object getSource() {
-		return index;
-	}
-	public void init() {
-		index.init();
-
-	}
-	/**
-	 * @see IndexInput#moveToNextFile()
-	 */
-	public void moveToNextFile() {
-		filePosition++;
-		if (!hasMoreFiles()) {
-			return;
-		}
-		currentFile= sortedFiles[filePosition - 1];
-	}
-	/**
-	 * @see IndexInput#moveToNextWordEntry()
-	 */
-	public void moveToNextWordEntry() /* throws IOException */ {
-		wordPosition++;
-		if (hasMoreWords())
-			currentWordEntry= sortedWordEntries[wordPosition - 1];
-	}
-	/**
-	 * @see IndexInput#open()
-	 */
-	public void open() {
-		sortedWordEntries= index.getSortedWordEntries();
-		sortedFiles= index.getSortedFiles();
-		filePosition= 1;
-		wordPosition= 1;
-		setFirstFile();
-		setFirstWord();
-	}
-	/**
-	 * @see IndexInput#query(String)
-	 */
-	public String[] query(String word) {
-		char[] wordChar= word.toCharArray();
-		WordEntry wordEntry= index.getWordEntry(wordChar);
-		int[] fileNums= wordEntry.getRefs();
-		String[] paths= new String[fileNums.length];
-		for (int i= 0; i < paths.length; i++)
-			paths[i]= getIndexedFile(fileNums[i]).getPath();
-		return paths;
-	}
-	public EntryResult[] queryEntries(char[] pattern, int matchRule) {
-		return null;
-	}
-	public EntryResult[] queryEntriesPrefixedBy(char[] prefix) {
-		return null;
-	}
-	public String[] queryFilesReferringToPrefix(char[] prefix) {
-			return null;
-	}
-	/**
-	 * @see IndexInput#queryInDocumentNames(String)
-	 */
-	public String[] queryInDocumentNames(String word) {
-		setFirstFile();
-		ArrayList matches= new ArrayList();
-		while (hasMoreFiles()) {
-			IndexedFile file= getCurrentFile();
-			if (file.getPath().indexOf(word) != -1)
-				matches.add(file.getPath());
-			moveToNextFile();
-		}
-		String[] match= new String[matches.size()];
-		matches.toArray(match);
-		return match;
-	}
-	/**
-	 * @see IndexInput#setFirstFile()
-	 */
-	protected void setFirstFile() {
-		filePosition= 1;
-		if (sortedFiles.length > 0) {
-			currentFile= sortedFiles[0];
-		}
-	}
-	/**
-	 * @see IndexInput#setFirstWord()
-	 */
-	protected void setFirstWord() {
-		wordPosition= 1;
-		if (sortedWordEntries.length > 0)
-			currentWordEntry= sortedWordEntries[0];
-	}
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/WordEntry.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/WordEntry.java
deleted file mode 100644
index 7c1e930..0000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/WordEntry.java
+++ /dev/null
@@ -1,160 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.internal.core.util.Util;
-
-public class WordEntry {
-	public char[] fWord;
-	protected int fNumRefs;
-	protected int[] fRefs;
-	public WordEntry() {
-		this(CharOperation.NO_CHAR);
-	}
-	public WordEntry(char[] word) {
-		fWord= word;
-		fNumRefs= 0;
-		fRefs= new int[1];
-	}
-	/**
-	 * Adds a reference and records the change in footprint.
-	 */
-	public int addRef(int fileNum) {
-		if (fNumRefs > 0 && fRefs[fNumRefs - 1] == fileNum) {
-			return 0;
-		}
-		if (fNumRefs < fRefs.length) {
-			fRefs[fNumRefs++]= fileNum;
-			return 0;
-		} 
-
-		// For rt.jar, 73265 word entries are created. 51997 have 1 ref, then 9438, 3738, 1980, 1214, 779, 547, 429, 371 etc.
-		int newSize= fNumRefs < 4 ? 4 : fNumRefs * 2; // so will start @ 1, grow to 4, 8, 16, 32, 64 etc.
-		System.arraycopy(fRefs, 0, fRefs= new int[newSize], 0, fNumRefs);
-		fRefs[fNumRefs++]= fileNum;
-		return (newSize - fNumRefs + 1) * 4;
-	}
-	/**
-	 * Adds a set of references and records the change in footprint.
-	 */
-	public void addRefs(int[] refs) {
-		int[] newRefs= new int[fNumRefs + refs.length];
-		int pos1= 0;
-		int pos2= 0;
-		int posNew= 0;
-		int compare;
-		int r1= 0;
-		int r2= 0;
-		while (pos1 < fNumRefs || pos2 < refs.length) {
-			if (pos1 >= fNumRefs) {
-				r2= refs[pos2];
-				compare= -1;
-			} else if (pos2 >= refs.length) {
-				compare= 1;
-				r1= fRefs[pos1];
-			} else {
-				r1= fRefs[pos1];
-				r2= refs[pos2];
-				compare= r2 - r1;
-			}
-			if (compare > 0) {
-				newRefs[posNew]= r1;
-				posNew++;
-				pos1++;
-			} else {
-				if (r2 != 0) {
-					newRefs[posNew]= r2;
-					posNew++;
-				}
-				pos2++;
-			}
-		}
-		fRefs= newRefs;
-		fNumRefs= posNew;
-		/*for (int i = 0; i < refs.length; i++)
-		addRef(refs[i]);
-		int[] newRefs = new int[fNumRefs];
-		System.arraycopy(fRefs, 0, newRefs, 0, fNumRefs);
-		fRefs = newRefs;
-		Util.sort(fRefs);*/
-	}
-	/**
-	 * Returns the size of the wordEntry
-	 */
-
-	public int footprint() {
-		return 8 + (3 * 4) + (8 + fWord.length * 2) + (8 + fRefs.length * 4);
-	}
-	/**
-	 * Returns the number of references, e.g. the number of files this word appears in.
-	 */
-	public int getNumRefs() {
-		return fNumRefs;
-	}
-	/**
-	 * returns the file number in the i position in the list of references.
-	 */
-	public int getRef(int i) {
-		if (i < fNumRefs) return fRefs[i];
-		throw new IndexOutOfBoundsException();
-	}
-	/**
-	 * Returns the references of the wordEntry (the number of the files it appears in).
-	 */
-
-	public int[] getRefs() {
-		int[] result= new int[fNumRefs];
-		System.arraycopy(fRefs, 0, result, 0, fNumRefs);
-		return result;
-	}
-	/**
-	 * returns the word of the wordEntry.
-	 */
-
-	public char[] getWord() {
-		return fWord;
-	}
-	/**
-	 * Changes the references of the wordEntry to match the mapping. For example,<br>
-	 * if the current references are [1 3 4]<br>
-	 * and mapping is [1 2 3 4 5]<br>
-	 * in references 1 becomes mapping[1] = 2, 3->4, and 4->5<br>
-	 * => references = [2 4 5].<br>
-	 */
-	public void mapRefs(int[] mappings) {
-		int position= 0;
-		for (int i= 0; i < fNumRefs; i++) {
-			int map= mappings[fRefs[i]];
-			if (map != -1 && map != 0)
-				fRefs[position++]= map;
-		}
-		fNumRefs= position;
-
-		//to be changed!
-		System.arraycopy(fRefs, 0, (fRefs= new int[fNumRefs]), 0, fNumRefs);
-		Util.sort(fRefs);
-	}
-	/**
-	 * Clears the wordEntry.
-	 */
-
-	public void reset(char[] word) {
-		for (int i= fNumRefs; i-- > 0;) {
-			fRefs[i]= 0;
-		}
-		fNumRefs= 0;
-		fWord= word;
-	}
-	public String toString() {
-		return new String(fWord);
-	}
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/WordEntryHashedArray.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/WordEntryHashedArray.java
deleted file mode 100644
index c5ab3aa..0000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/impl/WordEntryHashedArray.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- * 
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.index.impl;
-
-import org.eclipse.jdt.core.compiler.CharOperation;
-
-public final class WordEntryHashedArray {
-
-// to avoid using Enumerations, walk the objects skipping nulls
-public WordEntry elements[];
-public int elementSize; // number of elements in the table
-public int threshold;
-
-public WordEntryHashedArray(int size) {
-	if (size < 7) size = 7;
-	this.elements = new WordEntry[2 * size + 1];
-	this.elementSize = 0;
-	this.threshold = size + 1; // size is the expected number of elements
-}
-
-public WordEntry add(WordEntry entry) {
-	int length = elements.length;
-	char[] word = entry.getWord();
-	int index = CharOperation.hashCode(word) % length;
-	WordEntry current;
-	while ((current = elements[index]) != null) {
-		if (CharOperation.equals(current.getWord(), word)) return elements[index] = entry;
-		if (++index == length) index = 0;
-	}
-	elements[index] = entry;
-
-	// assumes the threshold is never equal to the size of the table
-	if (++elementSize > threshold) grow();
-	return entry;
-}
-
-public WordEntry[] asArray() {
-	WordEntry[] array = new WordEntry[elementSize];
-	int count = 0;
-	for (int i = 0, length = elements.length; i < length; i++) {
-		WordEntry current = elements[i];
-		if (current != null)
-			array[count++] = current;
-	}
-	if (count < array.length) // add a little protection because of 40950
-		System.arraycopy(array, 0, array = new WordEntry[count], 0, count);
-	return array;
-}
-
-public WordEntry get(char[] word) {
-	int length = elements.length;
-	int index = CharOperation.hashCode(word) % length;
-	WordEntry current;
-	while ((current = elements[index]) != null) {
-		if (CharOperation.equals(current.getWord(), word)) return current;
-		if (++index == length) index = 0;
-	}
-	return null;
-}
-
-private void grow() {
-	WordEntryHashedArray newArray = new WordEntryHashedArray(elementSize * 2); // double the number of expected elements
-	for (int i = 0, length = elements.length; i < length; i++)
-		if (elements[i] != null)
-			newArray.add(elements[i]);
-
-	this.elements = newArray.elements;
-	this.elementSize = newArray.elementSize;
-	this.threshold = newArray.threshold;
-}
-
-public String toString() {
-	String s = ""; //$NON-NLS-1$
-	WordEntry[] entries = asArray();
-	for (int i = 0, length = entries.length; i < length; i++)
-		s += entries[i].toString() + "\n"; 	//$NON-NLS-1$
-	return s;
-}
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/AbstractSearchScope.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/AbstractSearchScope.java
index 32eb69b..20759d2 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/AbstractSearchScope.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/AbstractSearchScope.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/HierarchyScope.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/HierarchyScope.java
index 7679f30..a3b0d62 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/HierarchyScope.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/HierarchyScope.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -161,8 +161,8 @@
 			IJavaProject[] projects = model.getJavaProjects();
 			HashSet visited = new HashSet();
 			for (int i = 0; i < projects.length; i++) {
-				IJavaProject project = projects[i];
-				IClasspathEntry[] classpath = project.getResolvedClasspath(true);
+				JavaProject project = (JavaProject) projects[i];
+				IClasspathEntry[] classpath = project.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
 				for (int j = 0; j < classpath.length; j++) {
 					if (rootPath.equals(classpath[j].getPath())) {
 						// add the project and its binary pkg fragment roots
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IIndexSearchRequestor.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IIndexSearchRequestor.java
deleted file mode 100644
index 5b703be..0000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IIndexSearchRequestor.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 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;
-
-public interface IIndexSearchRequestor {
-/**
- * Accepts the declaration of a class in the compilation unit with the given resource path.
- * The class is declared in the given package and with the given type name. 
- * <p>
- * Note that the resource path can be null if the search query doesn't require it (eg. get all class names).
- */
-void acceptClassDeclaration(String resourcePath, char[] simpleTypeName, char[][] enclosingTypeNames, char[] packageName);
-/**
- * Accepts the declaration of a constructor in the compilation unit with the given resource path.
- * The constructor is declared with a given name and number of arguments.
- */
-void acceptConstructorDeclaration(String resourcePath, char[] typeName, int parameterCount);
-/**
- * Accepts the reference to a constructor in the compilation unit with the given resource path.
- * The constructor is referenced using the given name and a number of arguments.
- *
- * Note that the resource path can be null if the search query doesn't require it.
- */
-void acceptConstructorReference(String resourcePath, char[] typeName, int parameterCount);
-/**
- * Accepts the declaration of a field in the compilation unit with the given resource path.
- * <p>
- * Note that the resource path can be null if the search query doesn't require it (eg. get all class names).
- * Likewise, the declaring package name and the declaring type names if the query doesn't require them.
- */
-void acceptFieldDeclaration(String resourcePath, char[] fieldName);
-/**
- * Accepts the reference to a field in the compilation unit with the given resource path.
- * The field is referenced using the given name 
- */
-void acceptFieldReference(String resourcePath, char[] fieldName);
-/**
- * Accepts the declaration of an interface in the compilation unit with the given resource path.
- * The interface is declared in the given package and with the given type name. 
- * <p>
- * Note that the resource path can be null if the search query doesn't require it (eg. get all interface names).
- */
-void acceptInterfaceDeclaration(String resourcePath, char[] simpleTypeName, char[][] enclosingTypeNames, char[] packageName);
-/**
- * Accepts the declaration of a method in the compilation unit with the given resource path.
- * The method is declared with a given method name and number of arguments.
- */
-void acceptMethodDeclaration(String resourcePath, char[] methodName, int parameterCount);
-/**
- * Accepts the reference to a method in the compilation unit with the given resource path.
- * The method is referenced using the given selector and a number of arguments.
- *
- * Note that the resource path can be null if the search query doesn't require it.
- */
-void acceptMethodReference(String resourcePath, char[] methodName, int parameterCount);
-/**
- * Accepts the reference to a package in the compilation unit with the given resource path.
- * The package is referenced using the given package name.
- *
- * Note that the resource path can be null if the search query doesn't require it.
- */
-void acceptPackageReference(String resourcePath, char[] packageName);
-/**
- * Accepts the reference to a supertype in the compilation unit with the given resource path.
- * Note that the resource path and/or the package name can be null.
- */
-void acceptSuperTypeReference(String resourcePath, char[] qualification, char[] typeName, char[] enclosingTypeName, char classOrInterface, char[] superQualification, char[] superTypeName, char superClassOrInterface, int modifiers);
-/**
- * Accepts the reference to a class in the compilation unit with the given resource path.
- * The class is referenced using the given type name.
- * <p>
- * Note that the resource path can be null if the search query doesn't require it.
- */
-void acceptTypeReference(String resourcePath, char[] typeName);
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IndexQueryRequestor.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IndexQueryRequestor.java
index fd2dc74..327dcee 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IndexQueryRequestor.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IndexQueryRequestor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IndexSearchAdapter.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IndexSearchAdapter.java
deleted file mode 100644
index 3c9a7d9..0000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IndexSearchAdapter.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 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;
-
-public class IndexSearchAdapter implements IIndexSearchRequestor {
-/**
- * @see IIndexSearchRequestor
- */
-public void acceptClassDeclaration(String resourcePath, char[] simpleTypeName, char[][] enclosingTypeNames, char[] packageName) {
-	// implements interface method
-}
-/**
- * @see IIndexSearchRequestor
- */
-public void acceptConstructorDeclaration(String resourcePath, char[] typeName, int parameterCount) {
-	// implements interface method
-}
-/**
- * @see IIndexSearchRequestor
- */
-public void acceptConstructorReference(String resourcePath, char[] typeName, int parameterCount) {
-	// implements interface method
-}
-/**
- * @see IIndexSearchRequestor
- */
-public void acceptFieldDeclaration(String resourcePath, char[] fieldName) {
-	// implements interface method
-}
-/**
- * @see IIndexSearchRequestor
- */
-public void acceptFieldReference(String resourcePath, char[] fieldName) {
-	// implements interface method
-}
-/**
- * @see IIndexSearchRequestor
- */
-public void acceptInterfaceDeclaration(String resourcePath, char[] simpleTypeName, char[][] enclosingTypeNames, char[] packageName) {
-	// implements interface method
-}
-/**
- * @see IIndexSearchRequestor
- */
-public void acceptMethodDeclaration(String resourcePath, char[] methodName, int parameterCount) {
-	// implements interface method
-}
-/**
- * @see IIndexSearchRequestor
- */
-public void acceptMethodReference(String resourcePath, char[] methodName, int parameterCount) {
-	// implements interface method
-}
-/**
- * @see IIndexSearchRequestor
- */
-public void acceptPackageReference(String resourcePath, char[] packageName) {
-	// implements interface method
-}
-/**
- * @see IIndexSearchRequestor
- */
-public void acceptSuperTypeReference(String resourcePath, char[] qualification, char[] typeName, char[] enclosingTypeName, char classOrInterface, char[] superQualification, char[] superTypeName, char superClassOrInterface, int modifiers){
-	// implements interface method
-}
-/**
- * @see IIndexSearchRequestor
- */
-public void acceptTypeReference(String resourcePath, char[] typeName) {
-	// implements interface method
-}
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IndexSelector.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IndexSelector.java
index 29a8aa9..abdc400 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IndexSelector.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IndexSelector.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -15,6 +15,7 @@
 import org.eclipse.core.resources.IWorkspaceRoot;
 import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
 import org.eclipse.jdt.core.IClasspathEntry;
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.IJavaModel;
@@ -23,7 +24,10 @@
 import org.eclipse.jdt.core.search.IJavaSearchScope;
 import org.eclipse.jdt.core.search.SearchPattern;
 import org.eclipse.jdt.internal.core.JarPackageFragmentRoot;
+import org.eclipse.jdt.internal.core.JavaModelManager;
 import org.eclipse.jdt.internal.core.JavaProject;
+import org.eclipse.jdt.internal.core.search.indexing.IndexManager;
+import org.eclipse.jdt.internal.core.search.matching.MatchLocator;
 
 /**
  * Selects the indexes that correspond to projects in a given search scope
@@ -32,7 +36,7 @@
 public class IndexSelector {
 	IJavaSearchScope searchScope;
 	SearchPattern pattern;
-	IPath[] indexKeys; // cache of the keys for looking index up
+	IPath[] indexLocations; // cache of the keys for looking index up
 	
 public IndexSelector(
 		IJavaSearchScope searchScope,
@@ -55,8 +59,8 @@
 			// it can see the focus only if it is on the classpath of a project that can see the focus
 			IJavaProject[] allProjects = model.getJavaProjects();
 			for (int i = 0, length = allProjects.length; i < length; i++) {
-				IJavaProject otherProject = allProjects[i];
-				IClasspathEntry[] entries = otherProject.getResolvedClasspath(true);
+				JavaProject otherProject = (JavaProject) allProjects[i];
+				IClasspathEntry[] entries = otherProject.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
 				for (int j = 0, length2 = entries.length; j < length2; j++) {
 					IClasspathEntry entry = entries[j];
 					if ((entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) 
@@ -68,51 +72,48 @@
 				}
 			}
 			return false;
-		} else {
-			// projectOrJarPath is a project
-			JavaProject focusProject = focus instanceof JarPackageFragmentRoot ? (JavaProject)focus.getParent() : (JavaProject)focus;
-			if (isPolymorphicSearch) {
-				// look for refering project
-				IClasspathEntry[] entries = focusProject.getExpandedClasspath(true);
-				for (int i = 0, length = entries.length; i < length; i++) {
-					IClasspathEntry entry = entries[i];
-					if ((entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) 
-						&& entry.getPath().equals(projectOrJarPath)) {
-							return true;
-					}
-				}
-			}
-			if (focus instanceof JarPackageFragmentRoot) {
-				// focus is part of a jar
-				IPath focusPath = focus.getPath();
-				IClasspathEntry[] entries = ((JavaProject)project).getExpandedClasspath(true);
-				for (int i = 0, length = entries.length; i < length; i++) {
-					IClasspathEntry entry = entries[i];
-					if ((entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) 
-						&& entry.getPath().equals(focusPath)) {
-							return true;
-					}
-				}
-				return false;
-			} else {
-				// focus is part of a project
-				if (focus.equals(project)) {
-					return true;
-				} else {
-					// look for dependent projects
-					IPath focusPath = focusProject.getProject().getFullPath();
-					IClasspathEntry[] entries = ((JavaProject)project).getExpandedClasspath(true);
-					for (int i = 0, length = entries.length; i < length; i++) {
-						IClasspathEntry entry = entries[i];
-						if ((entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) 
-							&& entry.getPath().equals(focusPath)) {
-								return true;
-						}
-					}
-					return false;
+		}
+		// projectOrJarPath is a project
+		JavaProject focusProject = focus instanceof JarPackageFragmentRoot ? (JavaProject)focus.getParent() : (JavaProject)focus;
+		if (isPolymorphicSearch) {
+			// look for refering project
+			IClasspathEntry[] entries = focusProject.getExpandedClasspath(true);
+			for (int i = 0, length = entries.length; i < length; i++) {
+				IClasspathEntry entry = entries[i];
+				if ((entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) 
+					&& entry.getPath().equals(projectOrJarPath)) {
+						return true;
 				}
 			}
 		}
+		if (focus instanceof JarPackageFragmentRoot) {
+			// focus is part of a jar
+			IPath focusPath = focus.getPath();
+			IClasspathEntry[] entries = ((JavaProject)project).getExpandedClasspath(true);
+			for (int i = 0, length = entries.length; i < length; i++) {
+				IClasspathEntry entry = entries[i];
+				if ((entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) 
+					&& entry.getPath().equals(focusPath)) {
+						return true;
+				}
+			}
+			return false;
+		} 
+		// focus is part of a project
+		if (focus.equals(project)) {
+			return true;
+		} 
+		// look for dependent projects
+		IPath focusPath = focusProject.getProject().getFullPath();
+		IClasspathEntry[] entries = ((JavaProject)project).getExpandedClasspath(true);
+		for (int i = 0, length = entries.length; i < length; i++) {
+			IClasspathEntry entry = entries[i];
+			if ((entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) 
+				&& entry.getPath().equals(focusPath)) {
+					return true;
+			}
+		}
+		return false;
 	} catch (JavaModelException e) {
 		return false;
 	}
@@ -120,13 +121,14 @@
 /*
  *  Compute the list of paths which are keying index files.
  */
-private void initializeIndexKeys() {
+private void initializeIndexLocations() {
 	
 	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);
+	IndexManager manager = JavaModelManager.getJavaModelManager().getIndexManager();
 	for (int i = 0; i < projectsAndJars.length; i++) {
 		IPath location;
 		IPath path = projectsAndJars[i];
@@ -139,18 +141,18 @@
 		}
 		if (projectOrJarFocus == null || canSeeFocus(projectOrJarFocus, isPolymorphicSearch, path)) {
 			if (requiredIndexKeys.indexOf(path) == -1) {
-				requiredIndexKeys.add(path);
+				requiredIndexKeys.add(new Path(manager.computeIndexLocation(path)));
 			}
 		}
 	}
-	this.indexKeys = new IPath[requiredIndexKeys.size()];
-	requiredIndexKeys.toArray(this.indexKeys);
+	this.indexLocations = new IPath[requiredIndexKeys.size()];
+	requiredIndexKeys.toArray(this.indexLocations);
 }
-public IPath[] getIndexKeys() {
-	if (this.indexKeys == null) {
-		this.initializeIndexKeys(); 
+public IPath[] getIndexLocations() {
+	if (this.indexLocations == null) {
+		this.initializeIndexLocations(); 
 	}
-	return this.indexKeys;
+	return this.indexLocations;
 }
 
 /**
@@ -161,14 +163,7 @@
 	IJavaProject project = model.getJavaProject(path.lastSegment());
 	if (project.exists()) {
 		return project;
-	} else {
-		return null;
 	}
-}
-public static IJavaElement getProjectOrJar(IJavaElement element) {
-	while (!(element instanceof IJavaProject) && !(element instanceof JarPackageFragmentRoot)) {
-		element = element.getParent();
-	}
-	return element;
+	return null;
 }
 }
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchDocument.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchDocument.java
index 6d139d4..3d23b40 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchDocument.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchDocument.java
@@ -1,13 +1,27 @@
+/*******************************************************************************
+ * 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;
 
 import java.io.IOException;
 
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.Path;
-import org.eclipse.jdt.core.JavaCore;
-import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.core.search.IJavaSearchScope;
+import org.eclipse.jdt.core.search.SearchDocument;
+import org.eclipse.jdt.core.search.SearchEngine;
+import org.eclipse.jdt.core.search.SearchParticipant;
+import org.eclipse.jdt.internal.core.search.processing.JobManager;
 
 public class JavaSearchDocument extends SearchDocument {
 	
@@ -32,7 +46,9 @@
 		try {
 			return org.eclipse.jdt.internal.compiler.util.Util.getFileByteContent(getLocation().toFile());
 		} catch (IOException e) {
-			/// TODO (jerome) log in VERBOSE mode e.printStackTrace();
+			if (SearchEngine.VERBOSE || JobManager.VERBOSE) { // used during search and during indexing
+				e.printStackTrace();
+			}
 			return null;
 		}
 	}
@@ -41,28 +57,41 @@
 		try {
 			return org.eclipse.jdt.internal.compiler.util.Util.getFileCharContent(getLocation().toFile(), getEncoding());
 		} catch (IOException e) {
-			/// TODO (jerome) log in VERBOSE mode e.printStackTrace();
+			if (SearchEngine.VERBOSE || JobManager.VERBOSE) { // used during search and during indexing
+				e.printStackTrace();
+			}
 			return null;
 		}
 	}
 	public String getEncoding() {
+		// Return the encoding of the associated file
 		IFile resource = getFile();
-		if (resource != null)
-			return JavaCore.create(resource.getProject()).getOption(JavaCore.CORE_ENCODING, true);
-		return JavaCore.getOption(JavaCore.CORE_ENCODING);
+		if (resource != null) {
+			try {
+				return resource.getCharset();
+			}
+			catch(CoreException ce) {
+				try {
+					return ResourcesPlugin.getWorkspace().getRoot().getDefaultCharset();
+				} catch (CoreException e) {
+					// use no encoding
+				}
+			}
+		}
+		return null;
 	}
 	private IFile getFile() {
 		if (this.file == null)
-			this.file = (IFile) ResourcesPlugin.getWorkspace().getRoot().findMember(new Path(this.documentPath));
+			this.file = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(getPath()));
 		return this.file;
 	}
 	private IPath getLocation() {
 		IFile resource = getFile();
 		if (resource != null)
 			return resource.getLocation();
-		return new Path(this.documentPath); // external file
+		return new Path(getPath()); // external file
 	}
 	public String toString() {
-		return "SearchDocument for " + this.documentPath; //$NON-NLS-1$
+		return "SearchDocument for " + getPath(); //$NON-NLS-1$
 	}
 }
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchParticipant.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchParticipant.java
index f424482..231a7f6 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchParticipant.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchParticipant.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -10,26 +10,11 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.search;
 
-import java.util.HashMap;
-import java.util.Iterator;
-
 import org.eclipse.core.runtime.*;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IPath;
-import org.eclipse.core.runtime.IProgressMonitor;
-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.core.search.IJavaSearchScope;
-import org.eclipse.jdt.core.search.SearchDocument;
-import org.eclipse.jdt.core.search.SearchRequestor;
-import org.eclipse.jdt.internal.core.CompilationUnit;
-import org.eclipse.jdt.internal.core.JarPackageFragmentRoot;
 import org.eclipse.jdt.internal.core.search.indexing.BinaryIndexer;
 import org.eclipse.jdt.internal.core.search.indexing.SourceIndexer;
 import org.eclipse.jdt.internal.core.search.matching.MatchLocator;
-import org.eclipse.jdt.core.search.SearchParticipant;
 
 /**
  * A search participant describes a particular extension to a generic search mechanism, allowing thus to 
@@ -43,33 +28,13 @@
  */
 public class JavaSearchParticipant extends SearchParticipant {
 	
-	public class WorkingCopyDocument extends JavaSearchDocument {
-		public ICompilationUnit workingCopy;
-		WorkingCopyDocument(ICompilationUnit workingCopy) {
-			super(workingCopy.getPath().toString(), JavaSearchParticipant.this);
-			this.charContents = ((CompilationUnit)workingCopy).getContents();
-			this.workingCopy = workingCopy;
-		}
-		public String toString() {
-			return "WorkingCopyDocument for " + getPath(); //$NON-NLS-1$
-		}
-	}
-	
 	IndexSelector indexSelector;
 	
-	/*
-	 * A table from path (String) to working copy document (WorkingCopopyDocument)
-	 */
-	ICompilationUnit[] workingCopies;
-	
-	public JavaSearchParticipant(ICompilationUnit[] workingCopies) {
-		this.workingCopies = workingCopies;
-	}
-
 	/* (non-Javadoc)
 	 * @see org.eclipse.jdt.core.search.SearchParticipant#beginSearching()
 	 */
 	public void beginSearching() {
+		super.beginSearching();
 		this.indexSelector = null;
 	}
 
@@ -78,6 +43,7 @@
 	 */
 	public void doneSearching() {
 		this.indexSelector = null;
+		super.doneSearching();
 	}
 
 	/* (non-Javadoc)
@@ -97,12 +63,15 @@
 	/* (non-Javadoc)
 	 * @see org.eclipse.jdt.core.search.SearchParticipant#indexDocument(SearchDocument)
 	 */
-	public void indexDocument(SearchDocument document, String indexPath) {
+	public void indexDocument(SearchDocument document, IPath indexPath) {
+		// TODO must verify that the document + indexPath match, when this is not called from scheduleDocumentIndexing
+		document.removeAllIndexEntries(); // in case the document was already indexed
+
 		String documentPath = document.getPath();
 		if (org.eclipse.jdt.internal.compiler.util.Util.isJavaFileName(documentPath)) {
-			new SourceIndexer(document, indexPath).indexDocument();
+			new SourceIndexer(document).indexDocument();
 		} else if (org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(documentPath)) {
-			new BinaryIndexer(document, indexPath).indexDocument();
+			new BinaryIndexer(document).indexDocument();
 		}
 	}
 	
@@ -117,42 +86,12 @@
 				pattern, 
 				requestor, 
 				scope,
-				this.workingCopies,
 				monitor == null ? null : new SubProgressMonitor(monitor, 95)
 		);
 
-		// working copies take precedence over corresponding compilation units
-		HashMap workingCopyDocuments = workingCopiesThatCanSeeFocus(pattern.focus, pattern.isPolymorphicSearch());
-		SearchDocument[] matches = null;
-		int length = indexMatches.length;
-		for (int i = 0; i < length; i++) {
-			SearchDocument searchDocument = indexMatches[i];
-			if (searchDocument.getParticipant() == this) {
-				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();
-			}
-		}
-
 		/* eliminating false matches and locating them */
 		if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
-		matchLocator.locateMatches(matches);
+		matchLocator.locateMatches(indexMatches);
 		
 
 		if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
@@ -170,31 +109,7 @@
 		if (this.indexSelector == null) {
 			this.indexSelector = new IndexSelector(scope, pattern);
 		}
-		return this.indexSelector.getIndexKeys();
+		return this.indexSelector.getIndexLocations();
 	}
 	
-	/*
-	 * Returns the working copies that can see the given focus.
-	 */
-	private HashMap workingCopiesThatCanSeeFocus(IJavaElement focus, boolean isPolymorphicSearch) {
-		if (this.workingCopies == 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 = this.workingCopies.length; i<length; i++) {
-			ICompilationUnit workingCopy = this.workingCopies[i];
-			IPath projectOrJar = IndexSelector.getProjectOrJar(workingCopy).getPath();
-			if (focus == null || IndexSelector.canSeeFocus(focus, isPolymorphicSearch, projectOrJar)) {
-				result.put(
-					workingCopy.getPath().toString(),
-					new WorkingCopyDocument(workingCopy)
-				);
-			}
-		}
-		return result;
-	}
-
 }
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchScope.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchScope.java
index 20a544a..44f8400 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchScope.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchScope.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -17,6 +17,7 @@
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.Path;
+import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.IClasspathEntry;
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.IJavaElementDelta;
@@ -28,6 +29,8 @@
 import org.eclipse.jdt.core.IPackageFragmentRoot;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.internal.core.JavaElement;
+import org.eclipse.jdt.internal.core.JavaModelManager;
+import org.eclipse.jdt.internal.core.JavaProject;
 
 /**
  * A Java-specific scope for searching relative to one or more java elements.
@@ -66,29 +69,54 @@
 	this.enclosingProjectsAndJars[length] = path;
 }
 
-public void add(IJavaProject javaProject, boolean includesPrereqProjects, HashSet visitedProjects) throws JavaModelException {
+public void add(JavaProject javaProject, int includeMask, HashSet visitedProjects) throws JavaModelException {
 	IProject project = javaProject.getProject();
 	if (!project.isAccessible() || !visitedProjects.add(project)) return;
 
 	this.addEnclosingProjectOrJar(project.getFullPath());
 
-	IClasspathEntry[] entries = javaProject.getResolvedClasspath(true);
+	IClasspathEntry[] entries = javaProject.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
 	IJavaModel model = javaProject.getJavaModel();
 	for (int i = 0, length = entries.length; i < length; i++) {
 		IClasspathEntry entry = entries[i];
 		switch (entry.getEntryKind()) {
 			case IClasspathEntry.CPE_LIBRARY:
-				IPath path = entry.getPath();
-				this.add(path, true);
-				this.addEnclosingProjectOrJar(path);
+				IClasspathEntry rawEntry = null;
+				JavaModelManager.PerProjectInfo perProjectInfo = javaProject.getPerProjectInfo();
+				if (perProjectInfo != null && perProjectInfo.resolvedPathToRawEntries != null) {
+					rawEntry = (IClasspathEntry) perProjectInfo.resolvedPathToRawEntries.get(entry.getPath());
+				}
+				if (rawEntry == null) break;
+				switch (rawEntry.getEntryKind()) {
+					case IClasspathEntry.CPE_LIBRARY:
+					case IClasspathEntry.CPE_VARIABLE:
+						if ((includeMask & APPLICATION_LIBRARIES) != 0) {
+							IPath path = entry.getPath();
+							add(path, true);
+							addEnclosingProjectOrJar(path);
+						}
+						break;
+					case IClasspathEntry.CPE_CONTAINER:
+						IClasspathContainer container = JavaCore.getClasspathContainer(rawEntry.getPath(), javaProject);
+						if (container == null) break;
+						if ((container.getKind() == IClasspathContainer.K_APPLICATION && (includeMask & APPLICATION_LIBRARIES) != 0)
+								|| (includeMask & SYSTEM_LIBRARIES) != 0) {
+							IPath path = entry.getPath();
+							add(path, true);
+							addEnclosingProjectOrJar(path);
+						}
+						break;
+				}
 				break;
 			case IClasspathEntry.CPE_PROJECT:
-				if (includesPrereqProjects) {
-					this.add(model.getJavaProject(entry.getPath().lastSegment()), true, visitedProjects);
+				if ((includeMask & REFERENCED_PROJECTS) != 0) {
+					add((JavaProject) model.getJavaProject(entry.getPath().lastSegment()), includeMask, visitedProjects);
 				}
 				break;
 			case IClasspathEntry.CPE_SOURCE:
-				this.add(entry.getPath(), true);
+				if ((includeMask & SOURCES) != 0) {
+					add(entry.getPath(), true);
+				}
 				break;
 		}
 	}
@@ -100,7 +128,8 @@
 			// a workspace sope should be used
 			break; 
 		case IJavaElement.JAVA_PROJECT:
-			this.add((IJavaProject)element, true, new HashSet(2));
+			int includeMask = SOURCES | APPLICATION_LIBRARIES | SYSTEM_LIBRARIES;
+			this.add((JavaProject)element, includeMask, new HashSet(2));
 			break;
 		case IJavaElement.PACKAGE_FRAGMENT_ROOT:
 			root = (IPackageFragmentRoot)element;
@@ -217,17 +246,14 @@
 			IJavaElement scopeElement = (IJavaElement)this.elements.get(i);
 			IJavaElement searchedElement = element;
 			while (searchedElement != null) {
-				if (searchedElement.equals(scopeElement)) {
+				if (searchedElement.equals(scopeElement))
 					return true;
-				} else {
-					searchedElement = searchedElement.getParent();
-				}
+				searchedElement = searchedElement.getParent();
 			}
 		}
 		return false;
-	} else {
-		return this.encloses(this.fullPath(element));
 	}
+	return this.encloses(this.fullPath(element));
 }
 
 /* (non-Javadoc)
@@ -239,19 +265,18 @@
 private IPath fullPath(IJavaElement element) {
 	if (element instanceof IPackageFragmentRoot) {
 		return ((IPackageFragmentRoot)element).getPath();
-	} else 	{
-		IJavaElement parent = element.getParent();
-		IPath parentPath = parent == null ? null : this.fullPath(parent);
-		IPath childPath;
-		if (element instanceof IPackageFragment) {
-			childPath = new Path(element.getElementName().replace('.', '/'));
-		} else if (element instanceof IOpenable) {
-			childPath = new Path(element.getElementName());
-		} else {
-			return parentPath;
-		}
-		return parentPath == null ? childPath : parentPath.append(childPath);
 	}
+	IJavaElement parent = element.getParent();
+	IPath parentPath = parent == null ? null : this.fullPath(parent);
+	IPath childPath;
+	if (element instanceof IPackageFragment) {
+		childPath = new Path(element.getElementName().replace('.', '/'));
+	} else if (element instanceof IOpenable) {
+		childPath = new Path(element.getElementName());
+	} else {
+		return parentPath;
+	}
+	return parentPath == null ? childPath : parentPath.append(childPath);
 }
 
 protected void initialize() {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaWorkspaceScope.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaWorkspaceScope.java
index 9db43aa..8d3d176 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaWorkspaceScope.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaWorkspaceScope.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -17,6 +17,7 @@
 import org.eclipse.jdt.core.IJavaElementDelta;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.internal.core.JavaModelManager;
+import org.eclipse.jdt.internal.core.JavaProject;
 import org.eclipse.jdt.core.IJavaProject;
 
 /**
@@ -74,8 +75,10 @@
 	super.initialize();
 	try {
 		IJavaProject[] projects = JavaModelManager.getJavaModelManager().getJavaModel().getJavaProjects();
-		for (int i = 0, length = projects.length; i < length; i++)
-			this.add(projects[i], false, new HashSet(2));
+		for (int i = 0, length = projects.length; i < length; i++) {
+			int includeMask = SOURCES | APPLICATION_LIBRARIES | SYSTEM_LIBRARIES;
+			this.add((JavaProject) projects[i], includeMask, new HashSet(2));
+		}
 	} catch (JavaModelException ignored) {
 		// ignore
 	}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/PathCollector.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/PathCollector.java
index 6ac350e..cff112e 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/PathCollector.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/PathCollector.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/PatternSearchJob.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/PatternSearchJob.java
index daf5c84..9e25e90 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/PatternSearchJob.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/PatternSearchJob.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -15,144 +15,109 @@
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.OperationCanceledException;
-import org.eclipse.jdt.core.search.IJavaSearchScope;
-import org.eclipse.jdt.core.search.SearchParticipant;
-import org.eclipse.jdt.core.search.SearchPattern;
+import org.eclipse.jdt.core.search.*;
 import org.eclipse.jdt.internal.core.JavaModelManager;
-import org.eclipse.jdt.internal.core.index.IIndex;
+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;
 
 public class PatternSearchJob implements IJob {
 
-	protected SearchPattern pattern;
-	protected IJavaSearchScope scope;
-	protected SearchParticipant participant;
-	protected IndexQueryRequestor requestor;
-	protected boolean areIndexesReady;
-	protected long executionTime = 0;
-	
-	public PatternSearchJob(
-		SearchPattern pattern,
-		SearchParticipant participant,
-		IJavaSearchScope scope,
-		IndexQueryRequestor requestor) {
+protected SearchPattern pattern;
+protected IJavaSearchScope scope;
+protected SearchParticipant participant;
+protected IndexQueryRequestor requestor;
+protected boolean areIndexesReady;
+protected long executionTime = 0;
 
-		this.pattern = pattern;
-		this.participant = participant;
-		this.scope = scope;
-		this.requestor = requestor;
-	}
-	public boolean belongsTo(String jobFamily) {
-		return true;
-	}
-	public void cancel() {
-		// search job is cancelled through progress 
-	}
-	public void ensureReadyToRun() {
-		if (!this.areIndexesReady) {
-			getIndexes(null/*progress*/); // may trigger some index recreation
-		}
-	}
-	public boolean execute(IProgressMonitor progressMonitor) {
+public PatternSearchJob(SearchPattern pattern, SearchParticipant participant, IJavaSearchScope scope, IndexQueryRequestor requestor) {
+	this.pattern = pattern;
+	this.participant = participant;
+	this.scope = scope;
+	this.requestor = requestor;
+}
+public boolean belongsTo(String jobFamily) {
+	return true;
+}
+public void cancel() {
+	// search job is cancelled through progress 
+}
+public void ensureReadyToRun() {
+	if (!this.areIndexesReady)
+		getIndexes(null/*progress*/); // may trigger some index recreation
+}
+public boolean execute(IProgressMonitor progressMonitor) {
+	if (progressMonitor != null && progressMonitor.isCanceled()) throw new OperationCanceledException();
 
-		if (progressMonitor != null && progressMonitor.isCanceled())
-			throw new OperationCanceledException();
-		boolean isComplete = COMPLETE;
-		executionTime = 0;
-		IIndex[] indexes = getIndexes(progressMonitor);
-		try {
-			int max = indexes.length;
+	boolean isComplete = COMPLETE;
+	executionTime = 0;
+	Index[] indexes = getIndexes(progressMonitor);
+	try {
+		int max = indexes.length;
+		if (progressMonitor != null)
+			progressMonitor.beginTask("", max); //$NON-NLS-1$
+		for (int i = 0; i < max; i++) {
+			isComplete &= search(indexes[i], progressMonitor);
 			if (progressMonitor != null) {
-				progressMonitor.beginTask("", max); //$NON-NLS-1$
-			}
-			for (int i = 0; i < max; i++) {
-				isComplete &= search(indexes[i], progressMonitor);
-				if (progressMonitor != null) {
-					if (progressMonitor.isCanceled()) {
-						throw new OperationCanceledException();
-					} else {
-						progressMonitor.worked(1);
-					}
-				}
-			}
-			if (JobManager.VERBOSE) {
-				JobManager.verbose("-> execution time: " + executionTime + "ms - " + this);//$NON-NLS-1$//$NON-NLS-2$
-			}
-			return isComplete;
-		} finally {
-			if (progressMonitor != null) {
-				progressMonitor.done();
+				if (progressMonitor.isCanceled()) throw new OperationCanceledException();
+				progressMonitor.worked(1);
 			}
 		}
+		if (JobManager.VERBOSE)
+			Util.verbose("-> execution time: " + executionTime + "ms - " + this);//$NON-NLS-1$//$NON-NLS-2$
+		return isComplete;
+	} finally {
+		if (progressMonitor != null)
+			progressMonitor.done();
 	}
-	public IIndex[] getIndexes(IProgressMonitor progressMonitor) {
-		
-		// acquire the in-memory indexes on the fly
-		IPath[] indexPathes = this.participant.selectIndexes(this.pattern, this.scope);
-		int length = indexPathes.length;
-		IIndex[] indexes = new IIndex[length];
-		int count = 0;
-		IndexManager indexManager = JavaModelManager.getJavaModelManager().getIndexManager();
-		for (int i = 0; i < length; i++){
-			if (progressMonitor != null && progressMonitor.isCanceled())
-				throw new OperationCanceledException();
-			// may trigger some index recreation work
-			IIndex index = indexManager.getIndex(indexPathes[i], true /*reuse index file*/, false /*do not create if none*/);
-			if (index != null) indexes[count++] = index; // only consider indexes which are ready yet
-		}
-		if (count != length) {
-			System.arraycopy(indexes, 0, indexes=new IIndex[count], 0, count);
-		}
+}
+public Index[] getIndexes(IProgressMonitor progressMonitor) {
+	// acquire the in-memory indexes on the fly
+	IPath[] indexLocations = this.participant.selectIndexes(this.pattern, this.scope);
+	int length = indexLocations.length;
+	Index[] indexes = new Index[length];
+	int count = 0;
+	IndexManager indexManager = JavaModelManager.getJavaModelManager().getIndexManager();
+	for (int i = 0; i < length; i++) {
+		if (progressMonitor != null && progressMonitor.isCanceled()) throw new OperationCanceledException();
+		// may trigger some index recreation work
+		String indexLocation = indexLocations[i].toOSString();
+		IPath containerPath = (IPath) indexManager.indexLocations.keyForValue(indexLocation);
+		Index index = indexManager.getIndex(containerPath, indexLocations[i].toOSString(), true /*reuse index file*/, false /*do not create if none*/);
+		if (index != null)
+			indexes[count++] = index; // only consider indexes which are ready
+	}
+	if (count == length) 
 		this.areIndexesReady = true;
-		return indexes;
-	}	
+	else
+		System.arraycopy(indexes, 0, indexes=new Index[count], 0, count);
+	return indexes;
+}	
+public boolean search(Index index, IProgressMonitor progressMonitor) {
+	if (index == null) return COMPLETE;
+	if (progressMonitor != null && progressMonitor.isCanceled()) throw new OperationCanceledException();
 
-	public boolean search(IIndex index, IProgressMonitor progressMonitor) {
-
-		if (progressMonitor != null && progressMonitor.isCanceled())
-			throw new OperationCanceledException();
-
-//			System.out.println("SANITY CHECK: search job using obsolete index: ["+index+ "] instead of: ["+inMemIndex+"]");
-		if (index == null)
-			return COMPLETE;
-		IndexManager indexManager = JavaModelManager.getJavaModelManager().getIndexManager();
-		ReadWriteMonitor monitor = indexManager.getMonitorFor(index);
-		if (monitor == null)
-			return COMPLETE; // index got deleted since acquired
-		try {
-			monitor.enterRead(); // ask permission to read
-
-			/* if index has changed, commit these before querying */
-			if (index.hasChanged()) {
-				try {
-					monitor.exitRead(); // free read lock
-					monitor.enterWrite(); // ask permission to write
-					indexManager.saveIndex(index);
-				} catch (IOException e) {
-					return FAILED;
-				} finally {
-					monitor.exitWriteEnterRead(); // finished writing and reacquire read permission
-				}
-			}
-			long start = System.currentTimeMillis();
-			pattern.findIndexMatches(
-				index,
-				requestor,
-				this.participant,
-				this.scope,
-				progressMonitor);
-			executionTime += System.currentTimeMillis() - start;
-			return COMPLETE;
-		} catch (IOException e) {
-			return FAILED;
-		} finally {
-			monitor.exitRead(); // finished reading
-		}
+	ReadWriteMonitor monitor = index.monitor;
+	if (monitor == null) return COMPLETE; // index got deleted since acquired
+	try {
+		monitor.enterRead(); // ask permission to read
+		long start = System.currentTimeMillis();
+		MatchLocator.findIndexMatches(this.pattern, index, requestor, this.participant, this.scope, progressMonitor);
+		executionTime += System.currentTimeMillis() - start;
+		return COMPLETE;
+	} catch (IOException e) {
+		if (e instanceof java.io.EOFException)
+			e.printStackTrace();
+		return FAILED;
+	} finally {
+		monitor.exitRead(); // finished reading
 	}
-	public String toString() {
-		return "searching " + pattern.toString(); //$NON-NLS-1$
-	}
+}
+public String toString() {
+	return "searching " + pattern.toString(); //$NON-NLS-1$
+}
 }
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/SubTypeSearchJob.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/SubTypeSearchJob.java
index 58f7e14..695bef4 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/SubTypeSearchJob.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/SubTypeSearchJob.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -11,92 +11,39 @@
 package org.eclipse.jdt.internal.core.search;
 
 import java.io.IOException;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
 
 import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.OperationCanceledException;
-import org.eclipse.jdt.core.search.IJavaSearchScope;
-import org.eclipse.jdt.core.search.SearchParticipant;
-import org.eclipse.jdt.core.search.SearchPattern;
-import org.eclipse.jdt.internal.core.JavaModelManager;
-import org.eclipse.jdt.internal.core.index.IIndex;
-import org.eclipse.jdt.internal.core.index.impl.BlocksIndexInput;
-import org.eclipse.jdt.internal.core.index.impl.IndexInput;
-import org.eclipse.jdt.internal.core.search.indexing.IndexManager;
-import org.eclipse.jdt.internal.core.search.indexing.ReadWriteMonitor;
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.internal.core.index.Index;
+import org.eclipse.jdt.internal.core.util.SimpleSet;
 
 public class SubTypeSearchJob extends PatternSearchJob {
 
-	Map inputs = new HashMap(5);
+SimpleSet indexes = new SimpleSet(5);
 
-public SubTypeSearchJob(
-		SearchPattern pattern,
-		SearchParticipant participant,
-		IJavaSearchScope scope,
-		IndexQueryRequestor requestor) {
-
-		super(
-			pattern,
-			participant,
-			scope,
-			requestor);
+public SubTypeSearchJob(SearchPattern pattern, SearchParticipant participant, IJavaSearchScope scope, IndexQueryRequestor requestor) {
+	super(pattern, participant, scope, requestor);
 }
-public void closeAll(){
-
-	Iterator openedInputs = inputs.values().iterator();
-	while (openedInputs.hasNext()){
-		IndexInput input = (IndexInput) openedInputs.next();
-		try {
-			input.close();
-		} catch(IOException e){
-			// ignore
-		}
+public void finished() {
+	try {
+		Object[] values = this.indexes.values;
+		for (int i = 0, l = values.length; i < l; i++)
+			if (values[i] != null)
+				((Index) values[i]).stopQuery();
+	} catch(IOException e) {
+		// ignore
 	} 
 }
-/**
- * execute method comment.
- */
-public boolean search(IIndex index, IProgressMonitor progressMonitor) {
-
-	if (progressMonitor != null && progressMonitor.isCanceled()) throw new OperationCanceledException();
-
-	if (index == null) return COMPLETE;		
-	IndexManager indexManager = JavaModelManager.getJavaModelManager().getIndexManager();
-	ReadWriteMonitor monitor = indexManager.getMonitorFor(index);
-	if (monitor == null) return COMPLETE; // index got deleted since acquired
+public boolean search(Index index, IProgressMonitor progressMonitor) {
+	if (index == null) return COMPLETE;
 	try {
-		monitor.enterRead(); // ask permission to read
-
-		/* if index has changed, commit these before querying */
-		if (index.hasChanged()){
-			try {
-				monitor.exitRead(); // free read lock
-				monitor.enterWrite(); // ask permission to write
-				indexManager.saveIndex(index);
-			} catch(IOException e){
-				return FAILED;
-			} finally {
-				monitor.exitWriteEnterRead(); // finished writing and reacquire read permission
-			}
+		if (!indexes.includes(index)) {
+			indexes.add(index);
+			index.startQuery();
 		}
-		long start = System.currentTimeMillis();
-
-		IndexInput input;
-		if ((input = (IndexInput) inputs.get(index)) == null){
-			input = new BlocksIndexInput(index.getIndexFile());
-			input.open();
-			inputs.put(index, input);
-			//System.out.println("Acquiring INPUT for "+index);
-		}
-		pattern.findIndexMatches(input, requestor, this.participant, this.scope, progressMonitor);
-		executionTime += System.currentTimeMillis() - start;
-		return COMPLETE;
-	} catch(IOException e){
+	} catch (IOException e) {
 		return FAILED;
-	} finally {
-		monitor.exitRead(); // finished reading
 	}
+	return super.search(index, progressMonitor);
 }
 }
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AbstractIndexer.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AbstractIndexer.java
index 7cafd2b..b2bec59 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AbstractIndexer.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AbstractIndexer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -10,34 +10,35 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.search.indexing;
 
-
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.search.SearchDocument;
-import org.eclipse.jdt.core.search.SearchParticipant;
 import org.eclipse.jdt.internal.core.search.matching.*;
 
 public abstract class AbstractIndexer implements IIndexConstants {
 
 	SearchDocument document;
-	String indexPath;
-	
-	public AbstractIndexer(SearchDocument document, String indexPath) {
+
+	public AbstractIndexer(SearchDocument document) {
 		this.document = document;
-		this.indexPath = indexPath;
 	}
 	public void addClassDeclaration(int modifiers, char[] packageName,char[] name,  char[][] enclosingTypeNames, char[] superclass, char[][] superinterfaces) {
-		addIndexEntry(TYPE_DECL, TypeDeclarationPattern.createIndexKey(packageName, enclosingTypeNames, name, true));
-	
+		addIndexEntry(TYPE_DECL, TypeDeclarationPattern.createIndexKey(name, packageName, enclosingTypeNames, CLASS_SUFFIX));
+
+		if (superclass != null)
+			addTypeReference(superclass);
 		addIndexEntry(
 			SUPER_REF, 
 			SuperTypeReferencePattern.createIndexKey(
 				modifiers, packageName, name, enclosingTypeNames, CLASS_SUFFIX, superclass, CLASS_SUFFIX));
-		if (superinterfaces != null)
-			for (int i = 0, max = superinterfaces.length; i < max; i++)
+		if (superinterfaces != null) {
+			for (int i = 0, max = superinterfaces.length; i < max; i++) {
+				addTypeReference(superinterfaces[i]);
 				addIndexEntry(
 					SUPER_REF,
 					SuperTypeReferencePattern.createIndexKey(
 						modifiers, packageName, name, enclosingTypeNames, CLASS_SUFFIX, superinterfaces[i], INTERFACE_SUFFIX));
+			}
+		}
 	}
 	public void addConstructorDeclaration(char[] typeName, char[][] parameterTypes, char[][] exceptionTypes) {
 		int argCount = parameterTypes == null ? 0 : parameterTypes.length;
@@ -50,27 +51,32 @@
 				addTypeReference(exceptionTypes[i]);
 	}
 	public void addConstructorReference(char[] typeName, int argCount) {
-		addIndexEntry(CONSTRUCTOR_REF, ConstructorPattern.createIndexKey(CharOperation.lastSegment(typeName,'.'), argCount));
+		char[] simpleTypeName = CharOperation.lastSegment(typeName,'.');
+		addTypeReference(simpleTypeName);
+		addIndexEntry(CONSTRUCTOR_REF, ConstructorPattern.createIndexKey(simpleTypeName, argCount));
 	}
 	public void addFieldDeclaration(char[] typeName, char[] fieldName) {
 		addIndexEntry(FIELD_DECL, FieldPattern.createIndexKey(fieldName));
 		addTypeReference(typeName);
 	}
 	public void addFieldReference(char[] fieldName) {
-		addIndexEntry(FIELD_REF, FieldPattern.createIndexKey(fieldName));
+		addNameReference(fieldName);
 	}
 	protected void addIndexEntry(char[] category, char[] key) {
-		SearchParticipant.addIndexEntry(category, key, this.document, this.indexPath);
+		this.document.addIndexEntry(category, key);
 	}
 	public void addInterfaceDeclaration(int modifiers, char[] packageName, char[] name, char[][] enclosingTypeNames, char[][] superinterfaces) {
-		addIndexEntry(TYPE_DECL, TypeDeclarationPattern.createIndexKey(packageName, enclosingTypeNames, name, false));
-	
-		if (superinterfaces != null)
-			for (int i = 0, max = superinterfaces.length; i < max; i++)
+		addIndexEntry(TYPE_DECL, TypeDeclarationPattern.createIndexKey(name, packageName, enclosingTypeNames, INTERFACE_SUFFIX));
+
+		if (superinterfaces != null) {
+			for (int i = 0, max = superinterfaces.length; i < max; i++) {
+				addTypeReference(superinterfaces[i]);
 				addIndexEntry(
 					SUPER_REF,
 					SuperTypeReferencePattern.createIndexKey(
 						modifiers, packageName, name, enclosingTypeNames, INTERFACE_SUFFIX, superinterfaces[i], INTERFACE_SUFFIX));
+			}
+		}
 	}
 	public void addMethodDeclaration(char[] methodName, char[][] parameterTypes, char[] returnType, char[][] exceptionTypes) {
 		int argCount = parameterTypes == null ? 0 : parameterTypes.length;
@@ -91,7 +97,7 @@
 		addIndexEntry(REF, name);
 	}
 	public void addTypeReference(char[] typeName) {
-		addIndexEntry(TYPE_REF, TypeReferencePattern.createIndexKey(CharOperation.lastSegment(typeName, '.')));
+		addNameReference(CharOperation.lastSegment(typeName, '.'));
 	}
 	public abstract void indexDocument();
 }
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddFolderToIndex.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddFolderToIndex.java
index fa52d9b..4df92c9 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddFolderToIndex.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddFolderToIndex.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -18,20 +18,22 @@
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.jdt.internal.core.index.IIndex;
+import org.eclipse.jdt.internal.core.index.Index;
 import org.eclipse.jdt.internal.core.search.processing.JobManager;
 import org.eclipse.jdt.internal.core.util.Util;
 
 class AddFolderToIndex extends IndexRequest {
 	IPath folderPath;
 	IProject project;
-	char[][] exclusionPattern;
+	char[][] inclusionPatterns;
+	char[][] exclusionPatterns;
 
-	public AddFolderToIndex(IPath folderPath, IProject project, char[][] exclusionPattern, IndexManager manager) {
+	public AddFolderToIndex(IPath folderPath, IProject project, char[][] inclusionPatterns, char[][] exclusionPatterns, IndexManager manager) {
 		super(project.getFullPath(), manager);
 		this.folderPath = folderPath;
 		this.project = project;
-		this.exclusionPattern = exclusionPattern;
+		this.inclusionPatterns = inclusionPatterns;
+		this.exclusionPatterns = exclusionPatterns;
 	}
 	public boolean execute(IProgressMonitor progressMonitor) {
 
@@ -41,9 +43,9 @@
 		if (folder == null || folder.getType() == IResource.FILE) return true; // nothing to do, source folder was removed
 
 		/* ensure no concurrent write access to index */
-		IIndex index = manager.getIndex(this.containerPath, true, /*reuse index file*/ true /*create if none*/);
+		Index index = this.manager.getIndex(this.containerPath, true, /*reuse index file*/ true /*create if none*/);
 		if (index == null) return true;
-		ReadWriteMonitor monitor = manager.getMonitorFor(index);
+		ReadWriteMonitor monitor = index.monitor;
 		if (monitor == null) return true; // index got deleted since acquired
 
 		try {
@@ -51,30 +53,48 @@
 
 			final IPath container = this.containerPath;
 			final IndexManager indexManager = this.manager;
-			final char[][] pattern = exclusionPattern;
-			folder.accept(
-				new IResourceProxyVisitor() {
-					public boolean visit(IResourceProxy proxy) /* throws CoreException */{
-						switch(proxy.getType()) {
-							case IResource.FILE :
-								if (org.eclipse.jdt.internal.compiler.util.Util.isJavaFileName(proxy.getName())) {
-									IResource resource = proxy.requestResource();
-									if (pattern == null || !Util.isExcluded(resource, pattern))
-										indexManager.addSource((IFile)resource, container);
-								}
+			if (this.exclusionPatterns == null && this.inclusionPatterns == null) {
+				folder.accept(
+					new IResourceProxyVisitor() {
+						public boolean visit(IResourceProxy proxy) /* throws CoreException */{
+							if (proxy.getType() == IResource.FILE) {
+								if (org.eclipse.jdt.internal.compiler.util.Util.isJavaFileName(proxy.getName()))
+									indexManager.addSource((IFile) proxy.requestResource(), container);
 								return false;
-							case IResource.FOLDER :
-								if (pattern != null && Util.isExcluded(proxy.requestResource(), pattern))
-									return false;
+							}
+							return true;
 						}
-						return true;
-					}
-				},
-				IResource.NONE
-			);
+					},
+					IResource.NONE
+				);
+			} else {
+				folder.accept(
+					new IResourceProxyVisitor() {
+						public boolean visit(IResourceProxy proxy) /* throws CoreException */{
+							switch(proxy.getType()) {
+								case IResource.FILE :
+									if (org.eclipse.jdt.internal.compiler.util.Util.isJavaFileName(proxy.getName())) {
+										IResource resource = proxy.requestResource();
+										if (!Util.isExcluded(resource, inclusionPatterns, exclusionPatterns))
+											indexManager.addSource((IFile)resource, container);
+									}
+									return false;
+								case IResource.FOLDER :
+									if (exclusionPatterns != null && inclusionPatterns == null) {
+										// if there are inclusion patterns then we must walk the children
+										if (Util.isExcluded(proxy.requestFullPath(), inclusionPatterns, exclusionPatterns, true)) 
+										    return false;
+									}
+							}
+							return true;
+						}
+					},
+					IResource.NONE
+				);
+			}
 		} catch (CoreException e) {
 			if (JobManager.VERBOSE) {
-				JobManager.verbose("-> failed to add " + this.folderPath + " to index because of the following exception:"); //$NON-NLS-1$ //$NON-NLS-2$
+				Util.verbose("-> failed to add " + this.folderPath + " to index because of the following exception:", System.err); //$NON-NLS-1$ //$NON-NLS-2$
 				e.printStackTrace();
 			}
 			return false;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddJarFileToIndex.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddJarFileToIndex.java
index 5b9701f..e263d9e 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddJarFileToIndex.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddJarFileToIndex.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -23,7 +23,7 @@
 import org.eclipse.jdt.core.search.SearchParticipant;
 import org.eclipse.jdt.internal.compiler.util.Util;
 import org.eclipse.jdt.internal.core.JavaModelManager;
-import org.eclipse.jdt.internal.core.index.IIndex;
+import org.eclipse.jdt.internal.core.index.Index;
 import org.eclipse.jdt.internal.core.search.JavaSearchDocument;
 import org.eclipse.jdt.internal.core.search.processing.JobManager;
 import org.eclipse.jdt.internal.core.util.SimpleLookupTable;
@@ -62,23 +62,23 @@
 		try {
 			// if index is already cached, then do not perform any check
 			// MUST reset the IndexManager if a jar file is changed
-			IIndex index = manager.getIndexForUpdate(this.containerPath, false, /*do not reuse index file*/ false /*do not create if none*/);
+			Index index = this.manager.getIndexForUpdate(this.containerPath, false, /*do not reuse index file*/ false /*do not create if none*/);
 			if (index != null) {
 				if (JobManager.VERBOSE)
-					JobManager.verbose("-> no indexing required (index already exists) for " + this.containerPath); //$NON-NLS-1$
+					org.eclipse.jdt.internal.core.util.Util.verbose("-> no indexing required (index already exists) for " + this.containerPath); //$NON-NLS-1$
 				return true;
 			}
 
-			index = manager.getIndexForUpdate(this.containerPath, true, /*reuse index file*/ true /*create if none*/);
+			index = this.manager.getIndexForUpdate(this.containerPath, true, /*reuse index file*/ true /*create if none*/);
 			if (index == null) {
 				if (JobManager.VERBOSE)
-					JobManager.verbose("-> index could not be created for " + this.containerPath); //$NON-NLS-1$
+					org.eclipse.jdt.internal.core.util.Util.verbose("-> index could not be created for " + this.containerPath); //$NON-NLS-1$
 				return true;
 			}
-			ReadWriteMonitor monitor = manager.getMonitorFor(index);
+			ReadWriteMonitor monitor = index.monitor;
 			if (monitor == null) {
 				if (JobManager.VERBOSE)
-					JobManager.verbose("-> index for " + this.containerPath + " just got deleted"); //$NON-NLS-1$//$NON-NLS-2$
+					org.eclipse.jdt.internal.core.util.Util.verbose("-> index for " + this.containerPath + " just got deleted"); //$NON-NLS-1$//$NON-NLS-2$
 				return true; // index got deleted since acquired
 			}
 			ZipFile zip = null;
@@ -106,15 +106,15 @@
 
 				if (this.isCancelled) {
 					if (JobManager.VERBOSE)
-						JobManager.verbose("-> indexing of " + zip.getName() + " has been cancelled"); //$NON-NLS-1$ //$NON-NLS-2$
+						org.eclipse.jdt.internal.core.util.Util.verbose("-> indexing of " + zip.getName() + " has been cancelled"); //$NON-NLS-1$ //$NON-NLS-2$
 					return false;
 				}
 
 				if (JobManager.VERBOSE)
-					JobManager.verbose("-> indexing " + zip.getName()); //$NON-NLS-1$
+					org.eclipse.jdt.internal.core.util.Util.verbose("-> indexing " + zip.getName()); //$NON-NLS-1$
 				long initialTime = System.currentTimeMillis();
 
-				String[] paths = index.queryInDocumentNames(""); // all file names //$NON-NLS-1$
+				String[] paths = index.queryDocumentNames(""); // all file names //$NON-NLS-1$
 				int max = paths == null ? 0 : paths.length;
 				if (max != 0) {
 					/* check integrity of the existing index file
@@ -146,7 +146,7 @@
 						}
 						if (!needToReindex) {
 							if (JobManager.VERBOSE)
-								JobManager.verbose("-> no indexing required (index is consistent with library) for " //$NON-NLS-1$
+								org.eclipse.jdt.internal.core.util.Util.verbose("-> no indexing required (index is consistent with library) for " //$NON-NLS-1$
 								+ zip.getName() + " (" //$NON-NLS-1$
 								+ (System.currentTimeMillis() - initialTime) + "ms)"); //$NON-NLS-1$
 							return true;
@@ -161,7 +161,7 @@
 				for (Enumeration e = zip.entries(); e.hasMoreElements();) {
 					if (this.isCancelled) {
 						if (JobManager.VERBOSE)
-							JobManager.verbose("-> indexing of " + zip.getName() + " has been cancelled"); //$NON-NLS-1$ //$NON-NLS-2$
+							org.eclipse.jdt.internal.core.util.Util.verbose("-> indexing of " + zip.getName() + " has been cancelled"); //$NON-NLS-1$ //$NON-NLS-2$
 						return false;
 					}
 
@@ -170,12 +170,12 @@
 					if (Util.isClassFileName(ze.getName())) {
 						final byte[] classFileBytes = org.eclipse.jdt.internal.compiler.util.Util.getZipEntryByteContent(ze, zip);
 						JavaSearchDocument entryDocument = new JavaSearchDocument(ze, zipFilePath, classFileBytes, participant);
-						this.manager.indexDocument(entryDocument, participant, index);
+						this.manager.indexDocument(entryDocument, participant, index, this.containerPath);
 					}
 				}
 				this.manager.saveIndex(index);
 				if (JobManager.VERBOSE)
-					JobManager.verbose("-> done indexing of " //$NON-NLS-1$
+					org.eclipse.jdt.internal.core.util.Util.verbose("-> done indexing of " //$NON-NLS-1$
 						+ zip.getName() + " (" //$NON-NLS-1$
 						+ (System.currentTimeMillis() - initialTime) + "ms)"); //$NON-NLS-1$
 			} finally {
@@ -188,7 +188,7 @@
 			}
 		} catch (IOException e) {
 			if (JobManager.VERBOSE) {
-				JobManager.verbose("-> failed to index " + this.containerPath + " because of the following exception:"); //$NON-NLS-1$ //$NON-NLS-2$
+				org.eclipse.jdt.internal.core.util.Util.verbose("-> failed to index " + this.containerPath + " because of the following exception:"); //$NON-NLS-1$ //$NON-NLS-2$
 				e.printStackTrace();
 			}
 			manager.removeIndex(this.containerPath);
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/BinaryIndexer.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/BinaryIndexer.java
index 808412b..114402c 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/BinaryIndexer.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/BinaryIndexer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -30,18 +30,34 @@
 	private static final char[] BOOLEAN = "boolean".toCharArray(); //$NON-NLS-1$
 	private static final char[] VOID = "void".toCharArray(); //$NON-NLS-1$
 	private static final char[] INIT = "<init>".toCharArray(); //$NON-NLS-1$
-	
-	private static final char[] ONE_DOLLAR = "$".toCharArray(); //$NON-NLS-1$
-	private static final char[] ONE_DOT = ".".toCharArray(); //$NON-NLS-1$
 
-	public BinaryIndexer(SearchDocument document, String indexPath) {
-		super(document, indexPath);
+	public BinaryIndexer(SearchDocument document) {
+		super(document);
 	}
-	public void addTypeReference(char[] typeName){
-	 
+	public void addTypeReference(char[] typeName) {
+		int length = typeName.length;
+		if (length > 2 && typeName[length - 2] == '$') {
+			switch (typeName[length - 1]) {
+				case '0' :
+				case '1' :
+				case '2' :
+				case '3' :
+				case '4' :
+				case '5' :
+				case '6' :
+				case '7' :
+				case '8' :
+				case '9' :
+					return; // skip local type names
+			}
+		}
+
 	 	// consider that A$B is a member type: so replace '$' with '.'
 	 	// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=40116)
-	 	typeName = CharOperation.replace(typeName, ONE_DOLLAR, ONE_DOT); // note this doesn't create a new array if no replacement is needed
+		if (CharOperation.indexOf('$', typeName) > 0) {
+			System.arraycopy(typeName, 0, typeName = new char[length], 0, length); // copy it so the original is not modified
+			CharOperation.replace(typeName, '$', '.');
+		}
 	 	super.addTypeReference(typeName);
 	}
 	/**
@@ -80,66 +96,60 @@
 		for (int i = 0, max = signature.length; i < max; i++) {
 			switch(signature[i]) {
 				case 'B':
-					if (arrayDim > 0) {
+					if (arrayDim > 0)
 						return convertToArrayType(BYTE, arrayDim);
-					} else {
-						return BYTE;
-					}
+					return BYTE;
+					
 				case 'C':
-					if (arrayDim > 0) {
+					if (arrayDim > 0)
 						return convertToArrayType(CHAR, arrayDim);
-					} else {
-						return CHAR;
-					}
+					return CHAR;
+					
 				case 'D':
-					if (arrayDim > 0) {
+					if (arrayDim > 0)
 						return convertToArrayType(DOUBLE, arrayDim);
-					} else {
-						return DOUBLE;
-					}
+					return DOUBLE;
+					
 				case 'F':
-					if (arrayDim > 0) {
+					if (arrayDim > 0)
 						return convertToArrayType(FLOAT, arrayDim);
-					} else {
-						return FLOAT;
-					}
+					return FLOAT;
+					
 				case 'I':
-					if (arrayDim > 0) {
-						return convertToArrayType(INT, arrayDim);
-					} else {
-						return INT;
-					}
+					if (arrayDim > 0)
+					return convertToArrayType(INT, arrayDim);
+					return INT;
+					
 				case 'J':
-					if (arrayDim > 0) {
+					if (arrayDim > 0)
 						return convertToArrayType(LONG, arrayDim);
-					} else {
-						return LONG;
-					}
+					return LONG;
+					
 				case 'L':
 					int indexOfSemiColon = CharOperation.indexOf(';', signature, i+1);
 					if (indexOfSemiColon == -1) throw new ClassFormatException(ClassFormatException.ErrInvalidMethodSignature);
 					if (arrayDim > 0) {
 						return convertToArrayType(replace('/','.',CharOperation.subarray(signature, i + 1, indexOfSemiColon)), arrayDim);
-					} else {
-						return replace('/','.',CharOperation.subarray(signature, i + 1, indexOfSemiColon));
 					}
+					return replace('/','.',CharOperation.subarray(signature, i + 1, indexOfSemiColon));
+					
 				case 'S':
-					if (arrayDim > 0) {
+					if (arrayDim > 0)
 						return convertToArrayType(SHORT, arrayDim);
-					} else {
-						return SHORT;
-					}
+					return SHORT;
+					
 				case 'Z':
-					if (arrayDim > 0) {
+					if (arrayDim > 0)
 						return convertToArrayType(BOOLEAN, arrayDim);
-					} else {
-						return BOOLEAN;
-					}
+					return BOOLEAN;
+					
 				case 'V':
 					return VOID;
+					
 				case '[':
 					arrayDim++;
 					break;
+					
 				default:
 					throw new ClassFormatException(ClassFormatException.ErrInvalidMethodSignature);
 			}
@@ -172,73 +182,74 @@
 			switch(signature[i]) {
 				case 'B':
 					parameterTypes[parameterTypesCounter++] = BYTE;
-					if (arrayDim > 0) {
+					if (arrayDim > 0)
 						convertToArrayType(parameterTypes, parameterTypesCounter-1, arrayDim);
-					}
 					arrayDim = 0;
 					break;
+					
 				case 'C':
 					parameterTypes[parameterTypesCounter++] = CHAR;
-					if (arrayDim > 0) {
+					if (arrayDim > 0)
 						convertToArrayType(parameterTypes, parameterTypesCounter-1, arrayDim);
-					}
 					arrayDim = 0;
 					break;
+
 				case 'D':
 					parameterTypes[parameterTypesCounter++] = DOUBLE;
-					if (arrayDim > 0) {
+					if (arrayDim > 0)
 						convertToArrayType(parameterTypes, parameterTypesCounter-1, arrayDim);
-					}
 					arrayDim = 0;
 					break;
+
 				case 'F':
 					parameterTypes[parameterTypesCounter++] = FLOAT;
-					if (arrayDim > 0) {
+					if (arrayDim > 0)
 						convertToArrayType(parameterTypes, parameterTypesCounter-1, arrayDim);
-					}
 					arrayDim = 0;
 					break;
+					
 				case 'I':
 					parameterTypes[parameterTypesCounter++] = INT;
-					if (arrayDim > 0) {
+					if (arrayDim > 0)
 						convertToArrayType(parameterTypes, parameterTypesCounter-1, arrayDim);
-					}
 					arrayDim = 0;
 					break;
+					
 				case 'J':
 					parameterTypes[parameterTypesCounter++] = LONG;
-					if (arrayDim > 0) {
+					if (arrayDim > 0)
 						convertToArrayType(parameterTypes, parameterTypesCounter-1, arrayDim);
-					}
 					arrayDim = 0;
 					break;
+
 				case 'L':
 					int indexOfSemiColon = CharOperation.indexOf(';', signature, i+1);
 					if (indexOfSemiColon == -1) throw new ClassFormatException(ClassFormatException.ErrInvalidMethodSignature);
 					parameterTypes[parameterTypesCounter++] = replace('/','.',CharOperation.subarray(signature, i + 1, indexOfSemiColon));
-					if (arrayDim > 0) {
+					if (arrayDim > 0)
 						convertToArrayType(parameterTypes, parameterTypesCounter-1, arrayDim);
-					}
 					i = indexOfSemiColon;
 					arrayDim = 0;
 					break;
+
 				case 'S':
 					parameterTypes[parameterTypesCounter++] = SHORT;
-					if (arrayDim > 0) {
+					if (arrayDim > 0)
 						convertToArrayType(parameterTypes, parameterTypesCounter-1, arrayDim);
-					}
 					arrayDim = 0;
 					break;
+
 				case 'Z':
 					parameterTypes[parameterTypesCounter++] = BOOLEAN;
-					if (arrayDim > 0) {
+					if (arrayDim > 0)
 						convertToArrayType(parameterTypes, parameterTypesCounter-1, arrayDim);
-					}
 					arrayDim = 0;
 					break;
+
 				case '[':
 					arrayDim++;
 					break;
+					
 				default:
 					throw new ClassFormatException(ClassFormatException.ErrInvalidMethodSignature);
 			}
@@ -256,66 +267,60 @@
 		for (int i = indexOfClosingParen + 1, max = signature.length; i < max; i++) {
 			switch(signature[i]) {
 				case 'B':
-					if (arrayDim > 0) {
+					if (arrayDim > 0)
 						return convertToArrayType(BYTE, arrayDim);
-					} else {
-						return BYTE;
-					}
+					return BYTE;
+					
 				case 'C':
-					if (arrayDim > 0) {
+					if (arrayDim > 0)
 						return convertToArrayType(CHAR, arrayDim);
-					} else {
-						return CHAR;
-					}
+					return CHAR;
+					
 				case 'D':
-					if (arrayDim > 0) {
+					if (arrayDim > 0)
 						return convertToArrayType(DOUBLE, arrayDim);
-					} else {
-						return DOUBLE;
-					}
+					return DOUBLE;
+
 				case 'F':
-					if (arrayDim > 0) {
+					if (arrayDim > 0)
 						return convertToArrayType(FLOAT, arrayDim);
-					} else {
-						return FLOAT;
-					}
+					return FLOAT;
+
 				case 'I':
-					if (arrayDim > 0) {
+					if (arrayDim > 0)
 						return convertToArrayType(INT, arrayDim);
-					} else {
-						return INT;
-					}
+					return INT;
+
 				case 'J':
-					if (arrayDim > 0) {
+					if (arrayDim > 0)
 						return convertToArrayType(LONG, arrayDim);
-					} else {
-						return LONG;
-					}
+					return LONG;
+
 				case 'L':
 					int indexOfSemiColon = CharOperation.indexOf(';', signature, i+1);
 					if (indexOfSemiColon == -1) throw new ClassFormatException(ClassFormatException.ErrInvalidMethodSignature);
 					if (arrayDim > 0) {
 						return convertToArrayType(replace('/','.',CharOperation.subarray(signature, i + 1, indexOfSemiColon)), arrayDim);
-					} else {
-						return replace('/','.',CharOperation.subarray(signature, i + 1, indexOfSemiColon));
 					}
+					return replace('/','.',CharOperation.subarray(signature, i + 1, indexOfSemiColon));
+
 				case 'S':
-					if (arrayDim > 0) {
+					if (arrayDim > 0)
 						return convertToArrayType(SHORT, arrayDim);
-					} else {
-						return SHORT;
-					}
+					return SHORT;
+
 				case 'Z':
-					if (arrayDim > 0) {
+					if (arrayDim > 0)
 						return convertToArrayType(BOOLEAN, arrayDim);
-					} else {
-						return BOOLEAN;
-					}
+					return BOOLEAN;
+
 				case 'V':
 					return VOID;
+
 				case '[':
 					arrayDim++;
 					break;
+					
 				default:
 					throw new ClassFormatException(ClassFormatException.ErrInvalidMethodSignature);
 			}
@@ -411,8 +416,11 @@
 					}
 					break;
 				case ClassFileConstants.ClassTag :
-					// add a type reference 
-					name = replace('/', '.', extractClassReference(constantPoolOffsets, reader, i)); // so that it looks like java.lang.String
+					// add a type reference
+					name = extractClassReference(constantPoolOffsets, reader, i);
+					if (name.length > 0 && name[0] == '[')
+						break; // skip over array references
+					name = replace('/', '.', name); // so that it looks like java.lang.String
 					addTypeReference(name);
 					
 					// also add a simple reference on each segment of the qualification (see http://bugs.eclipse.org/bugs/show_bug.cgi?id=24741)
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IIndexConstants.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IIndexConstants.java
index 4b034ae..4903047 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IIndexConstants.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IIndexConstants.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -13,19 +13,14 @@
 public interface IIndexConstants {
 
 	/* index encoding */
-	char[] REF= "ref/".toCharArray(); //$NON-NLS-1$
-	char[] FIELD_REF= "fieldRef/".toCharArray(); //$NON-NLS-1$
-	char[] METHOD_REF= "methodRef/".toCharArray(); //$NON-NLS-1$
-	char[] CONSTRUCTOR_REF= "constructorRef/".toCharArray(); //$NON-NLS-1$
-	char[] TYPE_REF= "typeRef/".toCharArray(); //$NON-NLS-1$
-	char[] SUPER_REF = "superRef/".toCharArray(); //$NON-NLS-1$
-	char[] TYPE_DECL = "typeDecl/".toCharArray(); //$NON-NLS-1$
-	int 	TYPE_DECL_LENGTH = 9;
-	char[] CLASS_DECL= "typeDecl/C/".toCharArray(); //$NON-NLS-1$
-	char[] INTERFACE_DECL= "typeDecl/I/".toCharArray(); //$NON-NLS-1$
-	char[] METHOD_DECL= "methodDecl/".toCharArray(); //$NON-NLS-1$
-	char[] CONSTRUCTOR_DECL= "constructorDecl/".toCharArray(); //$NON-NLS-1$
-	char[] FIELD_DECL= "fieldDecl/".toCharArray(); //$NON-NLS-1$
+	char[] REF= "ref".toCharArray(); //$NON-NLS-1$
+	char[] METHOD_REF= "methodRef".toCharArray(); //$NON-NLS-1$
+	char[] CONSTRUCTOR_REF= "constructorRef".toCharArray(); //$NON-NLS-1$
+	char[] SUPER_REF = "superRef".toCharArray(); //$NON-NLS-1$
+	char[] TYPE_DECL = "typeDecl".toCharArray(); //$NON-NLS-1$
+	char[] METHOD_DECL= "methodDecl".toCharArray(); //$NON-NLS-1$
+	char[] CONSTRUCTOR_DECL= "constructorDecl".toCharArray(); //$NON-NLS-1$
+	char[] FIELD_DECL= "fieldDecl".toCharArray(); //$NON-NLS-1$
 	char[] OBJECT = "Object".toCharArray(); //$NON-NLS-1$
 	char[][] COUNTS= 
 		new char[][] { new char[] {'/', '0'}, new char[] {'/', '1'}, new char[] {'/', '2'}, new char[] {'/', '3'}, new char[] {'/', '4'},
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexAllProject.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexAllProject.java
index 529956b..0c38803 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexAllProject.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexAllProject.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -26,8 +26,7 @@
 import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.internal.core.ClasspathEntry;
 import org.eclipse.jdt.internal.core.JavaProject;
-import org.eclipse.jdt.internal.core.index.IIndex;
-import org.eclipse.jdt.internal.core.search.JavaSearchDocument;
+import org.eclipse.jdt.internal.core.index.Index;
 import org.eclipse.jdt.internal.core.search.processing.JobManager;
 import org.eclipse.jdt.internal.core.util.SimpleLookupTable;
 import org.eclipse.jdt.internal.core.util.Util;
@@ -54,16 +53,15 @@
 		if (this.isCancelled || progressMonitor != null && progressMonitor.isCanceled()) return true;
 		if (!project.isAccessible()) return true; // nothing to do
 
-		IIndex index = this.manager.getIndexForUpdate(this.containerPath, true, /*reuse index file*/ true /*create if none*/);
+		Index index = this.manager.getIndexForUpdate(this.containerPath, true, /*reuse index file*/ true /*create if none*/);
 		if (index == null) return true;
-		ReadWriteMonitor monitor = this.manager.getMonitorFor(index);
+		ReadWriteMonitor monitor = index.monitor;
 		if (monitor == null) return true; // index got deleted since acquired
 
 		try {
 			monitor.enterRead(); // ask permission to read
-			saveIfNecessary(index, monitor);
 
-			String[] paths = index.queryInDocumentNames(""); // all file names //$NON-NLS-1$
+			String[] paths = index.queryDocumentNames(""); // all file names //$NON-NLS-1$
 			int max = paths == null ? 0 : paths.length;
 			final SimpleLookupTable indexedFileNames = new SimpleLookupTable(max == 0 ? 33 : max + 11);
 			final String OK = "OK"; //$NON-NLS-1$
@@ -98,7 +96,8 @@
 						}
 						final boolean hasOutputs = !outputs.isEmpty();
 						
-						final char[][] patterns = ((ClasspathEntry) entry).fullExclusionPatternChars();
+						final char[][] inclusionPatterns = ((ClasspathEntry) entry).fullInclusionPatternChars();
+						final char[][] exclusionPatterns = ((ClasspathEntry) entry).fullExclusionPatternChars();
 						if (max == 0) {
 							sourceFolder.accept(
 								new IResourceProxyVisitor() {
@@ -108,16 +107,21 @@
 											case IResource.FILE :
 												if (org.eclipse.jdt.internal.compiler.util.Util.isJavaFileName(proxy.getName())) {
 													IFile file = (IFile) proxy.requestResource();
-													if (file.getLocation() != null && (patterns == null || !Util.isExcluded(file, patterns)))
-														indexedFileNames.put(new JavaSearchDocument(file, null).getPath(), file);
+													if (file.getLocation() == null) return false;
+													if (exclusionPatterns != null || inclusionPatterns != null)
+														if (Util.isExcluded(file, inclusionPatterns, exclusionPatterns))
+															return false;
+													indexedFileNames.put(file.getFullPath().toString(), file);
 												}
 												return false;
 											case IResource.FOLDER :
-												if (patterns != null && Util.isExcluded(proxy.requestResource(), patterns))
-													return false;
-												if (hasOutputs && outputs.contains(proxy.requestFullPath())) {
-													return false;
+												if (exclusionPatterns != null && inclusionPatterns == null) {
+													// if there are inclusion patterns then we must walk the children
+													if (Util.isExcluded(proxy.requestFullPath(), inclusionPatterns, exclusionPatterns, true)) 
+													    return false;
 												}
+												if (hasOutputs && outputs.contains(proxy.requestFullPath()))
+													return false;
 										}
 										return true;
 									}
@@ -134,21 +138,23 @@
 												if (org.eclipse.jdt.internal.compiler.util.Util.isJavaFileName(proxy.getName())) {
 													IFile file = (IFile) proxy.requestResource();
 													IPath location = file.getLocation();
-													if (location != null && (patterns == null || !Util.isExcluded(file, patterns))) {
-														String path = new JavaSearchDocument(file, null).getPath();
-														indexedFileNames.put(path,
-															indexedFileNames.get(path) == null || indexLastModified < location.toFile().lastModified()
-																? (Object) file
-																: (Object) OK);
-													}
+													if (location == null) return false;
+													if (exclusionPatterns != null || inclusionPatterns != null)
+														if (Util.isExcluded(file, inclusionPatterns, exclusionPatterns))
+															return false;
+													String path = file.getFullPath().toString();
+													indexedFileNames.put(path,
+														indexedFileNames.get(path) == null || indexLastModified < location.toFile().lastModified()
+															? (Object) file
+															: (Object) OK);
 												}
 												return false;
 											case IResource.FOLDER :
-												if (patterns != null && Util.isExcluded(proxy.requestResource(), patterns))
+												if (exclusionPatterns != null || inclusionPatterns != null)
+													if (Util.isExcluded(proxy.requestResource(), inclusionPatterns, exclusionPatterns))
+														return false;
+												if (hasOutputs && outputs.contains(proxy.requestFullPath()))
 													return false;
-												if (hasOutputs && outputs.contains(proxy.requestFullPath())) {
-													return false;
-												}
 										}
 										return true;
 									}
@@ -181,14 +187,14 @@
 			this.manager.request(new SaveIndex(this.containerPath, this.manager));
 		} catch (CoreException e) {
 			if (JobManager.VERBOSE) {
-				JobManager.verbose("-> failed to index " + this.project + " because of the following exception:"); //$NON-NLS-1$ //$NON-NLS-2$
+				Util.verbose("-> failed to index " + this.project + " because of the following exception:", System.err); //$NON-NLS-1$ //$NON-NLS-2$
 				e.printStackTrace();
 			}
 			this.manager.removeIndex(this.containerPath);
 			return false;
 		} catch (IOException e) {
 			if (JobManager.VERBOSE) {
-				JobManager.verbose("-> failed to index " + this.project + " because of the following exception:"); //$NON-NLS-1$ //$NON-NLS-2$
+				Util.verbose("-> failed to index " + this.project + " because of the following exception:", System.err); //$NON-NLS-1$ //$NON-NLS-2$
 				e.printStackTrace();
 			}
 			this.manager.removeIndex(this.containerPath);
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexBinaryFolder.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexBinaryFolder.java
index f647c9e..a110150 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexBinaryFolder.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexBinaryFolder.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -20,10 +20,10 @@
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.jdt.internal.core.index.IIndex;
-import org.eclipse.jdt.internal.core.search.JavaSearchDocument;
+import org.eclipse.jdt.internal.core.index.Index;
 import org.eclipse.jdt.internal.core.search.processing.JobManager;
 import org.eclipse.jdt.internal.core.util.SimpleLookupTable;
+import org.eclipse.jdt.internal.core.util.Util;
 
 public class IndexBinaryFolder extends IndexRequest {
 	IFolder folder;
@@ -47,16 +47,15 @@
 		if (this.isCancelled || progressMonitor != null && progressMonitor.isCanceled()) return true;
 		if (!this.folder.isAccessible()) return true; // nothing to do
 
-		IIndex index = this.manager.getIndexForUpdate(this.containerPath, true, /*reuse index file*/ true /*create if none*/);
+		Index index = this.manager.getIndexForUpdate(this.containerPath, true, /*reuse index file*/ true /*create if none*/);
 		if (index == null) return true;
-		ReadWriteMonitor monitor = this.manager.getMonitorFor(index);
+		ReadWriteMonitor monitor = index.monitor;
 		if (monitor == null) return true; // index got deleted since acquired
 
 		try {
 			monitor.enterRead(); // ask permission to read
-			saveIfNecessary(index, monitor);
 
-			String[] paths = index.queryInDocumentNames(""); // all file names //$NON-NLS-1$
+			String[] paths = index.queryDocumentNames(""); // all file names //$NON-NLS-1$
 			int max = paths == null ? 0 : paths.length;
 			final SimpleLookupTable indexedFileNames = new SimpleLookupTable(max == 0 ? 33 : max + 11);
 			final String OK = "OK"; //$NON-NLS-1$
@@ -69,7 +68,7 @@
 							if (org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(proxy.getName())) {
 								IFile file = (IFile) proxy.requestResource();
 								if (file.getLocation() != null)
-									indexedFileNames.put(new JavaSearchDocument(file, null).getPath(), file);
+									indexedFileNames.put(file.getFullPath().toString(), file);
 							}
 							return false;
 						}
@@ -90,7 +89,7 @@
 									IFile file = (IFile) proxy.requestResource();
 									IPath location = file.getLocation();
 									if (location != null) {
-										String path = new JavaSearchDocument(file, null).getPath();
+										String path = file.getFullPath().toString();
 										indexedFileNames.put(path,
 											indexedFileNames.get(path) == null || indexLastModified < location.toFile().lastModified()
 												? (Object) file
@@ -128,14 +127,14 @@
 			this.manager.request(new SaveIndex(this.containerPath, this.manager));
 		} catch (CoreException e) {
 			if (JobManager.VERBOSE) {
-				JobManager.verbose("-> failed to index " + this.folder + " because of the following exception:"); //$NON-NLS-1$ //$NON-NLS-2$
+				Util.verbose("-> failed to index " + this.folder + " because of the following exception:", System.err); //$NON-NLS-1$ //$NON-NLS-2$
 				e.printStackTrace();
 			}
 			this.manager.removeIndex(this.containerPath);
 			return false;
 		} catch (IOException e) {
 			if (JobManager.VERBOSE) {
-				JobManager.verbose("-> failed to index " + this.folder + " because of the following exception:"); //$NON-NLS-1$ //$NON-NLS-2$
+				Util.verbose("-> failed to index " + this.folder + " because of the following exception:", System.err); //$NON-NLS-1$ //$NON-NLS-2$
 				e.printStackTrace();
 			}
 			this.manager.removeIndex(this.containerPath);
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java
index ed70f8f..5820b8d 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -10,44 +10,21 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.search.indexing;
 
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
+import java.io.*;
 import java.util.*;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
 import java.util.zip.CRC32;
 
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IFolder;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.IWorkspace;
-import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.resources.*;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.Path;
-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.core.*;
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.search.*;
-import org.eclipse.jdt.core.search.IJavaSearchScope;
-import org.eclipse.jdt.core.search.SearchEngine;
-import org.eclipse.jdt.core.search.SearchParticipant;
-import org.eclipse.jdt.internal.core.JavaModel;
-import org.eclipse.jdt.internal.core.JavaModelManager;
-import org.eclipse.jdt.internal.core.JavaProject;
-import org.eclipse.jdt.internal.core.index.*;
-import org.eclipse.jdt.internal.core.index.IIndex;
-import org.eclipse.jdt.internal.core.index.IIndexer;
-import org.eclipse.jdt.internal.core.index.impl.Index;
+import org.eclipse.jdt.internal.core.*;
+import org.eclipse.jdt.internal.core.index.Index;
 import org.eclipse.jdt.internal.core.search.JavaWorkspaceScope;
 import org.eclipse.jdt.internal.core.search.PatternSearchJob;
-import org.eclipse.jdt.internal.core.search.matching.TypeDeclarationPattern;
 import org.eclipse.jdt.internal.core.search.processing.IJob;
 import org.eclipse.jdt.internal.core.search.processing.JobManager;
 import org.eclipse.jdt.internal.core.util.SimpleLookupTable;
@@ -55,13 +32,12 @@
 
 public class IndexManager extends JobManager implements IIndexConstants {
 
-	public IWorkspace workspace;
-	public SimpleLookupTable indexNames = new SimpleLookupTable();
+	public SimpleLookupTable indexLocations = new SimpleLookupTable();
+	/*
+	 * key = an IPath, value = an Index
+	 */
 	private Map indexes = new HashMap(5);
 
-	/* read write monitors */
-	private Map monitors = new HashMap(5);
-
 	/* need to save ? */
 	private boolean needToSave = false;
 	private static final CRC32 checksumCalculator = new CRC32();
@@ -75,69 +51,108 @@
 	public static Integer UPDATING_STATE = new Integer(1);
 	public static Integer UNKNOWN_STATE = new Integer(2);
 	public static Integer REBUILDING_STATE = new Integer(3);
-	
-	/*
-	 * A table from document path + index path (String) to indexer output (IIndexerOutput)
-	 */
-	static Hashtable indexerOutputs = new Hashtable();
 
-public synchronized void aboutToUpdateIndex(IPath path, Integer newIndexState) {
+public synchronized void aboutToUpdateIndex(IPath containerPath, Integer newIndexState) {
 	// newIndexState is either UPDATING_STATE or REBUILDING_STATE
 	// must tag the index as inconsistent, in case we exit before the update job is started
-	String indexName = computeIndexName(path);
-	Object state = getIndexStates().get(indexName);
+	String indexLocation = computeIndexLocation(containerPath);
+	Object state = getIndexStates().get(indexLocation);
 	Integer currentIndexState = state == null ? UNKNOWN_STATE : (Integer) state;
 	if (currentIndexState.equals(REBUILDING_STATE)) return; // already rebuilding the index
 
 	int compare = newIndexState.compareTo(currentIndexState);
 	if (compare > 0) {
 		// so UPDATING_STATE replaces SAVED_STATE and REBUILDING_STATE replaces everything
-		updateIndexState(indexName, newIndexState);
-	} else if (compare < 0 && this.indexes.get(path) == null) {
+		updateIndexState(indexLocation, newIndexState);
+	} else if (compare < 0 && this.indexes.get(indexLocation) == null) {
 		// if already cached index then there is nothing more to do
-		rebuildIndex(indexName, path);
+		rebuildIndex(indexLocation, containerPath);
 	}
 }
 /**
  * Trigger addition of a resource to an index
  * Note: the actual operation is performed in background
  */
-public void addBinary(IFile resource, IPath indexedContainer){
+public void addBinary(IFile resource, IPath containerPath) {
 	if (JavaCore.getPlugin() == null) return;	
 	SearchParticipant participant = SearchEngine.getDefaultSearchParticipant();
 	SearchDocument document = participant.getDocument(resource.getFullPath().toString());
-	String indexPath = computeIndexName(indexedContainer);
-	participant.scheduleDocumentIndexing(document, indexedContainer.toString(), indexPath);
-}
-public void addIndexEntry(char[] category, char[] key, SearchDocument document, String indexPath) {
-	IIndexerOutput output = (IIndexerOutput) indexerOutputs.get(document);
-	if (output == null) return;
-	output.addRef(CharOperation.concat(category, key));
+	String indexLocation = computeIndexLocation(containerPath);
+	scheduleDocumentIndexing(document, containerPath, indexLocation, participant);
 }
 /**
  * Trigger addition of a resource to an index
  * Note: the actual operation is performed in background
  */
-public void addSource(IFile resource, IPath indexedContainer){
+public void addSource(IFile resource, IPath containerPath) {
 	if (JavaCore.getPlugin() == null) return;	
 	SearchParticipant participant = SearchEngine.getDefaultSearchParticipant();
 	SearchDocument document = participant.getDocument(resource.getFullPath().toString());
-	String indexPath = computeIndexName(indexedContainer);
-	participant.scheduleDocumentIndexing(document, indexedContainer.toString(), indexPath);
+	String indexLocation = computeIndexLocation(containerPath);
+	scheduleDocumentIndexing(document, containerPath, indexLocation, participant);
 }
-String computeIndexName(IPath path) {
-	String name = (String) indexNames.get(path);
-	if (name == null) {
-		String pathString = path.toOSString();
+/*
+ * Removes unused indexes from disk.
+ */
+public void cleanUpIndexes() {
+	SimpleLookupTable knownPaths = new SimpleLookupTable();
+	IJavaSearchScope scope = new JavaWorkspaceScope();
+	PatternSearchJob job = new PatternSearchJob(null, SearchEngine.getDefaultSearchParticipant(), scope, null);
+	Index[] selectedIndexes = job.getIndexes(null);
+	for (int j = 0, max = selectedIndexes.length; j < max; j++) {
+		// TODO should use getJavaPluginWorkingLocation()+index simple name to avoid bugs such as https://bugs.eclipse.org/bugs/show_bug.cgi?id=62267
+		String path = selectedIndexes[j].getIndexFile().getAbsolutePath();
+		knownPaths.put(path, path);
+	}
+
+	if (indexStates != null) {
+		Object[] keys = indexStates.keyTable;
+		for (int i = 0, l = keys.length; i < l; i++) {
+			String key = (String) keys[i];
+			if (key != null && !knownPaths.containsKey(key))
+				updateIndexState(key, null);
+		}
+	}
+
+	File indexesDirectory = new File(getJavaPluginWorkingLocation().toOSString());
+	if (indexesDirectory.isDirectory()) {
+		File[] indexesFiles = indexesDirectory.listFiles();
+		if (indexesFiles != null) {
+			for (int i = 0, indexesFilesLength = indexesFiles.length; i < indexesFilesLength; i++) {
+				String fileName = indexesFiles[i].getAbsolutePath();
+				if (!knownPaths.containsKey(fileName) && fileName.toLowerCase().endsWith(".index")) { //$NON-NLS-1$
+					if (VERBOSE)
+						Util.verbose("Deleting index file " + indexesFiles[i]); //$NON-NLS-1$
+					indexesFiles[i].delete();
+				}
+			}
+		}
+	}
+}
+public String computeIndexLocation(IPath containerPath) {
+	String indexLocation = (String) this.indexLocations.get(containerPath);
+	if (indexLocation == null) {
+		String pathString = containerPath.toOSString();
 		checksumCalculator.reset();
 		checksumCalculator.update(pathString.getBytes());
 		String fileName = Long.toString(checksumCalculator.getValue()) + ".index"; //$NON-NLS-1$
 		if (VERBOSE)
-			JobManager.verbose("-> index name for " + pathString + " is " + fileName); //$NON-NLS-1$ //$NON-NLS-2$
-		name = getJavaPluginWorkingLocation().append(fileName).toOSString();
-		indexNames.put(path, name);
+			Util.verbose("-> index name for " + pathString + " is " + fileName); //$NON-NLS-1$ //$NON-NLS-2$
+		indexLocation = getJavaPluginWorkingLocation().append(fileName).toOSString();
+		this.indexLocations.put(containerPath, indexLocation);
 	}
-	return name;
+	return indexLocation;
+}
+/*
+ * Creates an empty index at the given location, for the given container path, if none exist.
+ */
+public void ensureIndexExists(String indexLocation, IPath containerPath) {
+	SimpleLookupTable states = getIndexStates();
+	Object state = states.get(indexLocation);
+	if (state == null) {
+		updateIndexState(indexLocation, REBUILDING_STATE);
+		getIndex(containerPath, indexLocation, true, true);
+	}
 }
 /**
  * Returns the index for a given project, according to the following algorithm:
@@ -147,43 +162,40 @@
  * 
  * Warning: Does not check whether index is consistent (not being used)
  */
-public synchronized IIndex getIndex(IPath path, boolean reuseExistingFile, boolean createIfMissing) {
+public synchronized Index getIndex(IPath containerPath, String indexLocation, boolean reuseExistingFile, boolean createIfMissing) {
 	// Path is already canonical per construction
-	IIndex index = (IIndex) indexes.get(path);
+	Index index = (Index) indexes.get(indexLocation);
 	if (index == null) {
-		String indexName = computeIndexName(path);
-		Object state = getIndexStates().get(indexName);
+		Object state = getIndexStates().get(indexLocation);
 		Integer currentIndexState = state == null ? UNKNOWN_STATE : (Integer) state;
 		if (currentIndexState == UNKNOWN_STATE) {
 			// should only be reachable for query jobs
 			// IF you put an index in the cache, then AddJarFileToIndex fails because it thinks there is nothing to do
-			rebuildIndex(indexName, path);
+			rebuildIndex(indexLocation, containerPath);
 			return null;
 		}
 
 		// index isn't cached, consider reusing an existing index file
 		if (reuseExistingFile) {
-			File indexFile = new File(indexName);
+			File indexFile = new File(indexLocation);
 			if (indexFile.exists()) { // check before creating index so as to avoid creating a new empty index if file is missing
 				try {
-					index = new Index(indexName, "Index for " + path.toOSString(), true /*reuse index file*/); //$NON-NLS-1$
-					indexes.put(path, index);
-					monitors.put(index, new ReadWriteMonitor());
+					index = new Index(indexLocation, "Index for " + containerPath.toOSString(), true /*reuse index file*/); //$NON-NLS-1$
+					indexes.put(indexLocation, index);
 					return index;
 				} catch (IOException e) {
 					// failed to read the existing file or its no longer compatible
 					if (currentIndexState != REBUILDING_STATE) { // rebuild index if existing file is corrupt, unless the index is already being rebuilt
 						if (VERBOSE)
-							JobManager.verbose("-> cannot reuse existing index: "+indexName+" path: "+path.toOSString()); //$NON-NLS-1$ //$NON-NLS-2$
-						rebuildIndex(indexName, path);
+							Util.verbose("-> cannot reuse existing index: "+indexLocation+" path: "+containerPath.toOSString()); //$NON-NLS-1$ //$NON-NLS-2$
+						rebuildIndex(indexLocation, containerPath);
 						return null;
-					} else {
-						index = null; // will fall thru to createIfMissing & create a empty index for the rebuild all job to populate
-					}
+					} 
+					index = null; // will fall thru to createIfMissing & create a empty index for the rebuild all job to populate
 				}
 			}
 			if (currentIndexState == SAVED_STATE) { // rebuild index if existing file is missing
-				rebuildIndex(indexName, path);
+				rebuildIndex(indexLocation, containerPath);
 				return null;
 			}
 		} 
@@ -191,14 +203,13 @@
 		if (createIfMissing) {
 			try {
 				if (VERBOSE)
-					JobManager.verbose("-> create empty index: "+indexName+" path: "+path.toOSString()); //$NON-NLS-1$ //$NON-NLS-2$
-				index = new Index(indexName, "Index for " + path.toOSString(), false /*do not reuse index file*/); //$NON-NLS-1$
-				indexes.put(path, index);
-				monitors.put(index, new ReadWriteMonitor());
+					Util.verbose("-> create empty index: "+indexLocation+" path: "+containerPath.toOSString()); //$NON-NLS-1$ //$NON-NLS-2$
+				index = new Index(indexLocation, "Index for " + containerPath.toOSString(), false /*do not reuse index file*/); //$NON-NLS-1$
+				indexes.put(indexLocation, index);
 				return index;
 			} catch (IOException e) {
 				if (VERBOSE)
-					JobManager.verbose("-> unable to create empty index: "+indexName+" path: "+path.toOSString()); //$NON-NLS-1$ //$NON-NLS-2$
+					Util.verbose("-> unable to create empty index: "+indexLocation+" path: "+containerPath.toOSString()); //$NON-NLS-1$ //$NON-NLS-2$
 				// The file could not be created. Possible reason: the project has been deleted.
 				return null;
 			}
@@ -207,10 +218,22 @@
 	//System.out.println(" index name: " + path.toOSString() + " <----> " + index.getIndexFile().getName());	
 	return index;
 }
-public synchronized IIndex getIndexForUpdate(IPath path, boolean reuseExistingFile, boolean createIfMissing) {
-	String indexName = computeIndexName(path);
-	if (getIndexStates().get(indexName) == REBUILDING_STATE)
-		return getIndex(path, reuseExistingFile, createIfMissing);
+/**
+ * Returns the index for a given project, according to the following algorithm:
+ * - if index is already in memory: answers this one back
+ * - if (reuseExistingFile) then read it and return this index and record it in memory
+ * - if (createIfMissing) then create a new empty index and record it in memory
+ * 
+ * Warning: Does not check whether index is consistent (not being used)
+ */
+public synchronized Index getIndex(IPath containerPath, boolean reuseExistingFile, boolean createIfMissing) {
+	String indexLocation = computeIndexLocation(containerPath);
+	return getIndex(containerPath, indexLocation, reuseExistingFile, createIfMissing);
+}
+public synchronized Index getIndexForUpdate(IPath containerPath, boolean reuseExistingFile, boolean createIfMissing) {
+	String indexLocation = computeIndexLocation(containerPath);
+	if (getIndexStates().get(indexLocation) == REBUILDING_STATE)
+		return getIndex(containerPath, indexLocation, reuseExistingFile, createIfMissing);
 
 	return null; // abort the job since the index has been removed from the REBUILDING_STATE
 }
@@ -232,30 +255,21 @@
 private IPath getJavaPluginWorkingLocation() {
 	if (this.javaPluginLocation != null) return this.javaPluginLocation;
 
-	return this.javaPluginLocation = JavaCore.getPlugin().getStateLocation();
+	IPath stateLocation = JavaCore.getPlugin().getStateLocation();
+	
+	// TODO (jerome) workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=62267
+	String device = stateLocation.getDevice();
+	if (device != null && device.charAt(0) == '/') stateLocation = stateLocation.setDevice(device.substring(1));
+	
+	return this.javaPluginLocation = stateLocation;
 }
-/**
- * Index access is controlled through a read-write monitor so as
- * to ensure there is no concurrent read and write operations
- * (only concurrent reading is allowed).
- */
-public ReadWriteMonitor getMonitorFor(IIndex index){
-	return (ReadWriteMonitor) monitors.get(index);
-}
-public void indexDocument(final SearchDocument searchDocument, final SearchParticipant searchParticipant, final IIndex index) throws IOException {
-	index.add(searchDocument,
-		new IIndexer() {
-			public void index(SearchDocument document, IIndexerOutput output) throws IOException {
-				output.addDocument(document); // Add the name of the file to the index
-				String indexPath = index.getIndexFile().toString();
-				try {
-					indexerOutputs.put(document, output);
-					searchParticipant.indexDocument(searchDocument, indexPath);
-				} finally {
-					indexerOutputs.remove(document);
-				}
-			}
-		});
+public void indexDocument(SearchDocument searchDocument, SearchParticipant searchParticipant, Index index, IPath indexLocation) throws IOException {
+	try {
+		((InternalSearchDocument) searchDocument).index = index;
+		searchParticipant.indexDocument(searchDocument, indexLocation);
+	} finally {
+		((InternalSearchDocument) searchDocument).index = null;
+	}
 }
 /**
  * Trigger addition of the entire content of a project
@@ -268,11 +282,11 @@
 	// determine the new children
 	try {
 		JavaModel model = JavaModelManager.getJavaModelManager().getJavaModel();
-		IJavaProject javaProject = model.getJavaProject(project);	
+		JavaProject javaProject = (JavaProject) model.getJavaProject(project);	
 		// only consider immediate libraries - each project will do the same
 		// NOTE: force to resolve CP variables before calling indexer - 19303, so that initializers
 		// will be run in the current thread.
-		IClasspathEntry[] entries = javaProject.getResolvedClasspath(true);	
+		IClasspathEntry[] entries = javaProject.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);	
 		for (int i = 0; i < entries.length; i++) {
 			IClasspathEntry entry= entries[i];
 			if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY)
@@ -300,7 +314,11 @@
 	if (target instanceof IFile) {
 		request = new AddJarFileToIndex((IFile)target, this);
 	} else if (target instanceof java.io.File) {
-		request = new AddJarFileToIndex(path, this);
+		if (((java.io.File)target).isFile()) {
+			request = new AddJarFileToIndex(path, this);
+		} else {
+			return;
+		}
 	} else if (target instanceof IFolder) {
 		request = new IndexBinaryFolder((IFolder)target, this);
 	} else {
@@ -315,7 +333,7 @@
 /**
  * Index the content of the given source folder.
  */
-public void indexSourceFolder(JavaProject javaProject, IPath sourceFolder, final char[][] exclusionPattern) {
+public void indexSourceFolder(JavaProject javaProject, IPath sourceFolder, char[][] inclusionPatterns, char[][] exclusionPatterns) {
 	IProject project = javaProject.getProject();
 	if (this.jobEnd > this.jobStart) {
 		// check if a job to index the project is not already in the queue
@@ -324,15 +342,16 @@
 			if (request.equals(this.awaitingJobs[i])) return;
 	}
 
-	this.request(new AddFolderToIndex(sourceFolder, project, exclusionPattern, this));
+	this.request(new AddFolderToIndex(sourceFolder, project, inclusionPatterns, exclusionPatterns, this));
 }
-public void jobWasCancelled(IPath path) {
-	Object o = this.indexes.get(path);
-	if (o instanceof IIndex) {
-		this.monitors.remove(o);
-		this.indexes.remove(path);
+public void jobWasCancelled(IPath containerPath) {
+	String indexLocation = computeIndexLocation(containerPath);
+	Object o = this.indexes.get(indexLocation);
+	if (o instanceof Index) {
+		((Index) o).monitor = null;
+		this.indexes.remove(indexLocation);
 	}
-	updateIndexState(computeIndexName(path), UNKNOWN_STATE);
+	updateIndexState(indexLocation, UNKNOWN_STATE);
 }
 /**
  * Advance to the next available job, once the current one has been completed.
@@ -349,26 +368,22 @@
 protected void notifyIdle(long idlingTime){
 	if (idlingTime > 1000 && needToSave) saveIndexes();
 }
-/*
- * For debug purpose
- */
-public IIndex peekAtIndex(IPath path) {
-	return (IIndex) indexes.get(path);
-}
 /**
  * Name of the background process
  */
 public String processName(){
 	return Util.bind("process.name"); //$NON-NLS-1$
 }
-private void rebuildIndex(String indexName, IPath path) {
-	Object target = JavaModel.getTarget(ResourcesPlugin.getWorkspace().getRoot(), path, true);
+private void rebuildIndex(String indexLocation, IPath containerPath) {
+	IWorkspace workspace = ResourcesPlugin.getWorkspace();
+	if (workspace == null) return;
+	Object target = JavaModel.getTarget(workspace.getRoot(), containerPath, true);
 	if (target == null) return;
 
 	if (VERBOSE)
-		JobManager.verbose("-> request to rebuild index: "+indexName+" path: "+path.toOSString()); //$NON-NLS-1$ //$NON-NLS-2$
+		Util.verbose("-> request to rebuild index: "+indexLocation+" path: "+containerPath.toOSString()); //$NON-NLS-1$ //$NON-NLS-2$
 
-	updateIndexState(indexName, REBUILDING_STATE);
+	updateIndexState(indexLocation, REBUILDING_STATE);
 	IndexRequest request = null;
 	if (target instanceof IProject) {
 		IProject p = (IProject) target;
@@ -379,7 +394,7 @@
 	} else if (target instanceof IFile) {
 		request = new AddJarFileToIndex((IFile) target, this);
 	} else if (target instanceof java.io.File) {
-		request = new AddJarFileToIndex(path, this);
+		request = new AddJarFileToIndex(containerPath, this);
 	}
 	if (request != null)
 		request(request);
@@ -389,24 +404,25 @@
  * Returns the new empty index or null if it didn't exist before.
  * Warning: Does not check whether index is consistent (not being used)
  */
-public synchronized IIndex recreateIndex(IPath path) {
+public synchronized Index recreateIndex(IPath containerPath) {
 	// only called to over write an existing cached index...
 	try {
-		IIndex index = (IIndex) this.indexes.get(path);
-		ReadWriteMonitor monitor = (ReadWriteMonitor) this.monitors.remove(index);
-
 		// Path is already canonical
-		String indexPath = computeIndexName(path);
+		String indexLocation = computeIndexLocation(containerPath);
+		
+		Index index = (Index) this.indexes.get(indexLocation);
+		ReadWriteMonitor monitor = index == null ? null : index.monitor;
+
 		if (VERBOSE)
-			JobManager.verbose("-> recreating index: "+indexPath+" for path: "+path.toOSString()); //$NON-NLS-1$ //$NON-NLS-2$
-		index = new Index(indexPath, "Index for " + path.toOSString(), false /*reuse index file*/); //$NON-NLS-1$
-		indexes.put(path, index);
-		monitors.put(index, monitor);
+			Util.verbose("-> recreating index: "+indexLocation+" for path: "+containerPath.toOSString()); //$NON-NLS-1$ //$NON-NLS-2$
+		index = new Index(indexLocation, "Index for " + containerPath.toOSString(), false /*reuse index file*/); //$NON-NLS-1$
+		this.indexes.put(indexLocation, index);
+		index.monitor = monitor;
 		return index;
 	} catch (IOException e) {
 		// The file could not be created. Possible reason: the project has been deleted.
 		if (VERBOSE) {
-			JobManager.verbose("-> failed to recreate index for path: "+path.toOSString()); //$NON-NLS-1$ //$NON-NLS-2$
+			Util.verbose("-> failed to recreate index for path: "+containerPath.toOSString()); //$NON-NLS-1$ //$NON-NLS-2$
 			e.printStackTrace();
 		}
 		return null;
@@ -423,18 +439,18 @@
  * Removes the index for a given path. 
  * This is a no-op if the index did not exist.
  */
-public synchronized void removeIndex(IPath path) {
+public synchronized void removeIndex(IPath containerPath) {
 	if (VERBOSE)
-		JobManager.verbose("removing index " + path); //$NON-NLS-1$
-	String indexName = computeIndexName(path);
-	File indexFile = new File(indexName);
+		Util.verbose("removing index " + containerPath); //$NON-NLS-1$
+	String indexLocation = computeIndexLocation(containerPath);
+	File indexFile = new File(indexLocation);
 	if (indexFile.exists())
 		indexFile.delete();
-	Object o = this.indexes.get(path);
-	if (o instanceof IIndex)
-		this.monitors.remove(o);
-	this.indexes.remove(path);
-	updateIndexState(indexName, null);
+	Object o = this.indexes.get(indexLocation);
+	if (o instanceof Index)
+		((Index) o).monitor = null;
+	this.indexes.remove(indexLocation);
+	updateIndexState(indexLocation, null);
 }
 /**
  * Removes all indexes whose paths start with (or are equal to) the given path. 
@@ -442,13 +458,14 @@
 public synchronized void removeIndexFamily(IPath path) {
 	// only finds cached index files... shutdown removes all non-cached index files
 	ArrayList toRemove = null;
-	Iterator iterator = this.indexes.keySet().iterator();
-	while (iterator.hasNext()) {
-		IPath indexPath = (IPath) iterator.next();
-		if (path.isPrefixOf(indexPath)) {
+	Object[] containerPaths = this.indexLocations.keyTable;
+	for (int i = 0, length = containerPaths.length; i < length; i++) {
+		IPath containerPath = (IPath) containerPaths[i];
+		if (containerPath == null) continue;
+		if (path.isPrefixOf(containerPath)) {
 			if (toRemove == null)
 				toRemove = new ArrayList();
-			toRemove.add(indexPath);
+			toRemove.add(containerPath);
 		}
 	}
 	if (toRemove != null)
@@ -458,7 +475,7 @@
 /**
  * Remove the content of the given source folder from the index.
  */
-public void removeSourceFolderFromIndex(JavaProject javaProject, IPath sourceFolder, char[][] exclusionPatterns) {
+public void removeSourceFolderFromIndex(JavaProject javaProject, IPath sourceFolder, char[][] inclusionPatterns, char[][] exclusionPatterns) {
 	IProject project = javaProject.getProject();
 	if (this.jobEnd > this.jobStart) {
 		// check if a job to index the project is not already in the queue
@@ -467,40 +484,40 @@
 			if (request.equals(this.awaitingJobs[i])) return;
 	}
 
-	this.request(new RemoveFolderFromIndex(sourceFolder, exclusionPatterns, project, this));
+	this.request(new RemoveFolderFromIndex(sourceFolder, inclusionPatterns, exclusionPatterns, project, this));
 }
 /**
  * Flush current state
  */
-public void reset() {
+public synchronized void reset() {
 	super.reset();
 	if (this.indexes != null) {
 		this.indexes = new HashMap(5);
-		this.monitors = new HashMap(5);
 		this.indexStates = null;
 	}
-	this.indexNames = new SimpleLookupTable();
+	this.indexLocations = new SimpleLookupTable();
 	this.javaPluginLocation = null;
 }
-public void saveIndex(IIndex index) throws IOException {
+public void saveIndex(Index index) throws IOException {
 	// must have permission to write from the write monitor
 	if (index.hasChanged()) {
 		if (VERBOSE)
-			JobManager.verbose("-> saving index " + index.getIndexFile()); //$NON-NLS-1$
+			Util.verbose("-> saving index " + index.getIndexFile()); //$NON-NLS-1$
 		index.save();
 	}
-	String indexName = index.getIndexFile().getPath();
+	// TODO should use getJavaPluginWorkingLocation()+index simple name to avoid bugs such as https://bugs.eclipse.org/bugs/show_bug.cgi?id=62267
+	String indexLocation = index.getIndexFile().getPath();
 	if (this.jobEnd > this.jobStart) {
-		Object indexPath = indexNames.keyForValue(indexName);
-		if (indexPath != null) {
+		Object containerPath = this.indexLocations.keyForValue(indexLocation);
+		if (containerPath != null) {
 			for (int i = this.jobEnd; i > this.jobStart; i--) { // skip the current job
 				IJob job = this.awaitingJobs[i];
 				if (job instanceof IndexRequest)
-					if (((IndexRequest) job).containerPath.equals(indexPath)) return;
+					if (((IndexRequest) job).containerPath.equals(containerPath)) return;
 			}
 		}
 	}
-	updateIndexState(indexName, SAVED_STATE);
+	updateIndexState(indexLocation, SAVED_STATE);
 }
 /**
  * Commit all index memory changes to disk
@@ -511,50 +528,60 @@
 	synchronized(this) {
 		for (Iterator iter = this.indexes.values().iterator(); iter.hasNext();) {
 			Object o = iter.next();
-			if (o instanceof IIndex)
+			if (o instanceof Index)
 				toSave.add(o);
 		}
 	}
 
+	boolean allSaved = true;
 	for (int i = 0, length = toSave.size(); i < length; i++) {
-		IIndex index = (IIndex) toSave.get(i);
-		ReadWriteMonitor monitor = getMonitorFor(index);
+		Index index = (Index) toSave.get(i);
+		ReadWriteMonitor monitor = index.monitor;
 		if (monitor == null) continue; // index got deleted since acquired
 		try {
-			monitor.enterWrite();
-			try {
-				saveIndex(index);
-			} catch(IOException e){
-				if (VERBOSE) {
-					JobManager.verbose("-> got the following exception while saving:"); //$NON-NLS-1$
-					e.printStackTrace();
+			// take read lock before checking if index has changed
+			// don't take write lock yet since it can cause a deadlock (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=50571)
+			monitor.enterRead(); 
+			if (index.hasChanged()) {
+				if (monitor.exitReadEnterWrite()) {
+					try {
+						saveIndex(index);
+					} catch(IOException e) {
+						if (VERBOSE) {
+							Util.verbose("-> got the following exception while saving:", System.err); //$NON-NLS-1$
+							e.printStackTrace();
+						}
+						allSaved = false;
+					} finally {
+						monitor.exitWriteEnterRead();
+					}
+				} else {
+					allSaved = false;
 				}
-				//Util.log(e);
 			}
 		} finally {
-			monitor.exitWrite();
+			monitor.exitRead();
 		}
 	}
-	needToSave = false;
+	this.needToSave = !allSaved;
 }
-public void scheduleDocumentIndexing(final SearchDocument searchDocument, String containerPathString, final String indexPath, final SearchParticipant searchParticipant) {
-	IPath containerPath = new Path(containerPathString);
+public void scheduleDocumentIndexing(final SearchDocument searchDocument, IPath containerPath, final String indexLocation, final SearchParticipant searchParticipant) {
 	request(new IndexRequest(containerPath, this) {
 		public boolean execute(IProgressMonitor progressMonitor) {
 			if (this.isCancelled || progressMonitor != null && progressMonitor.isCanceled()) return true;
 			
 			/* ensure no concurrent write access to index */
-			IIndex index = getIndex(containerPath, true, /*reuse index file*/ true /*create if none*/);
+			Index index = getIndex(containerPath, indexLocation, true, /*reuse index file*/ true /*create if none*/);
 			if (index == null) return true;
-			ReadWriteMonitor monitor = getMonitorFor(index);
+			ReadWriteMonitor monitor = index.monitor;
 			if (monitor == null) return true; // index got deleted since acquired
 			
 			try {
 				monitor.enterWrite(); // ask permission to write
-				indexDocument(searchDocument, searchParticipant, index);
+				indexDocument(searchDocument, searchParticipant, index, new Path(indexLocation));
 			} catch (IOException e) {
 				if (JobManager.VERBOSE) {
-					JobManager.verbose("-> failed to index " + searchDocument.getPath() + " because of the following exception:"); //$NON-NLS-1$ //$NON-NLS-2$
+					Util.verbose("-> failed to index " + searchDocument.getPath() + " because of the following exception:", System.err); //$NON-NLS-1$ //$NON-NLS-2$
 					e.printStackTrace();
 				}
 				return false;
@@ -568,50 +595,6 @@
 		}
 	});
 }
-public void shutdown() {
-	if (VERBOSE)
-		JobManager.verbose("Shutdown"); //$NON-NLS-1$
-
-	SimpleLookupTable knownPaths = new SimpleLookupTable();
-	SearchParticipant[] participants = SearchEngine.getSearchParticipants();
-	IJavaSearchScope scope = new JavaWorkspaceScope();
-	for (int i = 0, length = participants.length; i < length; i++) {
-		SearchParticipant participant = participants[i];
-		SearchPattern pattern = new TypeDeclarationPattern(null, null, null, ' ', SearchPattern.R_PATTERN_MATCH);
-		PatternSearchJob job = new PatternSearchJob(pattern, participant, scope, null);
-		IIndex[] selectedIndexes = job.getIndexes(null);
-		for (int j = 0, max = selectedIndexes.length; j < max; j++) {
-			String path = selectedIndexes[j].getIndexFile().getAbsolutePath();
-			knownPaths.put(path, path);
-		}
-	}
-
-	if (indexStates != null) {
-		Object[] keys = indexStates.keyTable;
-		for (int i = 0, l = keys.length; i < l; i++) {
-			String key = (String) keys[i];
-			if (key != null && !knownPaths.containsKey(key))
-				updateIndexState(key, null);
-		}
-	}
-
-	File indexesDirectory = new File(getJavaPluginWorkingLocation().toOSString());
-	if (indexesDirectory.isDirectory()) {
-		File[] indexesFiles = indexesDirectory.listFiles();
-		if (indexesFiles != null) {
-			for (int i = 0, indexesFilesLength = indexesFiles.length; i < indexesFilesLength; i++) {
-				String fileName = indexesFiles[i].getAbsolutePath();
-				if (!knownPaths.containsKey(fileName) && fileName.toLowerCase().endsWith(".index")) { //$NON-NLS-1$
-					if (VERBOSE)
-						JobManager.verbose("Deleting index file " + indexesFiles[i]); //$NON-NLS-1$
-					indexesFiles[i].delete();
-				}
-			}
-		}
-	}
-
-	super.shutdown();
-}
 
 public String toString() {
 	StringBuffer buffer = new StringBuffer(10);
@@ -629,18 +612,18 @@
 		return org.eclipse.jdt.internal.compiler.util.Util.getFileCharContent(savedIndexNamesFile, null);
 	} catch (IOException ignored) {
 		if (VERBOSE)
-			JobManager.verbose("Failed to read saved index file names"); //$NON-NLS-1$
+			Util.verbose("Failed to read saved index file names"); //$NON-NLS-1$
 		return new char[0];
 	}
 }
-private void updateIndexState(String indexName, Integer indexState) {
+private synchronized void updateIndexState(String indexLocation, Integer indexState) {
 	getIndexStates(); // ensure the states are initialized
 	if (indexState != null) {
-		if (indexState.equals(indexStates.get(indexName))) return; // not changed
-		indexStates.put(indexName, indexState);
+		if (indexState.equals(indexStates.get(indexLocation))) return; // not changed
+		indexStates.put(indexLocation, indexState);
 	} else {
-		if (!indexStates.containsKey(indexName)) return; // did not exist anyway
-		indexStates.removeKey(indexName);
+		if (!indexStates.containsKey(indexLocation)) return; // did not exist anyway
+		indexStates.removeKey(indexLocation);
 	}
 
 	BufferedWriter writer = null;
@@ -656,7 +639,7 @@
 		}
 	} catch (IOException ignored) {
 		if (VERBOSE)
-			JobManager.verbose("Failed to write saved index file names"); //$NON-NLS-1$
+			Util.verbose("Failed to write saved index file names", System.err); //$NON-NLS-1$
 	} finally {
 		if (writer != null) {
 			try {
@@ -672,7 +655,7 @@
 		else if (indexState == UPDATING_STATE) state = "UPDATING"; //$NON-NLS-1$
 		else if (indexState == UNKNOWN_STATE) state = "UNKNOWN"; //$NON-NLS-1$
 		else if (indexState == REBUILDING_STATE) state = "REBUILDING"; //$NON-NLS-1$
-		JobManager.verbose("-> index state updated to: " + state + " for: "+indexName); //$NON-NLS-1$ //$NON-NLS-2$
+		Util.verbose("-> index state updated to: " + state + " for: "+indexLocation); //$NON-NLS-1$ //$NON-NLS-2$
 	}
 }
 }
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexRequest.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexRequest.java
index 153e015..ae74453 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexRequest.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexRequest.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -10,10 +10,7 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.search.indexing;
 
-import java.io.IOException;
-
 import org.eclipse.core.runtime.IPath;
-import org.eclipse.jdt.internal.core.index.IIndex;
 import org.eclipse.jdt.internal.core.search.processing.IJob;
 
 public abstract class IndexRequest implements IJob {
@@ -39,21 +36,6 @@
 		// tag the index as inconsistent
 		this.manager.aboutToUpdateIndex(this.containerPath, updatedIndexState());
 	}
-	/*
-	 * This code is assumed to be invoked while monitor has read lock
-	 */
-	protected void saveIfNecessary(IIndex index, ReadWriteMonitor monitor) throws IOException {
-		/* if index has changed, commit these before querying */
-		if (index.hasChanged()) {
-			try {
-				monitor.exitRead(); // free read lock
-				monitor.enterWrite(); // ask permission to write
-				this.manager.saveIndex(index);
-			} finally {
-				monitor.exitWriteEnterRead(); // finished writing and reacquire read permission
-			}
-		}
-	}
 	protected Integer updatedIndexState() {
 		return IndexManager.UPDATING_STATE;
 	}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/InternalSearchDocument.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/InternalSearchDocument.java
new file mode 100644
index 0000000..acf2d4a
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/InternalSearchDocument.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * 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.search.indexing;
+
+import org.eclipse.jdt.internal.core.index.Index;
+
+/**
+ * Internal search document implementation
+ */
+public class InternalSearchDocument {
+	Index index;
+	/*
+	 * Hidden by API SearchDocument subclass
+	 */
+	public void addIndexEntry(char[] category, char[] key) {
+		if (this.index != null)
+			index.addIndexEntry(category, key, this);
+	}
+	/*
+	 * Hidden by API SearchDocument subclass
+	 */
+	public void removeAllIndexEntries() {
+		if (this.index != null)
+			index.remove(getPath());
+	}
+	/*
+	 * Hidden by API SearchDocument subclass
+	 */
+	public String getPath() {
+		return null; // implemented by subclass
+	}
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/ReadWriteMonitor.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/ReadWriteMonitor.java
index 12092dd..bf44009 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/ReadWriteMonitor.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/ReadWriteMonitor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -16,22 +16,21 @@
  */
 public class ReadWriteMonitor {
 
-	/**
-	 * <0 : writing (cannot go beyond -1, i.e one concurrent writer)
-	 * =0 : idle
-	 * >0 : reading (number of concurrent readers)
-	 */
-	private int status = 0;
+/**
+ * <0 : writing (cannot go beyond -1, i.e one concurrent writer)
+ * =0 : idle
+ * >0 : reading (number of concurrent readers)
+ */
+private int status = 0;
 /**
  * Concurrent reading is allowed
  * Blocking only when already writing.
  */
 public synchronized void enterRead() {
-
-	while (status < 0){
+	while (status < 0) {
 		try {
 			wait();
-		} catch(InterruptedException e){
+		} catch(InterruptedException e) {
 			// ignore
 		}
 	}
@@ -42,11 +41,10 @@
  * Blocking only when already writing or reading.
  */
 public synchronized void enterWrite() {
-
-	while (status != 0){
+	while (status != 0) {
 		try {
 			wait();
-		} catch(InterruptedException e){
+		} catch(InterruptedException e) {
 			// ignore
 		}
 	}
@@ -68,6 +66,18 @@
 	if (++status == 0) notifyAll();
 }
 /**
+ * Atomic exitRead/enterWrite: Allows to keep monitor in between
+ * exit read and next enter write.
+ * Use when writing changes is optional, otherwise call the individual methods.
+ * Returns false if multiple readers are accessing the index.
+ */
+public synchronized boolean exitReadEnterWrite() {
+	if (status != 1) return false; // only continue if this is the only reader
+
+	status = -1;
+	return true;
+}
+/**
  * Atomic exitWrite/enterRead: Allows to keep monitor in between
  * exit write and next enter read.
  * When writing is over, all readers are granted permissing to restart
@@ -83,5 +93,19 @@
 public synchronized void exitWriteEnterRead() {
 	this.exitWrite();
 	this.enterRead();
-} 
+}
+public String toString() {
+	StringBuffer buffer = new StringBuffer();
+	if (status == 0) {
+		buffer.append("Monitor idle "); //$NON-NLS-1$
+	} else if (status < 0) {
+		buffer.append("Monitor writing "); //$NON-NLS-1$
+	} else if (status > 0) {
+		buffer.append("Monitor reading "); //$NON-NLS-1$
+	}
+	buffer.append("(status = "); //$NON-NLS-1$
+	buffer.append(this.status);
+	buffer.append(")"); //$NON-NLS-1$
+	return buffer.toString();
+}
 }
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/RemoveFolderFromIndex.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/RemoveFolderFromIndex.java
index f650608..e569201 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/RemoveFolderFromIndex.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/RemoveFolderFromIndex.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -16,18 +16,20 @@
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.Path;
-import org.eclipse.jdt.internal.core.index.IIndex;
+import org.eclipse.jdt.internal.core.index.Index;
 import org.eclipse.jdt.internal.core.search.processing.JobManager;
 import org.eclipse.jdt.internal.core.util.Util;
 
 class RemoveFolderFromIndex extends IndexRequest {
 	IPath folderPath;
+	char[][] inclusionPatterns;
 	char[][] exclusionPatterns;
 	IProject project;
 
-	public RemoveFolderFromIndex(IPath folderPath, char[][] exclusionPatterns, IProject project, IndexManager manager) {
+	public RemoveFolderFromIndex(IPath folderPath, char[][] inclusionPatterns, char[][] exclusionPatterns, IProject project, IndexManager manager) {
 		super(project.getFullPath(), manager);
 		this.folderPath = folderPath;
+		this.inclusionPatterns = inclusionPatterns;
 		this.exclusionPatterns = exclusionPatterns;
 		this.project = project;
 	}
@@ -36,24 +38,28 @@
 		if (this.isCancelled || progressMonitor != null && progressMonitor.isCanceled()) return true;
 
 		/* ensure no concurrent write access to index */
-		IIndex index = manager.getIndex(this.containerPath, true, /*reuse index file*/ false /*create if none*/);
+		Index index = this.manager.getIndex(this.containerPath, true, /*reuse index file*/ false /*create if none*/);
 		if (index == null) return true;
-		ReadWriteMonitor monitor = manager.getMonitorFor(index);
+		ReadWriteMonitor monitor = index.monitor;
 		if (monitor == null) return true; // index got deleted since acquired
 
 		try {
 			monitor.enterRead(); // ask permission to read
-			String[] paths = index.queryInDocumentNames(this.folderPath.toString());
+			String[] paths = index.queryDocumentNames(this.folderPath.toString());
 			// all file names belonging to the folder or its subfolders and that are not excluded (see http://bugs.eclipse.org/bugs/show_bug.cgi?id=32607)
-			for (int i = 0, max = paths == null ? 0 : paths.length; i < max; i++) {
-				String documentPath = paths[i];
-				if (this.exclusionPatterns == null || !Util.isExcluded(new Path(documentPath), this.exclusionPatterns)) {
-					manager.remove(documentPath, this.containerPath); // write lock will be acquired by the remove operation
+			if (this.exclusionPatterns == null && this.inclusionPatterns == null) {
+				for (int i = 0, max = paths == null ? 0 : paths.length; i < max; i++)
+					manager.remove(paths[i], this.containerPath); // write lock will be acquired by the remove operation
+			} else {
+				for (int i = 0, max = paths == null ? 0 : paths.length; i < max; i++) {
+					String documentPath = paths[i];
+					if (!Util.isExcluded(new Path(documentPath), this.inclusionPatterns, this.exclusionPatterns, false))
+						manager.remove(documentPath, this.containerPath); // write lock will be acquired by the remove operation
 				}
 			}
 		} catch (IOException e) {
 			if (JobManager.VERBOSE) {
-				JobManager.verbose("-> failed to remove " + this.folderPath + " from index because of the following exception:"); //$NON-NLS-1$ //$NON-NLS-2$
+				Util.verbose("-> failed to remove " + this.folderPath + " from index because of the following exception:", System.err); //$NON-NLS-1$ //$NON-NLS-2$
 				e.printStackTrace();
 			}
 			return false;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/RemoveFromIndex.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/RemoveFromIndex.java
index d4a1a9d..4f2552d 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/RemoveFromIndex.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/RemoveFromIndex.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -10,12 +10,9 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.search.indexing;
 
-import java.io.IOException;
-
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.jdt.internal.core.index.IIndex;
-import org.eclipse.jdt.internal.core.search.processing.JobManager;
+import org.eclipse.jdt.internal.core.index.Index;
 
 class RemoveFromIndex extends IndexRequest {
 	String resourceName;
@@ -29,20 +26,14 @@
 		if (this.isCancelled || progressMonitor != null && progressMonitor.isCanceled()) return true;
 
 		/* ensure no concurrent write access to index */
-		IIndex index = manager.getIndex(this.containerPath, true, /*reuse index file*/ false /*create if none*/);
+		Index index = this.manager.getIndex(this.containerPath, true, /*reuse index file*/ false /*create if none*/);
 		if (index == null) return true;
-		ReadWriteMonitor monitor = manager.getMonitorFor(index);
+		ReadWriteMonitor monitor = index.monitor;
 		if (monitor == null) return true; // index got deleted since acquired
 
 		try {
 			monitor.enterWrite(); // ask permission to write
 			index.remove(resourceName);
-		} catch (IOException e) {
-			if (JobManager.VERBOSE) {
-				JobManager.verbose("-> failed to remove " + this.resourceName + " from index because of the following exception:"); //$NON-NLS-1$ //$NON-NLS-2$
-				e.printStackTrace();
-			}
-			return false;
 		} finally {
 			monitor.exitWrite(); // free write lock
 		}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/SaveIndex.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/SaveIndex.java
index b53ecf8..403ffe1 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/SaveIndex.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/SaveIndex.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -14,8 +14,9 @@
 
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.jdt.internal.core.index.IIndex;
+import org.eclipse.jdt.internal.core.index.Index;
 import org.eclipse.jdt.internal.core.search.processing.JobManager;
+import org.eclipse.jdt.internal.core.util.Util;
 
 /*
  * Save the index of a project.
@@ -29,9 +30,9 @@
 		if (this.isCancelled || progressMonitor != null && progressMonitor.isCanceled()) return true;
 
 		/* ensure no concurrent write access to index */
-		IIndex index = this.manager.getIndex(this.containerPath, true /*reuse index file*/, false /*don't create if none*/);
+		Index index = this.manager.getIndex(this.containerPath, true /*reuse index file*/, false /*don't create if none*/);
 		if (index == null) return true;
-		ReadWriteMonitor monitor = this.manager.getMonitorFor(index);
+		ReadWriteMonitor monitor = index.monitor;
 		if (monitor == null) return true; // index got deleted since acquired
 
 		try {
@@ -39,7 +40,7 @@
 			this.manager.saveIndex(index);
 		} catch (IOException e) {
 			if (JobManager.VERBOSE) {
-				JobManager.verbose("-> failed to save index " + this.containerPath + " because of the following exception:"); //$NON-NLS-1$ //$NON-NLS-2$
+				Util.verbose("-> failed to save index " + this.containerPath + " because of the following exception:", System.err); //$NON-NLS-1$ //$NON-NLS-2$
 				e.printStackTrace();
 			}
 			return false;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/SourceIndexer.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/SourceIndexer.java
index f075013..03ef30b 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/SourceIndexer.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/SourceIndexer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -42,10 +42,9 @@
 	
 	protected DefaultProblemFactory problemFactory= new DefaultProblemFactory(Locale.getDefault());
 	
-	public SourceIndexer(SearchDocument document, String indexPath)	{
-		super(document, indexPath);
+	public SourceIndexer(SearchDocument document) {
+		super(document);
 	}
-	
 	public void indexDocument() {
 		// Create a new Parser
 		SourceIndexerRequestor requestor = new SourceIndexerRequestor(this);
@@ -57,9 +56,10 @@
 			this.problemFactory, 
 			new CompilerOptions(JavaCore.create(project).getOptions(true)), 
 			true); // index local declarations
+		parser.reportOnlyOneSyntaxError = true;
 	
 		// Always check javadoc while indexing
-		parser.javadocParser.checkJavadoc = true;
+		parser.javadocParser.checkDocComment = true;
 		
 		// Launch the parser
 		char[] source = null;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/SourceIndexerRequestor.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/SourceIndexerRequestor.java
index 29f4afe..b6773b9 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/SourceIndexerRequestor.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/SourceIndexerRequestor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -246,19 +246,21 @@
 public void exitMethod(int declarationEnd) {
 	this.methodDepth--;
 }
-public void popTypeName(){
-	try {
+public void popTypeName() {
+	if (depth > 0) {
 		enclosingTypeNames[--depth] = null;
-	} catch (ArrayIndexOutOfBoundsException e) {
-		if (JobManager.VERBOSE) {
+	} else if (JobManager.VERBOSE) {
+		// dump a trace so it can be tracked down
+		try {
+			enclosingTypeNames[-1] = null;
+		} catch (ArrayIndexOutOfBoundsException e) {
 			e.printStackTrace();
 		}
 	}
 }
-public void pushTypeName(char[] typeName){
-	if (depth == enclosingTypeNames.length){
+public void pushTypeName(char[] typeName) {
+	if (depth == enclosingTypeNames.length)
 		System.arraycopy(enclosingTypeNames, 0, enclosingTypeNames = new char[depth*2][], 0, depth);
-	}
 	enclosingTypeNames[depth++] = typeName;
 }
 }
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/AndPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/AndPattern.java
index 96ce69d..b4e102b 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/AndPattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/AndPattern.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -14,115 +14,63 @@
 
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.OperationCanceledException;
-import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.search.*;
-import org.eclipse.jdt.core.search.IJavaSearchScope;
-import org.eclipse.jdt.core.search.SearchParticipant;
-import org.eclipse.jdt.internal.core.index.impl.EntryResult;
-import org.eclipse.jdt.internal.core.index.impl.IndexInput;
-import org.eclipse.jdt.internal.core.index.impl.IndexedFile;
+import org.eclipse.jdt.internal.core.index.*;
 import org.eclipse.jdt.internal.core.search.IndexQueryRequestor;
+import org.eclipse.jdt.internal.core.util.SimpleSet;
 
 /**
  * Query the index multiple times and do an 'and' on the results.
  */
-public abstract class AndPattern extends SearchPattern { // TODO should rename IntersectingPattern, and make AndPattern a true subclass
+public abstract class AndPattern extends JavaSearchPattern { // TODO should rename IntersectingPattern, and make AndPattern a true subclass
 	
 public AndPattern(int patternKind, int matchRule) {
 	super(patternKind, matchRule);
 }
-
-/**
- * Query a given index for matching entries. 
- */
-protected void findIndexMatches(IndexInput input, IndexQueryRequestor requestor, SearchParticipant participant, IJavaSearchScope scope, IProgressMonitor progressMonitor, char[] queryKey, char[] category) throws IOException {
-
+public void findIndexMatches(Index index, IndexQueryRequestor requestor, SearchParticipant participant, IJavaSearchScope scope, IProgressMonitor progressMonitor) throws IOException {
 	if (progressMonitor != null && progressMonitor.isCanceled()) throw new OperationCanceledException();
-	
-	/* narrow down a set of entries using prefix criteria */
-	long[] possibleRefs = null;
-	int maxRefs = -1;
+
 	this.resetQuery();
-	SearchPattern indexRecord = null;
-	do {
-		queryKey = encodeIndexKey();
-		char[] pattern = CharOperation.concat(category, queryKey);
-		EntryResult[] entries = input.queryEntries(pattern, SearchPattern.R_PREFIX_MATCH);
-		if (entries == null) break;
+	SimpleSet intersectedNames = null;
+	try {
+		index.startQuery();
+		do {
+			SearchPattern pattern = ((InternalSearchPattern) this).currentPattern();
+			EntryResult[] entries = ((InternalSearchPattern)pattern).queryIn(index);
+			if (entries == null) return;
 
-		int numFiles = input.getNumFiles();
-		long[] references = null;
-		int referencesLength = -1;
-		for (int i = 0, max = entries.length; i < max; i++) {
-			if (progressMonitor != null && progressMonitor.isCanceled()) throw new OperationCanceledException();
+			SearchPattern decodedResult = pattern.getBlankPattern();
+			SimpleSet newIntersectedNames = new SimpleSet(3);
+			for (int i = 0, l = entries.length; i < l; i++) {
+				if (progressMonitor != null && progressMonitor.isCanceled()) throw new OperationCanceledException();
 
-			/* retrieve and decode entry */	
-			EntryResult entry = entries[i];
-			char[] word = entry.getWord();
-			char[] indexKey = CharOperation.subarray(word, category.length, word.length);
-			indexRecord = getIndexRecord();
-			indexRecord.decodeIndexKey(indexKey);
-			if (isMatchingIndexRecord()) {
-				/* accumulate references in an array of bits : 1 if the reference is present, 0 otherwise */
-				int[] fileReferences = entry.getFileReferences();
-				for (int j = 0, refLength = fileReferences.length; j < refLength; j++) {
-					int fileReference = fileReferences[j];
-					int vectorIndex = fileReference / 64; // a long has 64 bits
-					if (references == null) {
-						referencesLength = (numFiles / 64) + 1;
-						references = new long[referencesLength];
-					}
-					long mask = 1L << (fileReference % 64);
-					references[vectorIndex] |= mask;
-				}
-			}
-		}
-		
-		/* only select entries which actually match the entire search pattern */
-		if (references == null) return;
-		if (possibleRefs == null) {
-			/* first query : these are the possible references */
-			possibleRefs = references;
-			maxRefs = numFiles;
-		} else {
-			/* eliminate possible references that don't match the current references */
-			int possibleLength = possibleRefs.length;
-			for (int i = 0, length = references.length; i < length; i++) {
-				if (i < possibleLength)
-					possibleRefs[i] &= references[i];
-				else
-					possibleRefs[i] = 0;
-			}
-			// check to see that there are still possible references after the merge
-			while (--possibleLength >= 0 && possibleRefs[possibleLength] == 0);
-			if (possibleLength == -1) return;
-		}
-	} while (this.hasNextQuery());
-
-	/* report possible references that remain */
-	if (possibleRefs != null) {
-		int[] refs = new int[maxRefs];
-		int refsLength = 0;
-		for (int reference = 1; reference <= maxRefs; reference++) {
-			int vectorIndex = reference / 64; // a long has 64 bits
-			if ((possibleRefs[vectorIndex] & (1L << (reference % 64))) != 0)
-				refs[refsLength++] = reference;
-		}
-		System.arraycopy(refs, 0, refs = new int[refsLength], 0, refsLength);
-		for (int i = 0; i < refsLength; i++) { // TODO (jerome) merge with previous loop
-			int reference = refs[i];
-			if (reference != -1) { // if the reference has not been eliminated
-				IndexedFile file = input.getIndexedFile(reference);
-				if (file != null) {
-					String documentPath = IndexedFile.convertPath(file.getPath());
-					if (scope.encloses(documentPath)) {
-						if (!requestor.acceptIndexMatch(documentPath, indexRecord, participant)) 
-							throw new OperationCanceledException();
+				EntryResult entry = entries[i];
+				decodedResult.decodeIndexKey(entry.getWord());
+				if (pattern.matchesDecodedKey(decodedResult)) {
+					String[] names = entry.getDocumentNames(index);
+					if (intersectedNames != null) {
+						for (int j = 0, n = names.length; j < n; j++)
+							if (intersectedNames.includes(names[j]))
+								newIntersectedNames.add(names[j]);
+					} else {
+						for (int j = 0, n = names.length; j < n; j++)
+							newIntersectedNames.add(names[j]);
 					}
 				}
 			}
-		}
+
+			if (newIntersectedNames.elementSize == 0) return;
+			intersectedNames = newIntersectedNames;
+		} while (this.hasNextQuery());
+	} finally {
+		index.stopQuery();
 	}
+	if (intersectedNames == null) return;
+
+	Object[] names = intersectedNames.values;
+	for (int i = 0, l = names.length; i < l; i++)
+		if (names[i] != null)
+			((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/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ClassFileMatchLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ClassFileMatchLocator.java
index 1c025f3..f837a92 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ClassFileMatchLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ClassFileMatchLocator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -14,7 +14,6 @@
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.search.*;
-import org.eclipse.jdt.core.search.IJavaSearchResultCollector;
 import org.eclipse.jdt.internal.compiler.env.*;
 import org.eclipse.jdt.internal.compiler.lookup.*;
 import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
@@ -64,10 +63,10 @@
 	SearchPattern pattern = locator.pattern;
 	BinaryType binaryType = (BinaryType) classFile.getType();
 	if (matchBinary(pattern, info, null))
-		locator.reportBinaryMatch(null, binaryType, info, IJavaSearchResultCollector.EXACT_MATCH);
+		locator.reportBinaryMemberDeclaration(null, binaryType, info, SearchMatch.A_ACCURATE);
 
-	int accuracy = IJavaSearchResultCollector.EXACT_MATCH;
-	if (pattern.mustResolve) {
+	int accuracy = SearchMatch.A_ACCURATE;
+	if (((InternalSearchPattern)pattern).mustResolve) {
 		try {
 			BinaryTypeBinding binding = locator.cacheBinaryType(binaryType);
 			if (binding != null) {
@@ -81,7 +80,7 @@
 						IMethod methodHandle = binaryType.getMethod(
 							new String(method.isConstructor() ? binding.compoundName[binding.compoundName.length-1] : method.selector),
 							CharOperation.toStrings(Signature.getParameterTypes(convertClassFileFormat(method.signature()))));
-						locator.reportBinaryMatch(null, methodHandle, info, IJavaSearchResultCollector.EXACT_MATCH);
+						locator.reportBinaryMemberDeclaration(null, methodHandle, info, SearchMatch.A_ACCURATE);
 					}
 				}
 
@@ -90,7 +89,7 @@
 					FieldBinding field = fields[i];
 					if (locator.patternLocator.resolveLevel(field) == PatternLocator.ACCURATE_MATCH) {
 						IField fieldHandle = binaryType.getField(new String(field.name));
-						locator.reportBinaryMatch(null, fieldHandle, info, IJavaSearchResultCollector.EXACT_MATCH);
+						locator.reportBinaryMemberDeclaration(null, fieldHandle, info, SearchMatch.A_ACCURATE);
 					}
 				}
 
@@ -100,7 +99,7 @@
 		} catch (AbortCompilation e) { // if compilation was aborted it is a problem with the class path
 		}
 		// report as a potential match if binary info matches the pattern		
-		accuracy = IJavaSearchResultCollector.POTENTIAL_MATCH;
+		accuracy = SearchMatch.A_INACCURATE;
 	}
 
 	IBinaryMethod[] methods = info.getMethods();
@@ -111,7 +110,7 @@
 				IMethod methodHandle = binaryType.getMethod(
 					new String(method.isConstructor() ? info.getName() : method.getSelector()),
 					CharOperation.toStrings(Signature.getParameterTypes(convertClassFileFormat(method.getMethodDescriptor()))));
-				locator.reportBinaryMatch(null, methodHandle, info, accuracy);
+				locator.reportBinaryMemberDeclaration(null, methodHandle, info, accuracy);
 			}
 		}
 	}
@@ -122,7 +121,7 @@
 			IBinaryField field = fields[i];
 			if (matchBinary(pattern, field, info)) {
 				IField fieldHandle = binaryType.getField(new String(field.getName()));
-				locator.reportBinaryMatch(null, fieldHandle, info, accuracy);
+				locator.reportBinaryMemberDeclaration(null, fieldHandle, info, accuracy);
 			}
 		}
 	}
@@ -132,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 :
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ClasspathSourceDirectory.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ClasspathSourceDirectory.java
index b43713f..0b286d6 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ClasspathSourceDirectory.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ClasspathSourceDirectory.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -11,9 +11,11 @@
 package org.eclipse.jdt.internal.core.search.matching;
 
 import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
 import org.eclipse.jdt.internal.compiler.batch.CompilationUnit;
 import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
 import org.eclipse.jdt.internal.core.builder.ClasspathLocation;
@@ -27,11 +29,17 @@
 	SimpleLookupTable directoryCache;
 	String[] missingPackageHolder = new String[1];
 
-ClasspathSourceDirectory(IContainer sourceFolder, String encoding) {
+ClasspathSourceDirectory(IContainer sourceFolder) {
 	this.sourceFolder = sourceFolder;
 	IPath location = sourceFolder.getLocation();
 	this.sourceLocation = location != null ? location.addTrailingSeparator().toString() : ""; //$NON-NLS-1$
-	this.encoding = encoding;	
+	// Store default encoding
+	try {
+		this.encoding = this.sourceFolder.getDefaultCharset();
+	}
+	catch (CoreException ce) {
+		// let use no encoding by default
+	}
 	this.directoryCache = new SimpleLookupTable(5);
 }
 
@@ -89,7 +97,16 @@
 	if (!doesFileExist(sourceFileName, qualifiedPackageName)) return null; // most common case
 
 	String fullSourcePath = this.sourceLocation + qualifiedSourceFileName;
-	return new NameEnvironmentAnswer(new CompilationUnit(null, fullSourcePath, this.encoding));
+	IPath path = new Path(qualifiedSourceFileName);
+	IFile file = this.sourceFolder.getFile(path);
+	String fileEncoding = this.encoding;
+	try {
+		fileEncoding = file.getCharset();
+	}
+	catch (CoreException ce) {
+		// let use default encoding
+	}
+	return new NameEnvironmentAnswer(new CompilationUnit(null, fullSourcePath, fileEncoding));
 }
 
 public IPath getProjectRelativePath() {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorLocator.java
index e45244d..96b266e 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorLocator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -10,6 +10,7 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.search.matching;
 
+import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.internal.compiler.ast.*;
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
 import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
@@ -34,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;
@@ -59,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
@@ -69,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
 
@@ -94,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
@@ -112,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) {
@@ -127,6 +128,9 @@
 		return resolveLevel((ConstructorDeclaration) node, true);
 	return IMPOSSIBLE_MATCH;
 }
+protected int referenceType() {
+	return IJavaElement.METHOD;
+}
 protected int resolveLevel(AllocationExpression allocation) {
 	// constructor name is simple type name
 	char[][] typeName = allocation.type.getTypeName();
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorPattern.java
index b01dd0d..efce874 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorPattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorPattern.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -10,16 +10,14 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.search.matching;
 
+import java.io.IOException;
+
 import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.core.search.*;
+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 {
-
-private static ThreadLocal indexRecord = new ThreadLocal() {
-	protected Object initialValue() {
-		return new ConstructorPattern(false, false, null,null, null, null, R_EXACT_MATCH | R_CASE_SENSITIVE);
-	}
-};
+public class ConstructorPattern extends JavaSearchPattern implements IIndexConstants {
 
 protected boolean findDeclarations;
 protected boolean findReferences;
@@ -31,15 +29,21 @@
 public char[][] parameterSimpleNames;
 public int parameterCount;
 
+protected static char[][] REF_CATEGORIES = { CONSTRUCTOR_REF };
+protected static char[][] REF_AND_DECL_CATEGORIES = { CONSTRUCTOR_REF, CONSTRUCTOR_DECL };
+protected static char[][] DECL_CATEGORIES = { CONSTRUCTOR_DECL };
+
+/**
+ * Constructor entries are encoded as TypeName '/' Arity:
+ * e.g. 'X/0'
+ */
 public static char[] createIndexKey(char[] typeName, int argCount) {
-	ConstructorPattern record = getConstructorRecord();
-	record.declaringSimpleName = typeName;
-	record.parameterCount = argCount;
-	return record.encodeIndexKey();
+	char[] countChars = argCount < 10
+		? COUNTS[argCount]
+		: ("/" + String.valueOf(argCount)).toCharArray(); //$NON-NLS-1$
+	return CharOperation.concat(typeName, countChars);
 }
-public static ConstructorPattern getConstructorRecord() {
-	return (ConstructorPattern)indexRecord.get();
-}
+
 public ConstructorPattern(
 	boolean findDeclarations,
 	boolean findReferences,
@@ -49,27 +53,29 @@
 	char[][] parameterSimpleNames,
 	int matchRule) {
 
-	super(CONSTRUCTOR_PATTERN, matchRule);
+	this(matchRule);
 
 	this.findDeclarations = findDeclarations;
 	this.findReferences = findReferences;
 
-	boolean isCaseSensitive = isCaseSensitive();
-	this.declaringQualification = isCaseSensitive ? declaringQualification : CharOperation.toLowerCase(declaringQualification);
-	this.declaringSimpleName = 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] = isCaseSensitive ? parameterQualifications[i] : CharOperation.toLowerCase(parameterQualifications[i]);
-			this.parameterSimpleNames[i] = 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);
 }
 public void decodeIndexKey(char[] key) {
 	int size = key.length;
@@ -78,60 +84,21 @@
 	this.parameterCount = Integer.parseInt(new String(key, lastSeparatorIndex + 1, size - lastSeparatorIndex - 1));
 	this.declaringSimpleName = CharOperation.subarray(key, 0, lastSeparatorIndex);
 }
-/**
- * Constructor declaration entries are encoded as 'constructorDecl/' TypeName '/' Arity:
- * e.g. 'constructorDecl/X/0'
- *
- * Constructor reference entries are encoded as 'constructorRef/' TypeName '/' Arity:
- * e.g. 'constructorRef/X/0'
- */
-public char[] encodeIndexKey() {
-	// will have a common pattern in the new story
-	if (isCaseSensitive() && this.declaringSimpleName != null) {
-		switch(matchMode()) {
-			case EXACT_MATCH :
-				int arity = this.parameterCount;
-				if (arity >= 0) {
-					char[] countChars = arity < 10 ? COUNTS[arity] : ("/" + String.valueOf(arity)).toCharArray(); //$NON-NLS-1$
-					return CharOperation.concat(this.declaringSimpleName, countChars);
-				}
-			case PREFIX_MATCH :
-				return this.declaringSimpleName;
-			case PATTERN_MATCH :
-				int starPos = CharOperation.indexOf('*', this.declaringSimpleName);
-				switch(starPos) {
-					case -1 :
-						return this.declaringSimpleName;
-					default : 
-						char[] result = new char[starPos];
-						System.arraycopy(this.declaringSimpleName, 0, result, 0, starPos);
-						return result;
-					case 0 : // fall through
-				}
-		}
-	}
-	return CharOperation.NO_CHAR; // find them all
+public SearchPattern getBlankPattern() {
+	return new ConstructorPattern(R_EXACT_MATCH | R_CASE_SENSITIVE);
 }
-public SearchPattern getIndexRecord() {
-	return getConstructorRecord();
-}
-public char[][] getMatchCategories() {
+public char[][] getIndexCategories() {
 	if (this.findReferences)
-		if (this.findDeclarations) 
-			return new char[][] {CONSTRUCTOR_REF, CONSTRUCTOR_DECL};
-		else
-			return new char[][] {CONSTRUCTOR_REF};
-	else
-		if (this.findDeclarations)
-			return new char[][] {CONSTRUCTOR_DECL};
-		else
-			return CharOperation.NO_CHAR_CHAR;
+		return this.findDeclarations ? REF_AND_DECL_CATEGORIES : REF_CATEGORIES;
+	if (this.findDeclarations)
+		return DECL_CATEGORIES;
+	return CharOperation.NO_CHAR_CHAR;
 }
-public boolean isMatchingIndexRecord() {
-	ConstructorPattern record = getConstructorRecord();
-	if (this.parameterCount != -1 && this.parameterCount != record.parameterCount) return false;
+public boolean matchesDecodedKey(SearchPattern decodedPattern) {
+	ConstructorPattern pattern = (ConstructorPattern) decodedPattern;
 
-	return matchesName(this.declaringSimpleName, record.declaringSimpleName);
+	return (this.parameterCount == pattern.parameterCount || this.parameterCount == -1)
+		&& matchesName(this.declaringSimpleName, pattern.declaringSimpleName);
 }
 protected boolean mustResolve() {
 	if (this.declaringQualification != null) return true;
@@ -142,6 +109,31 @@
 			if (this.parameterQualifications[i] != null) return true;
 	return this.findReferences; // need to check resolved default constructors and explicit constructor calls
 }
+EntryResult[] queryIn(Index index) throws IOException {
+	char[] key = this.declaringSimpleName; // can be null
+	int matchRule = getMatchRule();
+
+	switch(getMatchMode()) {
+		case R_EXACT_MATCH :
+			if (this.declaringSimpleName != null && this.parameterCount >= 0)
+				key = createIndexKey(this.declaringSimpleName, this.parameterCount);
+			else // do a prefix query with the declaringSimpleName
+				matchRule = matchRule - R_EXACT_MATCH + R_PREFIX_MATCH;
+			break;
+		case R_PREFIX_MATCH :
+			// do a prefix query with the declaringSimpleName
+			break;
+		case R_PATTERN_MATCH :
+			if (this.parameterCount >= 0)
+				key = createIndexKey(this.declaringSimpleName == null ? ONE_STAR : this.declaringSimpleName, this.parameterCount);
+			else if (this.declaringSimpleName != null && this.declaringSimpleName[this.declaringSimpleName.length - 1] != '*')
+				key = CharOperation.concat(this.declaringSimpleName, ONE_STAR, SEPARATOR);
+			// else do a pattern query with just the declaringSimpleName
+			break;
+	}
+
+	return index.query(getIndexCategories(), key, matchRule); // match rule is irrelevant when the key is null
+}
 public String toString() {
 	StringBuffer buffer = new StringBuffer(20);
 	if (this.findDeclarations) {
@@ -170,14 +162,14 @@
 	}
 	buffer.append(')');
 	buffer.append(", "); //$NON-NLS-1$
-	switch(matchMode()) {
-		case EXACT_MATCH : 
+	switch(getMatchMode()) {
+		case R_EXACT_MATCH : 
 			buffer.append("exact match, "); //$NON-NLS-1$
 			break;
-		case PREFIX_MATCH :
+		case R_PREFIX_MATCH :
 			buffer.append("prefix match, "); //$NON-NLS-1$
 			break;
-		case PATTERN_MATCH :
+		case R_PATTERN_MATCH :
 			buffer.append("pattern match, "); //$NON-NLS-1$
 			break;
 	}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/DeclarationOfAccessedFieldsPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/DeclarationOfAccessedFieldsPattern.java
index d284cbd..287758a 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/DeclarationOfAccessedFieldsPattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/DeclarationOfAccessedFieldsPattern.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -23,6 +23,6 @@
 
 	this.enclosingElement = enclosingElement;
 	this.knownFields = new SimpleSet();
-	this.mustResolve = true;
+	((InternalSearchPattern)this).mustResolve = true;
 }
 }
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/DeclarationOfReferencedMethodsPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/DeclarationOfReferencedMethodsPattern.java
index 06ebb29..2828f21 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/DeclarationOfReferencedMethodsPattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/DeclarationOfReferencedMethodsPattern.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -25,6 +25,6 @@
 
 	this.enclosingElement = enclosingElement;
 	this.knownMethods = new SimpleSet();
-	this.mustResolve = true;
+	((InternalSearchPattern)this).mustResolve = true;
 }
 }
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/DeclarationOfReferencedTypesPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/DeclarationOfReferencedTypesPattern.java
index 80a80fd..cb98f4e 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/DeclarationOfReferencedTypesPattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/DeclarationOfReferencedTypesPattern.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -23,6 +23,6 @@
 
 	this.enclosingElement = enclosingElement;
 	this.knownTypes = new SimpleSet();
-	this.mustResolve = true;
+	((InternalSearchPattern)this).mustResolve = true;
 }
 }
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/FieldLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/FieldLocator.java
index ba0ac84..65c51be 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/FieldLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/FieldLocator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -14,7 +14,8 @@
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.core.search.IJavaSearchResultCollector;
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.core.search.SearchMatch;
 import org.eclipse.jdt.internal.compiler.ast.*;
 import org.eclipse.jdt.internal.compiler.env.IBinaryType;
 import org.eclipse.jdt.internal.compiler.lookup.*;
@@ -37,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
 }
@@ -89,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);
@@ -97,7 +98,7 @@
 protected void matchReportReference(ASTNode reference, IJavaElement element, int accuracy, MatchLocator locator) throws CoreException {
 	if (this.isDeclarationOfAccessedFieldsPattern) {
 		// need exact match to be able to open on type ref
-		if (accuracy != IJavaSearchResultCollector.EXACT_MATCH) return;
+		if (accuracy != SearchMatch.A_ACCURATE) return;
 
 		// element that references the field must be included in the enclosing element
 		DeclarationOfAccessedFieldsPattern declPattern = (DeclarationOfAccessedFieldsPattern) this.pattern; 
@@ -119,10 +120,16 @@
 			}
 		}
 	} else if (reference instanceof FieldReference) {
-		long position = ((FieldReference) reference).nameSourcePosition;
-		locator.report(position, position, element, accuracy);
+		FieldReference fieldReference = (FieldReference) reference;
+		long position = fieldReference.nameSourcePosition;
+		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) {
-		locator.report(reference.sourceStart, reference.sourceEnd, element, accuracy);
+		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;
 		int length = qNameRef.tokens.length;
@@ -139,10 +146,10 @@
 			} else {
 				switch (matchField(fieldBinding, false)) {
 					case ACCURATE_MATCH:
-						accuracies[indexOfFirstFieldBinding] = IJavaSearchResultCollector.EXACT_MATCH;
+						accuracies[indexOfFirstFieldBinding] = SearchMatch.A_ACCURATE;
 						break;
 					case INACCURATE_MATCH:
-						accuracies[indexOfFirstFieldBinding] = IJavaSearchResultCollector.POTENTIAL_MATCH;
+						accuracies[indexOfFirstFieldBinding] = SearchMatch.A_INACCURATE;
 						break;
 					default:
 						accuracies[indexOfFirstFieldBinding] = -1;
@@ -161,10 +168,10 @@
 				} else {
 					switch (matchField(otherBinding, false)) {
 						case ACCURATE_MATCH:
-							accuracies[i] = IJavaSearchResultCollector.EXACT_MATCH;
+							accuracies[i] = SearchMatch.A_ACCURATE;
 							break;
 						case INACCURATE_MATCH:
-							accuracies[i] = IJavaSearchResultCollector.POTENTIAL_MATCH;
+							accuracies[i] = SearchMatch.A_INACCURATE;
 							break;
 						default:
 							accuracies[i] = -1;
@@ -174,7 +181,7 @@
 				accuracies[i] = -1;
 			}
 		}
-		locator.reportAccurateReference(reference.sourceStart, reference.sourceEnd, qNameRef.tokens, element, accuracies);
+		locator.reportAccurateFieldReference(qNameRef, element, accuracies);
 	}
 }
 protected void reportDeclaration(FieldBinding fieldBinding, MatchLocator locator, SimpleSet knownFields) throws CoreException {
@@ -197,7 +204,7 @@
 		if (resource == null)
 			resource = type.getJavaProject().getProject();
 		info = locator.getBinaryInfo((org.eclipse.jdt.internal.core.ClassFile) type.getClassFile(), resource);
-		locator.reportBinaryMatch(resource, field, info, IJavaSearchResultCollector.EXACT_MATCH);
+		locator.reportBinaryMemberDeclaration(resource, field, info, SearchMatch.A_ACCURATE);
 	} else {
 		ClassScope scope = ((SourceTypeBinding) declaringClass).scope;
 		if (scope != null) {
@@ -211,18 +218,17 @@
 				}
 			} 
 			if (fieldDecl != null) {
-				locator.report(
-					resource, 
-					fieldDecl.sourceStart, 
-					fieldDecl.sourceEnd, 
-					field,
-					IJavaSearchResultCollector.EXACT_MATCH, 
-					locator.getParticipant());
+				int offset = fieldDecl.sourceStart;
+				SearchMatch match = new FieldDeclarationMatch(field, SearchMatch.A_ACCURATE, offset, fieldDecl.sourceEnd-offset+1, locator.getParticipant(), resource);
+				locator.report(match);
 
 			}
 		}
 	}
 }
+protected int referenceType() {
+	return IJavaElement.FIELD;
+}
 public int resolveLevel(ASTNode possiblelMatchingNode) {
 	if (this.pattern.findReferences) {
 		if (possiblelMatchingNode instanceof FieldReference)
@@ -253,8 +259,10 @@
 		int lastDot = CharOperation.lastIndexOf('.', bindingName);
 		if (lastDot > -1)
 			bindingName = CharOperation.subarray(bindingName, lastDot+1, bindingName.length);
-		if (matchesName(this.pattern.name, bindingName))
-			return matchField(fieldBinding, false);
+		if (matchesName(this.pattern.name, bindingName)) {
+			int level = matchField(fieldBinding, false);
+			if (level != IMPOSSIBLE_MATCH) return level;
+		}
 	} 
 	int otherMax = qNameRef.otherBindings == null ? 0 : qNameRef.otherBindings.length;
 	for (int i = 0; i < otherMax; i++) {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/FieldPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/FieldPattern.java
index ec7e3df..758e96f 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/FieldPattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/FieldPattern.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -11,15 +11,10 @@
 package org.eclipse.jdt.internal.core.search.matching;
 
 import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.core.search.SearchPattern;
+import org.eclipse.jdt.internal.core.search.indexing.IIndexConstants;
 
-public class FieldPattern extends VariablePattern {
-
-private static ThreadLocal indexRecord = new ThreadLocal() {
-	protected Object initialValue() {
-		return new FieldPattern(false, false, false, null, null, null, null, null, R_EXACT_MATCH | R_CASE_SENSITIVE);
-	}
-};
+public class FieldPattern extends VariablePattern implements IIndexConstants {
 
 // declaring type
 protected char[] declaringQualification;
@@ -29,17 +24,12 @@
 protected char[] typeQualification;
 protected char[] typeSimpleName;
 
-protected static char[][] REF_CATEGORIES = { FIELD_REF, REF };
-protected static char[][] REF_AND_DECL_CATEGORIES = { FIELD_REF, REF, FIELD_DECL };
+protected static char[][] REF_CATEGORIES = { REF };
+protected static char[][] REF_AND_DECL_CATEGORIES = { REF, FIELD_DECL };
 protected static char[][] DECL_CATEGORIES = { FIELD_DECL };
 
 public static char[] createIndexKey(char[] fieldName) {
-	FieldPattern record = getFieldRecord();
-	record.name = fieldName;
-	return record.encodeIndexKey();
-}
-public static FieldPattern getFieldRecord() {
-	return (FieldPattern)indexRecord.get();
+	return fieldName;
 }
 
 public FieldPattern(
@@ -55,35 +45,32 @@
 
 	super(FIELD_PATTERN, findDeclarations, readAccess, writeAccess, name, matchRule);
 
-	boolean isCaseSensitive = isCaseSensitive();
-	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.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;
 }
-public char[] encodeIndexKey() {
-	return encodeIndexKey(this.name);
+public SearchPattern getBlankPattern() {
+	return new FieldPattern(false, false, false, null, null, null, null, null, R_EXACT_MATCH | R_CASE_SENSITIVE);
 }
-public SearchPattern getIndexRecord() {
-	return getFieldRecord();
+public char[] getIndexKey() {
+	return this.name;
 }
-public char[][] getMatchCategories() {
-	return this.findReferences
-			? (this.findDeclarations || this.writeAccess ? REF_AND_DECL_CATEGORIES : REF_CATEGORIES)
-			: DECL_CATEGORIES;
+public char[][] getIndexCategories() {
+	if (this.findReferences)
+		return this.findDeclarations || this.writeAccess ? REF_AND_DECL_CATEGORIES : REF_CATEGORIES;
+	if (this.findDeclarations)
+		return DECL_CATEGORIES;
+	return CharOperation.NO_CHAR_CHAR;
 }
-public boolean isMatchingIndexRecord() {
-	return matchesName(this.name, getFieldRecord().name);
+public boolean matchesDecodedKey(SearchPattern decodedPattern) {
+	return true; // index key is not encoded so query results all match
 }
-/**
- * Returns whether a method declaration or message send will need to be resolved to 
- * find out if this method pattern matches it.
- */
 protected boolean mustResolve() {
 	if (this.declaringSimpleName != null || this.declaringQualification != null) return true;
 	if (this.typeSimpleName != null || this.typeQualification != null) return true;
@@ -115,14 +102,14 @@
 		buffer.append(typeSimpleName);
 	else if (typeQualification != null) buffer.append("*"); //$NON-NLS-1$
 	buffer.append(", "); //$NON-NLS-1$
-	switch(matchMode()){
-		case EXACT_MATCH : 
+	switch(getMatchMode()) {
+		case R_EXACT_MATCH : 
 			buffer.append("exact match, "); //$NON-NLS-1$
 			break;
-		case PREFIX_MATCH :
+		case R_PREFIX_MATCH :
 			buffer.append("prefix match, "); //$NON-NLS-1$
 			break;
-		case PATTERN_MATCH :
+		case R_PATTERN_MATCH :
 			buffer.append("pattern match, "); //$NON-NLS-1$
 			break;
 	}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/InternalSearchPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/InternalSearchPattern.java
new file mode 100644
index 0000000..9bd3a96
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/InternalSearchPattern.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * 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;
+
+	int kind;
+	boolean mustResolve = true;
+	
+	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.getIndexCategories(), pattern.getIndexKey(), pattern.getMatchRule());
+	}
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchMatch.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchMatch.java
deleted file mode 100644
index bc03040..0000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchMatch.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 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 org.eclipse.core.resources.IResource;
-import org.eclipse.jdt.core.IJavaElement;
-import org.eclipse.jdt.core.search.SearchMatch;
-import org.eclipse.jdt.core.search.SearchParticipant;
-
-public class JavaSearchMatch extends SearchMatch {
-	
-	public IResource resource;
-	public IJavaElement element;
-	
-	public JavaSearchMatch(
-			IResource resource,
-			IJavaElement element,
-			String documentPath,
-			int accuracy,  
-			SearchParticipant participant,
-			int sourceStart, 
-			int sourceEnd, 
-			int sourceLineNumber) {
-		super(
-			element.getElementName(), 
-			documentPath, 
-			accuracy, 
-			participant, 
-			sourceStart, 
-			sourceEnd, 
-			sourceLineNumber, 
-			element.toString());
-		this.resource = resource;
-		this.element = element;
-	}
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchNameEnvironment.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchNameEnvironment.java
index 27fea53..abef123 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchNameEnvironment.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchNameEnvironment.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -10,17 +10,21 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.search.matching;
 
+import java.util.HashMap;
 import java.util.zip.ZipFile;
 
 import org.eclipse.core.resources.IContainer;
 import org.eclipse.core.resources.IWorkspaceRoot;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPath;
+//import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.IPackageFragmentRoot;
-import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.JavaModelException;
+//import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
 import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
 import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
@@ -37,8 +41,28 @@
 	
 	ClasspathLocation[] locations;
 	
-public JavaSearchNameEnvironment(IJavaProject javaProject) {
+	/*
+	 * A map from the fully qualified slash-separated name of the main type (String) to the working copy
+	 */
+	HashMap workingCopies;
+	
+public JavaSearchNameEnvironment(IJavaProject javaProject, org.eclipse.jdt.core.ICompilationUnit[] copies) {
 	computeClasspathLocations(javaProject.getProject().getWorkspace().getRoot(), (JavaProject) javaProject);
+	try {
+		int length = copies == null ? 0 : copies.length;
+		this.workingCopies = new HashMap(length);
+		for (int i = 0; i < length; i++) {
+			org.eclipse.jdt.core.ICompilationUnit workingCopy = copies[i];
+			IPackageDeclaration[] pkgs = workingCopy.getPackageDeclarations();
+			String pkg = pkgs.length > 0 ? pkgs[0].getElementName() : ""; //$NON-NLS-1$
+			String cuName = workingCopy.getElementName();
+			String mainTypeName = cuName.substring(0, cuName.length() - SUFFIX_JAVA.length);
+			String qualifiedMainTypeName = pkg.length() == 0 ? mainTypeName : pkg.replace('.', '/') + '/' + mainTypeName;
+			this.workingCopies.put(qualifiedMainTypeName, workingCopy);
+		}
+	} catch (JavaModelException e) {
+		// working copy doesn't exist: cannot happen
+	}
 }
 
 public void cleanup() {
@@ -49,7 +73,6 @@
 
 private void computeClasspathLocations(IWorkspaceRoot workspaceRoot, JavaProject javaProject) {
 
-	String encoding = null;
 	IPackageFragmentRoot[] roots = null;
 	try {
 		roots = javaProject.getAllPackageFragmentRoots();
@@ -72,10 +95,7 @@
 			} else {
 				Object target = JavaModel.getTarget(workspaceRoot, path, false);
 				if (root.getKind() == IPackageFragmentRoot.K_SOURCE) {
-					if (encoding == null) {
-						encoding = javaProject.getOption(JavaCore.CORE_ENCODING, true);
-					}
-					cpLocations[index++] = new ClasspathSourceDirectory((IContainer)target, encoding);
+					cpLocations[index++] = new ClasspathSourceDirectory((IContainer)target);
 				} else {
 					cpLocations[index++] = ClasspathLocation.forBinaryFolder((IContainer) target, false);
 				}
@@ -109,10 +129,15 @@
 					sourceFileName = qSourceFileName.substring(typeNameStart);
 				}
 			}
-			answer = location.findClass(
-				sourceFileName,
-				qPackageName,
-				qSourceFileName);
+			ICompilationUnit workingCopy = (ICompilationUnit) this.workingCopies.get(qualifiedTypeName);
+			if (workingCopy != null) {
+				answer = new NameEnvironmentAnswer(workingCopy);
+			} else {
+				answer = location.findClass(
+					sourceFileName,
+					qPackageName,
+					qSourceFileName);
+			}
 		} else {
 			if (binaryFileName == null) {
 				qBinaryFileName = qualifiedTypeName + SUFFIX_STRING_class;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchPattern.java
new file mode 100644
index 0000000..b83ed08
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchPattern.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * 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.search.matching;
+
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.core.search.SearchPattern;
+
+
+public class JavaSearchPattern extends SearchPattern {
+	
+	/*
+	 * Whether this pattern is case sensitive.
+	 */
+	boolean isCaseSensitive;
+	
+	/*
+	 * One of R_EXACT_MATCH, R_PREFIX_MATCH, R_PATTERN_MATCH, R_REGEXP_MATCH.
+	 */
+	int matchMode;
+	
+	protected JavaSearchPattern(int patternKind, int matchRule) {
+		super(matchRule);
+		((InternalSearchPattern)this).kind = patternKind;
+		this.isCaseSensitive = (matchRule & R_CASE_SENSITIVE) != 0;
+		this.matchMode = matchRule - (this.isCaseSensitive ? R_CASE_SENSITIVE : 0);
+	}
+	
+	public SearchPattern getBlankPattern() {
+		return null;
+	}
+
+	int getMatchMode() {
+		return this.matchMode;
+	}
+
+	boolean isCaseSensitive () {
+		return this.isCaseSensitive;
+	}
+
+	/*
+	 * Optimization of implementation above (uses cached matchMode and isCaseSenistive)
+	 */
+	public boolean matchesName(char[] pattern, char[] name) {
+		if (pattern == null) return true; // null is as if it was "*"
+		if (name != null) {
+			switch (this.matchMode) {
+				case R_EXACT_MATCH :
+					return CharOperation.equals(pattern, name, this.isCaseSensitive);
+				case R_PREFIX_MATCH :
+					return CharOperation.prefixEquals(pattern, name, this.isCaseSensitive);
+				case R_PATTERN_MATCH :
+					if (!this.isCaseSensitive)
+						pattern = CharOperation.toLowerCase(pattern);
+					return CharOperation.match(pattern, name, this.isCaseSensitive);
+				case R_REGEXP_MATCH :
+					// TODO (jerome) implement regular expression match
+					return true;
+			}
+		}
+		return false;
+	}
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/LocalVariableLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/LocalVariableLocator.java
index ad58ceb..dc9a6fd 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/LocalVariableLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/LocalVariableLocator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -12,6 +12,7 @@
 
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.search.SearchMatch;
 import org.eclipse.jdt.internal.compiler.ast.*;
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
 import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
@@ -28,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
 }
@@ -43,14 +44,21 @@
 }
 protected void matchReportReference(ASTNode reference, IJavaElement element, int accuracy, MatchLocator locator) throws CoreException {
 	if (reference instanceof SingleNameReference) {
-		locator.report(reference.sourceStart, reference.sourceEnd, element, accuracy);
+		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];
-		locator.report(sourcePosition, sourcePosition, element, accuracy);
+		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();
-		locator.report(localVariable.nameStart, localVariable.nameEnd, localVariable, accuracy);
+		int offset = localVariable.nameStart;
+		SearchMatch match = locator.newLocalVariableReferenceMatch(localVariable, accuracy, offset, localVariable.nameEnd-offset+1, reference);
+		locator.report(match);
 	}
 }
 protected int matchContainer() {
@@ -65,6 +73,9 @@
 		? ACCURATE_MATCH
 		: IMPOSSIBLE_MATCH;
 }
+protected int referenceType() {
+	return IJavaElement.LOCAL_VARIABLE;
+}
 public int resolveLevel(ASTNode possiblelMatchingNode) {
 	if (this.pattern.findReferences)
 		if (possiblelMatchingNode instanceof NameReference)
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/LocalVariablePattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/LocalVariablePattern.java
index e3c322b..c9834c8 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/LocalVariablePattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/LocalVariablePattern.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -10,44 +10,25 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.search.matching;
 
-import java.io.IOException;
-
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.OperationCanceledException;
 import org.eclipse.jdt.core.*;
-import org.eclipse.jdt.core.IJavaElement;
-import org.eclipse.jdt.core.IPackageFragmentRoot;
-import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.search.*;
-import org.eclipse.jdt.core.search.IJavaSearchScope;
-import org.eclipse.jdt.core.search.SearchParticipant;
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
 import org.eclipse.jdt.internal.core.LocalVariable;
-import org.eclipse.jdt.internal.core.index.IIndex;
+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;
 
-public LocalVariablePattern(
-	boolean findDeclarations,
-	boolean readAccess,
-	boolean writeAccess,
-	LocalVariable localVariable,
-	int matchRule) {
-
+public LocalVariablePattern(boolean findDeclarations, boolean readAccess, boolean writeAccess, LocalVariable localVariable, int matchRule) {
 	super(LOCAL_VAR_PATTERN, findDeclarations, readAccess, writeAccess, localVariable.getElementName().toCharArray(), matchRule);
 	this.localVariable = localVariable;
 }
-public void decodeIndexKey(char[] key) {
-	// local variables are not indexed
-}
-public char[] encodeIndexKey() {
-	// local variables are not indexed
-	return null;
-}
-public void findIndexMatches(IIndex index, IndexQueryRequestor requestor, SearchParticipant participant, IJavaSearchScope scope, IProgressMonitor progressMonitor) throws IOException {
+public void findIndexMatches(Index index, IndexQueryRequestor requestor, SearchParticipant participant, IJavaSearchScope scope, IProgressMonitor progressMonitor) {
     IPackageFragmentRoot root = (IPackageFragmentRoot)this.localVariable.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
 	String path;
     if (root.isArchive()) {
@@ -57,22 +38,9 @@
     } else {
         path = this.localVariable.getPath().toString();
     }
-	if (scope.encloses(path)) {
+	if (scope.encloses(path))
 		if (!requestor.acceptIndexMatch(path, this, participant)) 
 			throw new OperationCanceledException();
-	}
-}
-public SearchPattern getIndexRecord() {
-	// local variables are not indexed
-	return null;
-}
-public char[][] getMatchCategories() {
-	// local variables are not indexed
-	return CharOperation.NO_CHAR_CHAR;
-}
-public boolean isMatchingIndexRecord() {
-	// local variables are not indexed
-	return false;
 }
 public String toString() {
 	StringBuffer buffer = new StringBuffer(20);
@@ -85,14 +53,14 @@
 	}
 	buffer.append(this.localVariable.toStringWithAncestors());
 	buffer.append(", "); //$NON-NLS-1$
-	switch(matchMode()){
-		case EXACT_MATCH : 
+	switch(getMatchMode()) {
+		case R_EXACT_MATCH : 
 			buffer.append("exact match, "); //$NON-NLS-1$
 			break;
-		case PREFIX_MATCH :
+		case R_PREFIX_MATCH :
 			buffer.append("prefix match, "); //$NON-NLS-1$
 			break;
-		case PATTERN_MATCH :
+		case R_PATTERN_MATCH :
 			buffer.append("pattern match, "); //$NON-NLS-1$
 			break;
 	}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java
index 4551fc1..004c579 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -11,7 +11,9 @@
 package org.eclipse.jdt.internal.core.search.matching;
 
 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;
@@ -32,18 +34,22 @@
 import org.eclipse.jdt.internal.compiler.lookup.*;
 import org.eclipse.jdt.internal.compiler.parser.*;
 import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.util.HashtableOfIntValues;
 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.JavaSearchParticipant;
+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;
 
 public class MatchLocator implements ITypeRequestor {
 
-public static final int MAX_AT_ONCE = 500;
+public static final int MAX_AT_ONCE = 400;
 
 // permanent state
 public SearchPattern pattern;
@@ -85,32 +91,31 @@
 public class LocalDeclarationVisitor extends ASTVisitor {
 	IJavaElement enclosingElement;
 	MatchingNodeSet nodeSet;
-	// TODO (jerome) Use an HashtableOfIntValues instead
-	HashMap occurrencesCounts = new HashMap(); // key = class name (String), value = occurrenceCount (Integer)
+	HashtableOfIntValues occurrencesCounts = new HashtableOfIntValues(); // key = class name (char[]), value = occurrenceCount (int)
 	public LocalDeclarationVisitor(IJavaElement enclosingElement, MatchingNodeSet nodeSet) {
 		this.enclosingElement = enclosingElement;
 		this.nodeSet = nodeSet;
 	}
 	public boolean visit(TypeDeclaration typeDeclaration, BlockScope unused) {
 		try {
-			String simpleName;
+			char[] simpleName;
 			if ((typeDeclaration.bits & ASTNode.IsAnonymousTypeMASK) != 0) {				
-				simpleName = ""; //$NON-NLS-1$
+				simpleName = CharOperation.NO_CHAR;
 			} else {
-				simpleName = new String(typeDeclaration.name);
+				simpleName = typeDeclaration.name;
 			}
-			Integer occurrenceCount = (Integer)occurrencesCounts.get(simpleName);
-			if (occurrenceCount == null) {
-				occurrenceCount = new Integer(1);
+			int occurrenceCount = occurrencesCounts.get(simpleName);
+			if (occurrenceCount == HashtableOfIntValues.NO_VALUE) {
+				occurrenceCount = 1;
 			} else {
-				occurrenceCount = new Integer(occurrenceCount.intValue()+1);
+				occurrenceCount = occurrenceCount + 1;
 			}
 			occurrencesCounts.put(simpleName, occurrenceCount);
 			if ((typeDeclaration.bits & ASTNode.IsAnonymousTypeMASK) != 0) {				
-				reportMatching(typeDeclaration, enclosingElement, -1, nodeSet, occurrenceCount.intValue());
+				reportMatching(typeDeclaration, enclosingElement, -1, nodeSet, occurrenceCount);
 			} else {
 				Integer level = (Integer) nodeSet.matchingNodes.removeKey(typeDeclaration);
-				reportMatching(typeDeclaration, enclosingElement, level != null ? level.intValue() : -1, nodeSet, occurrenceCount.intValue());
+				reportMatching(typeDeclaration, enclosingElement, level != null ? level.intValue() : -1, nodeSet, occurrenceCount);
 			}
 			return false; // don't visit members as this was done during reportMatching(...)
 		} catch (CoreException e) {
@@ -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,11 +240,51 @@
 	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,
 	IJavaSearchScope scope,
-	org.eclipse.jdt.core.ICompilationUnit[] workingCopies,
 	IProgressMonitor progressMonitor) {
 		
 	this.pattern = pattern;
@@ -175,7 +292,6 @@
 	this.matchContainer = this.patternLocator.matchContainer();
 	this.requestor = requestor;
 	this.scope = scope;
-	this.workingCopies = workingCopies;
 	this.progressMonitor = progressMonitor;
 }
 /**
@@ -241,6 +357,7 @@
 				this.options,
 				new DefaultProblemFactory());
 		this.basicParser = new Parser(problemReporter, false);
+		this.basicParser.reportOnlyOneSyntaxError = true;
 	}
 	return this.basicParser;
 }
@@ -248,7 +365,7 @@
  * Add the possibleMatch to the loop
  *  ->  build compilation unit declarations, their bindings and record their results.
  */
-protected void buildBindings(PossibleMatch possibleMatch) {
+protected void parseAndBuildBindings(PossibleMatch possibleMatch, boolean mustResolve) {
 	if (this.progressMonitor != null && this.progressMonitor.isCanceled())
 		throw new OperationCanceledException();
 
@@ -260,7 +377,7 @@
 		CompilationResult unitResult = new CompilationResult(possibleMatch, 1, 1, this.options.maxProblemsPerUnit);
 		CompilationUnitDeclaration parsedUnit = this.parser.dietParse(possibleMatch, unitResult);
 		if (parsedUnit != null) {
-			if (!parsedUnit.isEmpty())
+			if (mustResolve && !parsedUnit.isEmpty())
 				this.lookupEnvironment.buildTypeBindings(parsedUnit);
 
 			// add the possibleMatch with its parsedUnit to matchesToProcess
@@ -269,9 +386,6 @@
 			if (this.numberOfMatches == size)
 				System.arraycopy(this.matchesToProcess, 0, this.matchesToProcess = new PossibleMatch[size == 0 ? 1 : size * 2], 0, this.numberOfMatches);
 			this.matchesToProcess[this.numberOfMatches++] = possibleMatch;
-
-			if (this.progressMonitor != null)
-				this.progressMonitor.worked(4);
 		}
 	} finally {
 		this.parser.nodeSet = null;
@@ -310,7 +424,7 @@
 			this.pattern, 
 			simpleName,
 			qualification,
-			new MatchLocator(this.pattern, this.requestor, this.scope, this.workingCopies, this.progressMonitor), // clone MatchLocator so that it has no side effect
+			new MatchLocator(this.pattern, this.requestor, this.scope, this.progressMonitor), // clone MatchLocator so that it has no side effect
 			focusType, 
 			this.progressMonitor);
 	try {
@@ -337,13 +451,9 @@
 			IBinaryMethod[] methods = reader.getMethods();
 			if (methods != null) {
 				boolean firstIsSynthetic = false;
-				try {
-					if (type.isMember() && method.isConstructor() && !Flags.isStatic(type.getFlags())) { // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=48261
-						firstIsSynthetic = true;
-						argCount++;
-					}
-				} catch (JavaModelException e) {
-					// ignored
+				if (reader.isMember() && method.isConstructor() && !Flags.isStatic(reader.getModifiers())) { // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=48261
+					firstIsSynthetic = true;
+					argCount++;
 				}
 				nextMethod : for (int i = 0, methodsLength = methods.length; i < methodsLength; i++) {
 					IBinaryMethod binaryMethod = methods[i];
@@ -474,6 +584,9 @@
 	}
 	return null;
 }
+protected boolean encloses(IJavaElement element) {
+	return element != null && this.scope.encloses(element);
+}
 protected IBinaryType getBinaryInfo(ClassFile classFile, IResource resource) throws CoreException {
 	BinaryType binaryType = (BinaryType) classFile.getType();
 	if (classFile.isOpen())
@@ -533,7 +646,7 @@
 		this.parser.scanner.lineEnds = lineSeparatorPositions;
 		this.parser.scanner.linePtr = lineSeparatorPositions.length - 1;
 
-		if (this.parser.javadocParser.checkJavadoc) {
+		if (this.parser.javadocParser.checkDocComment) {
 			this.parser.javadocParser.scanner.setSource(contents);
 		}
 		this.parser.nodeSet = this.currentPossibleMatch.nodeSet;
@@ -561,12 +674,14 @@
 	if (this.nameEnvironment != null)
 		this.nameEnvironment.cleanup();
 
+	SearchableEnvironment searchableEnvironment = (SearchableEnvironment) project.newSearchableNameEnvironment(this.workingCopies);
+	
 	// if only one possible match, a file name environment costs too much,
 	// so use the existing searchable  environment which will populate the java model
 	// only for this possible match and its required types.
 	this.nameEnvironment = possibleMatchSize == 1
-		? (INameEnvironment) project.getSearchableNameEnvironment()
-		: (INameEnvironment) new JavaSearchNameEnvironment(project);
+		? (INameEnvironment) searchableEnvironment
+		: (INameEnvironment) new JavaSearchNameEnvironment(project, this.workingCopies);
 
 	// create lookup environment
 	this.options = new CompilerOptions(project.getOptions(true));
@@ -580,95 +695,112 @@
 	this.parser = MatchLocatorParser.createParser(problemReporter, this);
 
 	// remember project's name lookup
-	this.nameLookup = project.getNameLookup();
+	this.nameLookup = searchableEnvironment.nameLookup;
 
 	// initialize queue of units
 	this.numberOfMatches = 0;
 	this.matchesToProcess = new PossibleMatch[possibleMatchSize];
 }
-protected void locateMatches(JavaProject javaProject, PossibleMatch[] possibleMatches, int start, int length) throws JavaModelException {
+protected void locateMatches(JavaProject javaProject, PossibleMatch[] possibleMatches, int start, int length) throws CoreException {
 	initialize(javaProject, length);
 
+	// create and resolve binding (equivalent to beginCompilation() in Compiler)
+	boolean mustResolve = ((InternalSearchPattern)this.pattern).mustResolve;
+	boolean bindingsWereCreated = mustResolve;
 	try {
-		this.nameLookup.setUnitsToLookInside(this.workingCopies);
-
-		// create and resolve binding (equivalent to beginCompilation() in Compiler)
-		boolean bindingsWereCreated = true;
-		try {
-			for (int i = start, maxUnits = start + length; i < maxUnits; i++)
-				buildBindings(possibleMatches[i]);
+		for (int i = start, maxUnits = start + length; i < maxUnits; i++) {
+			PossibleMatch possibleMatch = possibleMatches[i];
+			try {
+				parseAndBuildBindings(possibleMatch, mustResolve);
+				if (!mustResolve)
+					process(possibleMatch, bindingsWereCreated);
+			} finally {
+				if (!mustResolve)
+					possibleMatch.cleanUp();
+			}
+		}
+		if (mustResolve)
 			lookupEnvironment.completeTypeBindings();
 
-			// create hierarchy resolver if needed
-			IType focusType = getFocusType();
-			if (focusType == null) {
-				this.hierarchyResolver = null;
-			} else if (!createHierarchyResolver(focusType, possibleMatches)) {
-				// focus type is not visible, use the super type names instead of the bindings
-				if (computeSuperTypeNames(focusType) == null) return;
-			}
-		} catch (AbortCompilation e) {
-			bindingsWereCreated = false;
+		// create hierarchy resolver if needed
+		IType focusType = getFocusType();
+		if (focusType == null) {
+			this.hierarchyResolver = null;
+		} else if (!createHierarchyResolver(focusType, possibleMatches)) {
+			// focus type is not visible, use the super type names instead of the bindings
+			if (computeSuperTypeNames(focusType) == null) return;
 		}
+	} catch (AbortCompilation e) {
+		bindingsWereCreated = false;
+	}
 
-		// possible match resolution
-		for (int i = 0; i < this.numberOfMatches; i++) {
-			if (this.progressMonitor != null && this.progressMonitor.isCanceled())
-				throw new OperationCanceledException();
-			PossibleMatch possibleMatch = this.matchesToProcess[i];
-			this.matchesToProcess[i] = null; // release reference to processed possible match
-			try {
-				process(possibleMatch, bindingsWereCreated);
-			} catch (AbortCompilation e) {
-				// problem with class path: it could not find base classes
-				// continue and try next matching openable reporting innacurate matches (since bindings will be null)
-				bindingsWereCreated = false;
-			} catch (JavaModelException e) {
-				// problem with class path: it could not find base classes
-				// continue and try next matching openable reporting innacurate matches (since bindings will be null)
-				bindingsWereCreated = false;
-			} catch (CoreException e) {
-				// core exception thrown by client's code: let it through
-				throw new JavaModelException(e);
-			} finally {
-				if (this.options.verbose)
-					System.out.println(Util.bind("compilation.done", //$NON-NLS-1$
-						new String[] {
-							String.valueOf(i + 1),
-							String.valueOf(numberOfMatches),
-							new String(possibleMatch.parsedUnit.getFileName())}));
-				// cleanup compilation unit result
-				possibleMatch.parsedUnit.cleanUp();
-				possibleMatch.parsedUnit = null;
-			}
-			if (this.progressMonitor != null)
-				this.progressMonitor.worked(5);
+	if (!mustResolve) {
+		return;
+	}
+	
+	// possible match resolution
+	for (int i = 0; i < this.numberOfMatches; i++) {
+		if (this.progressMonitor != null && this.progressMonitor.isCanceled())
+			throw new OperationCanceledException();
+		PossibleMatch possibleMatch = this.matchesToProcess[i];
+		this.matchesToProcess[i] = null; // release reference to processed possible match
+		try {
+			process(possibleMatch, bindingsWereCreated);
+		} catch (AbortCompilation e) {
+			// problem with class path: it could not find base classes
+			// continue and try next matching openable reporting innacurate matches (since bindings will be null)
+			bindingsWereCreated = false;
+		} catch (JavaModelException e) {
+			// problem with class path: it could not find base classes
+			// continue and try next matching openable reporting innacurate matches (since bindings will be null)
+			bindingsWereCreated = false;
+		} finally {
+			if (this.options.verbose)
+				System.out.println(Util.bind("compilation.done", //$NON-NLS-1$
+					new String[] {
+						String.valueOf(i + 1),
+						String.valueOf(numberOfMatches),
+						new String(possibleMatch.parsedUnit.getFileName())}));
+			// cleanup compilation unit result
+			possibleMatch.cleanUp();
 		}
-	} finally {
-		this.nameLookup.setUnitsToLookInside(null);
 	}
 }
 /**
  * Locate the matches amongst the possible matches.
  */
-protected void locateMatches(JavaProject javaProject, PossibleMatchSet matchSet) throws JavaModelException {
+protected void locateMatches(JavaProject javaProject, PossibleMatchSet matchSet) throws CoreException {
 	PossibleMatch[] possibleMatches = matchSet.getPossibleMatches(javaProject.getPackageFragmentRoots());
 	for (int index = 0, length = possibleMatches.length; index < length;) {
 		int max = Math.min(MAX_AT_ONCE, length - index);
 		locateMatches(javaProject, possibleMatches, index, max);
 		index += max;
+		if (this.progressMonitor != null)
+			this.progressMonitor.worked(max);
 	}
 }
 /**
  * Locate the matches in the given files and report them using the search requestor. 
  */
-public void locateMatches(SearchDocument[] searchDocuments) throws JavaModelException {
+public void locateMatches(SearchDocument[] searchDocuments) throws CoreException {
 	if (SearchEngine.VERBOSE) {
 		System.out.println("Locating matches in documents ["); //$NON-NLS-1$
 		for (int i = 0, length = searchDocuments.length; i < length; i++)
 			System.out.println("\t" + searchDocuments[i]); //$NON-NLS-1$
 		System.out.println("]"); //$NON-NLS-1$
 	}
+	
+	// extract working copies
+	ArrayList copies = new ArrayList();
+	for (int i = 0, length = searchDocuments.length; i < length; i++) {
+		SearchDocument document = searchDocuments[i];
+		if (document instanceof WorkingCopyDocument) {
+			copies.add(((WorkingCopyDocument)document).workingCopy);
+		}
+	}
+	int copiesLength = copies.size();
+	this.workingCopies = new org.eclipse.jdt.core.ICompilationUnit[copiesLength];
+	copies.toArray(this.workingCopies);
 
 	JavaModelManager manager = JavaModelManager.getJavaModelManager();
 	try {
@@ -680,14 +812,14 @@
 			this.handleFactory = new HandleFactory();
 
 		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); //$NON-NLS-1$
 		}
 
 		// initialize pattern for polymorphic search (ie. method reference pattern)
 		this.patternLocator.initializePolymorphicSearch(this);
 
 		JavaProject previousJavaProject = null;
+		int skipped = 0;
 		PossibleMatchSet matchSet = new PossibleMatchSet();
 		Util.sort(searchDocuments, new Util.Comparer() {
 			public int compare(Object a, Object b) {
@@ -701,12 +833,15 @@
 			// skip duplicate paths
 			SearchDocument searchDocument = searchDocuments[i];
 			String pathString = searchDocument.getPath();
-			if (i > 0 && pathString.equals(searchDocuments[i - 1].getPath())) continue;
+			if (i > 0 && pathString.equals(searchDocuments[i - 1].getPath())) {
+				skipped++;
+				continue;
+			}
 
 			Openable openable;
 			org.eclipse.jdt.core.ICompilationUnit workingCopy = null;
-			if (searchDocument instanceof JavaSearchParticipant.WorkingCopyDocument) {
-				workingCopy = ((JavaSearchParticipant.WorkingCopyDocument)searchDocument).workingCopy;
+			if (searchDocument instanceof WorkingCopyDocument) {
+				workingCopy = ((WorkingCopyDocument)searchDocument).workingCopy;
 				openable = (Openable) workingCopy;
 			} else {
 				openable = this.handleFactory.createOpenable(pathString, this.scope);
@@ -715,32 +850,27 @@
 
 			// create new parser and lookup environment if this is a new project
 			IResource resource = null;
-			try {
-				JavaProject javaProject = (JavaProject) openable.getJavaProject();
-				resource = workingCopy != null ? workingCopy.getResource() : openable.getResource();
-				if (resource == null)
-					resource = javaProject.getProject(); // case of a file in an external jar
-				if (!javaProject.equals(previousJavaProject)) {
-					// locate matches in previous project
-					if (previousJavaProject != null) {
-						try {
-							locateMatches(previousJavaProject, matchSet);
-						} catch (JavaModelException e) {
-							if (e.getException() instanceof CoreException) throw e;
-							// problem with classpath in this project -> skip it
-						}
-						matchSet.reset();
+			JavaProject javaProject = (JavaProject) openable.getJavaProject();
+			resource = workingCopy != null ? workingCopy.getResource() : openable.getResource();
+			if (resource == null)
+				resource = javaProject.getProject(); // case of a file in an external jar
+			if (!javaProject.equals(previousJavaProject)) {
+				// locate matches in previous project
+				if (previousJavaProject != null) {
+					try {
+						locateMatches(previousJavaProject, matchSet);
+					} catch (JavaModelException e) {
+						// problem with classpath in this project -> skip it
 					}
-					previousJavaProject = javaProject;
+					if (this.progressMonitor != null)
+						this.progressMonitor.worked(skipped);
+					matchSet.reset();
 				}
-			} catch (JavaModelException e) {
-				// file doesn't exist -> skip it
-				continue;
+				previousJavaProject = javaProject;
+				skipped = 0;
 			}
 			matchSet.add(new PossibleMatch(this, resource, openable, searchDocument));
-
-			if (this.progressMonitor != null)
-				this.progressMonitor.worked(1);
+			skipped++;
 		}
 
 		// last project
@@ -748,9 +878,10 @@
 			try {
 				locateMatches(previousJavaProject, matchSet);
 			} catch (JavaModelException e) {
-				if (e.getException() instanceof CoreException) throw e;
-				// problem with classpath in last project -> skip it
+				// problem with classpath in last project -> ignore
 			}
+			if (this.progressMonitor != null)
+				this.progressMonitor.worked(skipped);
 		} 
 
 		if (this.progressMonitor != null)
@@ -764,31 +895,26 @@
 /**
  * Locates the package declarations corresponding to this locator's pattern. 
  */
-public void locatePackageDeclarations(SearchParticipant participant) throws JavaModelException {
+public void locatePackageDeclarations(SearchParticipant participant) throws CoreException {
 	locatePackageDeclarations(this.pattern, participant);
 }
 /**
  * Locates the package declarations corresponding to the search pattern. 
  */
-protected void locatePackageDeclarations(SearchPattern searchPattern, SearchParticipant participant) throws JavaModelException {
+protected void locatePackageDeclarations(SearchPattern searchPattern, SearchParticipant participant) throws CoreException {
 	if (searchPattern instanceof OrPattern) {
 		SearchPattern[] patterns = ((OrPattern) searchPattern).patterns;
 		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();
-			SearchDocument document = participant.getDocument(resource.getFullPath().toString());
-			this.currentPossibleMatch = new PossibleMatch(this, resource, null, document);
-			try {
-				this.report(-1, -2, searchPattern.focus, IJavaSearchResultCollector.EXACT_MATCH);
-			} catch (CoreException e) {
-				if (e instanceof JavaModelException) {
-					throw (JavaModelException) e;
-				} else {
-					throw new JavaModelException(e);
-				}
-			}					
+		IJavaElement focus = ((InternalSearchPattern) searchPattern).focus;
+		if (focus != null) {
+			SearchDocument document = participant.getDocument(focus.getPath().toString());
+			this.currentPossibleMatch = new PossibleMatch(this, focus.getResource(), null, document);
+			if (encloses(focus)) {
+				SearchMatch match = newDeclarationMatch(focus, SearchMatch.A_ACCURATE, -1, -1);
+				report(match);
+			}
 			return;
 		}
 		PackageDeclarationPattern pkgPattern = (PackageDeclarationPattern) searchPattern;
@@ -808,7 +934,10 @@
 						SearchDocument document = participant.getDocument(resource.getFullPath().toString());
 						this.currentPossibleMatch = new PossibleMatch(this, resource, null, document);
 						try {
-							report(-1, -2, pkg, IJavaSearchResultCollector.EXACT_MATCH);
+							if (encloses(pkg)) {
+								SearchMatch match = newDeclarationMatch(pkg, SearchMatch.A_ACCURATE, -1, -1);
+								report(match);
+							}
 						} catch (JavaModelException e) {
 							throw e;
 						} catch (CoreException e) {
@@ -857,6 +986,107 @@
 	if (type.exists()) return type;
 	return null;
 }
+public SearchMatch newDeclarationMatch(
+		IJavaElement element,
+		int accuracy,
+		int offset,  
+		int length) {
+	SearchParticipant participant = getParticipant(); 
+	IResource resource = this.currentPossibleMatch.resource;
+	return newDeclarationMatch(element, accuracy, offset, length, participant, resource);
+}
+
+public SearchMatch newDeclarationMatch(
+		IJavaElement element,
+		int accuracy,
+		int offset,  
+		int length,
+		SearchParticipant participant, 
+		IResource resource) {
+	switch (element.getElementType()) {
+		case IJavaElement.PACKAGE_FRAGMENT:
+			return new PackageDeclarationMatch(element, accuracy, offset, length, participant, resource);
+		case IJavaElement.TYPE:
+			return new TypeDeclarationMatch(element, accuracy, offset, length, participant, resource);
+		case IJavaElement.FIELD:
+			return new FieldDeclarationMatch(element, accuracy, offset, length, participant, resource);
+		case IJavaElement.METHOD:
+			return new MethodDeclarationMatch(element, accuracy, offset, length, participant, resource);
+		case IJavaElement.LOCAL_VARIABLE:
+			return new LocalVariableDeclarationMatch(element, accuracy, offset, length, participant, resource);
+		default:
+			return null;
+	}
+}
+
+public SearchMatch newFieldReferenceMatch(
+		IJavaElement enclosingElement,
+		int accuracy,
+		int offset,  
+		int length,
+		ASTNode reference) {
+	int bits = reference.bits;
+	boolean isCoupoundAssigned = (bits & ASTNode.IsCompoundAssignedMASK) != 0;
+	boolean isReadAccess = isCoupoundAssigned || (bits & ASTNode.IsStrictlyAssignedMASK) == 0;
+	boolean isWriteAccess = isCoupoundAssigned || (bits & ASTNode.IsStrictlyAssignedMASK) != 0;
+	boolean insideDocComment = (bits & ASTNode.InsideJavadoc) != 0;
+	SearchParticipant participant = getParticipant(); 
+	IResource resource = this.currentPossibleMatch.resource;
+	return new FieldReferenceMatch(enclosingElement, accuracy, offset, length, isReadAccess, isWriteAccess, insideDocComment, participant, resource);
+}
+
+public SearchMatch newLocalVariableReferenceMatch(
+		IJavaElement enclosingElement,
+		int accuracy,
+		int offset,  
+		int length,
+		ASTNode reference) {
+	int bits = reference.bits;
+	boolean isCoupoundAssigned = (bits & ASTNode.IsCompoundAssignedMASK) != 0;
+	boolean isReadAccess = isCoupoundAssigned || (bits & ASTNode.IsStrictlyAssignedMASK) == 0;
+	boolean isWriteAccess = isCoupoundAssigned || (bits & ASTNode.IsStrictlyAssignedMASK) != 0;
+	boolean insideDocComment = (bits & ASTNode.InsideJavadoc) != 0;
+	SearchParticipant participant = getParticipant(); 
+	IResource resource = this.currentPossibleMatch.resource;
+	return new LocalVariableReferenceMatch(enclosingElement, accuracy, offset, length, isReadAccess, isWriteAccess, insideDocComment, participant, resource);
+}
+
+public SearchMatch newMethodReferenceMatch(
+		IJavaElement enclosingElement,
+		int accuracy,
+		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, offset, length, insideDocComment, participant, resource);
+}
+
+public SearchMatch newPackageReferenceMatch(
+		IJavaElement enclosingElement,
+		int accuracy,
+		int offset,  
+		int length,
+		ASTNode reference) {
+	SearchParticipant participant = getParticipant(); 
+	IResource resource = this.currentPossibleMatch.resource;
+	boolean insideDocComment = (reference.bits & ASTNode.InsideJavadoc) != 0;
+	return new PackageReferenceMatch(enclosingElement, accuracy, offset, length, insideDocComment, participant, resource);
+}
+
+public SearchMatch newTypeReferenceMatch(
+		IJavaElement enclosingElement,
+		int accuracy,
+		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, offset, length, insideDocComment, participant, resource);
+}
+
 /*
  * Process a compilation unit already parsed and build.
  */
@@ -877,7 +1107,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$
 
@@ -889,7 +1119,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
@@ -899,7 +1129,6 @@
 			throw e;
 		}
 	} finally {
-		this.currentPossibleMatch.cleanUp();
 		this.currentPossibleMatch = null;
 	}
 }
@@ -938,52 +1167,38 @@
 	for (int i = 0, l = types.length; i < l; i++)
 		purgeMethodStatements(types[i], true); 
 }
-protected void report(int sourceStart, int sourceEnd, IJavaElement element, int accuracy) throws CoreException {
-	if (element != null && this.scope.encloses(element)) {
-		if (SearchEngine.VERBOSE) {
-			IResource res = this.currentPossibleMatch.resource;
-			System.out.println("Reporting match"); //$NON-NLS-1$
-			System.out.println("\tResource: " + (res == null ? " <unknown> " : res.getFullPath().toString())); //$NON-NLS-2$//$NON-NLS-1$
-			System.out.println("\tPositions: [" + sourceStart + ", " + sourceEnd + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
-			System.out.println("\tJava element: " + ((JavaElement)element).toStringWithAncestors()); //$NON-NLS-1$
-			System.out.println(accuracy == IJavaSearchResultCollector.EXACT_MATCH
-				? "\tAccuracy: EXACT_MATCH" //$NON-NLS-1$
-				: "\tAccuracy: POTENTIAL_MATCH"); //$NON-NLS-1$
-		}
-		report(
-			this.currentPossibleMatch.resource, 
-			sourceStart, 
-			sourceEnd, 
-			element, 
-			accuracy, 
-			getParticipant());
-	}
-}
 public SearchParticipant getParticipant() {
 	return this.currentPossibleMatch.document.getParticipant();
 }
 
-protected void report(IResource resource, int sourceStart, int sourceEnd, IJavaElement element, int accuracy, SearchParticipant participant) throws CoreException {
+protected void report(SearchMatch match) throws CoreException {
 	long start = -1;
-	if (SearchEngine.VERBOSE)
+	if (SearchEngine.VERBOSE) {
 		start = System.currentTimeMillis();
-	String documentPath = element.getPath().toString();
-	SearchMatch match = new JavaSearchMatch(resource, element, documentPath, accuracy, participant, sourceStart, sourceEnd+1, -1);
+		System.out.println("Reporting match"); //$NON-NLS-1$
+		System.out.println("\tResource: " + match.getResource()); //$NON-NLS-2$//$NON-NLS-1$
+		System.out.println("\tPositions: [offset=" + match.getOffset() + ", length=" + match.getLength() + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		System.out.println("\tJava element: " + ((JavaElement)match.getElement()).toStringWithAncestors()); //$NON-NLS-1$
+		System.out.println(match.getAccuracy() == SearchMatch.A_ACCURATE
+			? "\tAccuracy: EXACT_MATCH" //$NON-NLS-1$
+			: "\tAccuracy: POTENTIAL_MATCH"); //$NON-NLS-1$
+	}
 	this.requestor.acceptSearchMatch(match);
 	if (SearchEngine.VERBOSE)
 		this.resultCollectorTime += System.currentTimeMillis()-start;
 }
-protected void report(long start, long end, IJavaElement element, int accuracy) throws CoreException {
-	report((int) (start >>> 32), (int) end, element, accuracy); // extract the start and end from the encoded long positions
-}
 /**
  * Finds the accurate positions of the sequence of tokens given by qualifiedName
  * in the source and reports a reference to this this qualified name
  * to the search requestor.
  */
-protected void reportAccurateReference(int sourceStart, int sourceEnd, char[] name, IJavaElement element, int accuracy) throws CoreException {
+protected void reportAccurateTypeReference(ASTNode typeRef, char[] name, IJavaElement element, int accuracy) throws CoreException {
 	if (accuracy == -1) return;
+	if (!encloses(element)) return;
 
+	int sourceStart = typeRef.sourceStart;
+	int sourceEnd = typeRef.sourceEnd;
+	
 	// compute source positions of the qualified reference 
 	Scanner scanner = this.parser.scanner;
 	scanner.setSource(this.currentPossibleMatch.getContents());
@@ -999,18 +1214,27 @@
 			// ignore
 		}
 		if (token == TerminalTokens.TokenNameIdentifier && this.pattern.matchesName(name, scanner.getCurrentTokenSource())) {
-			report(currentPosition, scanner.currentPosition - 1, element, accuracy);
+			int length = scanner.currentPosition-currentPosition;
+			SearchMatch match = newTypeReferenceMatch(element, accuracy, currentPosition, length, typeRef);
+			report(match);
 			return;
 		}
 	} while (token != TerminalTokens.TokenNameEOF);
-	report(sourceStart, sourceEnd, element, accuracy);
+	SearchMatch match = newTypeReferenceMatch(element, accuracy, sourceStart, sourceEnd-sourceStart+1, typeRef);
+	report(match);
 }
 /**
  * Finds the accurate positions of each valid token in the source and
  * reports a reference to this token to the search requestor.
  * A token is valid if it has an accuracy which is not -1.
  */
-protected void reportAccurateReference(int sourceStart, int sourceEnd, char[][] tokens, IJavaElement element, int[] accuracies) throws CoreException {
+protected void reportAccurateFieldReference(QualifiedNameReference qNameRef, IJavaElement element, int[] accuracies) throws CoreException {
+	if (!encloses(element)) return;
+	
+	int sourceStart = qNameRef.sourceStart;
+	int sourceEnd = qNameRef.sourceEnd;
+	char[][] tokens = qNameRef.tokens;
+	
 	// compute source positions of the qualified reference 
 	Scanner scanner = this.parser.scanner;
 	scanner.setSource(this.currentPossibleMatch.getContents());
@@ -1033,7 +1257,7 @@
 		if (token != TerminalTokens.TokenNameEOF) {
 			char[] currentTokenSource = scanner.getCurrentTokenSource();
 			boolean equals = false;
-			while (i < length && !(equals = this.pattern.matchesName(tokens[i++], currentTokenSource)));
+			while (i < length && !(equals = this.pattern.matchesName(tokens[i++], currentTokenSource))){/*empty*/}
 			if (equals && (previousValid == -1 || previousValid == i - 2)) {
 				previousValid = i - 1;
 				if (refSourceStart == -1)
@@ -1054,9 +1278,11 @@
 		if (accuracies[accuracyIndex] != -1) {
 			// accept reference
 			if (refSourceStart != -1) {
-				report(refSourceStart, refSourceEnd, element, accuracies[accuracyIndex]);
+				SearchMatch match = newFieldReferenceMatch(element, accuracies[accuracyIndex], refSourceStart, refSourceEnd-refSourceStart+1, qNameRef);
+				report(match);
 			} else {
-				report(sourceStart, sourceEnd, element, accuracies[accuracyIndex]);
+				SearchMatch match = newFieldReferenceMatch(element, accuracies[accuracyIndex], sourceStart, sourceEnd-sourceStart+1, qNameRef);
+				report(match);
 			}
 			i = 0;
 		}
@@ -1067,10 +1293,10 @@
 	} while (token != TerminalTokens.TokenNameEOF);
 
 }
-protected void reportBinaryMatch(IResource resource, IMember binaryMember, IBinaryType info, int accuracy) throws CoreException {
-	ISourceRange range = binaryMember.getNameRange();
+protected void reportBinaryMemberDeclaration(IResource resource, IMember binaryMember, IBinaryType info, int accuracy) throws CoreException {
+	ClassFile classFile = (ClassFile) binaryMember.getClassFile();
+	ISourceRange range = classFile.isOpen() ? binaryMember.getNameRange() : SourceMapper.fgUnknownRange;
 	if (range.getOffset() == -1) {
-		ClassFile classFile = (ClassFile) binaryMember.getClassFile();
 		SourceMapper mapper = classFile.getSourceMapper();
 		if (mapper != null) {
 			IType type = classFile.getType();
@@ -1082,12 +1308,9 @@
 			}
 		}
 	}
-	int startIndex = range.getOffset();
-	int endIndex = startIndex + range.getLength() - 1;
-	if (resource == null)
-		report(startIndex, endIndex, binaryMember, accuracy);
-	else
-		report(resource, startIndex, endIndex, binaryMember, accuracy, getParticipant());
+	if (resource == null) resource =  this.currentPossibleMatch.resource;
+	SearchMatch match = newDeclarationMatch(binaryMember, accuracy, range.getOffset(), range.getLength(), getParticipant(), resource);
+	report(match);
 }
 /**
  * Visit the given method declaration and report the nodes that match exactly the
@@ -1109,9 +1332,11 @@
 			} catch (InvalidInputException e) {
 				// ignore
 			}
-			int nameSourceEnd = scanner.currentPosition - 1;
-
-			report(nameSourceStart, nameSourceEnd, enclosingElement, accuracy);
+			if (encloses(enclosingElement)) {
+				int length = scanner.currentPosition - nameSourceStart;
+				SearchMatch match = newDeclarationMatch(enclosingElement, accuracy, nameSourceStart, length);
+				report(match);
+			}
 		}
 	}
 
@@ -1134,7 +1359,7 @@
 			if ((this.matchContainer & PatternLocator.METHOD_CONTAINER) != 0) {
 				if (enclosingElement == null)
 					enclosingElement = createHandle(method, parent);
-				if (enclosingElement != null) { // skip if unable to find method
+				if (encloses(enclosingElement)) {
 					for (int i = 0, l = nodes.length; i < l; i++) {
 						ASTNode node = nodes[i];
 						Integer level = (Integer) nodeSet.matchingNodes.removeKey(node);
@@ -1170,10 +1395,35 @@
 					: unit.scope.getTypeOrPackage(importRef.tokens);
 				this.patternLocator.matchLevelAndReportImportRef(importRef, binding, this);
 			} else {
-				nodeSet.addMatch(node, this.patternLocator.resolveLevel(node));
+				if (node instanceof JavadocSingleTypeReference) {
+					// special case for javadoc single type reference
+					JavadocSingleTypeReference singleRef = (JavadocSingleTypeReference) node;
+					if (singleRef.packageBinding != null) {
+						char[][] tokens = new char[][] { singleRef.token };
+						long[] positions = new long[] { (((long) singleRef.sourceStart) << 32) + singleRef.sourceEnd };
+						int tagStart = singleRef.tagSourceStart;
+						int tagEnd = singleRef.tagSourceEnd;
+						JavadocImportReference importRef = new JavadocImportReference(tokens, positions, tagStart, tagEnd);
+						this.patternLocator.matchLevelAndReportImportRef(importRef, singleRef.packageBinding, this);
+						continue;
+					}
+				} else if (node instanceof JavadocQualifiedTypeReference) {
+					// special case for javadoc qualified type reference
+					JavadocQualifiedTypeReference qualifRef = (JavadocQualifiedTypeReference) node;
+					if (qualifRef.packageBinding != null) {
+						char[][] tokens = qualifRef.tokens;
+						long[] positions = qualifRef.sourcePositions;
+						int tagStart = qualifRef.tagSourceStart;
+						int tagEnd = qualifRef.tagSourceEnd;
+						JavadocImportReference importRef = new JavadocImportReference(tokens, positions, tagStart, tagEnd);
+						this.patternLocator.matchLevelAndReportImportRef(importRef, qualifRef.packageBinding, this);
+						continue;
+					}
+				}
 			}
+			nodeSet.addMatch(node, this.patternLocator.resolveLevel(node));
 		}
-		nodeSet.possibleMatchingNodesSet = new SimpleSet();
+		nodeSet.possibleMatchingNodesSet = new SimpleSet(3);
 	}
 
 	if (nodeSet.matchingNodes.elementSize == 0) return; // no matching nodes were found
@@ -1215,7 +1465,11 @@
 	IJavaElement enclosingElement = null;
 	if (accuracy > -1) {
 		enclosingElement = createHandle(field, type, parent);
-		report(field.sourceStart, field.sourceEnd, enclosingElement, accuracy);
+		if (encloses(enclosingElement)) {
+			int offset = field.sourceStart;
+			SearchMatch match = newDeclarationMatch(enclosingElement, accuracy, offset, field.sourceEnd-offset+1);
+			report(match);
+		}
 	}
 
 	// handle the nodes for the local type first
@@ -1239,11 +1493,12 @@
 			} else {
 				if (enclosingElement == null)
 					enclosingElement = createHandle(field, type, parent);
-				for (int i = 0, l = nodes.length; i < l; i++) {
-					ASTNode node = nodes[i];
-					Integer level = (Integer) nodeSet.matchingNodes.removeKey(node);
-					this.patternLocator.matchReportReference(node, enclosingElement, level.intValue(), this);
-				}
+				if (encloses(enclosingElement))
+					for (int i = 0, l = nodes.length; i < l; i++) {
+						ASTNode node = nodes[i];
+						Integer level = (Integer) nodeSet.matchingNodes.removeKey(node);
+						this.patternLocator.matchReportReference(node, enclosingElement, level.intValue(), this);
+					}
 			}
 		}
 	}
@@ -1269,8 +1524,11 @@
 	if (enclosingElement == null) return;
 
 	// report the type declaration
-	if (accuracy > -1)
-		report(type.sourceStart, type.sourceEnd, enclosingElement, accuracy);
+	if (accuracy > -1 && encloses(enclosingElement)) {
+		int offset = type.sourceStart;
+		SearchMatch match = newDeclarationMatch(enclosingElement, accuracy, offset, type.sourceEnd-offset+1);
+		report(match);
+	}
 
 	boolean matchedClassContainer = (this.matchContainer & PatternLocator.CLASS_CONTAINER) != 0;
 
@@ -1285,7 +1543,8 @@
 				for (int i = 0, l = nodes.length; i < l; i++) {
 					ASTNode node = nodes[i];
 					Integer level = (Integer) nodeSet.matchingNodes.removeKey(node);
-					this.patternLocator.matchReportReference(node, enclosingElement, level.intValue(), this);
+					if (encloses(enclosingElement))
+						this.patternLocator.matchReportReference(node, enclosingElement, level.intValue(), this);
 				}
 			}
 		}
@@ -1366,4 +1625,5 @@
 	}
 	return false;
 }
+
 }
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocatorParser.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocatorParser.java
index d7884ec..ed74b1d 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocatorParser.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocatorParser.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -85,7 +85,7 @@
 
 protected MatchLocatorParser(ProblemReporter problemReporter, MatchLocator locator) {
 	super(problemReporter, true);
-
+	this.reportOnlyOneSyntaxError = true;
 	this.patternLocator = locator.patternLocator;
 	if ((locator.matchContainer & PatternLocator.CLASS_CONTAINER) != 0) {
 		this.localDeclarationVisitor = (locator.matchContainer & PatternLocator.METHOD_CONTAINER) != 0
@@ -96,48 +96,45 @@
 			? new MethodButNoClassDeclarationVisitor()
 			: new NoClassNoMethodDeclarationVisitor();
 	}
-
-	// Always check javadoc while matching indexes
-	this.javadocParser.checkJavadoc = true;
 }
 public void checkComment() {
 	super.checkComment();
-	if (this.javadocParser.checkJavadoc && this.javadoc != null) {
+	if (this.javadocParser.checkDocComment && this.javadoc != null) {
 		// Search for pattern locator matches in javadoc comment @throws/@exception tags
 		TypeReference[] thrownExceptions = this.javadoc.thrownExceptions;
-		int throwsTagsNbre = thrownExceptions == null ? 0 : thrownExceptions.length;
-		for (int i = 0; i < throwsTagsNbre; i++) {
+		int throwsTagsLength = thrownExceptions == null ? 0 : thrownExceptions.length;
+		for (int i = 0; i < throwsTagsLength; i++) {
 			TypeReference typeRef = thrownExceptions[i];
-			patternLocator.match(typeRef, nodeSet);
+			this.patternLocator.match(typeRef, this.nodeSet);
 		}
 
 		// Search for pattern locator matches in javadoc comment @see tags
 		Expression[] references = this.javadoc.references;
-		int seeTagsNbre = references == null ? 0 : references.length;
-		for (int i = 0; i < seeTagsNbre; i++) {
+		int seeTagsLength = references == null ? 0 : references.length;
+		for (int i = 0; i < seeTagsLength; i++) {
 			Expression reference = references[i];
 			if (reference instanceof TypeReference) {
 				TypeReference typeRef = (TypeReference) reference;
-				patternLocator.match(typeRef, nodeSet);
+				this.patternLocator.match(typeRef, this.nodeSet);
 			} else if (reference instanceof JavadocFieldReference) {
 				JavadocFieldReference fieldRef = (JavadocFieldReference) reference;
-				patternLocator.match(fieldRef, nodeSet);
-				if (fieldRef.receiver instanceof TypeReference) {
+				this.patternLocator.match(fieldRef, this.nodeSet);
+				if (fieldRef.receiver instanceof TypeReference && !fieldRef.receiver.isThis()) {
 					TypeReference typeRef = (TypeReference) fieldRef.receiver;
-					patternLocator.match(typeRef, nodeSet);
+					this.patternLocator.match(typeRef, this.nodeSet);
 				}
 			} else if (reference instanceof JavadocMessageSend) {
 				JavadocMessageSend messageSend = (JavadocMessageSend) reference;
-				patternLocator.match(messageSend, nodeSet);
-				if (messageSend.receiver instanceof TypeReference) {
+				this.patternLocator.match(messageSend, this.nodeSet);
+				if (messageSend.receiver instanceof TypeReference && !messageSend.receiver.isThis()) {
 					TypeReference typeRef = (TypeReference) messageSend.receiver;
-					patternLocator.match(typeRef, nodeSet);
+					this.patternLocator.match(typeRef, this.nodeSet);
 				}
 			} else if (reference instanceof JavadocAllocationExpression) {
 				JavadocAllocationExpression constructor = (JavadocAllocationExpression) reference;
-				patternLocator.match(constructor, nodeSet);
-				if (constructor.type != null) {
-					patternLocator.match(constructor.type, nodeSet);
+				this.patternLocator.match(constructor, this.nodeSet);
+				if (constructor.type != null && !constructor.type.isThis()) {
+					this.patternLocator.match(constructor.type, this.nodeSet);
 				}
 			}
 		}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchingNodeSet.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchingNodeSet.java
index 9d391ae..37decce 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchingNodeSet.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchingNodeSet.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -12,7 +12,7 @@
 
 import java.util.ArrayList;
 
-import org.eclipse.jdt.core.search.IJavaSearchResultCollector;
+import org.eclipse.jdt.core.search.SearchMatch;
 import org.eclipse.jdt.internal.compiler.ast.*;
 import org.eclipse.jdt.internal.compiler.util.HashtableOfLong;
 import org.eclipse.jdt.internal.core.util.SimpleLookupTable;
@@ -28,10 +28,10 @@
  * Map of matching ast nodes that don't need to be resolved to their accuracy level.
  * Each node is removed as it is reported.
  */
-SimpleLookupTable matchingNodes = new SimpleLookupTable(3);
-private HashtableOfLong matchingNodesKeys = new HashtableOfLong(3);
-static Integer EXACT_MATCH = new Integer(IJavaSearchResultCollector.EXACT_MATCH);
-static Integer POTENTIAL_MATCH = new Integer(IJavaSearchResultCollector.POTENTIAL_MATCH);
+SimpleLookupTable matchingNodes = new SimpleLookupTable(3); // node -> accuracy
+private HashtableOfLong matchingNodesKeys = new HashtableOfLong(3); // sourceRange -> node
+static Integer EXACT_MATCH = new Integer(SearchMatch.A_ACCURATE);
+static Integer POTENTIAL_MATCH = new Integer(SearchMatch.A_INACCURATE);
 
 /**
  * Set of possible matching ast nodes. They need to be resolved
@@ -86,6 +86,12 @@
 		if (node != null && start <= node.sourceStart && node.sourceEnd <= end)
 			return true;
 	}
+	nodes = this.matchingNodes.keyTable;
+	for (int i = 0, l = nodes.length; i < l; i++) {
+		ASTNode node = (ASTNode) nodes[i];
+		if (node != null && start <= node.sourceStart && node.sourceEnd <= end)
+			return true;
+	}
 	return false;
 }
 /**
@@ -132,6 +138,7 @@
 	return this.matchingNodes.removeKey(node);
 }
 public String toString() {
+	// TODO (jerome) should show both tables
 	StringBuffer result = new StringBuffer();
 	result.append("Exact matches:"); //$NON-NLS-1$
 	Object[] keyTable = this.matchingNodes.keyTable;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java
index 8a08a5d..78952df 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -14,7 +14,8 @@
 import org.eclipse.core.runtime.*;
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.core.search.IJavaSearchResultCollector;
+import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.core.search.SearchMatch;
 import org.eclipse.jdt.internal.compiler.ast.*;
 import org.eclipse.jdt.internal.compiler.env.IBinaryType;
 import org.eclipse.jdt.internal.compiler.lookup.*;
@@ -74,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;
@@ -87,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
@@ -129,12 +130,12 @@
 	return level;
 }
 /**
- * @see SearchPattern#matchReportReference
+ * @see org.eclipse.jdt.internal.core.search.matching.PatternLocator#matchReportReference(org.eclipse.jdt.internal.compiler.ast.ASTNode, org.eclipse.jdt.core.IJavaElement, int, org.eclipse.jdt.internal.core.search.matching.MatchLocator)
  */
 protected void matchReportReference(ASTNode reference, IJavaElement element, int accuracy, MatchLocator locator) throws CoreException {
 	if (this.isDeclarationOfReferencedMethodsPattern) {
 		// need exact match to be able to open on type ref
-		if (accuracy != IJavaSearchResultCollector.EXACT_MATCH) return;
+		if (accuracy != SearchMatch.A_ACCURATE) return;
 
 		// element that references the method must be included in the enclosing element
 		DeclarationOfReferencedMethodsPattern declPattern = (DeclarationOfReferencedMethodsPattern) this.pattern; 
@@ -143,16 +144,18 @@
 		if (element != null)
 			reportDeclaration(((MessageSend) reference).binding, locator, declPattern.knownMethods);
 	} else if (this.pattern.findReferences && reference instanceof MessageSend) {
-		// message ref are starting at the selector start
-		locator.report(
-			(int) (((MessageSend) reference).nameSourcePosition >>> 32),
-			reference.sourceEnd,
-			element,
-			accuracy);
+		int offset = (int) (((MessageSend) reference).nameSourcePosition >>> 32);
+		SearchMatch match = locator.newMethodReferenceMatch(element, accuracy, offset, reference.sourceEnd-offset+1, reference);
+		locator.report(match);
 	} else {
-		super.matchReportReference(reference, element, accuracy, locator);
+		int offset = reference.sourceStart;
+		SearchMatch match = locator.newMethodReferenceMatch(element, accuracy, offset, reference.sourceEnd-offset+1, reference);
+		locator.report(match);
 	}
 }
+protected int referenceType() {
+	return IJavaElement.METHOD;
+}
 protected void reportDeclaration(MethodBinding methodBinding, MatchLocator locator, SimpleSet knownMethods) throws CoreException {
 	ReferenceBinding declaringClass = methodBinding.declaringClass;
 	IType type = locator.lookupType(declaringClass);
@@ -175,7 +178,7 @@
 		if (resource == null)
 			resource = type.getJavaProject().getProject();
 		info = locator.getBinaryInfo((org.eclipse.jdt.internal.core.ClassFile)type.getClassFile(), resource);
-		locator.reportBinaryMatch(resource, method, info, IJavaSearchResultCollector.EXACT_MATCH);
+		locator.reportBinaryMemberDeclaration(resource, method, info, SearchMatch.A_ACCURATE);
 	} else {
 		ClassScope scope = ((SourceTypeBinding) declaringClass).scope;
 		if (scope != null) {
@@ -188,14 +191,11 @@
 					break;
 				}
 			} 
-			if (methodDecl != null)
-				locator.report(
-					resource, 
-					methodDecl.sourceStart, 
-					methodDecl.sourceEnd, 
-					method, 
-					IJavaSearchResultCollector.EXACT_MATCH, 
-					locator.getParticipant());
+			if (methodDecl != null) {
+				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/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodPattern.java
index 0671406..0f3f802 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodPattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodPattern.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -10,17 +10,15 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.search.matching;
 
+import java.io.IOException;
+
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.core.search.*;
+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 {
-
-private static ThreadLocal indexRecord = new ThreadLocal() {
-	protected Object initialValue() {
-		return new MethodPattern(false, false, null, null, null, null, null, null, null, null, R_EXACT_MATCH | R_CASE_SENSITIVE);
-	}
-};
+public class MethodPattern extends JavaSearchPattern implements IIndexConstants {
 
 protected boolean findDeclarations;
 protected boolean findReferences;
@@ -40,15 +38,21 @@
 // extra reference info
 protected IType declaringType;
 
+protected static char[][] REF_CATEGORIES = { METHOD_REF };
+protected static char[][] REF_AND_DECL_CATEGORIES = { METHOD_REF, METHOD_DECL };
+protected static char[][] DECL_CATEGORIES = { METHOD_DECL };
+
+/**
+ * Method entries are encoded as selector '/' Arity:
+ * e.g. 'foo/0'
+ */
 public static char[] createIndexKey(char[] selector, int argCount) {
-	MethodPattern record = getMethodRecord();
-	record.selector = selector;
-	record.parameterCount = argCount;
-	return record.encodeIndexKey();
+	char[] countChars = argCount < 10
+		? COUNTS[argCount]
+		: ("/" + String.valueOf(argCount)).toCharArray(); //$NON-NLS-1$
+	return CharOperation.concat(selector, countChars);
 }
-public static MethodPattern getMethodRecord() {
-	return (MethodPattern)indexRecord.get();
-}
+
 public MethodPattern(
 	boolean findDeclarations,
 	boolean findReferences,
@@ -62,31 +66,33 @@
 	IType declaringType,
 	int matchRule) {
 
-	super(METHOD_PATTERN, matchRule);
+	this(matchRule);
 
 	this.findDeclarations = findDeclarations;
 	this.findReferences = findReferences;
 
-	boolean isCaseSensitive = isCaseSensitive();
-	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);
+	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] = isCaseSensitive ? parameterQualifications[i] : CharOperation.toLowerCase(parameterQualifications[i]);
-			this.parameterSimpleNames[i] = 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);
 }
 public void decodeIndexKey(char[] key) {
 	int size = key.length;
@@ -95,77 +101,36 @@
 	this.parameterCount = Integer.parseInt(new String(key, lastSeparatorIndex + 1, size - lastSeparatorIndex - 1));
 	this.selector = CharOperation.subarray(key, 0, lastSeparatorIndex);
 }
-/**
- * Method declaration entries are encoded as 'methodDecl/' selector '/' Arity
- * e.g. 'methodDecl/X/0'
- *
- * Method reference entries are encoded as 'methodRef/' selector '/' Arity
- * e.g. 'methodRef/X/0'
- */
-public char[] encodeIndexKey() {
-	// will have a common pattern in the new story
-	if (isCaseSensitive() && this.selector != null) {
-		switch(matchMode()) {
-			case EXACT_MATCH :
-				int arity = this.parameterCount;
-				if (arity >= 0) {
-					char[] countChars = arity < 10 ? COUNTS[arity] : ("/" + String.valueOf(arity)).toCharArray(); //$NON-NLS-1$
-					return CharOperation.concat(this.selector, countChars);
-				}
-			case PREFIX_MATCH :
-				return this.selector;
-			case PATTERN_MATCH :
-				int starPos = CharOperation.indexOf('*', this.selector);
-				switch(starPos) {
-					case -1 :
-						return this.selector;
-					default : 
-						char[] result = new char[starPos];
-						System.arraycopy(this.selector, 0, result, 0, starPos);
-						return result;
-					case 0 : // fall through
-				}
-		}
-	}
-	return CharOperation.NO_CHAR; // find them all
+public SearchPattern getBlankPattern() {
+	return new MethodPattern(R_EXACT_MATCH | R_CASE_SENSITIVE);
 }
-public SearchPattern getIndexRecord() {
-	return getMethodRecord();
-}
-public char[][] getMatchCategories() {
+public char[][] getIndexCategories() {
 	if (this.findReferences)
-		if (this.findDeclarations) 
-			return new char[][] {METHOD_REF, METHOD_DECL};
-		else
-			return new char[][] {METHOD_REF};
-	else
-		if (this.findDeclarations)
-			return new char[][] {METHOD_DECL};
-		else
-			return CharOperation.NO_CHAR_CHAR;
+		return this.findDeclarations ? REF_AND_DECL_CATEGORIES : REF_CATEGORIES;
+	if (this.findDeclarations)
+		return DECL_CATEGORIES;
+	return CharOperation.NO_CHAR_CHAR;
 }
-public boolean isPolymorphicSearch() {
+boolean isPolymorphicSearch() {
 	return this.findReferences;
 }
-public boolean isMatchingIndexRecord() {
-	MethodPattern record = getMethodRecord();
-	if (this.parameterCount != -1 && this.parameterCount != record.parameterCount) return false;
+public boolean matchesDecodedKey(SearchPattern decodedPattern) {
+	MethodPattern pattern = (MethodPattern) decodedPattern;
 
-	return matchesName(this.selector, record.selector);
+	return (this.parameterCount == pattern.parameterCount || this.parameterCount == -1)
+		&& matchesName(this.selector, pattern.selector);
 }
 /**
  * Returns whether a method declaration or message send must be resolved to 
  * find out if this method pattern matches it.
  */
 protected boolean mustResolve() {
-	// declaring type 
-	// If declaring type is specified - even with simple name - always resolves 
-	// (see MethodPattern.matchLevel)
+	// declaring type
+	// If declaring type is specified - even with simple name - always resolves
 	if (declaringSimpleName != null || declaringQualification != null) return true;
 
 	// return type
-	// If return type is specified - even with simple name - always resolves 
-	// (see MethodPattern.matchLevel)
+	// If return type is specified - even with simple name - always resolves
 	if (returnSimpleName != null || returnQualification != null) return true;
 
 	// parameter types
@@ -174,6 +139,31 @@
 			if (parameterQualifications[i] != null) return true;
 	return false;
 }
+EntryResult[] queryIn(Index index) throws IOException {
+	char[] key = this.selector; // can be null
+	int matchRule = getMatchRule();
+
+	switch(getMatchMode()) {
+		case R_EXACT_MATCH :
+			if (this.selector != null && this.parameterCount >= 0)
+				key = createIndexKey(this.selector, this.parameterCount);
+			else // do a prefix query with the selector
+				matchRule = matchRule - R_EXACT_MATCH + R_PREFIX_MATCH;
+			break;
+		case R_PREFIX_MATCH :
+			// do a prefix query with the selector
+			break;
+		case R_PATTERN_MATCH :
+			if (this.parameterCount >= 0)
+				key = createIndexKey(this.selector == null ? ONE_STAR : this.selector, this.parameterCount);
+			else if (this.selector != null && this.selector[this.selector.length - 1] != '*')
+				key = CharOperation.concat(this.selector, ONE_STAR, SEPARATOR);
+			// else do a pattern query with just the selector
+			break;
+	}
+
+	return index.query(getIndexCategories(), key, matchRule); // match rule is irrelevant when the key is null
+}
 public String toString() {
 	StringBuffer buffer = new StringBuffer(20);
 	if (this.findDeclarations) {
@@ -214,14 +204,14 @@
 	else if (returnQualification != null)
 		buffer.append("*"); //$NON-NLS-1$
 	buffer.append(", "); //$NON-NLS-1$
-	switch(matchMode()) {
-		case EXACT_MATCH : 
+	switch(getMatchMode()) {
+		case R_EXACT_MATCH : 
 			buffer.append("exact match, "); //$NON-NLS-1$
 			break;
-		case PREFIX_MATCH :
+		case R_PREFIX_MATCH :
 			buffer.append("prefix match, "); //$NON-NLS-1$
 			break;
-		case PATTERN_MATCH :
+		case R_PATTERN_MATCH :
 			buffer.append("pattern match, "); //$NON-NLS-1$
 			break;
 	}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/OrLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/OrLocator.java
index ba19fa1..95daf71 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/OrLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/OrLocator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -153,9 +153,10 @@
 	PatternLocator closestPattern = null;
 	int level = IMPOSSIBLE_MATCH;
 	for (int i = 0, length = this.patternLocators.length; i < length; i++) {
-		int newLevel = this.patternLocators[i].resolveLevel(binding);
+		PatternLocator patternLocator = this.patternLocators[i];
+		int newLevel = patternLocator.referenceType() == 0 ? IMPOSSIBLE_MATCH : patternLocator.resolveLevel(binding);
 		if (newLevel > level) {
-			closestPattern = this.patternLocators[i];
+			closestPattern = patternLocator;
 			if (newLevel == ACCURATE_MATCH) break;
 			level = newLevel;
 		}
@@ -181,9 +182,10 @@
 	PatternLocator closestPattern = null;
 	int level = IMPOSSIBLE_MATCH;
 	for (int i = 0, length = this.patternLocators.length; i < length; i++) {
-		int newLevel = this.patternLocators[i].resolveLevel(reference);
+		PatternLocator patternLocator = this.patternLocators[i];
+		int newLevel = patternLocator.referenceType() == 0 ? IMPOSSIBLE_MATCH : patternLocator.resolveLevel(reference);
 		if (newLevel > level) {
-			closestPattern = this.patternLocators[i];
+			closestPattern = patternLocator;
 			if (newLevel == ACCURATE_MATCH) break;
 			level = newLevel;
 		}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/OrPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/OrPattern.java
index 8df1a85..924ac36 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/OrPattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/OrPattern.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -13,20 +13,19 @@
 import java.io.IOException;
 
 import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.search.*;
-import org.eclipse.jdt.core.search.IJavaSearchScope;
-import org.eclipse.jdt.core.search.SearchParticipant;
-import org.eclipse.jdt.internal.core.index.impl.IndexInput;
+import org.eclipse.jdt.internal.core.index.Index;
 import org.eclipse.jdt.internal.core.search.IndexQueryRequestor;
+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.matchRule, rightPattern.matchRule));
-	this.mustResolve = leftPattern.mustResolve || rightPattern.mustResolve;
+	super(Math.max(leftPattern.getMatchRule(), rightPattern.getMatchRule()));
+	((InternalSearchPattern)this).kind = OR_PATTERN;
+	((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;
@@ -43,54 +42,24 @@
 	else
 		System.arraycopy(rightPatterns, 0, this.patterns, leftSize, rightSize);
 }
-
-public void decodeIndexKey(char[] key) {
-	// not used for OrPattern
-}
-
-public char[] encodeIndexKey() {
-	// not used for OrPattern
-	return null;
-}
-
-/**
- * Query a given index for matching entries. 
- *
- */
-public void findIndexMatches(IndexInput input, 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)
-	for (int i = 0, length = this.patterns.length; i < length; i++)
-		this.patterns[i].findIndexMatches(input, requestor, participant, scope, progressMonitor);
+	try {
+		index.startQuery();
+		for (int i = 0, length = this.patterns.length; i < length; i++)
+			((InternalSearchPattern)this.patterns[i]).findIndexMatches(index, requestor, participant, scope, progressMonitor);
+	} finally {
+		index.stopQuery();
+	}
 }
-
-public SearchPattern getIndexRecord() {
-	// not used for OrPattern
+public SearchPattern getBlankPattern() {
 	return null;
 }
-
-/* (non-Javadoc)
- * @see org.eclipse.jdt.internal.core.search.pattern.InternalSearchPattern#isMatchingIndexEntry()
- */
-public boolean isMatchingIndexRecord() {
-	return false;
-}
-
-/**
- * see SearchPattern.isPolymorphicSearch
- */
-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;
 }
-
-/* (non-Javadoc)
- * @see org.eclipse.jdt.internal.core.search.pattern.InternalSearchPattern#getMatchCategories()
- */
-public char[][] getMatchCategories() {
-	return CharOperation.NO_CHAR_CHAR;
-}
-
 public String toString() {
 	StringBuffer buffer = new StringBuffer();
 	buffer.append(this.patterns[0].toString());
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PackageDeclarationLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PackageDeclarationLocator.java
index d4e163b..4172f22 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PackageDeclarationLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PackageDeclarationLocator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PackageDeclarationPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PackageDeclarationPattern.java
index 5f71f88..2f2a5c9 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PackageDeclarationPattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PackageDeclarationPattern.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -10,15 +10,10 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.search.matching;
 
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.core.search.*;
-import org.eclipse.jdt.core.search.IJavaSearchScope;
-import org.eclipse.jdt.core.search.SearchParticipant;
-import org.eclipse.jdt.internal.core.index.impl.IndexInput;
-import org.eclipse.jdt.internal.core.search.IndexQueryRequestor;
+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 JavaSearchPattern implements IIndexConstants {
 
 protected char[] pkgName;
 
@@ -26,28 +21,10 @@
 	super(PKG_DECL_PATTERN, matchRule);
 	this.pkgName = pkgName;
 }
-public void decodeIndexKey(char[] key) {
-	// package declarations are not indexed
-}
-public char[] encodeIndexKey() {
+EntryResult[] queryIn(Index index) {
 	// package declarations are not indexed
 	return null;
 }
-public void findIndexMatches(IndexInput input, IndexQueryRequestor requestor, SearchParticipant participant, IJavaSearchScope scope, IProgressMonitor progressMonitor) /* throws IOException */ {
-	// package declarations are not indexed
-}
-public SearchPattern getIndexRecord() {
-	// package declarations are not indexed
-	return null;
-}
-public char[][] getMatchCategories() {
-	// package declarations are not indexed
-	return CharOperation.NO_CHAR_CHAR;
-}
-public boolean isMatchingIndexRecord() {
-	// package declarations are not indexed
-	return false;
-}
 public String toString() {
 	StringBuffer buffer = new StringBuffer(20);
 	buffer.append("PackageDeclarationPattern: <"); //$NON-NLS-1$
@@ -56,14 +33,14 @@
 	else
 		buffer.append("*"); //$NON-NLS-1$
 	buffer.append(">, "); //$NON-NLS-1$
-	switch(matchMode()){
-		case EXACT_MATCH : 
+	switch(getMatchMode()) {
+		case R_EXACT_MATCH : 
 			buffer.append("exact match, "); //$NON-NLS-1$
 			break;
-		case PREFIX_MATCH :
+		case R_PREFIX_MATCH :
 			buffer.append("prefix match, "); //$NON-NLS-1$
 			break;
-		case PATTERN_MATCH :
+		case R_PATTERN_MATCH :
 			buffer.append("pattern match, "); //$NON-NLS-1$
 			break;
 	}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PackageReferenceLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PackageReferenceLocator.java
index 7277c8f..77d76a9 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PackageReferenceLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PackageReferenceLocator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -16,7 +16,8 @@
 import org.eclipse.jdt.core.IPackageFragment;
 import org.eclipse.jdt.core.IPackageFragmentRoot;
 import org.eclipse.jdt.core.JavaModelException;
-import org.eclipse.jdt.core.search.IJavaSearchConstants;
+import org.eclipse.jdt.core.search.SearchMatch;
+import org.eclipse.jdt.core.search.SearchPattern;
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.ast.*;
 import org.eclipse.jdt.internal.compiler.lookup.*;
@@ -25,14 +26,9 @@
 public class PackageReferenceLocator extends PatternLocator {
 
 protected PackageReferencePattern pattern;
-	
-public PackageReferenceLocator(PackageReferencePattern pattern) {
-	super(pattern);
 
-	this.pattern = pattern;
-}
 // check that referenced type is actually defined in this package fragment
-public boolean isDeclaringPackageFragment(IPackageFragment packageFragment, ReferenceBinding typeBinding) {
+public static boolean isDeclaringPackageFragment(IPackageFragment packageFragment, ReferenceBinding typeBinding) {
 	char[] fileName = typeBinding.getFileName();
 	if (fileName != null) {
 		// retrieve the actual file name from the full path (sources are generally only containing it already)
@@ -63,6 +59,12 @@
 	}
 	return true; // by default, do not eliminate 
 }
+
+public PackageReferenceLocator(PackageReferencePattern pattern) {
+	super(pattern);
+
+	this.pattern = pattern;
+}
 public int match(ASTNode node, MatchingNodeSet nodeSet) { // interested in ImportReference
 	if (!(node instanceof ImportReference)) return IMPOSSIBLE_MATCH;
 
@@ -80,8 +82,11 @@
 }
 //public int match(TypeDeclaration node, MatchingNodeSet nodeSet) - SKIP IT
 public int match(TypeReference node, MatchingNodeSet nodeSet) { // interested in QualifiedTypeReference only
+	if (node instanceof JavadocSingleTypeReference) {
+		char[][] tokens = new char[][] { ((JavadocSingleTypeReference) node).token };
+		return nodeSet.addMatch(node, matchLevelForTokens(tokens));
+	}
 	if (!(node instanceof QualifiedTypeReference)) return IMPOSSIBLE_MATCH;
-
 	return nodeSet.addMatch(node, matchLevelForTokens(((QualifiedTypeReference) node).tokens));
 }
 
@@ -97,12 +102,12 @@
 	if (this.pattern.pkgName == null) return ACCURATE_MATCH;
 
 	switch (this.matchMode) {
-		case IJavaSearchConstants.EXACT_MATCH:
-		case IJavaSearchConstants.PREFIX_MATCH:
+		case SearchPattern.R_EXACT_MATCH:
+		case SearchPattern.R_PREFIX_MATCH:
 			if (CharOperation.prefixEquals(this.pattern.pkgName, CharOperation.concatWith(tokens, '.'), this.isCaseSensitive))
 				return POSSIBLE_MATCH;
 			break;
-		case IJavaSearchConstants.PATTERN_MATCH:
+		case SearchPattern.R_PATTERN_MATCH:
 			char[] patternName = this.pattern.pkgName[this.pattern.pkgName.length - 1] == '*'
 				? this.pattern.pkgName
 				: CharOperation.concat(this.pattern.pkgName, ".*".toCharArray()); //$NON-NLS-1$
@@ -116,16 +121,23 @@
 	if (binding == null) {
 		this.matchReportReference(importRef, element, accuracy, locator);
 	} else {
-		long[] positions = importRef.sourcePositions;
-		int last = positions.length - 1;
-		if (binding instanceof ProblemReferenceBinding)
-			binding = ((ProblemReferenceBinding) binding).original;
-		if (binding instanceof ReferenceBinding) {
-			PackageBinding pkgBinding = ((ReferenceBinding) binding).fPackage;
-			if (pkgBinding != null)
-				last = pkgBinding.compoundName.length;
+		if (locator.encloses(element)) {
+			long[] positions = importRef.sourcePositions;
+			int last = positions.length - 1;
+			if (binding instanceof ProblemReferenceBinding)
+				binding = ((ProblemReferenceBinding) binding).original;
+			if (binding instanceof ReferenceBinding) {
+				PackageBinding pkgBinding = ((ReferenceBinding) binding).fPackage;
+				if (pkgBinding != null)
+					last = pkgBinding.compoundName.length;
+			}
+			if (binding instanceof PackageBinding)
+				last = ((PackageBinding) binding).compoundName.length;
+			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);
 		}
-		locator.report(positions[0], positions[last - 1], element, accuracy);
 	}
 }
 protected void matchReportReference(ASTNode reference, IJavaElement element, int accuracy, MatchLocator locator) throws CoreException {
@@ -180,9 +192,16 @@
 	}
 	if (last == -1) {
 		last = this.pattern.segments.length;
-		if (last > positions.length) last = positions.length;
 	}
-	locator.report(positions[0], positions[last - 1], element, accuracy);
+	if (last == 0) return;
+	if (last > positions.length) last = positions.length;
+	int sourceStart = (int) (positions[0] >>> 32);
+	int sourceEnd = ((int) positions[last - 1]);
+	SearchMatch match = locator.newPackageReferenceMatch(element, accuracy, sourceStart, sourceEnd-sourceStart+1, reference);
+	locator.report(match);
+}
+protected int referenceType() {
+	return IJavaElement.PACKAGE_FRAGMENT;
 }
 public int resolveLevel(ASTNode node) {
 	if (node instanceof QualifiedTypeReference)
@@ -198,6 +217,8 @@
 	char[][] compoundName = null;
 	if (binding instanceof ImportBinding) {
 		compoundName = ((ImportBinding) binding).compoundName;
+	} else if (binding instanceof PackageBinding) {
+		compoundName = ((PackageBinding) binding).compoundName;
 	} else {
 		if (binding instanceof ArrayBinding)
 			binding = ((ArrayBinding) binding).leafComponentType;
@@ -212,9 +233,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/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PackageReferencePattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PackageReferencePattern.java
index 28cc5b6..ad10331 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PackageReferencePattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PackageReferencePattern.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -11,70 +11,58 @@
 package org.eclipse.jdt.internal.core.search.matching;
 
 import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.core.search.SearchPattern;
+import org.eclipse.jdt.internal.core.search.indexing.IIndexConstants;
 
-public class PackageReferencePattern extends AndPattern {
-
-private static ThreadLocal indexRecord = new ThreadLocal() {
-	protected Object initialValue() {
-		return new PackageReferencePattern("*".toCharArray(), R_EXACT_MATCH | R_CASE_SENSITIVE); //$NON-NLS-1$;
-	}
-};
+public class PackageReferencePattern extends AndPattern implements IIndexConstants {
 
 protected char[] pkgName;
 
 protected char[][] segments;
 protected int currentSegment;
 
-public static PackageReferencePattern getPackageReferenceRecord() {
-	return (PackageReferencePattern)indexRecord.get();
-}
-	
+protected static char[][] CATEGORIES = { REF };
+
 public PackageReferencePattern(char[] pkgName, int matchRule) {
-	super(PKG_REF_PATTERN, matchRule);
+	this(matchRule);
 
 	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 = isCaseSensitive() ? pkgName : CharOperation.toLowerCase(pkgName);
 		this.segments = CharOperation.splitOn('.', this.pkgName);
-		this.mustResolve = true;
+		((InternalSearchPattern)this).mustResolve = true;
 	}
 }
+PackageReferencePattern(int matchRule) {
+	super(PKG_REF_PATTERN, matchRule);
+}
 public void decodeIndexKey(char[] key) {
 	// Package reference keys are encoded as 'name' (where 'name' is the last segment of the package name)
-	this.segments[0] = key;
+	this.pkgName = key;
 }
-public char[] encodeIndexKey() {
-	if (this.currentSegment < 0) return null;
+public SearchPattern getBlankPattern() {
+	return new PackageReferencePattern(R_EXACT_MATCH | R_CASE_SENSITIVE);
+}
+public char[] getIndexKey() {
 	// Package reference keys are encoded as 'name' (where 'name' is the last segment of the package name)
-	return encodeIndexKey(this.segments[this.currentSegment]);
+	if (this.currentSegment >= 0) 
+		return this.segments[this.currentSegment];
+	return null;
 }
-public SearchPattern getIndexRecord() {
-	return getPackageReferenceRecord();
+public char[][] getIndexCategories() {
+	return CATEGORIES;
 }
-public char[][] getMatchCategories() {
-	return new char[][] {REF};
-}
-/*
- * @see AndPattern#hasNextQuery()
- */
 protected boolean hasNextQuery() {
 	// if package has at least 4 segments, don't look at the first 2 since they are mostly
 	// redundant (eg. in 'org.eclipse.jdt.core.*' 'org.eclipse' is used all the time)
 	return --this.currentSegment >= (this.segments.length >= 4 ? 2 : 0);
 }
-/*
- * @see SearchPattern#isMatchingIndexRecord()
- */
-public boolean isMatchingIndexRecord() {
-	return matchesName(this.segments[this.currentSegment], ((PackageReferencePattern)getIndexRecord()).segments[0]);
+public boolean matchesDecodedKey(SearchPattern decodedPattern) {
+	return true; // index key is not encoded so query results all match
 }
-/**
- * @see AndPattern#resetQuery()
- */
 protected void resetQuery() {
 	/* walk the segments from end to start as it will find less potential references using 'lang' than 'java' */
 	this.currentSegment = this.segments.length - 1;
@@ -87,7 +75,7 @@
 	else
 		buffer.append("*"); //$NON-NLS-1$
 	buffer.append(">, "); //$NON-NLS-1$
-	switch(matchMode()){
+	switch(getMatchMode()) {
 		case R_EXACT_MATCH : 
 			buffer.append("exact match, "); //$NON-NLS-1$
 			break;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PatternLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PatternLocator.java
index e98a69c..da3da17 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PatternLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PatternLocator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -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,9 @@
 
 
 public PatternLocator(SearchPattern pattern) {
-	this.matchMode = pattern.matchMode();
-	this.isCaseSensitive = pattern.isCaseSensitive();
+	int matchRule = pattern.getMatchRule();
+	this.isCaseSensitive = (matchRule & SearchPattern.R_CASE_SENSITIVE) != 0;
+	this.matchMode = matchRule - (this.isCaseSensitive ? SearchPattern.R_CASE_SENSITIVE : 0);
 }
 /**
  * Initializes this search pattern so that polymorphic search can be performed.
@@ -155,11 +156,11 @@
 	if (pattern == null) return true; // null is as if it was "*"
 	if (name != null) {
 		switch (this.matchMode) {
-			case IJavaSearchConstants.EXACT_MATCH :
+			case SearchPattern.R_EXACT_MATCH :
 				return CharOperation.equals(pattern, name, this.isCaseSensitive);
-			case IJavaSearchConstants.PREFIX_MATCH :
+			case SearchPattern.R_PREFIX_MATCH :
 				return CharOperation.prefixEquals(pattern, name, this.isCaseSensitive);
-			case IJavaSearchConstants.PATTERN_MATCH :
+			case SearchPattern.R_PATTERN_MATCH :
 				if (!this.isCaseSensitive)
 					pattern = CharOperation.toLowerCase(pattern);
 				return CharOperation.match(pattern, name, this.isCaseSensitive);
@@ -208,8 +209,8 @@
 			binding, 
 			locator.createImportHandle(importRef), 
 			level == ACCURATE_MATCH
-				? IJavaSearchResultCollector.EXACT_MATCH
-				: IJavaSearchResultCollector.POTENTIAL_MATCH,
+				? SearchMatch.A_ACCURATE
+				: SearchMatch.A_INACCURATE,
 			locator);
 	}
 }
@@ -217,15 +218,41 @@
  * Reports the match of the given import reference.
  */
 protected void matchReportImportRef(ImportReference importRef, Binding binding, IJavaElement element, int accuracy, MatchLocator locator) throws CoreException {
-	// default is to report a match as a regular ref.
-	this.matchReportReference(importRef, element, accuracy, locator);
+	if (locator.encloses(element)) {
+		// default is to report a match as a regular ref.
+		this.matchReportReference(importRef, element, accuracy, locator);
+	}
 }
 /**
  * Reports the match of the given reference.
  */
 protected void matchReportReference(ASTNode reference, IJavaElement element, int accuracy, MatchLocator locator) throws CoreException {
-	// default is to report a match on the whole node.
-	locator.report(reference.sourceStart, reference.sourceEnd, element, accuracy);
+	SearchMatch match = null;
+	int referenceType = referenceType();
+	int offset = reference.sourceStart;
+	switch (referenceType) {
+		case IJavaElement.PACKAGE_FRAGMENT:
+			match = locator.newPackageReferenceMatch(element, accuracy, offset, reference.sourceEnd-offset+1, reference);
+			break;
+		case IJavaElement.TYPE:
+			match = locator.newTypeReferenceMatch(element, accuracy, offset, reference.sourceEnd-offset+1, reference);
+			break;
+		case IJavaElement.FIELD:
+			match = locator.newFieldReferenceMatch(element, accuracy, offset, reference.sourceEnd-offset+1, reference);
+			break;
+		case IJavaElement.METHOD:
+			match = locator.newMethodReferenceMatch(element, accuracy, offset, reference.sourceEnd-offset+1, reference);
+			break;
+		case IJavaElement.LOCAL_VARIABLE:
+			match = locator.newLocalVariableReferenceMatch(element, accuracy, offset, reference.sourceEnd-offset+1, reference);
+			break;
+	}
+	if (match != null) {
+		locator.report(match);
+	}
+}
+protected int referenceType() {
+	return 0; // defaults to unknown (a generic JavaSearchMatch will be created)
 }
 /**
  * Finds out whether the given ast node matches this search pattern.
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PossibleMatch.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PossibleMatch.java
index 42015dd..009ddc8 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PossibleMatch.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PossibleMatch.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -43,6 +43,11 @@
 }
 public void cleanUp() {
 	this.source = null;
+	if (this.parsedUnit != null) {
+		this.parsedUnit.cleanUp();
+		this.parsedUnit = null;
+	}
+	this.nodeSet = null;
 }
 public boolean equals(Object obj) {
 	if (this.compoundName == null) return super.equals(obj);
@@ -68,7 +73,7 @@
 /**
  * The exact openable file name. In particular, will be the originating .class file for binary openable with attached
  * source.
- * @see PackageReferenceLocator#isDeclaringPackageFragment(IPackageFragment, ReferenceBinding)
+ * @see PackageReferenceLocator#isDeclaringPackageFragment(IPackageFragment, org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding)
  */
 public char[] getFileName() {
 	return this.openable.getElementName().toCharArray();
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PossibleMatchSet.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PossibleMatchSet.java
index 84033c7..358b32d 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PossibleMatchSet.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PossibleMatchSet.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/QualifiedTypeDeclarationPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/QualifiedTypeDeclarationPattern.java
index a657c89..c807f27 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/QualifiedTypeDeclarationPattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/QualifiedTypeDeclarationPattern.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -12,72 +12,54 @@
 
 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 {
-	
-private static ThreadLocal indexRecord = new ThreadLocal() {
-	protected Object initialValue() {
-		return new QualifiedTypeDeclarationPattern(null, null, ' ', R_EXACT_MATCH | R_CASE_SENSITIVE);
-	}
-};
+public class QualifiedTypeDeclarationPattern extends TypeDeclarationPattern implements IIndexConstants {
 
 protected char[] qualification;
 
-public static QualifiedTypeDeclarationPattern getQualifiedTypeDeclarationRecord() {
-	return (QualifiedTypeDeclarationPattern)indexRecord.get();
-}
-public QualifiedTypeDeclarationPattern(
-	char[] qualification,
-	char[] simpleName,
-	char classOrInterface,
-	int matchRule) {
+public QualifiedTypeDeclarationPattern(char[] qualification, char[] simpleName, char classOrInterface, int matchRule) {
+	this(matchRule);
 
-	super(matchRule);
-
-	boolean isCaseSensitive = isCaseSensitive();
-	this.qualification = isCaseSensitive ? qualification : CharOperation.toLowerCase(qualification);
-	this.simpleName = isCaseSensitive ? simpleName : CharOperation.toLowerCase(simpleName);
+	this.qualification = isCaseSensitive() ? qualification : CharOperation.toLowerCase(qualification);
+	this.simpleName = isCaseSensitive() ? simpleName : CharOperation.toLowerCase(simpleName);
 	this.classOrInterface = classOrInterface;
 
-	this.mustResolve = qualification != null;
+	((InternalSearchPattern)this).mustResolve = this.qualification != null;
+}
+QualifiedTypeDeclarationPattern(int matchRule) {
+	super(matchRule);
 }
 public void decodeIndexKey(char[] key) {
-	int size = key.length;
+	int slash = CharOperation.indexOf(SEPARATOR, key, 0);
+	this.simpleName = CharOperation.subarray(key, 0, slash);
 
-	this.classOrInterface = key[0];
-	int oldSlash = 1;
-	int slash = CharOperation.indexOf(SEPARATOR, key, oldSlash + 1);
-	char[] pkgName = slash == oldSlash + 1
-		? CharOperation.NO_CHAR
-		: CharOperation.subarray(key, oldSlash+1, slash);
-	this.simpleName = CharOperation.subarray(key, slash + 1, slash = CharOperation.indexOf(SEPARATOR, key, slash + 1));
-
-	char[][] decodedEnclosingTypeNames;
-	if (slash + 1 < size) {
-		decodedEnclosingTypeNames = (slash + 3 == size && key[slash + 1] == ONE_ZERO[0])
-			? ONE_ZERO_CHAR
-			: CharOperation.splitOn('/', CharOperation.subarray(key, slash + 1, size - 1));
+	int start = slash + 1;
+	slash = CharOperation.indexOf(SEPARATOR, key, start);
+	int secondSlash = CharOperation.indexOf(SEPARATOR, key, slash + 1);
+	if (start + 1 == secondSlash) {
+		this.qualification = CharOperation.NO_CHAR; // no package name or enclosingTypeNames
+	} else if (slash + 1 == secondSlash) {
+		this.qualification = CharOperation.subarray(key, start, slash); // only a package name
 	} else {
-		decodedEnclosingTypeNames = CharOperation.NO_CHAR_CHAR;
+		this.qualification = CharOperation.subarray(key, start, secondSlash);
+		this.qualification[slash - start] = '.';
 	}
-	this.qualification = CharOperation.concatWith(pkgName, decodedEnclosingTypeNames, '.');
+
+	this.classOrInterface = key[key.length - 1];
 }
-public SearchPattern getIndexRecord() {
-	return getQualifiedTypeDeclarationRecord();
+public SearchPattern getBlankPattern() {
+	return new QualifiedTypeDeclarationPattern(R_EXACT_MATCH | R_CASE_SENSITIVE);
 }
-public boolean isMatchingIndexRecord() {
-	QualifiedTypeDeclarationPattern record = getQualifiedTypeDeclarationRecord();
+public boolean matchesDecodedKey(SearchPattern decodedPattern) {
+	QualifiedTypeDeclarationPattern pattern = (QualifiedTypeDeclarationPattern) decodedPattern;
 	switch(this.classOrInterface) {
 		case CLASS_SUFFIX :
 		case INTERFACE_SUFFIX :
-			if (this.classOrInterface != record.classOrInterface) return false;
-		case TYPE_SUFFIX : // nothing
+			if (this.classOrInterface != pattern.classOrInterface) return false;
 	}
 
-	if (!matchesName(this.pkg, record.qualification))
-		return false;
-	
-	return matchesName(this.simpleName, record.simpleName);
+	return matchesName(this.simpleName, pattern.simpleName) && matchesName(this.qualification, pattern.qualification);
 }
 public String toString() {
 	StringBuffer buffer = new StringBuffer(20);
@@ -102,14 +84,14 @@
 	else
 		buffer.append("*"); //$NON-NLS-1$
 	buffer.append(">, "); //$NON-NLS-1$
-	switch(matchMode()){
-		case EXACT_MATCH : 
+	switch(getMatchMode()) {
+		case R_EXACT_MATCH : 
 			buffer.append("exact match, "); //$NON-NLS-1$
 			break;
-		case PREFIX_MATCH :
+		case R_PREFIX_MATCH :
 			buffer.append("prefix match, "); //$NON-NLS-1$
 			break;
-		case PATTERN_MATCH :
+		case R_PATTERN_MATCH :
 			buffer.append("pattern match, "); //$NON-NLS-1$
 			break;
 	}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeNamesCollector.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeNamesCollector.java
index 24a4592..ac6d8a6 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeNamesCollector.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeNamesCollector.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -26,6 +26,7 @@
 import org.eclipse.jdt.internal.core.search.*;
 import org.eclipse.jdt.internal.core.search.indexing.IIndexConstants;
 import org.eclipse.jdt.internal.core.search.indexing.IndexManager;
+import org.eclipse.jdt.internal.core.util.ASTNodeFinder;
 import org.eclipse.jdt.internal.core.util.Util;
 
 /**
@@ -35,6 +36,42 @@
  */
 public class SuperTypeNamesCollector {
 
+	/**
+	 * An ast visitor that visits type declarations and member type declarations
+	 * collecting their super type names.
+	 */
+	public class TypeDeclarationVisitor extends ASTVisitor {
+		public boolean visit(TypeDeclaration typeDeclaration, BlockScope scope) {
+			ReferenceBinding binding = typeDeclaration.binding;
+			if (SuperTypeNamesCollector.this.matches(binding))
+				SuperTypeNamesCollector.this.collectSuperTypeNames(binding);
+			return true;
+		}
+		public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope scope) {
+			ReferenceBinding binding = typeDeclaration.binding;
+			if (SuperTypeNamesCollector.this.matches(binding))
+				SuperTypeNamesCollector.this.collectSuperTypeNames(binding);
+			return true;
+		}
+		public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope scope) {
+			ReferenceBinding binding = memberTypeDeclaration.binding;
+			if (SuperTypeNamesCollector.this.matches(binding))
+				SuperTypeNamesCollector.this.collectSuperTypeNames(binding);
+			return true;
+		}
+		public boolean visit(FieldDeclaration fieldDeclaration, MethodScope scope) {
+			return false; // don't visit field declarations
+		}
+		public boolean visit(Initializer initializer, MethodScope scope) {
+			return false; // don't visit initializers
+		}
+		public boolean visit(ConstructorDeclaration constructorDeclaration, ClassScope scope) {
+			return false; // don't visit constructor declarations
+		}
+		public boolean visit(MethodDeclaration methodDeclaration, ClassScope scope) {
+			return false; // don't visit method declarations
+		}
+	}
 SearchPattern pattern;
 char[] typeSimpleName;
 char[] typeQualification;
@@ -44,43 +81,6 @@
 char[][][] result;
 int resultIndex;
 
-/**
- * An ast visitor that visits type declarations and member type declarations
- * collecting their super type names.
- */
-public class TypeDeclarationVisitor extends ASTVisitor {
-	public boolean visit(TypeDeclaration typeDeclaration, BlockScope scope) {
-		ReferenceBinding binding = typeDeclaration.binding;
-		if (SuperTypeNamesCollector.this.matches(binding))
-			SuperTypeNamesCollector.this.collectSuperTypeNames(binding);
-		return true;
-	}
-	public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope scope) {
-		ReferenceBinding binding = typeDeclaration.binding;
-		if (SuperTypeNamesCollector.this.matches(binding))
-			SuperTypeNamesCollector.this.collectSuperTypeNames(binding);
-		return true;
-	}
-	public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope scope) {
-		ReferenceBinding binding = memberTypeDeclaration.binding;
-		if (SuperTypeNamesCollector.this.matches(binding))
-			SuperTypeNamesCollector.this.collectSuperTypeNames(binding);
-		return true;
-	}
-	public boolean visit(FieldDeclaration fieldDeclaration, MethodScope scope) {
-		return false; // don't visit field declarations
-	}
-	public boolean visit(Initializer initializer, MethodScope scope) {
-		return false; // don't visit initializers
-	}
-	public boolean visit(ConstructorDeclaration constructorDeclaration, ClassScope scope) {
-		return false; // don't visit constructor declarations
-	}
-	public boolean visit(MethodDeclaration methodDeclaration, ClassScope scope) {
-		return false; // don't visit method declarations
-	}
-}
-
 public SuperTypeNamesCollector(
 	SearchPattern pattern,
 	char[] typeSimpleName,
@@ -108,9 +108,8 @@
 }
 /*
  * Parse the given compiation unit and build its type bindings.
- * Don't build methods and fields.
  */
-protected CompilationUnitDeclaration buildBindings(ICompilationUnit compilationUnit) throws JavaModelException {
+protected CompilationUnitDeclaration buildBindings(ICompilationUnit compilationUnit, boolean isTopLevelOrMember) throws JavaModelException {
 	final IFile file = (IFile) compilationUnit.getResource();
 	final String fileName = file.getFullPath().lastSegment();
 	final char[] mainTypeName = fileName.substring(0, fileName.length() - 5).toCharArray();
@@ -130,10 +129,18 @@
 		};
 
 	CompilationResult compilationResult = new CompilationResult(sourceUnit, 1, 1, 0);
-	CompilationUnitDeclaration unit = this.locator.basicParser().dietParse(sourceUnit, compilationResult);
+	CompilationUnitDeclaration unit = 
+		isTopLevelOrMember ?
+			this.locator.basicParser().dietParse(sourceUnit, compilationResult) :
+			this.locator.basicParser().parse(sourceUnit, compilationResult);
 	if (unit != null) {
 		this.locator.lookupEnvironment.buildTypeBindings(unit);
-		this.locator.lookupEnvironment.completeTypeBindings(unit, false);
+		this.locator.lookupEnvironment.completeTypeBindings(unit, !isTopLevelOrMember);
+		if (!isTopLevelOrMember) {
+			if (unit.scope != null)
+				unit.scope.faultInTypes(); // fault in fields & methods
+			unit.resolve();
+		}
 	}
 	return unit;
 }
@@ -144,7 +151,6 @@
 		this.resultIndex = 0;
 		JavaProject javaProject = (JavaProject) this.type.getJavaProject();
 		this.locator.initialize(javaProject, 0);
-		this.locator.nameLookup.setUnitsToLookInside(this.locator.workingCopies); // NB: this uses a PerThreadObject, so it is thread safe
 		try {
 			if (this.type.isBinary()) {
 				BinaryTypeBinding binding = this.locator.cacheBinaryType(this.type);
@@ -152,15 +158,18 @@
 					collectSuperTypeNames(binding);
 			} else {
 				ICompilationUnit unit = this.type.getCompilationUnit();
-				CompilationUnitDeclaration parsedUnit = buildBindings(unit);
-				if (parsedUnit != null)
-					parsedUnit.traverse(new TypeDeclarationVisitor(), parsedUnit.scope);
+				SourceType sourceType = (SourceType) this.type;
+				boolean isTopLevelOrMember = sourceType.getOuterMostLocalContext() == null;
+				CompilationUnitDeclaration parsedUnit = buildBindings(unit, isTopLevelOrMember);
+				if (parsedUnit != null) {
+					TypeDeclaration typeDecl = new ASTNodeFinder(parsedUnit).findType(this.type);
+					if (typeDecl != null && typeDecl.binding != null) 
+						collectSuperTypeNames(typeDecl.binding);
+				}
 			}
 		} catch (AbortCompilation e) {
 			// problem with classpath: report inacurrate matches
 			return null;
-		} finally {
-			this.locator.nameLookup.setUnitsToLookInside(null);
 		}
 		if (this.result.length > this.resultIndex)
 			System.arraycopy(this.result, 0, this.result = new char[this.resultIndex][][], 0, this.resultIndex);
@@ -177,40 +186,32 @@
 	JavaProject previousProject = null;
 	this.result = new char[1][][];
 	this.resultIndex = 0;
-	try {
-		for (int i = 0, length = paths.length; i < length; i++) {
-			try {
-				Openable openable = this.locator.handleFactory.createOpenable(paths[i], this.locator.scope);
-				if (openable == null) continue; // outside classpath
+	for (int i = 0, length = paths.length; i < length; i++) {
+		try {
+			Openable openable = this.locator.handleFactory.createOpenable(paths[i], this.locator.scope);
+			if (openable == null) continue; // outside classpath
 
-				IJavaProject project = openable.getJavaProject();
-				if (!project.equals(previousProject)) {
-					if (previousProject != null)
-						this.locator.nameLookup.setUnitsToLookInside(null);
-					previousProject = (JavaProject) project;
-					this.locator.initialize(previousProject, 0);
-					this.locator.nameLookup.setUnitsToLookInside(this.locator.workingCopies);
-				}
-				if (openable instanceof ICompilationUnit) {
-					ICompilationUnit unit = (ICompilationUnit) openable;
-					CompilationUnitDeclaration parsedUnit = buildBindings(unit);
-					if (parsedUnit != null)
-						parsedUnit.traverse(new TypeDeclarationVisitor(), parsedUnit.scope);
-				} else if (openable instanceof IClassFile) {
-					IClassFile classFile = (IClassFile) openable;
-					BinaryTypeBinding binding = this.locator.cacheBinaryType(classFile.getType());
-					if (matches(binding))
-						collectSuperTypeNames(binding);
-				}
-			} catch (AbortCompilation e) {
-				// ignore: continue with next element
-			} catch (JavaModelException e) {
-				// ignore: continue with next element
+			IJavaProject project = openable.getJavaProject();
+			if (!project.equals(previousProject)) {
+				previousProject = (JavaProject) project;
+				this.locator.initialize(previousProject, 0);
 			}
+			if (openable instanceof ICompilationUnit) {
+				ICompilationUnit unit = (ICompilationUnit) openable;
+				CompilationUnitDeclaration parsedUnit = buildBindings(unit, true /*only toplevel and member types are visible to the focus type*/);
+				if (parsedUnit != null)
+					parsedUnit.traverse(new TypeDeclarationVisitor(), parsedUnit.scope);
+			} else if (openable instanceof IClassFile) {
+				IClassFile classFile = (IClassFile) openable;
+				BinaryTypeBinding binding = this.locator.cacheBinaryType(classFile.getType());
+				if (matches(binding))
+					collectSuperTypeNames(binding);
+			}
+		} catch (AbortCompilation e) {
+			// ignore: continue with next element
+		} catch (JavaModelException e) {
+			// ignore: continue with next element
 		}
-	} finally {
-		if (previousProject != null)
-			this.locator.nameLookup.setUnitsToLookInside(null);
 	}
 	if (this.result.length > this.resultIndex)
 		System.arraycopy(this.result, 0, this.result = new char[this.resultIndex][][], 0, this.resultIndex);
@@ -246,7 +247,7 @@
 		null, // do find member types
 		this.typeSimpleName,
 		IIndexConstants.TYPE_SUFFIX,
-		this.pattern.matchRule);
+		this.pattern.getMatchRule());
 	IndexQueryRequestor searchRequestor = new IndexQueryRequestor(){
 		public boolean acceptIndexMatch(String documentPath, SearchPattern indexRecord, SearchParticipant participant) {
 			TypeDeclarationPattern record = (TypeDeclarationPattern)indexRecord;
@@ -260,7 +261,7 @@
 	indexManager.performConcurrentJob(
 		new PatternSearchJob(
 			searchPattern, 
-			new JavaSearchParticipant(this.locator.workingCopies),
+			new JavaSearchParticipant(),
 			scope, 
 			searchRequestor),
 		IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH,
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeReferenceLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeReferenceLocator.java
index 929c54a..3f8b2dd 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeReferenceLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeReferenceLocator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -10,6 +10,7 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.search.matching;
 
+import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.internal.compiler.ast.*;
 import org.eclipse.jdt.internal.compiler.lookup.*;
 
@@ -32,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) {
@@ -42,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;
 }
@@ -50,6 +51,9 @@
 protected int matchContainer() {
 	return CLASS_CONTAINER;
 }
+protected int referenceType() {
+	return IJavaElement.TYPE;
+}
 public int resolveLevel(ASTNode node) {
 	if (!(node instanceof TypeReference)) return IMPOSSIBLE_MATCH;
 
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeReferencePattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeReferencePattern.java
index 3a25cac..05acc8d 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeReferencePattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeReferencePattern.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -10,24 +10,14 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.search.matching;
 
-import java.io.*;
-import java.util.HashMap;
+import java.io.IOException;
 
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.OperationCanceledException;
 import org.eclipse.jdt.core.compiler.*;
 import org.eclipse.jdt.core.search.*;
 import org.eclipse.jdt.internal.core.search.indexing.IIndexConstants;
-import org.eclipse.jdt.internal.core.index.impl.*;
-import org.eclipse.jdt.internal.core.search.*;
+import org.eclipse.jdt.internal.core.index.*;
 
-public class SuperTypeReferencePattern extends SearchPattern {
-
-private static ThreadLocal indexRecord = new ThreadLocal() {
-	protected Object initialValue() {
-		return new SuperTypeReferencePattern(null, null, false, R_EXACT_MATCH | R_CASE_SENSITIVE);
-	}
-};
+public class SuperTypeReferencePattern extends JavaSearchPattern implements IIndexConstants {
 
 public char[] superQualification;
 public char[] superSimpleName;
@@ -41,12 +31,7 @@
 
 protected boolean checkOnlySuperinterfaces; // used for IMPLEMENTORS
 
-/**
- * A map from IndexInputs to IEntryResult[]
- */
-public HashMap entryResults;
-
-private static final EntryResult[] NO_ENTRY_RESULT = new EntryResult[0];
+protected static char[][] CATEGORIES = { SUPER_REF };
 
 public static char[] createIndexKey(
 	int modifiers,
@@ -57,211 +42,164 @@
 	char[] superTypeName,
 	char superClassOrInterface) {
 
-	SuperTypeReferencePattern record = getSuperTypeReferenceRecord();
-	record.modifiers = modifiers;
-	record.pkgName = packageName;
-	record.classOrInterface = classOrInterface;
-	record.superClassOrInterface = superClassOrInterface;
 	if (superTypeName == null)
 		superTypeName = OBJECT;
-	record.enclosingTypeName = CharOperation.concatWith(enclosingTypeNames, '$');
-	record.simpleName = CharOperation.lastSegment(typeName, '.');
-	record.superSimpleName = CharOperation.lastSegment(superTypeName, '.');
-	record.superQualification = null;
-	if (record.superSimpleName != superTypeName) {
-		int length = superTypeName.length - record.superSimpleName.length - 1;
-		record.superQualification = new char[length];
-		System.arraycopy(superTypeName, 0, record.superQualification, 0, length);
+	char[] superSimpleName = CharOperation.lastSegment(superTypeName, '.');
+	char[] superQualification = null;
+	if (superSimpleName != superTypeName) {
+		int length = superTypeName.length - superSimpleName.length - 1;
+		superQualification = new char[length];
+		System.arraycopy(superTypeName, 0, superQualification, 0, length);
 	}
 
 	// if the supertype name contains a $, then split it into: source name and append the $ prefix to the qualification
 	//	e.g. p.A$B ---> p.A$ + B
-	char[] superTypeSourceName = CharOperation.lastSegment(record.superSimpleName, '$');
-	if (superTypeSourceName != record.superSimpleName) {
-		int start = record.superQualification == null ? 0 : record.superQualification.length + 1;
-		int prefixLength = record.superSimpleName.length - superTypeSourceName.length;
+	char[] superTypeSourceName = CharOperation.lastSegment(superSimpleName, '$');
+	if (superTypeSourceName != superSimpleName) {
+		int start = superQualification == null ? 0 : superQualification.length + 1;
+		int prefixLength = superSimpleName.length - superTypeSourceName.length;
 		char[] mangledQualification = new char[start + prefixLength];
-		if (record.superQualification != null) {
-			System.arraycopy(record.superQualification, 0, mangledQualification, 0, start-1);
+		if (superQualification != null) {
+			System.arraycopy(superQualification, 0, mangledQualification, 0, start-1);
 			mangledQualification[start-1] = '.';
 		}
-		System.arraycopy(record.superSimpleName, 0, mangledQualification, start, prefixLength);
-		record.superQualification = mangledQualification;
-		record.superSimpleName = superTypeSourceName;
-	} 
-	
-	return record.encodeIndexKey();
+		System.arraycopy(superSimpleName, 0, mangledQualification, start, prefixLength);
+		superQualification = mangledQualification;
+		superSimpleName = superTypeSourceName;
+	}
+
+	char[] simpleName = CharOperation.lastSegment(typeName, '.');
+	char[] enclosingTypeName = CharOperation.concatWith(enclosingTypeNames, '$');
+	if (superQualification != null && CharOperation.equals(superQualification, packageName))
+		packageName = ONE_ZERO; // save some space
+
+	// superSimpleName / superQualification / simpleName / enclosingTypeName / packageName / superClassOrInterface classOrInterface modifiers
+	int superLength = superSimpleName == null ? 0 : superSimpleName.length;
+	int superQLength = superQualification == null ? 0 : superQualification.length;
+	int simpleLength = simpleName == null ? 0 : simpleName.length;
+	int enclosingLength = enclosingTypeName == null ? 0 : enclosingTypeName.length;
+	int packageLength = packageName == null ? 0 : packageName.length;
+	char[] result = new char[superLength + superQLength + simpleLength + enclosingLength + packageLength + 8];
+	int pos = 0;
+	if (superLength > 0) {
+		System.arraycopy(superSimpleName, 0, result, pos, superLength);
+		pos += superLength;
+	}
+	result[pos++] = SEPARATOR;
+	if (superQLength > 0) {
+		System.arraycopy(superQualification, 0, result, pos, superQLength);
+		pos += superQLength;
+	}
+	result[pos++] = SEPARATOR;
+	if (simpleLength > 0) {
+		System.arraycopy(simpleName, 0, result, pos, simpleLength);
+		pos += simpleLength;
+	}
+	result[pos++] = SEPARATOR;
+	if (enclosingLength > 0) {
+		System.arraycopy(enclosingTypeName, 0, result, pos, enclosingLength);
+		pos += enclosingLength;
+	}
+	result[pos++] = SEPARATOR;
+	if (packageLength > 0) {
+		System.arraycopy(packageName, 0, result, pos, packageLength);
+		pos += packageLength;
+	}
+	result[pos++] = SEPARATOR;
+	result[pos++] = superClassOrInterface;
+	result[pos++] = classOrInterface;
+	result[pos] = (char) modifiers;
+	return result;
 }
-public static SuperTypeReferencePattern getSuperTypeReferenceRecord() {
-	return (SuperTypeReferencePattern)indexRecord.get();
-}
-public SuperTypeReferencePattern(char[] superQualification, char[] superSimpleName, int matchRule) {
-	this(superQualification, superSimpleName, false, matchRule);
-}
+
 public SuperTypeReferencePattern(
 	char[] superQualification,
 	char[] superSimpleName,
 	boolean checkOnlySuperinterfaces,
 	int matchRule) {
 
-	super(SUPER_REF_PATTERN, matchRule);
+	this(matchRule);
 
-	boolean isCaseSensitive = isCaseSensitive();
-	this.superQualification = isCaseSensitive ? superQualification : CharOperation.toLowerCase(superQualification);
-	this.superSimpleName = 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) {
+	super(SUPER_REF_PATTERN, matchRule);
+}
 /*
- * superSimpleName / superQualification / superClassOrInterface /  simpleName / enclosingTypeName / pkgName / classOrInterface modifiers
+ * superSimpleName / superQualification / simpleName / enclosingTypeName / pkgName / superClassOrInterface classOrInterface modifiers
  */
 public void decodeIndexKey(char[] key) {
-	int slash = -1;
-	this.superSimpleName = CharOperation.subarray(key, slash + 1, slash = CharOperation.indexOf(SEPARATOR, key, slash + 1));
-	int oldSlash = slash;
-	slash = CharOperation.indexOf(SEPARATOR, key, slash + 1);
-	this.superQualification = (slash == oldSlash + 1)
-		? null // could not have been known at index time
-		: CharOperation.subarray(key, oldSlash + 1, slash);
-	this.superClassOrInterface = key[slash + 1];
-	slash += 2;
-	this.simpleName = CharOperation.subarray(key, slash + 1, slash = CharOperation.indexOf(SEPARATOR, key, slash + 1));
-	oldSlash = slash;
-	slash = CharOperation.indexOf(SEPARATOR, key, slash + 1);
-	if (slash == oldSlash + 1) { // could not have been known at index time
+	int slash = CharOperation.indexOf(SEPARATOR, key, 0);
+	this.superSimpleName = CharOperation.subarray(key, 0, slash);
+
+	// some values may not have been know when indexed so decode as null
+	int start = slash + 1;
+	slash = CharOperation.indexOf(SEPARATOR, key, start);
+	this.superQualification = slash == start ? null : CharOperation.subarray(key, start, slash);
+
+	slash = CharOperation.indexOf(SEPARATOR, key, start = slash + 1);
+	this.simpleName = CharOperation.subarray(key, start, slash);
+
+	slash = CharOperation.indexOf(SEPARATOR, key, start = slash + 1);
+	if (slash == start) {
 		this.enclosingTypeName = null;
 	} else {
-		this.enclosingTypeName = (slash == oldSlash + 2 && key[oldSlash + 1] == ONE_ZERO[0])
-			? ONE_ZERO
-			: CharOperation.subarray(key, oldSlash + 1, slash);
+		char[] names = CharOperation.subarray(key, start, slash);
+		this.enclosingTypeName = CharOperation.equals(ONE_ZERO, names) ? ONE_ZERO : names;
 	}
-	oldSlash = slash;
-	slash = CharOperation.indexOf(SEPARATOR, key, slash + 1);
-	this.pkgName = (slash == oldSlash + 1)
-		? null // could not have been known at index time
-		: CharOperation.subarray(key, oldSlash + 1, slash);
-	this.classOrInterface = key[slash + 1];
-	this.modifiers = key[slash + 2]; // implicit cast to int type
+
+	slash = CharOperation.indexOf(SEPARATOR, key, start = slash + 1);
+	if (slash == start) {
+		this.pkgName = null;
+	} else {
+		char[] names = CharOperation.subarray(key, start, slash);
+		this.pkgName = CharOperation.equals(ONE_ZERO, names) ? this.superQualification : names;
+	}
+
+	this.superClassOrInterface = key[slash + 1];
+	this.classOrInterface = key[slash + 2];
+	this.modifiers = key[slash + 3]; // implicit cast to int type
 }
-/*
- * superSimpleName / superQualification / superClassOrInterface /  simpleName / enclosingTypeName / pkgName / classOrInterface modifiers
- */
-public char[] encodeIndexKey() {
-	int superSimpleNameLength = this.superSimpleName == null ? 0 : this.superSimpleName.length;
-	int superQualificationLength = this.superQualification == null ? 0 : this.superQualification.length;
-	int simpleNameLength = this.simpleName == null ? 0 : this.simpleName.length;
-	int enclosingTypeNameLength = this.enclosingTypeName == null ? 0 : this.enclosingTypeName.length;
-	int pkgNameLength = this.pkgName == null ? 0 : this.pkgName.length;
-
-	int length = superSimpleNameLength + superQualificationLength + simpleNameLength
-		+ enclosingTypeNameLength + pkgNameLength + 9;
-	char[] result = new char[length];
-	int pos = 0;
-	if (superSimpleNameLength > 0) {
-		System.arraycopy(this.superSimpleName, 0, result, pos, superSimpleNameLength);
-		pos += superSimpleNameLength;
-	}
-	result[pos++] = SEPARATOR;
-	if (this.superClassOrInterface != 0) { // 0 when querying index
-		if (superQualificationLength > 0) {
-			System.arraycopy(this.superQualification, 0, result, pos, superQualificationLength);
-			pos += superQualificationLength;
-		}
-		result[pos++] = SEPARATOR;
-		result[pos++] = this.superClassOrInterface;
-		result[pos++] = SEPARATOR;
-		if (simpleNameLength > 0) {
-			System.arraycopy(this.simpleName, 0, result, pos, simpleNameLength);
-			pos += simpleNameLength;
-		}
-		result[pos++] = SEPARATOR;
-		if (enclosingTypeNameLength > 0) {
-			System.arraycopy(this.enclosingTypeName, 0, result, pos, enclosingTypeNameLength);
-			pos += enclosingTypeNameLength;
-		}
-		result[pos++] = SEPARATOR;
-		if (pkgNameLength > 0) {
-			System.arraycopy(this.pkgName, 0, result, pos, pkgNameLength);
-			pos += pkgNameLength;
-		}
-		result[pos++] = SEPARATOR;
-		result[pos++] = this.classOrInterface;
-		result[pos++] = (char) this.modifiers;
-	}
-	if (pos != length) {
-		System.arraycopy(result, 0, result = new char[pos], 0, pos);
-	}
-	return result;
+public SearchPattern getBlankPattern() {
+	return new SuperTypeReferencePattern(R_EXACT_MATCH | R_CASE_SENSITIVE);
 }
-/**
- * Query a given index for matching entries. 
- */
-public void findIndexMatches(IndexInput input, IndexQueryRequestor requestor, SearchParticipant participant, IJavaSearchScope scope, IProgressMonitor progressMonitor) throws IOException {
-	if (this.entryResults == null) {
-		// non-optimized case
-		super.findIndexMatches(input, requestor, participant, scope, progressMonitor);	
-		return;
-	}
-
-	if (progressMonitor != null && progressMonitor.isCanceled()) throw new OperationCanceledException();
-
-	/* narrow down a set of entries using prefix criteria */
-	EntryResult[] entries = (EntryResult[]) this.entryResults.get(input);
-	if (entries == null) {
-		entries = input.queryEntriesPrefixedBy(SUPER_REF);
-		if (entries == null)
-			entries = NO_ENTRY_RESULT;
-		this.entryResults.put(input, entries);
-	}
-	if (entries == NO_ENTRY_RESULT) return;
-
-	/* only select entries which actually match the entire search pattern */
-	int slash = SUPER_REF.length;
-	char[] name = this.superSimpleName;
-	int length = name == null ? 0 : name.length;
-	nextEntry: for (int i = 0, max = entries.length; i < max; i++) {
-		/* check that the entry is a super ref to the super simple name */
-		EntryResult entry = entries[i];
-		if (name != null) {
-			char[] word = entry.getWord();
-			if (slash + length >= word.length) continue;
-			
-			// ensure it is the end of the ref (a simple name is not a prefix of ref)
-			if (word[length + slash] != '/') continue; 
-			
-			// compare ref to simple name
-			for (int j = 0; j < length; j++)
-				if (word[j + slash] != name[j]) continue nextEntry;
-		}
-
-		/* retrieve and decode entry */	
-		char[] word = entry.getWord();
-		char[] indexKey = CharOperation.subarray(word, SUPER_REF.length, word.length);
-		SearchPattern record = getIndexRecord();
-		record.decodeIndexKey(indexKey);
-
-		int[] references = entry.getFileReferences();
-		for (int iReference = 0, refererencesLength = references.length; iReference < refererencesLength; iReference++) {
-			String documentPath = IndexedFile.convertPath( input.getIndexedFile(references[iReference]).getPath());
-			if (scope.encloses(documentPath)) {
-				if (!requestor.acceptIndexMatch(documentPath, record, participant)) 
-					throw new OperationCanceledException();
-			}
-		}
-	}
+public char[][] getIndexCategories() {
+	return CATEGORIES;
 }
-public SearchPattern getIndexRecord() {
-	return getSuperTypeReferenceRecord();
-}
-public char[][] getMatchCategories() {
-	return new char[][] {SUPER_REF};
-}
-public boolean isMatchingIndexRecord() {
-	SuperTypeReferencePattern record = getSuperTypeReferenceRecord();
+public boolean matchesDecodedKey(SearchPattern decodedPattern) {
+	SuperTypeReferencePattern pattern = (SuperTypeReferencePattern) decodedPattern;
 	if (this.checkOnlySuperinterfaces)
-		if (record.superClassOrInterface != IIndexConstants.INTERFACE_SUFFIX) return false;
+		if (pattern.superClassOrInterface != IIndexConstants.INTERFACE_SUFFIX) return false;
 
-	return matchesName(this.superSimpleName, record.superSimpleName);
+	if (pattern.superQualification != null)
+		if (!matchesName(this.superQualification, pattern.superQualification)) return false;
+
+	return matchesName(this.superSimpleName, pattern.superSimpleName);
+}
+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(getMatchMode()) {
+		case R_EXACT_MATCH :
+			// do a prefix query with the superSimpleName
+			matchRule = matchRule - R_EXACT_MATCH + R_PREFIX_MATCH;
+			if (this.superSimpleName != null)
+				key = CharOperation.append(this.superSimpleName, SEPARATOR);
+			break;
+		case R_PREFIX_MATCH :
+			// do a prefix query with the superSimpleName
+			break;
+		case R_PATTERN_MATCH :
+			// do a pattern query with the superSimpleName
+			break;
+	}
+
+	return index.query(getIndexCategories(), key, matchRule); // match rule is irrelevant when the key is null
 }
 public String toString(){
 	StringBuffer buffer = new StringBuffer(20);
@@ -274,14 +212,14 @@
 	else
 		buffer.append("*"); //$NON-NLS-1$
 	buffer.append(">, "); //$NON-NLS-1$
-	switch(matchMode()){
-		case EXACT_MATCH : 
+	switch(getMatchMode()) {
+		case R_EXACT_MATCH : 
 			buffer.append("exact match, "); //$NON-NLS-1$
 			break;
-		case PREFIX_MATCH :
+		case R_PREFIX_MATCH :
 			buffer.append("prefix match, "); //$NON-NLS-1$
 			break;
-		case PATTERN_MATCH :
+		case R_PATTERN_MATCH :
 			buffer.append("pattern match, "); //$NON-NLS-1$
 			break;
 	}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationLocator.java
index f062336..58ee864 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationLocator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -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/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationPattern.java
index 9243333..80f3a99 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationPattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationPattern.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -10,16 +10,14 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.search.matching;
 
+import java.io.IOException;
+
 import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.core.search.*;
+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 {
-
-private static ThreadLocal indexRecord = new ThreadLocal() {
-	protected Object initialValue() {
-		return new TypeDeclarationPattern(null, null, null, ' ', R_EXACT_MATCH | R_CASE_SENSITIVE);
-	}
-};
+public class TypeDeclarationPattern extends JavaSearchPattern implements IIndexConstants {
 
 public char[] simpleName;
 public char[] pkg;
@@ -30,20 +28,47 @@
 // set to TYPE_SUFFIX for matching both classes and interfaces
 public char classOrInterface; 
 
-public static char[] createIndexKey(char[] packageName, char[][] enclosingTypeNames, char[] typeName, boolean isClass) {
-	TypeDeclarationPattern record = getTypeDeclarationRecord();
-	record.pkg = packageName;
-	record.enclosingTypeNames = enclosingTypeNames;
-	record.simpleName = typeName;
-	record.classOrInterface = isClass ? CLASS_SUFFIX : INTERFACE_SUFFIX;
-	return record.encodeIndexKey();
+protected static char[][] CATEGORIES = { TYPE_DECL };
+
+public static char[] createIndexKey(char[] typeName, char[] packageName, char[][] enclosingTypeNames, char classOrInterface) {
+	int typeNameLength = typeName == null ? 0 : typeName.length;
+	int packageLength = packageName == null ? 0 : packageName.length;
+	int enclosingNamesLength = 0;
+	if (enclosingTypeNames != null) {
+		for (int i = 0, length = enclosingTypeNames.length; i < length;) {
+			enclosingNamesLength += enclosingTypeNames[i].length;
+			if (++i < length)
+				enclosingNamesLength++; // for the '.' separator
+		}
+	}
+
+	char[] result = new char[typeNameLength + packageLength + enclosingNamesLength + 4];
+	int pos = 0;
+	if (typeNameLength > 0) {
+		System.arraycopy(typeName, 0, result, pos, typeNameLength);
+		pos += typeNameLength;
+	}
+	result[pos++] = SEPARATOR;
+	if (packageLength > 0) {
+		System.arraycopy(packageName, 0, result, pos, packageLength);
+		pos += packageLength;
+	}
+	result[pos++] = SEPARATOR;
+	if (enclosingNamesLength > 0) {
+		for (int i = 0, length = enclosingTypeNames.length; i < length;) {
+			char[] enclosingName = enclosingTypeNames[i];
+			int itsLength = enclosingName.length;
+			System.arraycopy(enclosingName, 0, result, pos, itsLength);
+			pos += itsLength;
+			if (++i < length)
+				result[pos++] = '.';
+		}
+	}
+	result[pos++] = SEPARATOR;
+	result[pos] = classOrInterface;
+	return result;
 }
-public static TypeDeclarationPattern getTypeDeclarationRecord() {
-	return (TypeDeclarationPattern)indexRecord.get();
-}
-public TypeDeclarationPattern(int matchRule) {
-	super(TYPE_DECL_PATTERN, matchRule);
-}
+
 public TypeDeclarationPattern(
 	char[] pkg,
 	char[][] enclosingTypeNames,
@@ -51,11 +76,10 @@
 	char classOrInterface,
 	int matchRule) {
 
-	super(TYPE_DECL_PATTERN, matchRule);
+	this(matchRule);
 
-	boolean isCaseSensitive = isCaseSensitive();
-	this.pkg = isCaseSensitive ? pkg : CharOperation.toLowerCase(pkg);
-	if (isCaseSensitive || enclosingTypeNames == null) {
+	this.pkg = isCaseSensitive() ? pkg : CharOperation.toLowerCase(pkg);
+	if (isCaseSensitive() || enclosingTypeNames == null) {
 		this.enclosingTypeNames = enclosingTypeNames;
 	} else {
 		int length = enclosingTypeNames.length;
@@ -63,136 +87,106 @@
 		for (int i = 0; i < length; i++)
 			this.enclosingTypeNames[i] = CharOperation.toLowerCase(enclosingTypeNames[i]);
 	}
-	this.simpleName = isCaseSensitive ? simpleName : CharOperation.toLowerCase(simpleName);
+	this.simpleName = isCaseSensitive() ? simpleName : CharOperation.toLowerCase(simpleName);
 	this.classOrInterface = classOrInterface;
-	
-	this.mustResolve = pkg != null && enclosingTypeNames != null;
+
+	((InternalSearchPattern)this).mustResolve = this.pkg != null && this.enclosingTypeNames != null;
+}
+TypeDeclarationPattern(int matchRule) {
+	super(TYPE_DECL_PATTERN, matchRule);
 }
 /*
- * Type entries are encoded as 'typeDecl/' ('C' | 'I') '/' PackageName '/' TypeName '/' EnclosingTypeName
- * e.g. typeDecl/C/java.lang/Object/
- * e.g. typeDecl/I/java.lang/Cloneable/
- * e.g. typeDecl/C/javax.swing/LazyValue/UIDefaults
- * 
- * Current encoding is optimized for queries: all classes/interfaces
+ * Type entries are encoded as simpleTypeName / packageName / enclosingTypeName / 'C' or 'I'
+ * e.g. Object/java.lang//C
+ * e.g. Cloneable/java.lang//I
+ * e.g. LazyValue/javax.swing/UIDefaults/C
  */
 public void decodeIndexKey(char[] key) {
-	int size = key.length;
+	int slash = CharOperation.indexOf(SEPARATOR, key, 0);
+	this.simpleName = CharOperation.subarray(key, 0, slash);
 
-	this.classOrInterface = key[0];
-	int oldSlash = 1;
-	int slash = CharOperation.indexOf(SEPARATOR, key, oldSlash + 1);
-	this.pkg = (slash == oldSlash + 1)
-		? CharOperation.NO_CHAR
-		: CharOperation.subarray(key, oldSlash + 1, slash);
-	this.simpleName = CharOperation.subarray(key, slash + 1, slash = CharOperation.indexOf(SEPARATOR, key, slash + 1));
+	int start = slash + 1;
+	slash = CharOperation.indexOf(SEPARATOR, key, start);
+	this.pkg = slash == start ? CharOperation.NO_CHAR : CharOperation.subarray(key, start, slash);
 
-	if (slash+1 < size) {
-		this.enclosingTypeNames = (slash + 3 == size && key[slash + 1] == ONE_ZERO[0])
-			? ONE_ZERO_CHAR
-			: CharOperation.splitOn('/', CharOperation.subarray(key, slash+1, size-1));
-	} else {
+	slash = CharOperation.indexOf(SEPARATOR, key, start = slash + 1);
+	if (slash == start) {
 		this.enclosingTypeNames = CharOperation.NO_CHAR_CHAR;
-	}
-}
-/*
- * classOrInterface / package / simpleName / enclosingTypeNames
- */
-public char[] encodeIndexKey() {
-	char[] packageName = isCaseSensitive() ? pkg : null;
-	switch(this.classOrInterface) {
-		case CLASS_SUFFIX :
-			if (packageName == null) 
-				return new char[] {CLASS_SUFFIX, SEPARATOR};
-			break;
-		case INTERFACE_SUFFIX :
-			if (packageName == null) 
-				return new char[] {INTERFACE_SUFFIX, SEPARATOR};
-			break;
-		default :
-			return CharOperation.NO_CHAR; // cannot do better given encoding
+	} else {
+		char[] names = CharOperation.subarray(key, start, slash);
+		this.enclosingTypeNames = CharOperation.equals(ONE_ZERO, names) ? ONE_ZERO_CHAR : CharOperation.splitOn('.', names);
 	}
 
-	char[] typeName = isCaseSensitive() ? this.simpleName : null;
-	if (typeName != null && matchMode() == PATTERN_MATCH) {
-		int starPos = CharOperation.indexOf('*', typeName);
-		switch(starPos) {
-			case -1 :
-				break;
-			case 0 :
-				typeName = null;
-				break;
-			default : 
-				typeName = CharOperation.subarray(typeName, 0, starPos);
-		}
-	}
-
-	int packageLength = packageName.length;
-	int enclosingTypeNamesLength = 0;
-	if (this.enclosingTypeNames != null)
-		for (int i = 0, length = this.enclosingTypeNames.length; i < length; i++)
-			enclosingTypeNamesLength += this.enclosingTypeNames[i].length + 1;
-	int pos = 0;
-	int typeNameLength = typeName == null ? 0 : typeName.length;
-	int resultLength = pos + packageLength + typeNameLength + enclosingTypeNamesLength + 4;
-	char[] result = new char[resultLength];
-	result[pos++] = this.classOrInterface;
-	result[pos++] = SEPARATOR;
-	if (packageLength > 0) {
-		System.arraycopy(packageName, 0, result, pos, packageLength);
-		pos += packageLength;
-	}
-	result[pos++] = SEPARATOR;
-	if (typeName != null) {
-		System.arraycopy(typeName, 0, result, pos, typeNameLength);
-		pos += typeNameLength;
-
-		result[pos++] = SEPARATOR;
-		if (enclosingTypeNames != null) {
-			for (int i = 0, length = this.enclosingTypeNames.length; i < length; i++) {
-				int enclosingTypeNameLength = this.enclosingTypeNames[i].length;
-				System.arraycopy(this.enclosingTypeNames[i], 0, result, pos, enclosingTypeNameLength);
-				pos += enclosingTypeNameLength;
-				result[pos++] = SEPARATOR;
-			}
-		}
-	}
-	if (pos != resultLength) {
-		System.arraycopy(result, 0, result = new char[pos], 0, pos);
-	}
-	return result;
+	this.classOrInterface = key[key.length - 1];
 }
-public SearchPattern getIndexRecord() {
-	return getTypeDeclarationRecord();
+public SearchPattern getBlankPattern() {
+	return new TypeDeclarationPattern(R_EXACT_MATCH | R_CASE_SENSITIVE);
 }
-public char[][] getMatchCategories() {
-	return new char[][] {TYPE_DECL};
+public char[][] getIndexCategories() {
+	return CATEGORIES;
 }
-public boolean isMatchingIndexRecord() {
-	TypeDeclarationPattern record = getTypeDeclarationRecord();
+public boolean matchesDecodedKey(SearchPattern decodedPattern) {
+	TypeDeclarationPattern pattern = (TypeDeclarationPattern) decodedPattern;
 	switch(this.classOrInterface) {
 		case CLASS_SUFFIX :
 		case INTERFACE_SUFFIX :
-			if (this.classOrInterface != record.classOrInterface) return false;
-		case TYPE_SUFFIX : // nothing
+			if (this.classOrInterface != pattern.classOrInterface) return false;
 	}
 
-	/* check qualification - exact match only */
-	if (this.pkg != null && !CharOperation.equals(this.pkg, record.pkg, isCaseSensitive()))
+	if (!matchesName(this.simpleName, pattern.simpleName))
 		return false;
-	/* check enclosingTypeName - exact match only */
+
+	// check package - exact match only
+	if (this.pkg != null && !CharOperation.equals(this.pkg, pattern.pkg, isCaseSensitive()))
+		return false;
+
+	// check enclosingTypeNames - exact match only
 	if (this.enclosingTypeNames != null) {
-		// empty char[][] means no enclosing type (in which case, the decoded one is the empty char array)
-		if (this.enclosingTypeNames.length == 0) {
-			if (record.enclosingTypeNames != CharOperation.NO_CHAR_CHAR) return false;
-		} else {
-			if (!CharOperation.equals(this.enclosingTypeNames, record.enclosingTypeNames, isCaseSensitive()))
-				if (!CharOperation.equals(record.enclosingTypeNames, ONE_ZERO_CHAR)) // if not a local or anonymous type
-					return false;
-		}
+		if (this.enclosingTypeNames.length == 0)
+			return pattern.enclosingTypeNames.length == 0;
+		if (this.enclosingTypeNames.length == 1 && pattern.enclosingTypeNames.length == 1)
+			return CharOperation.equals(this.enclosingTypeNames[0], pattern.enclosingTypeNames[0], isCaseSensitive());
+		if (pattern.enclosingTypeNames == ONE_ZERO_CHAR)
+			return true; // is a local or anonymous type
+		return CharOperation.equals(this.enclosingTypeNames, pattern.enclosingTypeNames, isCaseSensitive());
+	}
+	return true;
+}
+EntryResult[] queryIn(Index index) throws IOException {
+	char[] key = this.simpleName; // can be null
+	int matchRule = getMatchRule();
+
+	switch(getMatchMode()) {
+		case R_PREFIX_MATCH :
+			// do a prefix query with the simpleName
+			break;
+		case R_EXACT_MATCH :
+			if (this.simpleName != null) {
+				matchRule = matchRule - R_EXACT_MATCH + R_PREFIX_MATCH;
+				key = this.pkg == null
+					? CharOperation.append(this.simpleName, SEPARATOR)
+					: CharOperation.concat(this.simpleName, SEPARATOR, this.pkg, SEPARATOR, CharOperation.NO_CHAR);
+				break; // do a prefix query with the simpleName and possibly the pkg
+			}
+			matchRule = matchRule - R_EXACT_MATCH + R_PATTERN_MATCH;
+			// fall thru to encode the key and do a pattern query
+		case R_PATTERN_MATCH :
+			if (this.pkg == null) {
+				if (this.simpleName == null) {
+					if (this.classOrInterface == CLASS_SUFFIX || this.classOrInterface == INTERFACE_SUFFIX)
+						key = new char[] {ONE_STAR[0], SEPARATOR, this.classOrInterface}; // find all classes or all interfaces
+				} else if (this.simpleName[this.simpleName.length - 1] != '*') {
+					key = CharOperation.concat(this.simpleName, ONE_STAR, SEPARATOR);
+				}
+				break; // do a pattern query with the current encoded key
+			}
+			// must decode to check enclosingTypeNames due to the encoding of local types
+			key = CharOperation.concat(
+				this.simpleName == null ? ONE_STAR : this.simpleName, SEPARATOR, this.pkg, SEPARATOR, ONE_STAR);
+			break;
 	}
 
-	return matchesName(this.simpleName, record.simpleName);
+	return index.query(getIndexCategories(), key, matchRule); // match rule is irrelevant when the key is null
 }
 public String toString() {
 	StringBuffer buffer = new StringBuffer(20);
@@ -227,14 +221,14 @@
 	else
 		buffer.append("*"); //$NON-NLS-1$
 	buffer.append(">, "); //$NON-NLS-1$
-	switch(matchMode()){
-		case EXACT_MATCH : 
+	switch(getMatchMode()){
+		case R_EXACT_MATCH : 
 			buffer.append("exact match, "); //$NON-NLS-1$
 			break;
-		case PREFIX_MATCH :
+		case R_PREFIX_MATCH :
 			buffer.append("prefix match, "); //$NON-NLS-1$
 			break;
-		case PATTERN_MATCH :
+		case R_PATTERN_MATCH :
 			buffer.append("pattern match, "); //$NON-NLS-1$
 			break;
 	}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeReferenceLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeReferenceLocator.java
index d530ab0..de89e5a 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeReferenceLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeReferenceLocator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -33,7 +33,7 @@
 }
 protected IJavaElement findElement(IJavaElement element, int accuracy) {
 	// need exact match to be able to open on type ref
-	if (accuracy != IJavaSearchResultCollector.EXACT_MATCH) return null;
+	if (accuracy != SearchMatch.A_ACCURATE) return null;
 
 	// element that references the type must be included in the enclosing element
 	DeclarationOfReferencedTypesPattern declPattern = (DeclarationOfReferencedTypesPattern) this.pattern; 
@@ -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++)
@@ -100,11 +100,11 @@
 			: CharOperation.concat(this.pattern.qualification, this.pattern.simpleName, '.');
 		char[] qualifiedTypeName = CharOperation.concatWith(tokens, '.');
 		switch (this.matchMode) {
-			case IJavaSearchConstants.EXACT_MATCH :
-			case IJavaSearchConstants.PREFIX_MATCH :
+			case SearchPattern.R_EXACT_MATCH :
+			case SearchPattern.R_PREFIX_MATCH :
 				if (CharOperation.prefixEquals(qualifiedPattern, qualifiedTypeName, this.isCaseSensitive)) return POSSIBLE_MATCH;
 				break;
-			case IJavaSearchConstants.PATTERN_MATCH:
+			case SearchPattern.R_PATTERN_MATCH:
 				if (CharOperation.match(qualifiedPattern, qualifiedTypeName, this.isCaseSensitive)) return POSSIBLE_MATCH;
 				break;
 		}
@@ -135,21 +135,30 @@
 		// try to match all enclosing types for which the token matches as well.
 		while (typeBinding != null && lastIndex >= 0) {
 			if (resolveLevelForType(this.pattern.simpleName, this.pattern.qualification, typeBinding) == ACCURATE_MATCH) {
-				long[] positions = importRef.sourcePositions;
-				locator.report(positions[this.pattern.qualification == null ? lastIndex : 0], positions[lastIndex], element, accuracy);
+				if (locator.encloses(element)) {
+					long[] positions = importRef.sourcePositions;
+					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;
 			}
 			lastIndex--;
 			typeBinding = typeBinding.enclosingType();
 		}
 	}
-	locator.reportAccurateReference(importRef.sourceStart, importRef.sourceEnd, this.pattern.simpleName, element, accuracy);
+	locator.reportAccurateTypeReference(importRef, this.pattern.simpleName, element, accuracy);
 }
 protected void matchReportReference(ArrayTypeReference arrayRef, IJavaElement element, int accuracy, MatchLocator locator) throws CoreException {
-	if (this.pattern.simpleName == null)
-		locator.report(arrayRef.sourceStart, arrayRef.sourceEnd, element, accuracy);
-	else
-		locator.reportAccurateReference(arrayRef.sourceStart, arrayRef.sourceEnd, this.pattern.simpleName, element, accuracy);
+	if (this.pattern.simpleName == null) {
+		if (locator.encloses(element)) {
+			int offset = arrayRef.sourceStart;
+			SearchMatch match = locator.newTypeReferenceMatch(element, accuracy, offset, arrayRef.sourceEnd-offset+1, arrayRef);
+			locator.report(match);
+		}
+	} else
+		locator.reportAccurateTypeReference(arrayRef, this.pattern.simpleName, element, accuracy);
 }
 protected void matchReportReference(ASTNode reference, IJavaElement element, int accuracy, MatchLocator locator) throws CoreException {
 	if (this.isDeclarationOfReferencedTypesPattern) {
@@ -164,8 +173,11 @@
 		matchReportReference((QualifiedTypeReference) reference, element, accuracy, locator);
 	else if (reference instanceof ArrayTypeReference)
 		matchReportReference((ArrayTypeReference) reference, element, accuracy, locator);
-	else
-		super.matchReportReference(reference, element, accuracy, locator);
+	else {
+		int offset = reference.sourceStart;
+		SearchMatch match = locator.newTypeReferenceMatch(element, accuracy, offset, reference.sourceEnd-offset+1, reference);
+		locator.report(match);
+	}
 }
 protected void matchReportReference(QualifiedNameReference qNameRef, IJavaElement element, int accuracy, MatchLocator locator) throws CoreException {
 	Binding binding = qNameRef.binding;
@@ -202,15 +214,20 @@
 		ReferenceBinding refBinding = (ReferenceBinding) typeBinding; 
 		while (refBinding != null && lastIndex >= 0) {
 			if (resolveLevelForType(this.pattern.simpleName, this.pattern.qualification, refBinding) == ACCURATE_MATCH) {
-				long[] positions = qNameRef.sourcePositions;
-				locator.report(positions[this.pattern.qualification == null ? lastIndex : 0], positions[lastIndex], element, accuracy);
+				if (locator.encloses(element)) {
+					long[] positions = qNameRef.sourcePositions;
+					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;
 			}
 			lastIndex--;
 			refBinding = refBinding.enclosingType();
 		}
 	}
-	locator.reportAccurateReference(qNameRef.sourceStart, qNameRef.sourceEnd, this.pattern.simpleName, element, accuracy);
+	locator.reportAccurateTypeReference(qNameRef, this.pattern.simpleName, element, accuracy);
 }
 protected void matchReportReference(QualifiedTypeReference qTypeRef, IJavaElement element, int accuracy, MatchLocator locator) throws CoreException {
 	TypeBinding typeBinding = qTypeRef.resolvedType;
@@ -227,15 +244,23 @@
 		ReferenceBinding refBinding = (ReferenceBinding) typeBinding; 
 		while (refBinding != null && lastIndex >= 0) {
 			if (resolveLevelForType(this.pattern.simpleName, this.pattern.qualification, refBinding) == ACCURATE_MATCH) {
-				long[] positions = qTypeRef.sourcePositions;
-				locator.report(positions[this.pattern.qualification == null ? lastIndex : 0], positions[lastIndex], element, accuracy);
+				if (locator.encloses(element)) {
+					long[] positions = qTypeRef.sourcePositions;
+					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;
 			}
 			lastIndex--;
 			refBinding = refBinding.enclosingType();
 		}
 	}
-	locator.reportAccurateReference(qTypeRef.sourceStart, qTypeRef.sourceEnd, this.pattern.simpleName, element, accuracy);
+	locator.reportAccurateTypeReference(qTypeRef, this.pattern.simpleName, element, accuracy);
+}
+protected int referenceType() {
+	return IJavaElement.TYPE;
 }
 protected void reportDeclaration(ASTNode reference, IJavaElement element, MatchLocator locator, SimpleSet knownTypes) throws CoreException {
 	int maxType = -1;
@@ -297,18 +322,14 @@
 	while (maxType >= 0 && type != null) {
 		if (!knownTypes.includes(type)) {
 			if (isBinary) {
-				locator.reportBinaryMatch(resource, type, info, IJavaSearchResultCollector.EXACT_MATCH);
+				locator.reportBinaryMemberDeclaration(resource, type, info, SearchMatch.A_ACCURATE);
 			} else {
 				ClassScope scope = ((SourceTypeBinding) typeBinding).scope;
 				if (scope != null) {
 					TypeDeclaration typeDecl = scope.referenceContext;
-					locator.report(
-						resource, 
-						typeDecl.sourceStart, 
-						typeDecl.sourceEnd, 
-						type, 
-						IJavaSearchResultCollector.EXACT_MATCH, 
-						locator.getParticipant());
+					int offset = typeDecl.sourceStart;
+					SearchMatch match = new TypeDeclarationMatch(type, SearchMatch.A_ACCURATE, offset, typeDecl.sourceEnd-offset+1, locator.getParticipant(), resource);
+					locator.report(match);
 				}
 			}
 			knownTypes.add(type);
@@ -341,6 +362,13 @@
 	if (typeBinding instanceof ProblemReferenceBinding)
 		typeBinding = ((ProblemReferenceBinding) typeBinding).original;
 
+	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;
+	}
+
 	return resolveLevelForTypeOrEnclosingTypes(this.pattern.simpleName, this.pattern.qualification, typeBinding);
 }
 protected int resolveLevel(NameReference nameRef) {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeReferencePattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeReferencePattern.java
index 8e561c9..3faf697 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeReferencePattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeReferencePattern.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -11,15 +11,10 @@
 package org.eclipse.jdt.internal.core.search.matching;
 
 import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.core.search.SearchPattern;
+import org.eclipse.jdt.internal.core.search.indexing.IIndexConstants;
 
-public class TypeReferencePattern extends AndPattern {
-
-private static ThreadLocal indexRecord = new ThreadLocal() {
-	protected Object initialValue() {
-		return new TypeReferencePattern(null, null, R_EXACT_MATCH | R_CASE_SENSITIVE);
-	}
-};
+public class TypeReferencePattern extends AndPattern implements IIndexConstants {
 
 protected char[] qualification;
 protected char[] simpleName;
@@ -30,78 +25,56 @@
 protected char[][] segments;
 protected int currentSegment;
 
-protected static char[][] CATEGORIES = { TYPE_REF, SUPER_REF, REF, CONSTRUCTOR_REF };
-protected static char[][] REF_CATEGORIES = { REF };
+protected static char[][] CATEGORIES = { REF };
 
-public static char[] createIndexKey(char[] typeName) {
-	TypeReferencePattern record = getTypeReferenceRecord();
-	record.simpleName = typeName;
-	return record.encodeIndexKey();
-}
-public static TypeReferencePattern getTypeReferenceRecord() {
-	return (TypeReferencePattern)indexRecord.get();
-}
 public TypeReferencePattern(char[] qualification, char[] simpleName, int matchRule) {
-	super(TYPE_REF_PATTERN, matchRule);
+	this(matchRule);
 
 	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);
-	
-	this.mustResolve = true; // always resolve (in case of a simple name reference being a potential match)
+	else
+		this.segments = null;
+
+	((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);
 }
 public void decodeIndexKey(char[] key) {
-	int nameLength = CharOperation.indexOf(SEPARATOR, key);
-	if (nameLength != -1)
-		key = CharOperation.subarray(key, 0, nameLength);
-	
 	this.simpleName = key;
+}
+public SearchPattern getBlankPattern() {
+	return new TypeReferencePattern(R_EXACT_MATCH | R_CASE_SENSITIVE);
+}
+public char[] getIndexKey() {
+	if (this.simpleName != null)
+		return this.simpleName;
 
 	// Optimization, eg. type reference is 'org.eclipse.jdt.core.*'
-	this.segments[0] = key;
+	if (this.currentSegment >= 0) 
+		return this.segments[this.currentSegment];
+	return null;
 }
-public char[] encodeIndexKey() {
-	if (this.simpleName == null) // Optimization, eg. type reference is 'org.eclipse.jdt.core.*'
-		if (this.currentSegment < 0) 
-			return null;
-		else
-			return encodeIndexKey(this.segments[this.currentSegment]);
-	else
-		return encodeIndexKey(this.simpleName);
+public char[][] getIndexCategories() {
+	return CATEGORIES;
 }
-public SearchPattern getIndexRecord() {
-	return getTypeReferenceRecord();
-}
-public char[][] getMatchCategories() {
-	return this.simpleName == null ? REF_CATEGORIES : CATEGORIES;
-}
-/**
- * @see AndPattern#hasNextQuery
- */
 protected boolean hasNextQuery() {
-	if (this.simpleName != null) return false;
+	if (this.segments == null) return false;
 
 	// Optimization, eg. type reference is 'org.eclipse.jdt.core.*'
 	// if package has at least 4 segments, don't look at the first 2 since they are mostly
 	// redundant (eg. in 'org.eclipse.jdt.core.*' 'org.eclipse' is used all the time)
 	return --this.currentSegment >= (this.segments.length >= 4 ? 2 : 0);
 }
-public boolean isMatchingIndexRecord() {
-	if (this.simpleName == null) {
-		// Optimization, eg. type reference is 'org.eclipse.jdt.core.*'
-		return matchesName(this.segments[this.currentSegment], getTypeReferenceRecord().segments[0]);
-	} else {
-		return matchesName(this.simpleName, getTypeReferenceRecord().simpleName);
-	}
+public boolean matchesDecodedKey(SearchPattern decodedPattern) {
+	return true; // index key is not encoded so query results all match
 }
-/**
- * @see AndPattern#resetQuery
- */
 protected void resetQuery() {
 	/* walk the segments from end to start as it will find less potential references using 'lang' than 'java' */
-	if (this.simpleName == null)
+	if (this.segments != null)
 		this.currentSegment = this.segments.length - 1;
 }
 public String toString() {
@@ -117,14 +90,14 @@
 	else
 		buffer.append("*"); //$NON-NLS-1$
 	buffer.append(">, "); //$NON-NLS-1$
-	switch(matchMode()){
-		case EXACT_MATCH : 
+	switch(getMatchMode()) {
+		case R_EXACT_MATCH : 
 			buffer.append("exact match, "); //$NON-NLS-1$
 			break;
-		case PREFIX_MATCH :
+		case R_PREFIX_MATCH :
 			buffer.append("prefix match, "); //$NON-NLS-1$
 			break;
-		case PATTERN_MATCH :
+		case R_PATTERN_MATCH :
 			buffer.append("pattern match, "); //$NON-NLS-1$
 			break;
 	}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/VariableLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/VariableLocator.java
index 52ca6a1..c8a7f9c 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/VariableLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/VariableLocator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -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/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/VariablePattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/VariablePattern.java
index e2ebe94..61276ed 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/VariablePattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/VariablePattern.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -11,9 +11,8 @@
 package org.eclipse.jdt.internal.core.search.matching;
 
 import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.core.search.*;
 
-public abstract class VariablePattern extends SearchPattern {
+public abstract class VariablePattern extends JavaSearchPattern {
 
 protected boolean findDeclarations;
 protected boolean findReferences;
@@ -21,15 +20,8 @@
 protected boolean writeAccess;
 
 protected char[] name;
-	
-public VariablePattern(
-	int patternKind,
-	boolean findDeclarations,
-	boolean readAccess,
-	boolean writeAccess,
-	char[] name,
-	int matchRule) {
 
+public VariablePattern(int patternKind, boolean findDeclarations, boolean readAccess, boolean writeAccess, char[] name, int matchRule) {
 	super(patternKind, matchRule);
 
 	this.findDeclarations = findDeclarations; // set to find declarations & all occurences
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/pattern/InternalSearchPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/pattern/InternalSearchPattern.java
deleted file mode 100644
index ec588ff..0000000
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/pattern/InternalSearchPattern.java
+++ /dev/null
@@ -1,237 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2003 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 org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.OperationCanceledException;
-import org.eclipse.jdt.core.IJavaElement;
-import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.core.search.*;
-import org.eclipse.jdt.internal.core.JavaModelManager;
-import org.eclipse.jdt.internal.core.index.IIndex;
-import org.eclipse.jdt.internal.core.index.impl.*;
-import org.eclipse.jdt.internal.core.search.*;
-import org.eclipse.jdt.internal.core.search.indexing.IndexManager;
-import org.eclipse.jdt.internal.core.util.Util;
-
-/**
- * TODO add spec
- */
-public abstract class InternalSearchPattern {
-
-	public final int kind;
-	public final int matchRule;
-	
-	/* focus element (used for reference patterns*/
-	public IJavaElement focus;
-
-	public InternalSearchPattern(int patternKind, int matchRule) {
-		this.kind = patternKind;
-		this.matchRule = matchRule;
-	}
-	
-	/*
-	 * @see SearchPattern
-	 */
-	public abstract void decodeIndexKey(char[] key);
-
-	/*
-	 * @see SearchPattern
-	 */
-	public abstract char[] encodeIndexKey();
-
-	protected char[] encodeIndexKey(char[] key) {
-		// TODO (kent) with new index, need to encode key for case insensitive queries too
-		// also want to pass along the entire pattern
-		if (isCaseSensitive() && key != null) {
-			switch(matchMode()) {
-				case SearchPattern.R_EXACT_MATCH :
-				case  SearchPattern.R_PREFIX_MATCH :
-					return key;
-				case  SearchPattern.R_PATTERN_MATCH :
-					int starPos = CharOperation.indexOf('*', key);
-					switch(starPos) {
-						case -1 :
-							return key;
-						default : 
-							char[] result = new char[starPos];
-							System.arraycopy(key, 0, result, 0, starPos);
-							return result;
-						case 0 : // fall through
-					}
-					break;
-				case  SearchPattern.R_REGEXP_MATCH:
-					// TODO (jerome) implement
-					return key;
-			}
-		}
-		return CharOperation.NO_CHAR; // find them all
-	}
-
-	/**
-	 * Query a given index for matching entries. 
-	 */
-	public void findIndexMatches(IIndex index, IndexQueryRequestor requestor, SearchParticipant participant, IJavaSearchScope scope, IProgressMonitor progressMonitor) throws IOException {
-	
-		if (progressMonitor != null && progressMonitor.isCanceled()) throw new OperationCanceledException();
-		IndexInput input = new BlocksIndexInput(index.getIndexFile());
-		try {
-			input.open();
-			findIndexMatches(input, requestor, participant, scope, progressMonitor);
-		} finally {
-			input.close();
-		}
-	}
-	
-	/**
-	 * Query a given index for matching entries. 
-	 *
-	 */
-	public void findIndexMatches(IndexInput input, IndexQueryRequestor requestor, SearchParticipant participant, IJavaSearchScope scope, IProgressMonitor progressMonitor) throws IOException {
-	
-		char[][] categories = getMatchCategories();
-		char[] queryKey = encodeIndexKey();
-		for (int iCategory = 0, categoriesLength = categories.length; iCategory < categoriesLength; iCategory++) {
-			if (progressMonitor != null && progressMonitor.isCanceled()) throw new OperationCanceledException();
-
-			char[] category = categories[iCategory];
-			findIndexMatches(input, requestor, participant, scope, progressMonitor, queryKey, category);
-		}
-	}
-	
-	protected void findIndexMatches(IndexInput input, IndexQueryRequestor requestor, SearchParticipant participant, IJavaSearchScope scope, IProgressMonitor progressMonitor, char[] queryKey, char[] category) throws IOException {
-		/* narrow down a set of entries using prefix criteria */
-		// TODO per construction the queryKey will always be the most specific prefix. This should evolve to be the search pattern directly, using proper match rule
-		// ideally the index query API should be defined to avoid the need for concatenating the category to the key
-		char[] pattern = CharOperation.concat(category, queryKey);
-		EntryResult[] entries = input.queryEntries(pattern, SearchPattern.R_PREFIX_MATCH);
-		if (entries == null) return;
-
-		/* only select entries which actually match the entire search pattern */
-		for (int iMatch = 0, matchesLength = entries.length; iMatch < matchesLength; iMatch++) {
-			if (progressMonitor != null && progressMonitor.isCanceled()) throw new OperationCanceledException();
-
-			/* retrieve and decode entry */	
-			EntryResult entry = entries[iMatch];
-			char[] word = entry.getWord();
-			char[] indexKey = CharOperation.subarray(word, category.length, word.length);
-			SearchPattern indexRecord = getIndexRecord();
-			indexRecord.decodeIndexKey(indexKey);
-			if (isMatchingIndexRecord()) {
-				int[] references = entry.getFileReferences();
-				for (int iReference = 0, refererencesLength = references.length; iReference < refererencesLength; iReference++) {
-					String documentPath = IndexedFile.convertPath( input.getIndexedFile(references[iReference]).getPath());
-					if (scope.encloses(documentPath)) {
-						if (!requestor.acceptIndexMatch(documentPath, indexRecord, participant)) 
-							throw new OperationCanceledException();
-					}
-				}
-			}
-		}
-	}
-
-	/**
-	 * Searches for matches to a given query. Search queries can be created using helper
-	 * methods (from a String pattern or a Java element) and encapsulate the description of what is
-	 * being searched (for example, search method declarations in a case sensitive way).
-	 *
-	 * @param scope the search result has to be limited to the given scope
-	 * @param resultCollector a callback object to which each match is reported
-	 */
-	public void findMatches(SearchParticipant[] participants, IJavaSearchScope scope, SearchRequestor requestor, IProgressMonitor monitor) throws CoreException {
-		
-		if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
-		
-		/* initialize progress monitor */
-		if (monitor != null) {
-			monitor.beginTask(Util.bind("engine.searching"), 100); //$NON-NLS-1$
-		}
-
-		if (SearchEngine.VERBOSE) {
-			System.out.println("Searching for " + this + " in " + scope); //$NON-NLS-1$//$NON-NLS-2$
-		}
-	
-		IndexManager indexManager = JavaModelManager.getJavaModelManager().getIndexManager();
-		try {
-			requestor.beginReporting();
-			
-			for (int iParticipant = 0, length = participants == null ? 0 : participants.length; iParticipant < length; iParticipant++) {
-				
-				if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
-	
-				SearchParticipant participant = participants[iParticipant];
-				try {
-					participant.beginSearching();
-					requestor.enterParticipant(participant);
-		
-					// find index matches			
-					PathCollector pathCollector = new PathCollector();
-					indexManager.performConcurrentJob(
-						new PatternSearchJob(
-							(SearchPattern)this, 
-							participant,
-							scope, 
-							pathCollector),
-						IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH,
-						monitor);
-					if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
-		
-					// locate index matches if any (note that all search matches could have been issued during index querying)
-					String[] indexMatchPaths = pathCollector.getPaths();
-					pathCollector = null; // release
-					int indexMatchLength = indexMatchPaths == null ? 0 : indexMatchPaths.length;
-					SearchDocument[] indexMatches = new SearchDocument[indexMatchLength];
-					for (int iMatch = 0;iMatch < indexMatchLength; iMatch++) {
-						String documentPath = indexMatchPaths[iMatch];
-						indexMatches[iMatch] = participant.getDocument(documentPath);
-					}
-					participant.locateMatches(indexMatches, (SearchPattern)this, scope, requestor, monitor);
-				} finally {		
-					requestor.exitParticipant(participant);
-					participant.doneSearching();
-				}
-
-				if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
-			}
-		} finally {
-			requestor.endReporting();
-			if (monitor != null) monitor.done();
-		}
-	}			
-
-	public abstract SearchPattern getIndexRecord();
-	
-	public abstract char[][] getMatchCategories();
-
-	public boolean isCaseSensitive() {
-		return (this.matchRule & SearchPattern.R_CASE_SENSITIVE) != 0;
-	}
-	
-	public abstract boolean isMatchingIndexRecord();
-
-	/*
-	 * Returns whether this pattern is a polymorphic search pattern.
-	 */
-	public boolean isPolymorphicSearch() {
-		return false;
-	}
-
-	/*
-	 * One of R_EXACT_MATCH, R_PATTERN_MATCH, R_PREFIX_MATCH or R_REGEDP_MATCH
-	 */
-	public int matchMode() {
-		return this.matchRule & ~SearchPattern.R_CASE_SENSITIVE;
-	}
-
-}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/IJob.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/IJob.java
index b800a59..c6f0832 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/IJob.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/IJob.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/JobManager.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/JobManager.java
index 3763cd1..1375e3a 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/JobManager.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/JobManager.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * 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
@@ -10,9 +10,11 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.search.processing;
 
+import org.eclipse.core.runtime.*;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.OperationCanceledException;
 import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.core.runtime.jobs.Job;
 import org.eclipse.jdt.internal.core.util.Util;
 
 public abstract class JobManager implements Runnable {
@@ -26,8 +28,9 @@
 	/* background processing */
 	protected Thread processingThread;
 
-	/* flag indicating whether job execution is enabled or not */
-	private boolean enabled = true;
+	/* counter indicating whether job execution is enabled or not, disabled if <= 0 
+	    it cannot go beyond 1 */
+	private int enableCount = 1;
 
 	public static boolean VERBOSE = false;
 	/* flag indicating that the activation has completed */
@@ -35,10 +38,6 @@
 	
 	private int awaitingClients = 0;
 
-	public static void verbose(String log) {
-		System.out.println("(" + Thread.currentThread() + ") " + log); //$NON-NLS-1$//$NON-NLS-2$
-	}
-
 	/**
 	 * Invoked exactly once, in background, before starting processing any job
 	 */
@@ -57,14 +56,14 @@
 	 * Until the job has completed, the job manager will keep answering the same job.
 	 */
 	public synchronized IJob currentJob() {
-		if (this.enabled && this.jobStart <= this.jobEnd)
+		if (this.enableCount > 0 && this.jobStart <= this.jobEnd)
 			return this.awaitingJobs[this.jobStart];
 		return null;
 	}
 	public void disable() {
-		this.enabled = false;
+		this.enableCount--;
 		if (VERBOSE)
-			JobManager.verbose("DISABLING background indexing"); //$NON-NLS-1$
+			Util.verbose("DISABLING background indexing"); //$NON-NLS-1$
 	}
 	/**
 	 * Remove the index from cache for a given project.
@@ -73,9 +72,8 @@
 	public void discardJobs(String jobFamily) {
 
 		if (VERBOSE)
-			JobManager.verbose("DISCARD   background job family - " + jobFamily); //$NON-NLS-1$
+			Util.verbose("DISCARD   background job family - " + jobFamily); //$NON-NLS-1$
 
-		boolean wasEnabled = isEnabled();
 		try {
 			IJob currentJob;
 			// cancel current job if it belongs to the given family
@@ -90,7 +88,7 @@
 				while (this.processingThread != null && this.executing){
 					try {
 						if (VERBOSE)
-							JobManager.verbose("-> waiting end of current background job - " + currentJob); //$NON-NLS-1$ //$NON-NLS-2$
+							Util.verbose("-> waiting end of current background job - " + currentJob); //$NON-NLS-1$ //$NON-NLS-2$
 						Thread.sleep(50);
 					} catch(InterruptedException e){
 						// ignore
@@ -108,7 +106,7 @@
 						this.awaitingJobs[++loc] = currentJob;
 					} else {
 						if (VERBOSE)
-							JobManager.verbose("-> discarding background job  - " + currentJob); //$NON-NLS-1$
+							Util.verbose("-> discarding background job  - " + currentJob); //$NON-NLS-1$
 						currentJob.cancel();
 					}
 				}
@@ -116,21 +114,17 @@
 				this.jobEnd = loc;
 			}
 		} finally {
-			if (wasEnabled)
-				enable();
+			enable();
 		}
 		if (VERBOSE)
-			JobManager.verbose("DISCARD   DONE with background job family - " + jobFamily); //$NON-NLS-1$
+			Util.verbose("DISCARD   DONE with background job family - " + jobFamily); //$NON-NLS-1$
 	}
 	public synchronized void enable() {
-		this.enabled = true;
+		this.enableCount++;
 		if (VERBOSE)
-			JobManager.verbose("ENABLING  background indexing"); //$NON-NLS-1$
+			Util.verbose("ENABLING  background indexing"); //$NON-NLS-1$
 		this.notifyAll(); // wake up the background thread if it is waiting (context must be synchronized)			
 	}
-	public boolean isEnabled() {
-		return this.enabled;
-	}
 	/**
 	 * Advance to the next available job, once the current one has been completed.
 	 * Note: clients awaiting until the job count is zero are still waiting at this point.
@@ -169,7 +163,7 @@
 	 */
 	public boolean performConcurrentJob(IJob searchJob, int waitingPolicy, IProgressMonitor progress) {
 		if (VERBOSE)
-			JobManager.verbose("STARTING  concurrent job - " + searchJob); //$NON-NLS-1$
+			Util.verbose("STARTING  concurrent job - " + searchJob); //$NON-NLS-1$
 
 		searchJob.ensureReadyToRun();
 
@@ -182,25 +176,23 @@
 
 				case IJob.ForceImmediate :
 					if (VERBOSE)
-						JobManager.verbose("-> NOT READY - forcing immediate - " + searchJob);//$NON-NLS-1$
-					boolean wasEnabled = isEnabled();
+						Util.verbose("-> NOT READY - forcing immediate - " + searchJob);//$NON-NLS-1$
 					try {
 						disable(); // pause indexing
 						status = searchJob.execute(progress == null ? null : new SubProgressMonitor(progress, concurrentJobWork));
 					} finally {
-						if (wasEnabled)
-							enable();
+						enable();
 					}
 					if (VERBOSE)
-						JobManager.verbose("FINISHED  concurrent job - " + searchJob); //$NON-NLS-1$
+						Util.verbose("FINISHED  concurrent job - " + searchJob); //$NON-NLS-1$
 					return status;
 
 				case IJob.CancelIfNotReady :
 					if (VERBOSE)
-						JobManager.verbose("-> NOT READY - cancelling - " + searchJob); //$NON-NLS-1$
+						Util.verbose("-> NOT READY - cancelling - " + searchJob); //$NON-NLS-1$
 					if (progress != null) progress.setCanceled(true);
 					if (VERBOSE)
-						JobManager.verbose("CANCELED concurrent job - " + searchJob); //$NON-NLS-1$
+						Util.verbose("CANCELED concurrent job - " + searchJob); //$NON-NLS-1$
 					throw new OperationCanceledException();
 
 				case IJob.WaitUntilReady :
@@ -231,7 +223,7 @@
 							// currentJob can be null when jobs have been added to the queue but job manager is not enabled
 							if (currentJob != null && currentJob != previousJob) {
 								if (VERBOSE)
-									JobManager.verbose("-> NOT READY - waiting until ready - " + searchJob);//$NON-NLS-1$
+									Util.verbose("-> NOT READY - waiting until ready - " + searchJob);//$NON-NLS-1$
 								if (subProgress != null) {
 									subProgress.subTask(
 										Util.bind("manager.filesToIndex", Integer.toString(awaitingWork))); //$NON-NLS-1$
@@ -241,7 +233,7 @@
 							}
 							try {
 								if (VERBOSE)
-									JobManager.verbose("-> GOING TO SLEEP - " + searchJob);//$NON-NLS-1$
+									Util.verbose("-> GOING TO SLEEP - " + searchJob);//$NON-NLS-1$
 								Thread.sleep(50);
 							} catch (InterruptedException e) {
 								// ignore
@@ -262,7 +254,7 @@
 		if (progress != null)
 			progress.done();
 		if (VERBOSE)
-			JobManager.verbose("FINISHED  concurrent job - " + searchJob); //$NON-NLS-1$
+			Util.verbose("FINISHED  concurrent job - " + searchJob); //$NON-NLS-1$
 		return status;
 	}
 	public abstract String processName();
@@ -280,17 +272,17 @@
 		}
 		this.awaitingJobs[this.jobEnd] = job;
 		if (VERBOSE) {
-			JobManager.verbose("REQUEST   background job - " + job); //$NON-NLS-1$
-			JobManager.verbose("AWAITING JOBS count: " + awaitingJobsCount()); //$NON-NLS-1$
+			Util.verbose("REQUEST   background job - " + job); //$NON-NLS-1$
+			Util.verbose("AWAITING JOBS count: " + awaitingJobsCount()); //$NON-NLS-1$
 		}
 		notifyAll(); // wake up the background thread if it is waiting
 	}
 	/**
 	 * Flush current state
 	 */
-	public void reset() {
+	public synchronized void reset() {
 		if (VERBOSE)
-			JobManager.verbose("Reset"); //$NON-NLS-1$
+			Util.verbose("Reset"); //$NON-NLS-1$
 
 		if (this.processingThread != null) {
 			discardJobs(null); // discard all jobs
@@ -311,6 +303,24 @@
 		long idlingStart = -1;
 		activateProcessing();
 		try {
+			class ProgressJob extends Job {
+				ProgressJob(String name) {
+					super(name);
+				}
+				protected IStatus run(IProgressMonitor monitor) {
+					int awaitingJobsCount;
+					while ((awaitingJobsCount = awaitingJobsCount()) > 0) {
+						monitor.subTask(Util.bind("manager.filesToIndex", Integer.toString(awaitingJobsCount))); //$NON-NLS-1$
+						try {
+							Thread.sleep(500);
+						} catch (InterruptedException e) {
+							// ignore
+						}
+					}
+					return Status.OK_STATUS;
+				}
+			}
+			ProgressJob progressJob = null;
 			while (this.processingThread != null) {
 				try {
 					IJob job;
@@ -320,6 +330,7 @@
 
 						// must check for new job inside this sync block to avoid timing hole
 						if ((job = currentJob()) == null) {
+							if (progressJob != null) progressJob = null;
 							if (idlingStart < 0)
 								idlingStart = System.currentTimeMillis();
 							else
@@ -336,17 +347,23 @@
 						continue;
 					}
 					if (VERBOSE) {
-						JobManager.verbose(awaitingJobsCount() + " awaiting jobs"); //$NON-NLS-1$
-						JobManager.verbose("STARTING background job - " + job); //$NON-NLS-1$
+						Util.verbose(awaitingJobsCount() + " awaiting jobs"); //$NON-NLS-1$
+						Util.verbose("STARTING background job - " + job); //$NON-NLS-1$
 					}
 					try {
 						this.executing = true;
+						if (progressJob == null) {
+							progressJob = new ProgressJob(Util.bind("manager.indexingInProgress")); //$NON-NLS-1$
+							progressJob.setPriority(Job.LONG);
+							progressJob.setSystem(true);
+							progressJob.schedule();
+						}
 						/*boolean status = */job.execute(null);
 						//if (status == FAILED) request(job);
 					} finally {
 						this.executing = false;
 						if (VERBOSE)
-							JobManager.verbose("FINISHED background job - " + job); //$NON-NLS-1$
+							Util.verbose("FINISHED background job - " + job); //$NON-NLS-1$
 						moveToNextJob();
 						if (this.awaitingClients == 0)
 							Thread.sleep(50);
@@ -383,6 +400,9 @@
 	 */
 	public void shutdown() {
 
+		if (VERBOSE)
+			Util.verbose("Shutdown"); //$NON-NLS-1$
+
 		disable();
 		discardJobs(null); // will wait until current executing job has completed
 		Thread thread = this.processingThread;
@@ -401,7 +421,7 @@
 	}
 	public String toString() {
 		StringBuffer buffer = new StringBuffer(10);
-		buffer.append("Enabled:").append(this.enabled).append('\n'); //$NON-NLS-1$
+		buffer.append("Enable count:").append(this.enableCount).append('\n'); //$NON-NLS-1$
 		int numJobs = this.jobEnd - this.jobStart + 1;
 		buffer.append("Jobs in queue:").append(numJobs).append('\n'); //$NON-NLS-1$
 		for (int i = 0; i < numJobs && i < 15; i++) {