New compiler level v_785_R33x
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/BindingKey.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/BindingKey.java
index 2196a29..c3234b5 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/BindingKey.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/BindingKey.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005 IBM Corporation and others.
+ * Copyright (c) 2005, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -67,8 +67,13 @@
 	 * For example:
 	 * <pre>
 	 * <code>
-	 * createParameterizedTypeBindingKey("Ljava/util/Map<TK;TV;>;", new String[] {"Ljava/lang/String;", "Ljava/lang/Object;"}) -> "Ljava/util/Map<Ljava/lang/String;Ljava/lang/Object;>;"
-	 * createParameterizedTypeBindingKey("Ljava/util/List<TE;>;", new String[] {}) -> "Ljava/util/List<>;"
+	 * createParameterizedTypeBindingKey(
+	 *     "Ljava/util/Map&lt;TK;TV;&gt;;", 
+	 *     new String[] {"Ljava/lang/String;", "Ljava/lang/Object;"}) -&gt; 
+	 *       "Ljava/util/Map&lt;Ljava/lang/String;Ljava/lang/Object;&gt;;"
+	 * createParameterizedTypeBindingKey(
+	 *     "Ljava/util/List&lt;TE;&gt;;", new String[] {}) -&gt; 
+	 *       "Ljava/util/List&lt;&gt;;"
 	 * </code>
 	 * </pre>
 	 * </p>
@@ -121,8 +126,10 @@
 	 * For example:
 	 * <pre>
 	 * <code>
-	 * createTypeVariableBindingKey("T", "Ljava/util/List<TE;>;") -> "Ljava/util/List<TE;>;:TT;"
-	 * createTypeVariableBindingKey("SomeTypeVariable", "Lp/X;.foo()V") -> "Lp/X;.foo()V:TSomeTypeVariable;"
+	 * createTypeVariableBindingKey("T", "Ljava/util/List&lt;TE;&gt;;") -&gt; 
+	 *   "Ljava/util/List&lt;TE;&gt;;:TT;"
+	 * createTypeVariableBindingKey("SomeTypeVariable", "Lp/X;.foo()V") -&gt; 
+	 *   "Lp/X;.foo()V:TSomeTypeVariable;"
 	 * </code>
 	 * </pre>
 	 * </p>
@@ -150,9 +157,11 @@
 	 * For example:
 	 * <pre>
 	 * <code>
-	 * createWilcardTypeBindingKey(null, Signature.C_STAR) -> "*"
-	 * createWilcardTypeBindingKey("Ljava/util/List<TE;>;", Signature.C_SUPER) -> "-Ljava/util/List<TE;>;"
-	 * createWilcardTypeBindingKey("Ljava/util/ArrayList;", Signature.C_EXTENDS) -> "+Ljava/util/ArrayList;"
+	 * createWilcardTypeBindingKey(null, Signature.C_STAR) -&gt; "*"
+	 * createWilcardTypeBindingKey("Ljava/util/List&lt;TE;&gt;;",
+	 *    Signature.C_SUPER) -&gt; "-Ljava/util/List&lt;TE;&gt;;"
+	 * createWilcardTypeBindingKey("Ljava/util/ArrayList;", Signature.C_EXTENDS) -&gt;
+	 *    "+Ljava/util/ArrayList;"
 	 * </code>
 	 * </pre>
 	 * </p>
@@ -173,7 +182,21 @@
 		}
 		return null;
 	}
-	
+
+	/**
+	 * Returns the thrown exception signatures of the element represented by this binding key.
+	 * If this binding key does not  represent a method or does not throw any exception,
+	 * returns an empty array.
+	 * 
+	 * @return the thrown exceptions signatures
+	 * @since 3.3
+	 */
+	public String[] getThrownExceptions() {
+		KeyToSignature keyToSignature = new KeyToSignature(this.key, KeyToSignature.THROWN_EXCEPTIONS);
+		keyToSignature.parse();
+		return keyToSignature.getThrownExceptions();
+	}
+
 	/**
 	 * Returns the type argument signatures of the element represented by this binding key.
 	 * If this binding key doesn't represent a parameterized type or a parameterized method,
@@ -221,15 +244,15 @@
 	}
 	
 	/**
-	 * Internal method.
-	 * <p>
-	 * This method transforms this binding key into a signature. 
-	 * This method is not intended to be called by clients.
-	 * </p>
+	 * Transforms this binding key into a resolved signature.
+	 * If this binding key represents a field, the returned signature is
+	 * the declaring type's signature.
 	 * 
-	 * @return the signature for this binding key
+	 * @return the resolved signature for this binding key
+	 * @see Signature
+	 * @since 3.2
 	 */
-	public String internalToSignature() {
+	public String toSignature() {
 		KeyToSignature keyToSignature = new KeyToSignature(this.key, KeyToSignature.SIGNATURE);
 		keyToSignature.parse();
 		return keyToSignature.signature.toString();
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/BufferChangedEvent.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/BufferChangedEvent.java
index b03507c..2b09ad9 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/BufferChangedEvent.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/BufferChangedEvent.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ClasspathContainerInitializer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ClasspathContainerInitializer.java
index 578a8a2..a1c437b 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ClasspathContainerInitializer.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ClasspathContainerInitializer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -17,8 +17,8 @@
  *******************************************************************************/
 package org.eclipse.jdt.core;
 
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.*;
+import org.eclipse.jdt.internal.core.JavaModelStatus;
 
 /**
  * Abstract base implementation of all classpath container initializer.
@@ -27,22 +27,44 @@
  * <p>
  * Clients should subclass this class to implement a specific classpath
  * container initializer. The subclass must have a public 0-argument
- * constructor and a concrete implementation of <code>initialize</code>.
+ * constructor and a concrete implementation of {@link #initialize(IPath, IJavaProject)}.
  * <p>
  * Multiple classpath containers can be registered, each of them declares
  * the container ID they can handle, so as to narrow the set of containers they
- * can resolve, in other words, a container initializer is guaranteed to only be 
+ * can resolve, in other words, a container initializer is guaranteed to only be
  * activated to resolve containers which match the ID they registered onto.
  * <p>
  * In case multiple container initializers collide on the same container ID, the first
  * registered one will be invoked.
- * 
+ *
  * @see IClasspathEntry
  * @see IClasspathContainer
  * @since 2.0
  */
 public abstract class ClasspathContainerInitializer {
-	
+
+	/**
+	 * Status code indicating that an attribute is not supported.
+	 *
+	 * @see #getAccessRulesStatus(IPath, IJavaProject)
+	 * @see #getAttributeStatus(IPath, IJavaProject, String)
+	 * @see #getSourceAttachmentStatus(IPath, IJavaProject)
+	 *
+	 * @since 3.3
+	 */
+	public static final int ATTRIBUTE_NOT_SUPPORTED = 1;
+
+	/**
+	 * Status code indicating that an attribute is not modifiable.
+	 *
+	 * @see #getAccessRulesStatus(IPath, IJavaProject)
+	 * @see #getAttributeStatus(IPath, IJavaProject, String)
+	 * @see #getSourceAttachmentStatus(IPath, IJavaProject)
+	 *
+	 * @since 3.3
+	 */
+	public static final int ATTRIBUTE_READ_ONLY = 2;
+
    /**
      * Creates a new classpath container initializer.
      */
@@ -59,7 +81,7 @@
      * the second segment can be used as an additional hint when performing the resolution.
      * <p>
      * The initializer is invoked if a container path needs to be resolved for a given project, and no
-     * value for it was recorded so far. The implementation of the initializer would typically set the 
+     * value for it was recorded so far. The implementation of the initializer would typically set the
      * corresponding container using <code>JavaCore#setClasspathContainer</code>.
      * <p>
      * A container initialization can be indirectly performed while attempting to resolve a project
@@ -69,10 +91,10 @@
      * infinite regression of initializations.
      * <p>
      * A container initialization may also occur indirectly when setting a project classpath, as the operation
-     * needs to resolve the classpath for validation purpose. While the operation is in progress, a referenced 
-     * container initializer may be invoked. If the initializer further tries to access the referring project classpath, 
-     * it will not see the new assigned classpath until the operation has completed. Note that once the Java 
-     * change notification occurs (at the end of the operation), the model has been updated, and the project 
+     * needs to resolve the classpath for validation purpose. While the operation is in progress, a referenced
+     * container initializer may be invoked. If the initializer further tries to access the referring project classpath,
+     * it will not see the new assigned classpath until the operation has completed. Note that once the Java
+     * change notification occurs (at the end of the operation), the model has been updated, and the project
      * classpath can be queried normally.
 	 * <p>
 	 * This method is called by the Java model to give the party that defined
@@ -96,23 +118,23 @@
 	 * </ul>
 	 * The effects of using other Java model APIs are unspecified.
 	 * </p>
-	 * 
-     * @param containerPath a two-segment path (ID/hint) identifying the container that needs 
+	 *
+     * @param containerPath a two-segment path (ID/hint) identifying the container that needs
      * 	to be resolved
      * @param project the Java project in which context the container is to be resolved.
      *    This allows generic containers to be bound with project specific values.
      * @throws CoreException if an exception occurs during the initialization
-     * 
+     *
      * @see JavaCore#getClasspathContainer(IPath, IJavaProject)
      * @see JavaCore#setClasspathContainer(IPath, IJavaProject[], IClasspathContainer[], org.eclipse.core.runtime.IProgressMonitor)
      * @see IClasspathContainer
      */
     public abstract void initialize(IPath containerPath, IJavaProject project) throws CoreException;
-    
+
     /**
-     * Returns <code>true</code> if this container initializer can be requested to perform updates 
+     * Returns <code>true</code> if this container initializer can be requested to perform updates
      * on its own container values. If so, then an update request will be performed using
-     * <code>ClasspathContainerInitializer#requestClasspathContainerUpdate</code>/
+     * {@link #requestClasspathContainerUpdate(IPath, IJavaProject, IClasspathContainer)}.
      * <p>
      * @param containerPath the path of the container which requires to be updated
      * @param project the project for which the container is to be updated
@@ -120,24 +142,24 @@
      * @since 2.1
      */
     public boolean canUpdateClasspathContainer(IPath containerPath, IJavaProject project) {
-    	
+
 		// By default, classpath container initializers do not accept updating containers
-    	return false; 
+    	return false;
     }
 
 	/**
-	 * Request a registered container definition to be updated according to a container suggestion. The container suggestion 
-	 * only acts as a place-holder to pass along the information to update the matching container definition(s) held by the 
-	 * container initializer. In particular, it is not expected to store the container suggestion as is, but rather adjust 
+	 * Request a registered container definition to be updated according to a container suggestion. The container suggestion
+	 * only acts as a place-holder to pass along the information to update the matching container definition(s) held by the
+	 * container initializer. In particular, it is not expected to store the container suggestion as is, but rather adjust
 	 * the actual container definition based on suggested changes.
 	 * <p>
 	 * IMPORTANT: In reaction to receiving an update request, a container initializer will update the corresponding
-	 * container definition (after reconciling changes) at its earliest convenience, using 
-	 * <code>JavaCore#setClasspathContainer(IPath, IJavaProject[], IClasspathContainer[], IProgressMonitor)</code>. 
+	 * container definition (after reconciling changes) at its earliest convenience, using
+	 * {@link JavaCore#setClasspathContainer(IPath, IJavaProject[], IClasspathContainer[], IProgressMonitor)}.
 	 * Until it does so, the update will not be reflected in the Java Model.
 	 * <p>
 	 * In order to anticipate whether the container initializer allows to update its containers, the predicate
-	 * <code>JavaCore#canUpdateClasspathContainer</code> should be used.
+	 * {@link #canUpdateClasspathContainer(IPath, IJavaProject)} should be used.
 	 * <p>
 	 * @param containerPath the path of the container which requires to be updated
      * @param project the project for which the container is to be updated
@@ -147,6 +169,7 @@
 	 * @see ClasspathContainerInitializer#canUpdateClasspathContainer(IPath, IJavaProject)
 	 * @since 2.1
 	 */
+
     public void requestClasspathContainerUpdate(IPath containerPath, IJavaProject project, IClasspathContainer containerSuggestion) throws CoreException {
 
 		// By default, classpath container initializers do not accept updating containers
@@ -155,26 +178,64 @@
 	/**
 	 * Returns a readable description for a container path. A readable description for a container path can be
 	 * used for improving the display of references to container, without actually needing to resolve them.
-	 * A good implementation should answer a description consistent with the description of the associated 
-	 * target container (see <code>IClasspathContainer.getDescription()</code>).
-	 * 
+	 * A good implementation should answer a description consistent with the description of the associated
+	 * target container (see {@link IClasspathContainer#getDescription()}).
+	 *
 	 * @param containerPath the path of the container which requires a readable description
 	 * @param project the project from which the container is referenced
 	 * @return a string description of the container
 	 * @since 2.1
-	 */    
+	 */
     public String getDescription(IPath containerPath, IJavaProject project) {
-    	
+
     	// By default, a container path is the only available description
     	return containerPath.makeRelative().toString();
     }
 
+    /**
+     * Returns a classpath container that is used after this initializer failed to bind a classpath container
+     * to a {@link IClasspathContainer} for the given project. A non-<code>null</code>
+     * failure container indicates that there will be no more request to initialize the given container
+     * for the given project.
+     * <p>
+     * By default a non-<code>null</code> failure container with no classpath entries is returned.
+     * Clients wishing to get a chance to run the initializer again should override this method
+     * and return <code>null</code>.
+     * </p>
+     *
+ 	 * @param containerPath the path of the container which failed to initialize
+	 * @param project the project from which the container is referenced
+	 * @return the default failure container, or <code>null</code> if wishing to run the initializer again
+     * @since 3.3
+     */
+    public IClasspathContainer getFailureContainer(final IPath containerPath, IJavaProject project) {
+    	final String description = getDescription(containerPath, project);
+    	return
+    		new IClasspathContainer() {
+				public IClasspathEntry[] getClasspathEntries() {
+					return new IClasspathEntry[0];
+				}
+				public String getDescription() {
+					return description;
+				}
+				public int getKind() {
+					return 0;
+				}
+				public IPath getPath() {
+					return containerPath;
+				}
+				public String toString() {
+					return getDescription();
+				}
+			};
+	}
+
 	/**
 	 * Returns an object which identifies a container for comparison purpose. This allows
-	 * to eliminate redundant containers when accumulating classpath entries (e.g. 
+	 * 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 
+	 * initializer cannot be held responsible for determining comparison IDs for arbitrary
 	 * containers.
 	 * <p>
 	 * @param containerPath the path of the container which is being checked
@@ -192,5 +253,115 @@
 			return containerPath.segment(0);
 		}
 	}
+
+	/**
+	 * Returns the access rules attribute status according to this initializer.
+	 * <p>
+	 * The returned {@link IStatus status} can have one of the following severities:
+	 * <ul>
+	 * <li>{@link IStatus#OK OK}: means that the attribute is supported
+	 * 	<strong>and</strong> is modifiable</li>
+	 * <li>{@link IStatus#ERROR ERROR}: means that either the attribute
+	 * 	is not supported or is not modifiable.<br>
+	 * 	In this case, the {@link IStatus#getCode() code}will have
+	 * 	respectively the {@link #ATTRIBUTE_NOT_SUPPORTED} value
+	 * 	or the {@link #ATTRIBUTE_READ_ONLY} value.</li>
+	 * </ul>
+	 * </p><p>
+	 * The status message can contain more information.
+	 * </p><p>
+	 * If the subclass does not override this method, then the default behavior is
+	 * to return {@link IStatus#OK OK} if and only if the classpath container can
+	 * be updated (see {@link #canUpdateClasspathContainer(IPath, IJavaProject)}).
+	 * </p>
+	 *
+	 * @param containerPath the path of the container which requires to be
+	 * 	updated
+	 * @param project the project for which the container is to be updated
+	 * @return returns the access rules attribute status
+	 *
+	 * @since 3.3
+	 */
+	public IStatus getAccessRulesStatus(IPath containerPath, IJavaProject project) {
+
+		if (canUpdateClasspathContainer(containerPath, project)) {
+			return Status.OK_STATUS;
+		}
+		return new JavaModelStatus(ATTRIBUTE_READ_ONLY);
+	}
+
+	/**
+	 * Returns the extra attribute status according to this initializer.
+	 * <p>
+	 * The returned {@link IStatus status} can have one of the following severities:
+	 * <ul>
+	 * <li>{@link IStatus#OK OK}: means that the attribute is supported
+	 * 	<strong>and</strong> is modifiable</li>
+	 * <li>{@link IStatus#ERROR ERROR}: means that either the attribute
+	 * 	is not supported or is not modifiable.<br>
+	 * 	In this case, the {@link IStatus#getCode() code}will have
+	 * 	respectively the {@link #ATTRIBUTE_NOT_SUPPORTED} value
+	 * 	or the {@link #ATTRIBUTE_READ_ONLY} value.</li>
+	 * </ul>
+	 * </p><p>
+	 * The status message can contain more information.
+	 * </p><p>
+	 * If the subclass does not override this method, then the default behavior is
+	 * to return {@link IStatus#OK OK} if and only if the classpath container can
+	 * be updated (see {@link #canUpdateClasspathContainer(IPath, IJavaProject)}).
+	 * </p>
+	 *
+	 * @param containerPath the path of the container which requires to be
+	 * 	updated
+	 * @param project the project for which the container is to be updated
+	 * @param attributeKey the key of the extra attribute
+	 * @return returns the extra attribute status
+	 * @see IClasspathAttribute
+	 *
+	 * @since 3.3
+	 */
+	public IStatus getAttributeStatus(IPath containerPath, IJavaProject project, String attributeKey) {
+
+		if (canUpdateClasspathContainer(containerPath, project)) {
+			return Status.OK_STATUS;
+		}
+		return new JavaModelStatus(ATTRIBUTE_READ_ONLY);
+	}
+
+	/**
+	 * Returns the source attachment attribute status according to this initializer.
+	 * <p>
+	 * The returned {@link IStatus status} can have one of the following severities:
+	 * <ul>
+	 * <li>{@link IStatus#OK OK}: means that the attribute is supported
+	 * 	<strong>and</strong> is modifiable</li>
+	 * <li>{@link IStatus#ERROR ERROR}: means that either the attribute
+	 * 	is not supported or is not modifiable.<br>
+	 * 	In this case, the {@link IStatus#getCode() code}will have
+	 * 	respectively the {@link #ATTRIBUTE_NOT_SUPPORTED} value
+	 * 	or the {@link #ATTRIBUTE_READ_ONLY} value.</li>
+	 * </ul>
+	 * </p><p>
+	 * The status message can contain more information.
+	 * </p><p>
+	 * If the subclass does not override this method, then the default behavior is
+	 * to return {@link IStatus#OK OK} if and only if the classpath container can
+	 * be updated (see {@link #canUpdateClasspathContainer(IPath, IJavaProject)}).
+	 * </p>
+	 *
+	 * @param containerPath the path of the container which requires to be
+	 * 	updated
+	 * @param project the project for which the container is to be updated
+	 * @return returns the source attachment attribute status
+	 *
+	 * @since 3.3
+	 */
+	public IStatus getSourceAttachmentStatus(IPath containerPath, IJavaProject project) {
+
+		if (canUpdateClasspathContainer(containerPath, project)) {
+			return Status.OK_STATUS;
+		}
+		return new JavaModelStatus(ATTRIBUTE_READ_ONLY);
+	}
 }
 
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ClasspathVariableInitializer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ClasspathVariableInitializer.java
index 49d21b4..f277284 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ClasspathVariableInitializer.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ClasspathVariableInitializer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionContext.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionContext.java
index b853f87..e07e3cb 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionContext.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionContext.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005 IBM Corporation and others.
+ * Copyright (c) 2005, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -11,16 +11,79 @@
 package org.eclipse.jdt.core;
 
 import org.eclipse.jdt.internal.codeassist.InternalCompletionContext;
+import org.eclipse.jdt.internal.codeassist.complete.CompletionOnJavadoc;
 
 /**
  * Completion context.
  * 
  * Represent the context in which the completion occurs.
+ * <p>
+ * This class is not intended to be instantiated or subclassed by clients.
+ * </p>
  * 
  * @see CompletionRequestor#acceptContext(CompletionContext)
  * @since 3.1
  */
 public final class CompletionContext extends InternalCompletionContext {
+
+	/**
+	 * The completion token is unknown.
+	 * @since 3.2
+	 */
+	public static final int TOKEN_KIND_UNKNOWN = 0;
+	
+	/**
+	 * The completion token is a name.
+	 * @since 3.2
+	 */
+	public static final int TOKEN_KIND_NAME = 1;
+	/**
+	 * The completion token is a string literal.
+	 * The string literal ends quote can be not present the source.
+	 * <code>"foo"</code> or <code>"foo</code>. 
+	 * @since 3.2
+	 */
+	
+	public static final int TOKEN_KIND_STRING_LITERAL = 2;
+	/**
+	 * Tell user whether completion takes place in a javadoc comment or not.
+	 * 
+	 * @return boolean true if completion takes place in a javadoc comment, false otherwise.
+	 * @since 3.2
+	 */
+	public boolean isInJavadoc() {
+		return this.javadoc != 0;
+	}
+
+	/**
+	 * Tell user whether completion takes place in text area of a javadoc comment or not.
+	 * 
+	 * @return boolean true if completion takes place in a text area of a javadoc comment, false otherwise.
+	 * @since 3.2
+	 */
+	public boolean isInJavadocText() {
+		return (this.javadoc & CompletionOnJavadoc.TEXT) != 0;
+	}
+
+	/**
+	 * Tell user whether completion takes place in a formal reference of a javadoc tag or not.
+	 * Tags with formal reference are:
+	 * <ul>
+	 * 	<li>&#64;see</li>
+	 * 	<li>&#64;throws</li>
+	 * 	<li>&#64;exception</li>
+	 * 	<li>{&#64;link Object}</li>
+	 * 	<li>{&#64;linkplain Object}</li>
+	 * 	<li>{&#64;value} when compiler compliance is set at leats to 1.5</li>
+	 * </ul>
+	 * 
+	 * @return boolean true if completion takes place in formal reference of a javadoc tag, false otherwise.
+	 * @since 3.2
+	 */
+	public boolean isInJavadocFormalReference() {
+		return (this.javadoc & CompletionOnJavadoc.FORMAL_REFERENCE) != 0;
+	}
+
 	/**
 	 * Return signatures of expected types of a potential completion proposal at the completion position.
 	 * 
@@ -47,4 +110,137 @@
 	public char[][] getExpectedTypesKeys() {
 		return this.expectedTypesKeys;
 	}
+	
+	/**
+	 * Returns the completed token.
+	 * This token is either the identifier or Java language keyword
+	 * or the string literal under, immediately preceding, 
+	 * the original request offset. If the original request offset
+	 * is not within or immediately after an identifier or keyword or
+	 * a string literal then the returned value is <code>null</code>.
+	 * 
+	 * @return completed token or <code>null</code>
+	 * @since 3.2
+	 */
+	public char[] getToken() {
+		return this.token;
+	}
+	
+	/**
+	 * Returns the kind of completion token being proposed.
+	 * <p>
+	 * The set of different kinds of completion token is
+	 * expected to change over time. It is strongly recommended
+	 * that clients do <b>not</b> assume that the kind is one of the
+	 * ones they know about, and code defensively for the
+	 * possibility of unexpected future growth.
+	 * </p>
+	 * 
+	 * @return the kind; one of the kind constants declared on
+	 * this class whose name starts with <code>TOKEN_KIND</code>,
+	 * or possibly a kind unknown to the caller
+	 * @since 3.2
+	 */
+	public int getTokenKind() {
+		return this.tokenKind;
+	}
+	
+	/**
+	 * Returns the character index of the start of the
+	 * subrange in the source file buffer containing the
+	 * relevant token being completed. This
+	 * token is either the identifier or Java language keyword
+	 * under, or immediately preceding, the original request 
+	 * offset. If the original request offset is not within
+	 * or immediately after an identifier or keyword, then the
+	 * position returned is original request offset and the
+	 * token range is empty.
+	 * 
+	 * @return character index of token start position (inclusive)
+	 * @since 3.2
+	 */
+	public int getTokenStart() {
+		return this.tokenStart;
+	}
+	
+	/**
+	 * Returns the character index of the end (exclusive) of the subrange
+	 * in the source file buffer containing the
+	 * relevant token. When there is no relevant token, the
+	 * range is empty
+	 * (<code>getTokenEnd() == getTokenStart() - 1</code>).
+	 * 
+	 * @return character index of token end position (exclusive)
+	 * @since 3.2
+	 */
+	// TODO (david) https://bugs.eclipse.org/bugs/show_bug.cgi?id=132558
+	public int getTokenEnd() {
+		return this.tokenEnd;
+	}
+	
+	/**
+	 * Returns the offset position in the source file buffer
+	 * after which code assist is requested.
+	 * 
+	 * @return offset position in the source file buffer
+	 * @since 3.2
+	 */
+	public int getOffset() {
+		return this.offset;
+	}
+	
+	public String toString() {
+		StringBuffer buffer = new StringBuffer();
+		
+		buffer.append("completion offset="); //$NON-NLS-1$
+		buffer.append(this.offset);
+		buffer.append('\n');
+		
+		buffer.append("completion range=["); //$NON-NLS-1$
+		buffer.append(this.tokenStart);
+		buffer.append(", "); //$NON-NLS-1$
+		buffer.append(this.tokenEnd);
+		buffer.append("]\n"); //$NON-NLS-1$
+		
+		buffer.append("completion token="); //$NON-NLS-1$
+		String string = "null"; //$NON-NLS-1$
+		if(token == null) {
+			buffer.append(string);
+		} else {
+			buffer.append('\"');
+			buffer.append(this.token);
+			buffer.append('\"');
+		}
+		buffer.append('\n');
+		
+		buffer.append("expectedTypesSignatures="); //$NON-NLS-1$
+		if(this.expectedTypesSignatures == null) {
+			buffer.append(string);
+		} else {
+			buffer.append('{');
+			for (int i = 0; i < this.expectedTypesSignatures.length; i++) {
+				if(i > 0) buffer.append(',');
+				buffer.append(this.expectedTypesSignatures[i]);
+				
+			}
+			buffer.append('}');
+		}
+		buffer.append('\n');
+		
+		buffer.append("expectedTypesKeys="); //$NON-NLS-1$
+		if(expectedTypesSignatures == null) {
+			buffer.append(string);
+		} else {
+			buffer.append('{');
+			for (int i = 0; i < this.expectedTypesKeys.length; i++) {
+				if(i > 0) buffer.append(',');
+				buffer.append(this.expectedTypesKeys[i]);
+				
+			}
+			buffer.append('}');
+		}
+		buffer.append('\n');
+			
+		return buffer.toString();
+	}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionFlags.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionFlags.java
new file mode 100755
index 0000000..bda7c36
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionFlags.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core;
+
+/**
+ * Utility class for decoding additional flags in completion proposal.
+ * <p>
+ * This class provides static methods only; it is not intended to be
+ * instantiated or subclassed by clients.
+ * </p>
+ *
+ * @see CompletionProposal#getAdditionalFlags()
+ * 
+ * @since 3.3
+ */
+public final class CompletionFlags {
+	/**
+	 * Constant representing the absence of any flag
+	 */
+	public static final int Default = 0x0000;
+	
+	/**
+	 * Constant representing a static import
+	 */
+	public static final int StaticImport = 0x0001;
+
+	/**
+	 * Not instantiable.
+	 */
+	private CompletionFlags() {
+		// Not instantiable
+	}
+	
+	/**
+	 * Returns whether the given integer includes the {@link #StaticImport} flag.
+	 *
+	 * @param flags the flags
+	 * @return <code>true</code> if the {@link #StaticImport} flag is included
+	 */
+	public static boolean isStaticImport(int flags) {
+		return (flags & StaticImport) != 0;
+	}
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionProposal.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionProposal.java
index 74a3813..cf8d8bf 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionProposal.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionProposal.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004, 2005 IBM Corporation and others.
+ * Copyright (c) 2004, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -43,8 +43,8 @@
  * competing proposals.
  * </p>
  * <p>
- * The completion engine creates instances of this class; it is not
- * intended to be used by other clients.
+ * The completion engine creates instances of this class; it is not intended 
+ * to be instantiated or subclassed by clients.
  * </p>
  * 
  * @see ICodeAssist#codeComplete(int, CompletionRequestor)
@@ -411,6 +411,319 @@
 	 * @since 3.1
 	 */
 	public static final int ANNOTATION_ATTRIBUTE_REF = 13;
+
+	/**
+	 * Completion is a link reference to a field in a javadoc text.
+	 * This kind of completion might occur in a context like
+	 * <code>"	* blabla System.o^ blabla"</code> and complete it to
+	 * <code>"	* blabla {&#64;link System#out } blabla"</code>.
+	 * <p>
+	 * The following additional context information is available
+	 * for this kind of completion proposal at little extra cost:
+	 * <ul>
+	 * <li>{@link #getDeclarationSignature()} -
+	 * the type signature of the type that declares the field that is referenced
+	 * </li>
+	 * <li>{@link #getFlags()} -
+	 * the modifiers flags (including ACC_ENUM) of the field that is referenced
+	 * </li>
+	 * <li>{@link #getName()} -
+	 * the simple name of the field that is referenced
+	 * </li>
+	 * <li>{@link #getSignature()} -
+	 * the type signature of the field's type (as opposed to the
+	 * signature of the type in which the referenced field
+	 * is declared)
+	 * </li>
+	 * </ul>
+	 * </p>
+	 * 
+	 * @see #getKind()
+	 * @since 3.2
+	 */
+	public static final int JAVADOC_FIELD_REF = 14;
+
+	/**
+	 * Completion is a link reference to a method in a javadoc text.
+	 * This kind of completion might occur in a context like
+	 * <code>"	* blabla Runtime#get^ blabla"</code> and complete it to
+	 * <code>"	* blabla {&#64;link Runtime#getRuntime() }"</code>.
+	 * <p>
+	 * The following additional context information is available
+	 * for this kind of completion proposal at little extra cost:
+	 * <ul>
+	 * <li>{@link #getDeclarationSignature()} -
+	 * the type signature of the type that declares the method that is referenced
+	 * </li>
+	 * <li>{@link #getFlags()} -
+	 * the modifiers flags of the method that is referenced
+	 * </li>
+	 * <li>{@link #getName()} -
+	 * the simple name of the method that is referenced
+	 * </li>
+	 * <li>{@link #getSignature()} -
+	 * the method signature of the method that is referenced
+	 * </li>
+	 * </ul>
+	 * </p>
+	 * 
+	 * @see #getKind()
+	 * @since 3.2
+	 */
+	public static final int JAVADOC_METHOD_REF = 15;
+
+	/**
+	 * Completion is a link reference to a type in a javadoc text.
+	 * Any kind of type is allowed, including primitive types, reference types,
+	 * array types, parameterized types, and type variables.
+	 * This kind of completion might occur in a context like
+	 * <code>"	* blabla Str^ blabla"</code> and complete it to
+	 * <code>"	* blabla {&#64;link String } blabla"</code>.
+	 * <p>
+	 * The following additional context information is available
+	 * for this kind of completion proposal at little extra cost:
+	 * <ul>
+	 * <li>{@link #getDeclarationSignature()} -
+	 * the dot-based package name of the package that contains
+	 * the type that is referenced
+	 * </li>
+	 * <li>{@link #getSignature()} -
+	 * the type signature of the type that is referenced
+	 * </li>
+	 * <li>{@link #getFlags()} -
+	 * the modifiers flags (including Flags.AccInterface, AccEnum,
+	 * and AccAnnotation) of the type that is referenced
+	 * </li>
+	 * </ul>
+	 * </p>
+	 * 
+	 * @see #getKind()
+	 * @since 3.2
+	 */
+	public static final int JAVADOC_TYPE_REF = 16;
+
+	/**
+	 * Completion is a value reference to a static field in a javadoc text.
+	 * This kind of completion might occur in a context like
+	 * <code>"	* blabla System.o^ blabla"</code> and complete it to
+	 * <code>"	* blabla {&#64;value System#out } blabla"</code>.
+	 * <p>
+	 * The following additional context information is available
+	 * for this kind of completion proposal at little extra cost:
+	 * <ul>
+	 * <li>{@link #getDeclarationSignature()} -
+	 * the type signature of the type that declares the field that is referenced
+	 * </li>
+	 * <li>{@link #getFlags()} -
+	 * the modifiers flags (including ACC_ENUM) of the field that is referenced
+	 * </li>
+	 * <li>{@link #getName()} -
+	 * the simple name of the field that is referenced
+	 * </li>
+	 * <li>{@link #getSignature()} -
+	 * the type signature of the field's type (as opposed to the
+	 * signature of the type in which the referenced field
+	 * is declared)
+	 * </li>
+	 * </ul>
+	 * </p>
+	 * 
+	 * @see #getKind()
+	 * @since 3.2
+	 */
+	public static final int JAVADOC_VALUE_REF = 17;
+
+	/**
+	 * Completion is a method argument or a class/method type parameter
+	 * in javadoc param tag.
+	 * This kind of completion might occur in a context like
+	 * <code>"	* @param arg^ blabla"</code> and complete it to
+	 * <code>"	* @param argument blabla"</code>.
+	 * or
+	 * <code>"	* @param &lt;T^ blabla"</code> and complete it to
+	 * <code>"	* @param &lt;TT&gt; blabla"</code>.
+	 * <p>
+	 * The following additional context information is available
+	 * for this kind of completion proposal at little extra cost:
+	 * <ul>
+	 * <li>{@link #getDeclarationSignature()} -
+	 * the type signature of the type that declares the field that is referenced
+	 * </li>
+	 * <li>{@link #getFlags()} -
+	 * the modifiers flags (including ACC_ENUM) of the field that is referenced
+	 * </li>
+	 * <li>{@link #getName()} -
+	 * the simple name of the field that is referenced
+	 * </li>
+	 * <li>{@link #getSignature()} -
+	 * the type signature of the field's type (as opposed to the
+	 * signature of the type in which the referenced field
+	 * is declared)
+	 * </li>
+	 * </ul>
+	 * </p>
+	 * 
+	 * @see #getKind()
+	 * @since 3.2
+	 */
+	public static final int JAVADOC_PARAM_REF = 18;
+
+	/**
+	 * Completion is a javadoc block tag.
+	 * This kind of completion might occur in a context like
+	 * <code>"	* @s^ blabla"</code> and complete it to
+	 * <code>"	* @see blabla"</code>.
+	 * <p>
+	 * The following additional context information is available
+	 * for this kind of completion proposal at little extra cost:
+	 * <ul>
+	 * <li>{@link #getDeclarationSignature()} -
+	 * the type signature of the type that declares the field that is referenced
+	 * </li>
+	 * <li>{@link #getFlags()} -
+	 * the modifiers flags (including ACC_ENUM) of the field that is referenced
+	 * </li>
+	 * <li>{@link #getName()} -
+	 * the simple name of the field that is referenced
+	 * </li>
+	 * <li>{@link #getSignature()} -
+	 * the type signature of the field's type (as opposed to the
+	 * signature of the type in which the referenced field
+	 * is declared)
+	 * </li>
+	 * </ul>
+	 * </p>
+	 * 
+	 * @see #getKind()
+	 * @since 3.2
+	 */
+	public static final int JAVADOC_BLOCK_TAG = 19;
+
+	/**
+	 * Completion is a javadoc inline tag.
+	 * This kind of completion might occur in a context like
+	 * <code>"	* Insert @l^ Object"</code> and complete it to
+	 * <code>"	* Insert {&#64;link Object }"</code>.
+	 * <p>
+	 * The following additional context information is available
+	 * for this kind of completion proposal at little extra cost:
+	 * <ul>
+	 * <li>{@link #getDeclarationSignature()} -
+	 * the type signature of the type that declares the field that is referenced
+	 * </li>
+	 * <li>{@link #getFlags()} -
+	 * the modifiers flags (including ACC_ENUM) of the field that is referenced
+	 * </li>
+	 * <li>{@link #getName()} -
+	 * the simple name of the field that is referenced
+	 * </li>
+	 * <li>{@link #getSignature()} -
+	 * the type signature of the field's type (as opposed to the
+	 * signature of the type in which the referenced field
+	 * is declared)
+	 * </li>
+	 * </ul>
+	 * </p>
+	 * 
+	 * @see #getKind()
+	 * @since 3.2
+	 */
+	public static final int JAVADOC_INLINE_TAG = 20;
+
+	/**
+	 * Completion is an import of reference to a static field.
+	 * <p>
+	 * The following additional context information is available
+	 * for this kind of completion proposal at little extra cost:
+	 * <ul>
+	 * <li>{@link #getDeclarationSignature()} -
+	 * the type signature of the type that declares the field that is imported
+	 * </li>
+	 * <li>{@link #getFlags()} -
+	 * the modifiers flags (including ACC_ENUM) of the field that is imported
+	 * </li>
+	 * <li>{@link #getName()} -
+	 * the simple name of the field that is imported
+	 * </li>
+	 * <li>{@link #getSignature()} -
+	 * the type signature of the field's type (as opposed to the
+	 * signature of the type in which the referenced field
+	 * is declared)
+	 * </li>
+	 * <li>{@link #getAdditionalFlags()} -
+	 * the completion flags (including ComletionFlags.StaticImport)
+	 * of the proposed import
+	 * </li>
+	 * </ul>
+	 * </p>
+	 * 
+	 * @see #getKind()
+	 * 
+	 * @since 3.3
+	 */
+	public static final int FIELD_IMPORT = 21;
+	
+	/**
+	 * Completion is an import of reference to a static method.
+	 * <p>
+	 * The following additional context information is available
+	 * for this kind of completion proposal at little extra cost:
+	 * <ul>
+	 * <li>{@link #getDeclarationSignature()} -
+	 * the type signature of the type that declares the method that is imported
+	 * </li>
+	 * <li>{@link #getFlags()} -
+	 * the modifiers flags of the method that is imported
+	 * </li>
+	 * <li>{@link #getName()} -
+	 * the simple name of the method that is imported
+	 * </li>
+	 * <li>{@link #getSignature()} -
+	 * the method signature of the method that is imported
+	 * </li>
+	 * <li>{@link #getAdditionalFlags()} -
+	 * the completion flags (including ComletionFlags.StaticImport)
+	 * of the proposed import
+	 * </li>
+	 * </ul>
+	 * </p>
+	 * 
+	 * @see #getKind()
+	 * 
+	 * @since 3.3
+	 */
+	public static final int METHOD_IMPORT = 22;
+	
+	/**
+	 * Completion is an import of reference to a type.
+	 * Only reference to reference types are allowed.
+	 * <p>
+	 * The following additional context information is available
+	 * for this kind of completion proposal at little extra cost:
+	 * <ul>
+	 * <li>{@link #getDeclarationSignature()} -
+	 * the dot-based package name of the package that contains
+	 * the type that is imported
+	 * </li>
+	 * <li>{@link #getSignature()} -
+	 * the type signature of the type that is imported
+	 * </li>
+	 * <li>{@link #getFlags()} -
+	 * the modifiers flags (including Flags.AccInterface, AccEnum,
+	 * and AccAnnotation) of the type that is imported
+	 * </li>
+	 * <li>{@link #getAdditionalFlags()} -
+	 * the completion flags (including ComletionFlags.StaticImport)
+	 * of the proposed import
+	 * </li>
+	 * </ul>
+	 * </p>
+	 * 
+	 * @see #getKind()
+	 * 
+	 * @since 3.3
+	 */
+	public static final int TYPE_IMPORT = 23;
 	
 	/**
 	 * First valid completion kind.
@@ -424,7 +737,7 @@
 	 * 
 	 * @since 3.1
 	 */
-	protected static final int LAST_KIND = ANNOTATION_ATTRIBUTE_REF;
+	protected static final int LAST_KIND = TYPE_IMPORT;
 	
 	/**
 	 * Kind of completion request.
@@ -513,6 +826,13 @@
 	private char[] key = null;
 	
 	/**
+	 * Array of required completion proposals, or <code>null</code> if none.
+	 * The proposal can not be applied if the required proposals aren't applied.
+	 * Defaults to <code>null</code>.
+	 */
+	private CompletionProposal[] requiredProposals;
+	
+	/**
 	 * Modifier flags relevant in the context, or
 	 * <code>Flags.AccDefault</code> if none.
 	 * Defaults to <code>Flags.AccDefault</code>.
@@ -520,6 +840,13 @@
 	private int flags = Flags.AccDefault;
 	
 	/**
+	 * Completion flags relevant in the context, or
+	 * <code>CompletionFlags.Default</code> if none.
+	 * Defaults to <code>CompletionFlags.Default</code>.
+	 */
+	private int additionalFlags = CompletionFlags.Default;
+	
+	/**
 	 * Parameter names (for method completions), or
 	 * <code>null</code> if none. Lazily computed.
 	 * Defaults to <code>null</code>.
@@ -566,13 +893,69 @@
 			throw new IllegalArgumentException();
 		}
 		if (this.completion == null || completionLocation < 0) {
-			throw new IllegalArgumentException();
+			// Work around for bug 132558 (https://bugs.eclipse.org/bugs/show_bug.cgi?id=132558).
+			// completionLocation can be -1 if the completion occur at the start of a file or
+			// the start of a code snippet but this API isn't design to support negative position.
+			if(this.completion == null || completionLocation != -1) {
+				throw new IllegalArgumentException();
+			}
+			completionLocation = 0;
 		}
 		this.completionKind = kind;
 		this.completionLocation = completionLocation;
 	}
 	
 	/**
+	 * Returns the completion flags relevant in the context, or
+	 * <code>CompletionFlags.Default</code> if none.
+	 * <p>
+	 * This field is available for the following kinds of
+	 * completion proposals:
+	 * <ul>
+	 * <li><code>FIELD_IMPORT</code> - completion flags
+	 * of the attribute that is referenced. Completion flags for
+	 * this proposal kind can only include <code>CompletionFlags.StaticImport</code></li>
+	 * <li><code>METHOD_IMPORT</code> - completion flags
+	 * of the attribute that is referenced. Completion flags for
+	 * this proposal kind can only include <code>CompletionFlags.StaticImport</code></li>
+	 * <li><code>TYPE_IMPORT</code> - completion flags
+	 * of the attribute that is referenced. Completion flags for
+	 * this proposal kind can only include <code>CompletionFlags.StaticImport</code></li>
+	 * </ul>
+	 * For other kinds of completion proposals, this method returns
+	 * <code>CompletionFlags.Default</code>.
+	 * </p>
+	 * 
+	 * @return the completion flags, or
+	 * <code>CompletionFlags.Default</code> if none
+	 * @see CompletionFlags
+	 * 
+	 * @since 3.3
+	 */
+	public int getAdditionalFlags() {
+		return this.additionalFlags;
+	}
+
+	/**
+	 * Sets the completion flags relevant in the context.
+	 * <p>
+	 * If not set, defaults to none.
+	 * </p>
+	 * <p>
+	 * The completion engine creates instances of this class and sets
+	 * its properties; this method is not intended to be used by other clients.
+	 * </p>
+	 * 
+	 * @param additionalFlags the completion flags, or
+	 * <code>CompletionFlags.Default</code> if none
+	 * 
+	 * @since 3.3
+	 */
+	public void setAdditionalFlags(int additionalFlags) {
+		this.additionalFlags = additionalFlags;
+	}
+	
+	/**
 	 * Returns the kind of completion being proposed.
 	 * <p>
 	 * The set of different kinds of completion proposals is
@@ -593,12 +976,13 @@
 	/**
 	 * Returns the character index in the source file buffer
 	 * where source completion was requested (the 
-	 * <code>offset</code>parameter to
-	 * <code>ICodeAssist.codeComplete</code>.
+	 * <code>offset</code> parameter to
+	 * <code>ICodeAssist.codeComplete</code> minus one).
 	 * 
 	 * @return character index in source file buffer
 	 * @see ICodeAssist#codeComplete(int,CompletionRequestor)
 	 */
+	// TODO (david) https://bugs.eclipse.org/bugs/show_bug.cgi?id=132558
 	public int getCompletionLocation() {
 		return this.completionLocation;
 	}
@@ -825,16 +1209,22 @@
 	 * of the annotation that declares the attribute that is referenced</li>
 	 * <li><code>ANONYMOUS_CLASS_DECLARATION</code> - type signature
 	 * of the type that is being subclassed or implemented</li>
-	 * 	<li><code>FIELD_REF</code> - type signature
+	 * 	<li><code>FIELD_IMPORT</code> - type signature
+	 * of the type that declares the field that is imported</li>
+	 *  <li><code>FIELD_REF</code> - type signature
 	 * of the type that declares the field that is referenced</li>
-	 * 	<li><code>METHOD_REF</code> - type signature
+	 * 	<li><code>METHOD_IMPORT</code> - type signature
+	 * of the type that declares the method that is imported</li>
+	 *  <li><code>METHOD_REF</code> - type signature
 	 * of the type that declares the method that is referenced</li>
 	 * 	<li><code>METHOD_DECLARATION</code> - type signature
 	 * of the type that declares the method that is being
 	 * implemented or overridden</li>
 	 * 	<li><code>PACKAGE_REF</code> - dot-based package 
 	 * name of the package that is referenced</li>
-	 * 	<li><code>TYPE_REF</code> - dot-based package 
+	 * 	<li><code>TYPE_IMPORT</code> - dot-based package 
+	 * name of the package containing the type that is imported</li>
+	 *  <li><code>TYPE_REF</code> - dot-based package 
 	 * name of the package containing the type that is referenced</li>
 	 *  <li><code>POTENTIAL_METHOD_DECLARATION</code> - type signature
 	 * of the type that declares the method that is being created</li>
@@ -924,11 +1314,13 @@
 	 * completion proposals:
 	 * <ul>
 	 *  <li><code>ANNOTATION_ATTRIBUT_REF</code> - the name of the attribute</li>
-	 * 	<li><code>FIELD_REF</code> - the name of the field</li>
+	 * 	<li><code>FIELD_IMPORT</code> - the name of the field</li>
+	 *  <li><code>FIELD_REF</code> - the name of the field</li>
 	 * 	<li><code>KEYWORD</code> - the keyword</li>
 	 * 	<li><code>LABEL_REF</code> - the name of the label</li>
 	 * 	<li><code>LOCAL_VARIABLE_REF</code> - the name of the local variable</li>
-	 * 	<li><code>METHOD_REF</code> - the name of the method (the type simple name for constructor)</li>
+	 * 	<li><code>METHOD_IMPORT</code> - the name of the method</li>
+	 *  <li><code>METHOD_REF</code> - the name of the method (the type simple name for constructor)</li>
 	 * 	<li><code>METHOD_DECLARATION</code> - the name of the method (the type simple name for constructor)</li>
 	 * 	<li><code>VARIABLE_DECLARATION</code> - the name of the variable</li>
 	 *  <li><code>POTENTIAL_METHOD_DECLARATION</code> - the name of the method</li>
@@ -976,14 +1368,20 @@
 	 * of the referenced attribute's type</li>
 	 * <li><code>ANONYMOUS_CLASS_DECLARATION</code> - method signature
 	 * of the constructor that is being invoked</li>
-	 * 	<li><code>FIELD_REF</code> - the type signature
+	 * 	<li><code>FIELD_IMPORT</code> - the type signature
+	 * of the referenced field's type</li>
+	 *  <li><code>FIELD_REF</code> - the type signature
 	 * of the referenced field's type</li>
 	 * 	<li><code>LOCAL_VARIABLE_REF</code> - the type signature
 	 * of the referenced local variable's type</li>
-	 * 	<li><code>METHOD_REF</code> - method signature
+	 * 	<li><code>METHOD_IMPORT</code> - method signature
+	 * of the method that is imported</li>
+	 *  <li><code>METHOD_REF</code> - method signature
 	 * of the method that is referenced</li>
 	 * 	<li><code>METHOD_DECLARATION</code> - method signature
 	 * of the method that is being implemented or overridden</li>
+	 * 	<li><code>TYPE_IMPORT</code> - type signature
+	 * of the type that is imported</li>
 	 * 	<li><code>TYPE_REF</code> - type signature
 	 * of the type that is referenced</li>
 	 * 	<li><code>VARIABLE_DECLARATION</code> - the type signature
@@ -1074,10 +1472,10 @@
 //	 * of the type that is being subclassed or implemented</li>
 //	 * 	<li><code>FIELD_REF</code> - the dot-based type name
 //	 * of the type that declares the field that is referenced
-//	 * or an anonymous type instanciation ("new X(){}") if it is an anonymous type</li>
+//	 * or an anonymous type instantiation ("new X(){}") if it is an anonymous type</li>
 //	 * 	<li><code>METHOD_REF</code> - the dot-based type name
 //	 * of the type that declares the method that is referenced
-//	 * or an anonymous type instanciation ("new X(){}") if it is an anonymous type</li>
+//	 * or an anonymous type instantiation ("new X(){}") if it is an anonymous type</li>
 //	 * 	<li><code>METHOD_DECLARATION</code> - the dot-based type name
 //	 * of the type that declares the method that is being
 //	 * implemented or overridden</li>
@@ -1205,7 +1603,7 @@
 //	}
 //	
 //	/**
-//	 * Returns the parameter type names without teh package fragment of
+//	 * Returns the parameter type names without the package fragment of
 //	 * the method relevant in the context, or <code>null</code> if none.
 //	 * <p>
 //	 * This field is available for the following kinds of
@@ -1280,23 +1678,33 @@
 	 * of the attribute that is referenced; 
 	 * <li><code>ANONYMOUS_CLASS_DECLARATION</code> - modifier flags
 	 * of the constructor that is referenced</li>
-	 * 	<li><code>FIELD_REF</code> - modifier flags
+	 * 	<li><code>FIELD_IMPORT</code> - modifier flags
+	 * of the field that is imported.</li>
+	 *  <li><code>FIELD_REF</code> - modifier flags
 	 * of the field that is referenced; 
 	 * <code>Flags.AccEnum</code> can be used to recognize
 	 * references to enum constants
 	 * </li>
 	 * 	<li><code>KEYWORD</code> - modifier flag
-	 * corrresponding to the modifier keyword</li>
+	 * corresponding to the modifier keyword</li>
 	 * 	<li><code>LOCAL_VARIABLE_REF</code> - modifier flags
 	 * of the local variable that is referenced</li>
+	 *  <li><code>METHOD_IMPORT</code> - modifier flags
+	 * of the method that is imported;
+	 *  </li>
 	 * 	<li><code>METHOD_REF</code> - modifier flags
 	 * of the method that is referenced;
 	 * <code>Flags.AccAnnotation</code> can be used to recognize
 	 * references to annotation type members
 	 * </li>
-	 * 	<li><code>METHOD_DECLARATION</code> - modifier flags
+	 * <li><code>METHOD_DECLARATION</code> - modifier flags
 	 * for the method that is being implemented or overridden</li>
-	 * 	<li><code>TYPE_REF</code> - modifier flags
+	 * <li><code>TYPE_IMPORT</code> - modifier flags
+	 * of the type that is imported; <code>Flags.AccInterface</code>
+	 * can be used to recognize references to interfaces, 
+	 * <code>Flags.AccEnum</code> enum types,
+	 * and <code>Flags.AccAnnotation</code> annotation types</li>
+	 * <li><code>TYPE_REF</code> - modifier flags
 	 * of the type that is referenced; <code>Flags.AccInterface</code>
 	 * can be used to recognize references to interfaces, 
 	 * <code>Flags.AccEnum</code> enum types,
@@ -1337,6 +1745,69 @@
 	}
 	
 	/**
+	 * Returns the required completion proposals.
+	 * The proposal can be apply only if these required completion proposals are also applied.
+	 * If the required proposal aren't applied the completion could create completion problems.
+	 * 
+	 * <p>
+	 * This field is available for the following kinds of
+	 * completion proposals:
+	 * <ul>
+	 * 	<li><code>FIELD_REF</code> - The allowed required proposals for this kind are:
+	 *   <ul>
+	 *    <li><code>TYPE_REF</code></li>
+	 *    <li><code>TYPE_IMPORT</code></li>
+	 *    <li><code>FIELD_IMPORT</code></li>
+	 *   </ul>
+	 * </li>
+	 * 	<li><code>METHOD_REF</code> - The allowed required proposals for this kind are:
+	 *   <ul>
+	 *    <li><code>TYPE_REF</code></li>
+	 *    <li><code>TYPE_IMPORT</code></li>
+	 *    <li><code>METHOD_IMPORT</code></li>
+	 *   </ul>
+	 *  </li>
+	 * </ul>
+	 * </p>
+	 * <p>
+	 * Other kinds of required proposals will be returned in the future, therefore clients of this
+	 * API must allow with {@link CompletionRequestor#setAllowsRequiredProposals(int, int, boolean)} 
+	 * only kinds which are in this list to avoid unexpected results in the future.
+	 * </p>
+	 * <p>
+	 * A required completion proposal cannot have required completion proposals.
+	 * </p>
+	 * 
+	 * @return the required completion proposals, or <code>null</code> if none.
+	 * 
+	 * @see CompletionRequestor#setAllowsRequiredProposals(int, int,boolean)
+	 * 
+	 * @since 3.3
+	 */
+	public CompletionProposal[] getRequiredProposals() {
+		return this.requiredProposals;
+	}
+	
+	
+	/**
+	 * Sets the list of required completion proposals, or <code>null</code> if none.
+	 * <p>
+	 * If not set, defaults to none.
+	 * </p>
+	 * <p>
+	 * The completion engine creates instances of this class and sets
+	 * its properties; this method is not intended to be used by other clients.
+	 * </p>
+	 * 
+	 * @param proposals the list of required completion proposals, or
+	 * <code>null</code> if none
+     * @since 3.3
+	 */
+	public void setRequiredProposals(CompletionProposal[] proposals) {
+		this.requiredProposals = proposals;
+	}
+	
+	/**
 	 * Finds the method parameter names.
 	 * This information is relevant to method reference (and
 	 * method declaration proposals). Returns <code>null</code>
@@ -1346,7 +1817,7 @@
 	 * </p>
 	 * <p>
 	 * <b>Note that this is an expensive thing to compute, which may require
-	 * parsing Java source files, etc. Use sparingly.
+	 * parsing Java source files, etc. Use sparingly.</b>
 	 * </p>
 	 * 
 	 * @param monitor the progress monitor, or <code>null</code> if none
@@ -1475,4 +1946,110 @@
 	public boolean isConstructor() {
 		return this.isConstructor;
 	}
+	
+	public String toString() {
+		StringBuffer buffer = new StringBuffer();
+		buffer.append('[');
+		switch(this.completionKind) {
+			case CompletionProposal.ANONYMOUS_CLASS_DECLARATION :
+				buffer.append("ANONYMOUS_CLASS_DECLARATION"); //$NON-NLS-1$
+				break;
+			case CompletionProposal.FIELD_REF :
+				buffer.append("FIELD_REF"); //$NON-NLS-1$
+				break;
+			case CompletionProposal.KEYWORD :
+				buffer.append("KEYWORD"); //$NON-NLS-1$
+				break;
+			case CompletionProposal.LABEL_REF :
+				buffer.append("LABEL_REF"); //$NON-NLS-1$
+				break;
+			case CompletionProposal.LOCAL_VARIABLE_REF :
+				buffer.append("LOCAL_VARIABLE_REF"); //$NON-NLS-1$
+				break;
+			case CompletionProposal.METHOD_DECLARATION :
+				buffer.append("METHOD_DECLARATION"); //$NON-NLS-1$
+				if(this.isConstructor) {
+					buffer.append("<CONSTRUCTOR>"); //$NON-NLS-1$
+				}
+				break;
+			case CompletionProposal.METHOD_REF :
+				buffer.append("METHOD_REF"); //$NON-NLS-1$
+				if(this.isConstructor) {
+					buffer.append("<CONSTRUCTOR>"); //$NON-NLS-1$
+				}
+				break;
+			case CompletionProposal.PACKAGE_REF :
+				buffer.append("PACKAGE_REF"); //$NON-NLS-1$
+				break;
+			case CompletionProposal.TYPE_REF :
+				buffer.append("TYPE_REF"); //$NON-NLS-1$
+				break;
+			case CompletionProposal.VARIABLE_DECLARATION :
+				buffer.append("VARIABLE_DECLARATION"); //$NON-NLS-1$
+				break;
+			case CompletionProposal.POTENTIAL_METHOD_DECLARATION :
+				buffer.append("POTENTIAL_METHOD_DECLARATION"); //$NON-NLS-1$
+				break;
+			case CompletionProposal.METHOD_NAME_REFERENCE :
+				buffer.append("METHOD_IMPORT"); //$NON-NLS-1$
+				break;
+			case CompletionProposal.ANNOTATION_ATTRIBUTE_REF :
+				buffer.append("ANNOTATION_ATTRIBUTE_REF"); //$NON-NLS-1$
+				break;
+			case CompletionProposal.JAVADOC_BLOCK_TAG :
+				buffer.append("JAVADOC_BLOCK_TAG"); //$NON-NLS-1$
+				break;
+			case CompletionProposal.JAVADOC_INLINE_TAG :
+				buffer.append("JAVADOC_INLINE_TAG"); //$NON-NLS-1$
+				break;
+			case CompletionProposal.JAVADOC_FIELD_REF:
+				buffer.append("JAVADOC_FIELD_REF"); //$NON-NLS-1$
+				break;
+			case CompletionProposal.JAVADOC_METHOD_REF :
+				buffer.append("JAVADOC_METHOD_REF"); //$NON-NLS-1$
+				break;
+			case CompletionProposal.JAVADOC_TYPE_REF :
+				buffer.append("JAVADOC_TYPE_REF"); //$NON-NLS-1$
+				break;
+			case CompletionProposal.JAVADOC_PARAM_REF :
+				buffer.append("JAVADOC_PARAM_REF"); //$NON-NLS-1$
+				break;
+			case CompletionProposal.JAVADOC_VALUE_REF :
+				buffer.append("JAVADOC_VALUE_REF"); //$NON-NLS-1$
+				break;
+			case CompletionProposal.FIELD_IMPORT :
+				buffer.append("FIELD_IMPORT"); //$NON-NLS-1$
+				break;
+			case CompletionProposal.METHOD_IMPORT :
+				buffer.append("METHOD_IMPORT"); //$NON-NLS-1$
+				break;
+			case CompletionProposal.TYPE_IMPORT :
+				buffer.append("TYPE_IMPORT"); //$NON-NLS-1$
+				break;
+			default :
+				buffer.append("PROPOSAL"); //$NON-NLS-1$
+				break;
+				
+		}
+		buffer.append("]{completion:"); //$NON-NLS-1$
+		if (this.completion != null) buffer.append(this.completion);
+		buffer.append(", declSign:"); //$NON-NLS-1$
+		if (this.declarationSignature != null) buffer.append(this.declarationSignature);  
+		buffer.append(", sign:"); //$NON-NLS-1$
+		if (this.signature != null) buffer.append(this.signature);
+		buffer.append(", declKey:"); //$NON-NLS-1$
+		if (this.declarationKey != null) buffer.append(this.declarationKey);
+		buffer.append(", key:"); //$NON-NLS-1$
+		if (this.key != null) buffer.append(key);
+		buffer.append(", name:"); //$NON-NLS-1$
+		if (this.name != null) buffer.append(this.name);
+		buffer.append(", ["); //$NON-NLS-1$
+		buffer.append(this.replaceStart);
+		buffer.append(',');
+		buffer.append(this.replaceEnd);
+		buffer.append("], relevance="); //$NON-NLS-1$
+		buffer.append(this.relevance);
+		buffer.append('}');
+		return buffer.toString();
+	}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionRequestor.java
index f2654b6..fe1fb1c 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionRequestor.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionRequestor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004, 2005 IBM Corporation and others.
+ * Copyright (c) 2004, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -20,7 +20,7 @@
  * </p>
  * <p>
  * The code assist engine normally invokes methods on completion
- * requestors in the following sequence:
+ * requestor in the following sequence:
  * <pre>
  * requestor.beginReporting();
  * requestor.acceptContext(context);
@@ -59,6 +59,15 @@
 	 * 1 << completionProposalKind
 	 */
 	private int ignoreSet = 0;
+	
+	private String[] favoriteReferences;
+	
+	/**
+	 * The set of CompletionProposal kinds that this requestor
+	 * allows for required proposals; <code>0</code> means the set is empty.
+	 * 1 << completionProposalKind
+	 */
+	private int requiredProposalAllowSet[] = null;
 
 	/**
 	 * Creates a new completion requestor.
@@ -80,10 +89,10 @@
 	 * @see #setIgnored(int, boolean)
 	 * @see CompletionProposal#getKind()
 	 */
-	public final boolean isIgnored(int completionProposalKind) {
+	public boolean isIgnored(int completionProposalKind) {
 		if (completionProposalKind < CompletionProposal.FIRST_KIND
 			|| completionProposalKind > CompletionProposal.LAST_KIND) {
-				throw new IllegalArgumentException();
+				throw new IllegalArgumentException("Unknown kind of completion proposal: "+completionProposalKind); //$NON-NLS-1$
 		}
 		return 0 != (this.ignoreSet & (1 << completionProposalKind));
 	}
@@ -99,10 +108,10 @@
 	 * @see #isIgnored(int)
 	 * @see CompletionProposal#getKind()
 	 */
-	public final void setIgnored(int completionProposalKind, boolean ignore) {
+	public void setIgnored(int completionProposalKind, boolean ignore) {
 		if (completionProposalKind < CompletionProposal.FIRST_KIND
 			|| completionProposalKind > CompletionProposal.LAST_KIND) {
-				throw new IllegalArgumentException();
+				throw new IllegalArgumentException("Unknown kind of completion proposal: "+completionProposalKind); //$NON-NLS-1$
 		}
 		if (ignore) {
 			this.ignoreSet |= (1 << completionProposalKind);
@@ -112,6 +121,118 @@
 	}
 	
 	/**
+	 * Returns whether a proposal of a given kind with a required proposal
+	 * of the given kind is allowed.
+	 * 
+	 * @param proposalKind one of the kind constants declared
+	 * @param requiredProposalKind one of the kind constants declared
+	 * on <code>CompletionProposal</code>
+	 * @return <code>true</code> if a proposal of a given kind with a required proposal
+	 * of the given kind is allowed by this requestor, and <code>false</code> 
+	 * if it isn't of interest.
+	 * <p>
+	 * By default, all kinds of required proposals aren't allowed.
+	 * </p>
+	 * @see #setAllowsRequiredProposals(int, int, boolean)
+	 * @see CompletionProposal#getKind()
+	 * @see CompletionProposal#getRequiredProposals()
+	 * 
+	 * @since 3.3
+	 */
+	public boolean isAllowingRequiredProposals(int proposalKind, int requiredProposalKind) {
+		if (proposalKind < CompletionProposal.FIRST_KIND
+			|| proposalKind > CompletionProposal.LAST_KIND) {
+				throw new IllegalArgumentException("Unknown kind of completion proposal: "+requiredProposalKind); //$NON-NLS-1$
+			}
+		
+		if (requiredProposalKind < CompletionProposal.FIRST_KIND
+			|| requiredProposalKind > CompletionProposal.LAST_KIND) {
+				throw new IllegalArgumentException("Unknown required kind of completion proposal: "+requiredProposalKind); //$NON-NLS-1$
+		}
+		if (this.requiredProposalAllowSet == null) return false;
+		
+		return 0 != (this.requiredProposalAllowSet[proposalKind] & (1 << requiredProposalKind));
+	}
+	
+	/**
+	 * Sets whether a proposal of a given kind with a required proposal
+	 * of the given kind is allowed.
+	 * 
+	 * Currently only a subset of kinds support required proposals. To see what combinations
+	 * are supported you must look at {@link CompletionProposal#getRequiredProposals()}
+	 * documentation.
+	 * 
+	 * @param proposalKind one of the kind constants declared
+	 * @param requiredProposalKind one of the kind constants declared
+	 * on <code>CompletionProposal</code>
+	 * @param allow <code>true</code> if a proposal of a given kind with a required proposal
+	 * of the given kind is allowed by this requestor, and <code>false</code> 
+	 * if it isn't of interest
+	 * @see #isAllowingRequiredProposals(int, int)
+	 * @see CompletionProposal#getKind()
+	 * @see CompletionProposal#getRequiredProposals()
+	 * 
+	 * @since 3.3
+	 */
+	public void setAllowsRequiredProposals(int proposalKind, int requiredProposalKind, boolean allow) {
+		if (proposalKind < CompletionProposal.FIRST_KIND
+			|| proposalKind > CompletionProposal.LAST_KIND) {
+				throw new IllegalArgumentException("Unknown kind of completion proposal: "+requiredProposalKind); //$NON-NLS-1$
+		}
+		if (requiredProposalKind < CompletionProposal.FIRST_KIND
+			|| requiredProposalKind > CompletionProposal.LAST_KIND) {
+				throw new IllegalArgumentException("Unknown required kind of completion proposal: "+requiredProposalKind); //$NON-NLS-1$
+		}
+		
+		if (this.requiredProposalAllowSet == null) {
+			this.requiredProposalAllowSet = new int[CompletionProposal.LAST_KIND + 1];
+		}
+		
+		if (allow) {
+			this.requiredProposalAllowSet[proposalKind] |= (1 << requiredProposalKind);
+		} else {
+			this.requiredProposalAllowSet[proposalKind] &= ~(1 << requiredProposalKind);
+		}
+	}
+	
+	/**
+	 * Returns the favorite references which are used to compute some completion proposals.
+	 * <p>
+	 * A favorite reference is a qualified reference as it can be seen in an import statement.<br>
+	 * e.g. <code>{"java.util.Arrays"}</code><br>
+	 * It can be an on demand reference.<br>
+	 * e.g. <code>{"java.util.Arrays.*"}</code>
+	 * It can be a reference to a static method or field (as in a static import)<br>
+	 * e.g. <code>{"java.util.Arrays.equals"}</code>
+	 * </p>
+	 * <p>
+	 * Currently only on demand type references (<code>"java.util.Arrays.*"</code>),
+	 * references to a static method or a static field are used to compute completion proposals.
+	 * Other kind of reference could be used in the future.
+	 * </p>
+	 * @return favorite imports
+	 * 
+	 * @since 3.3
+	 */
+	public String[] getFavoriteReferences() {
+		return this.favoriteReferences;
+	}
+	
+	/**
+	 * Set the favorite references which will be used to compute some completion proposals.
+	 * A favorite reference is a qualified reference as it can be seen in an import statement.<br>
+	 * 
+	 * @param favoriteImports
+	 * 
+	 * @see #getFavoriteReferences()
+	 * 
+	 * @since 3.3
+	 */
+	public void setFavoriteReferences(String[] favoriteImports) {
+		this.favoriteReferences = favoriteImports;
+	}
+	
+	/**
 	 * Pro forma notification sent before reporting a batch of
 	 * completion proposals.
 	 * <p>
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionRequestorAdapter.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionRequestorAdapter.java
index 1cc38aa..bb872dc 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionRequestorAdapter.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionRequestorAdapter.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CorrectionEngine.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CorrectionEngine.java
index d873606..2b1f71f 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CorrectionEngine.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CorrectionEngine.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,6 +10,7 @@
  *******************************************************************************/
 package org.eclipse.jdt.core;
 
+import java.util.Hashtable;
 import java.util.Map;
 
 import org.eclipse.core.resources.*;
@@ -273,11 +274,19 @@
 					break;
 				}
 			}
-			
-			this.compilationUnit.codeComplete(
-				completionPosition,
-				this.completionRequestor
-			);
+			Hashtable oldOptions = JavaCore.getOptions();
+			try {
+				Hashtable options = new Hashtable(oldOptions);
+				options.put(JavaCore.CODEASSIST_CAMEL_CASE_MATCH, JavaCore.DISABLED);
+				JavaCore.setOptions(options);
+				
+				this.compilationUnit.codeComplete(
+					completionPosition,
+					this.completionRequestor
+				);
+			} finally {
+				JavaCore.setOptions(oldOptions);
+			}
 		} catch (JavaModelException e) {
 			return;
 		} catch (InvalidInputException e) {
@@ -386,6 +395,26 @@
 			}
 		}
 	};
+
+	
+	/**
+	 * Return an array of strings which contains one entry per warning token
+	 * accepted by the <code>@SuppressWarnings</code> annotation. This array is
+	 * neither null nor empty, it contains at least the String <code>all</code>.
+	 * It should not be modified by the caller (please take a copy if modifications
+	 * are needed).<br>
+	 * <b>Note:</b> The tokens returned are not necessarily standardized across Java 
+	 * compilers. If you were to use one of these tokens in a <code>@SuppressWarnings</code> 
+	 * annotation in the Java source code, the effects (if any) may vary from 
+	 * compiler to compiler.
+	 * 
+	 * @return an array of strings which contains one entry per warning token
+	 * 			accepted by the <code>@SuppressWarnings</code> annotation.
+	 * @since 3.2
+	 */
+	public static String[] getAllWarningTokens() {
+		return CompilerOptions.warningTokens;
+	}
 	
 	/**
 	 * Helper method for decoding problem marker attributes. Returns an array of String arguments
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ElementChangedEvent.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ElementChangedEvent.java
index 00a51c4..2a3ed08 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ElementChangedEvent.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ElementChangedEvent.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/Flags.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/Flags.java
index 1097d50..687af9e 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/Flags.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/Flags.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -12,7 +12,7 @@
  *******************************************************************************/
 package org.eclipse.jdt.core;
 
-import org.eclipse.jdt.internal.compiler.env.IConstants;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
 
 /**
  * Utility class for decoding modifier flags in Java elements.
@@ -35,82 +35,82 @@
 	 * Constant representing the absence of any flag
 	 * @since 3.0
 	 */
-	public static final int AccDefault = 0;
+	public static final int AccDefault = ClassFileConstants.AccDefault;
 	/**
 	 * Public access flag. See The Java Virtual Machine Specification for more details.
 	 * @since 2.0
 	 */
-	public static final int AccPublic = IConstants.AccPublic;
+	public static final int AccPublic = ClassFileConstants.AccPublic;
 	/**
 	 * Private access flag. See The Java Virtual Machine Specification for more details.
 	 * @since 2.0
 	 */
-	public static final int AccPrivate = IConstants.AccPrivate;
+	public static final int AccPrivate = ClassFileConstants.AccPrivate;
 	/**
 	 * Protected access flag. See The Java Virtual Machine Specification for more details.
 	 * @since 2.0
 	 */
-	public static final int AccProtected = IConstants.AccProtected;
+	public static final int AccProtected = ClassFileConstants.AccProtected;
 	/**
 	 * Static access flag. See The Java Virtual Machine Specification for more details.
 	 * @since 2.0
 	 */
-	public static final int AccStatic = IConstants.AccStatic;
+	public static final int AccStatic = ClassFileConstants.AccStatic;
 	/**
 	 * Final access flag. See The Java Virtual Machine Specification for more details.
 	 * @since 2.0
 	 */
-	public static final int AccFinal = IConstants.AccFinal;
+	public static final int AccFinal = ClassFileConstants.AccFinal;
 	/**
 	 * Synchronized access flag. See The Java Virtual Machine Specification for more details.
 	 * @since 2.0
 	 */
-	public static final int AccSynchronized = IConstants.AccSynchronized;
+	public static final int AccSynchronized = ClassFileConstants.AccSynchronized;
 	/**
 	 * Volatile property flag. See The Java Virtual Machine Specification for more details.
 	 * @since 2.0
 	 */
-	public static final int AccVolatile = IConstants.AccVolatile;
+	public static final int AccVolatile = ClassFileConstants.AccVolatile;
 	/**
 	 * Transient property flag. See The Java Virtual Machine Specification for more details.
 	 * @since 2.0
 	 */
-	public static final int AccTransient = IConstants.AccTransient;
+	public static final int AccTransient = ClassFileConstants.AccTransient;
 	/**
 	 * Native property flag. See The Java Virtual Machine Specification for more details.
 	 * @since 2.0
 	 */
-	public static final int AccNative = IConstants.AccNative;
+	public static final int AccNative = ClassFileConstants.AccNative;
 	/**
 	 * Interface property flag. See The Java Virtual Machine Specification for more details.
 	 * @since 2.0
 	 */
-	public static final int AccInterface = IConstants.AccInterface;
+	public static final int AccInterface = ClassFileConstants.AccInterface;
 	/**
 	 * Abstract property flag. See The Java Virtual Machine Specification for more details.
 	 * @since 2.0
 	 */
-	public static final int AccAbstract = IConstants.AccAbstract;
+	public static final int AccAbstract = ClassFileConstants.AccAbstract;
 	/**
 	 * Strictfp property flag. See The Java Virtual Machine Specification for more details.
 	 * @since 2.0
 	 */
-	public static final int AccStrictfp = IConstants.AccStrictfp;
+	public static final int AccStrictfp = ClassFileConstants.AccStrictfp;
 	/**
 	 * Super property flag. See The Java Virtual Machine Specification for more details.
 	 * @since 2.0
 	 */
-	public static final int AccSuper = IConstants.AccSuper;
+	public static final int AccSuper = ClassFileConstants.AccSuper;
 	/**
 	 * Synthetic property flag. See The Java Virtual Machine Specification for more details.
 	 * @since 2.0
 	 */
-	public static final int AccSynthetic = IConstants.AccSynthetic;
+	public static final int AccSynthetic = ClassFileConstants.AccSynthetic;
 	/**
 	 * Deprecated property flag. See The Java Virtual Machine Specification for more details.
 	 * @since 2.0
 	 */
-	public static final int AccDeprecated = IConstants.AccDeprecated;
+	public static final int AccDeprecated = ClassFileConstants.AccDeprecated;
 	
 	/**
 	 * Bridge method property flag (added in J2SE 1.5). Used to flag a compiler-generated
@@ -118,7 +118,7 @@
 	 * See The Java Virtual Machine Specification for more details.
 	 * @since 3.0
 	 */
-	public static final int AccBridge = IConstants.AccBridge;
+	public static final int AccBridge = ClassFileConstants.AccBridge;
 
 	/**
 	 * Varargs method property flag (added in J2SE 1.5).
@@ -126,21 +126,21 @@
 	 * See The Java Virtual Machine Specification for more details.
 	 * @since 3.0
 	 */
-	public static final int AccVarargs = IConstants.AccVarargs;
+	public static final int AccVarargs = ClassFileConstants.AccVarargs;
 
 	/**
 	 * Enum property flag (added in J2SE 1.5).
 	 * See The Java Virtual Machine Specification for more details.
 	 * @since 3.0
 	 */
-	public static final int AccEnum = 0x4000;
+	public static final int AccEnum = ClassFileConstants.AccEnum;
 
 	/**
 	 * Annotation property flag (added in J2SE 1.5).
 	 * See The Java Virtual Machine Specification for more details.
 	 * @since 3.0
 	 */
-	public static final int AccAnnotation = 0x2000;
+	public static final int AccAnnotation = ClassFileConstants.AccAnnotation;
 
 	/**
 	 * Not instantiable.
@@ -196,6 +196,17 @@
 		return (flags & AccNative) != 0;
 	}
 	/**
+	 * Returns whether the given integer does not include one of the 
+	 * <code>public</code>, <code>private</code>, or <code>protected</code> flags.
+	 *
+	 * @param flags the flags
+	 * @return <code>true</code> if no visibility flag is set
+	 * @since 3.2
+	 */
+	public static boolean isPackageDefault(int flags) {
+		return (flags & (AccPublic | AccPrivate | AccProtected)) == 0;
+	}
+	/**
 	 * Returns whether the given integer includes the <code>private</code> modifier.
 	 *
 	 * @param flags the flags
@@ -232,6 +243,16 @@
 		return (flags & AccStatic) != 0;
 	}
 	/**
+	 * Returns whether the given integer includes the <code>super</code> modifier.
+	 *
+	 * @param flags the flags
+	 * @return <code>true</code> if the <code>super</code> modifier is included
+	 * @since 3.2
+	 */
+	public static boolean isSuper(int flags) {
+		return (flags & AccSuper) != 0;
+	}
+	/**
 	 * Returns whether the given integer includes the <code>strictfp</code> modifier.
 	 *
 	 * @param flags the flags
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IAccessRule.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IAccessRule.java
index 9079343..ee952bb 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IAccessRule.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IAccessRule.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -70,6 +70,20 @@
 	int K_DISCOURAGED = 2;
 
 	/**
+	 * <p>Flag indicating that whether a type matching this rule should be ignored iff a type with 
+	 * the same qualified name can be found on a later classpath entry with a better 
+	 * accessibility.</p>
+	 * <p>E.g. if a type p.X matches a rule K_NON_ACCESSIBLE | IGNORE_IF_BETTER 
+	 * on a library entry 'lib1' and another type p.X also matches a rule 
+	 * K_DISCOURAGED on library entry 'lib2' ('lib2' being after 'lib1' on the 
+	 * classpath), then p.X from 'lib2' will be used and reported as 
+	 * discouraged.</p>
+	 * 
+	 * @since 3.2
+	 */
+	int IGNORE_IF_BETTER = 0x100;
+
+	/**
 	 * Returns the file pattern for this access rule.
 	 * 
 	 * @return the file pattern for this access rule
@@ -83,5 +97,22 @@
 	 * @return the kind of this access rule
 	 */
 	int getKind();
+	
+	/**
+	 * <p>Returns whether a type matching this rule should be ignored iff a type with 
+	 * the same qualified name can be found on a later classpath entry with a better 
+	 * accessibility.</p>
+	 * <p>E.g. if a type p.X matches a rule K_NON_ACCESSIBLE | IGNORE_IF_BETTER 
+	 * on a library entry 'lib1' and another type p.X also matches a rule 
+	 * K_DISCOURAGED on library entry 'lib2' ('lib2' being after 'lib1' on the 
+	 * classpath), then p.X from 'lib2' will be used and reported as 
+	 * discouraged.</p>
+	 * 
+	 * @return whether a type matching this rule should be ignored iff a type 
+	 *              with the same qualified name can be found on a later classpath 
+	 *              entry with a better accessibility
+	 * @since 3.2
+	 */
+	boolean ignoreIfBetter();
 
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IBuffer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IBuffer.java
index 79b59af..c50d704 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IBuffer.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IBuffer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IBufferChangedListener.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IBufferChangedListener.java
index b790380..2db385b 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IBufferChangedListener.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IBufferChangedListener.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IBufferFactory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IBufferFactory.java
index 171c64e..cb93d1a 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IBufferFactory.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IBufferFactory.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -16,7 +16,7 @@
  * This interface may be implemented by clients.
  * </p>
  * @since 2.0
- * @deprecated Use <code>WorkingCopyOwner</code> instead
+ * @deprecated Use {@link WorkingCopyOwner} instead
  */
 public interface IBufferFactory {
 
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClassFile.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClassFile.java
index 6d06467..b9bd115 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClassFile.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClassFile.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -13,10 +13,10 @@
 import org.eclipse.core.runtime.IProgressMonitor;
 
 /**
- * Represents an entire binary type (single <code>.class</code> file). 
+ * Represents an entire binary type (single <code>.class</code> file).
  * A class file has a single child of type <code>IType</code>.
  * Class file elements need to be opened before they can be navigated.
- * If a class file cannot be parsed, its structure remains unknown. Use 
+ * If a class file cannot be parsed, its structure remains unknown. Use
  * <code>IJavaElement.isStructureKnown</code> to determine whether this is the
  * case.
  * <p>
@@ -31,57 +31,75 @@
  *
  * @see IPackageFragmentRoot#attachSource(org.eclipse.core.runtime.IPath, org.eclipse.core.runtime.IPath, IProgressMonitor)
  */
- 
-public interface IClassFile extends IJavaElement, IParent, IOpenable, ISourceReference, ICodeAssist {
+
+public interface IClassFile extends ITypeRoot {
+
 /**
- * Returns the smallest element within this class file that 
- * includes the given source position (a method, field, etc.), or
- * <code>null</code> if there is no element other than the class file
- * itself at the given position, or if the given position is not
- * within the source range of this class file.
+ * Changes this class file handle into a working copy. A new {@link IBuffer} is
+ * created using the given owner. Uses the primary owner if <code>null</code> is
+ * specified.
+ * <p>
+ * When switching to working copy mode, problems are reported to the given
+ * {@link IProblemRequestor}. Note that once in working copy mode, the given
+ * {@link IProblemRequestor} is ignored. Only the original {@link IProblemRequestor}
+ * is used to report subsequent problems.
+ * </p>
+ * <p>
+ * Once in working copy mode, changes to this working copy or its children are done in memory.
+ * Only the new buffer is affected.
+ * </p>
+ * <p>
+ * Using {@link ICompilationUnit#commitWorkingCopy(boolean, IProgressMonitor)} on the working copy
+ * will throw a <code>JavaModelException</code> as a class file is implicetly read-only.
+ * </p>
+ * <p>
+ * If this class file was already in working copy mode, an internal counter is incremented and no
+ * other action is taken on this working copy. To bring this working copy back into the original mode
+ * (where it reflects the underlying resource), {@link ICompilationUnit#discardWorkingCopy} must be call as many
+ * times as {@link #becomeWorkingCopy(IProblemRequestor, WorkingCopyOwner, IProgressMonitor)}.
+ * </p>
+ * <p>
+ * The primary compilation unit of a class file's working copy does not exist if the class file is not
+ * in working copy mode (<code>classFileWorkingCopy.getPrimary().exists() == false</code>).
+ * </p>
+ * <p>
+ * The resource of a class file's working copy is <code>null</code> if the class file is in an external jar file.
+ * </p>
  *
- * @param position a source position inside the class file
- * @return the innermost Java element enclosing a given source position or <code>null</code>
- *  if none (excluding the class file).
+ * @param problemRequestor a requestor which will get notified of problems detected during
+ * 	reconciling as they are discovered. The requestor can be set to <code>null</code> indicating
+ * 	that the client is not interested in problems.
+ * @param owner the given {@link WorkingCopyOwner}, or <code>null</code> for the primary owner
+ * @param monitor a progress monitor used to report progress while opening this compilation unit
+ * 	or <code>null</code> if no progress should be reported
+ * @return a working copy for this class file
+ * @throws JavaModelException if this compilation unit could not become a working copy.
+ * @see ICompilationUnit#discardWorkingCopy()
+ * @since 3.2
+ * @deprecated Use {@link ITypeRoot#getWorkingCopy(WorkingCopyOwner, IProgressMonitor)} instead.
+ * 	Note that if this deprecated method is used, problems will be reported to the given problem requestor
+ * 	as well as the problem requestor returned by the working copy owner (if not null).
+ */
+ICompilationUnit becomeWorkingCopy(IProblemRequestor problemRequestor, WorkingCopyOwner owner, IProgressMonitor monitor) throws JavaModelException;
+/**
+ * Returns the bytes contained in this class file.
+ *
+ * @return the bytes contained in this class file
  *
  * @exception JavaModelException if this element does not exist or if an
  *      exception occurs while accessing its corresponding resource
+ * @since 3.3
  */
-IJavaElement getElementAt(int position) throws JavaModelException;
+byte[] getBytes() throws JavaModelException;
 /**
  * Returns the type contained in this class file.
+ * This is a handle-only method. The type may or may not exist.
  *
  * @return the type contained in this class file
- *
- * @exception JavaModelException if this element does not exist or if an
- *      exception occurs while accessing its corresponding resource
  */
-IType getType() throws JavaModelException;
+IType getType();
 /**
- * Returns a working copy on the source associated with this class file using the given 
- * owner to create the buffer, or <code>null</code> if there is no source associated
- * with the class file.
- * <p>
- * The buffer will be automatically initialized with the source of the class file
- * upon creation.
- * <p>
- * The only valid operations on this working copy are <code>getBuffer()</code> or <code>getPrimary()</code>.
- *
- * @param owner the owner that creates a buffer that is used to get the content of the working copy
- *                 or <code>null</code> if the primary owner should be used
- * @param monitor a progress monitor used to report progress while opening this compilation unit
- *                 or <code>null</code> if no progress should be reported 
- * @return a  a working copy on the source associated with this class file
- * @exception JavaModelException if the source of this class file can
- *   not be determined. Reasons include:
- * <ul>
- * <li> This class file does not exist (ELEMENT_DOES_NOT_EXIST)</li>
- * </ul>
- * @since 3.0
- */
-ICompilationUnit getWorkingCopy(WorkingCopyOwner owner, IProgressMonitor monitor) throws JavaModelException;
-/**
- * Returns a working copy on the source associated with this class file using the given 
+ * Returns a working copy on the source associated with this class file using the given
  * factory to create the buffer, or <code>null</code> if there is no source associated
  * with the class file.
  * <p>
@@ -91,7 +109,7 @@
  * The only valid operations on this working copy are <code>getBuffer()</code> or <code>getOriginalElement</code>.
  *
  * @param monitor a progress monitor used to report progress while opening this compilation unit
- *                 or <code>null</code> if no progress should be reported 
+ *                 or <code>null</code> if no progress should be reported
  * @param factory the factory that creates a buffer that is used to get the content of the working copy
  *                 or <code>null</code> if the internal factory should be used
  * @return a  a working copy on the source associated with this class file
@@ -101,9 +119,10 @@
  * <li> This class file does not exist (ELEMENT_DOES_NOT_EXIST)</li>
  * </ul>
  * @since 2.0
- * @deprecated Use getWorkingCopy(WorkingCopyOwner, IProgressMonitor) instead
+ * @deprecated Use {@link ITypeRoot#getWorkingCopy(WorkingCopyOwner, IProgressMonitor)} instead
  */
-IJavaElement getWorkingCopy(IProgressMonitor monitor, IBufferFactory factory) throws JavaModelException;/**
+IJavaElement getWorkingCopy(IProgressMonitor monitor, IBufferFactory factory) throws JavaModelException;
+/**
  * Returns whether this type represents a class. This is not guaranteed to be
  * instantaneous, as it may require parsing the underlying file.
  *
@@ -115,7 +134,7 @@
 boolean isClass() throws JavaModelException;
 /**
  * Returns whether this type represents an interface. This is not guaranteed to
- * be instantaneous, as it may require parsing the underlying file. 
+ * be instantaneous, as it may require parsing the underlying file.
  *
  * @return <code>true</code> if the class file represents an interface.
  *
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathAttribute.java
index 74625ab..0e976e1 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathAttribute.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005 IBM Corporation and others.
+ * Copyright (c) 2005, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -13,6 +13,9 @@
 /**
  * A classpath attribute defines a name/value pair that can be persisted with a classpath entry. Such an attribute
  * can be created using the factory method {@link JavaCore#newClasspathAttribute(String, String) newClasspathAttribute(String name, String value)}.
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
  * 
  * @see JavaCore#newContainerEntry(
  *			org.eclipse.core.runtime.IPath containerPath, 
@@ -57,6 +60,18 @@
 	String JAVADOC_LOCATION_ATTRIBUTE_NAME = "javadoc_location"; //$NON-NLS-1$
 	
 	/**
+	 * Constant for the name of the optional attribute. The possible values
+	 * for this attribute are <code>"true"</code> or <code>"false"</code>. 
+	 * When not present, <code>"false"</code> is assumed.
+	 * If the value of this attribute is <code>"true"</code>, the classpath entry
+	 * is optional. If the underlying resource or jar file doesn't exist, no error
+	 * is reported and the classpath entry is ignored.
+	 * 
+	 * @since 3.2
+	 */
+	String OPTIONAL = "optional"; //$NON-NLS-1$
+	
+	/**
 	 * Returns the name of this classpath attribute.
 	 * 
 	 * @return the name of this classpath attribute.
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathContainer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathContainer.java
index 28b5b44..d4e0072 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathContainer.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathContainer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathEntry.java
index 7e9ff1a..6948c09 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathEntry.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathEntry.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -15,21 +15,23 @@
 /** 
  * An entry on a Java project classpath identifying one or more package fragment
  * roots. A classpath entry has a content kind (either source, 
- * <code>K_SOURCE</code>, or binary, <code>K_BINARY</code>), which is inherited
+ * {@link IPackageFragmentRoot#K_SOURCE}, or binary, {@link IPackageFragmentRoot#K_BINARY}), which is inherited
  * by each package fragment root and package fragment associated with the entry.
  * <p>
  * A classpath entry can refer to any of the following:<ul>
  * 
  *	<li>Source code in the current project. In this case, the entry identifies a
  *		root folder in the current project containing package fragments and
- *		<code>.java</code> source files. The root folder itself represents a default
- *		package, subfolders represent package fragments, and <code>.java</code> files
+ *		source files with one of the {@link JavaCore#getJavaLikeExtensions() 
+ *		Java-like extensions}. The root folder itself represents a default
+ *		package, subfolders represent package fragments, and files with a
+ *     Java-like extension (e.g. <code>.java</code> files)
  *		represent compilation units. All compilation units will be compiled when
  * 		the project is built. The classpath entry must specify the
  *		absolute path to the root folder. Entries of this kind are 
- *		associated with the <code>CPE_SOURCE</code> constant.
+ *		associated with the {@link #CPE_SOURCE} constant.
  *      Source classpath entries can carry inclusion and exclusion patterns for
- *      selecting which <code>.java</code> source files appear as compilation
+ *      selecting which source files appear as compilation
  *      units and get compiled when the project is built.
  *  </li>
  * 
@@ -38,7 +40,7 @@
  *		package fragments and <code>.class</code> files.  The classpath entry
  *		must specify the absolute path to the JAR (or root folder), and in case it refers
  *		to an external JAR, then there is no associated resource in the workbench. Entries 
- *		of this kind are associated with the <code>CPE_LIBRARY</code> constant.</li>
+ *		of this kind are associated with the {@link #CPE_LIBRARY} constant.</li>
  * 
  *	<li>A required project. In this case the entry identifies another project in
  *		the workspace. The required project is used as a binary library when compiling
@@ -49,50 +51,50 @@
  *		is performed against a required project's source code, and compilation is 
  *		performed against a required project's last built state.  The
  *		classpath entry must specify the absolute path to the
- *		project. Entries of this kind are  associated with the <code>CPE_PROJECT</code>
+ *		project. Entries of this kind are  associated with the {@link #CPE_PROJECT}
  *		constant. 
  * 		Note: referencing a required project with a classpath entry refers to the source 
  *     code or associated <code>.class</code> files located in its output location. 
  *     It will also automatically include any other libraries or projects that the required project's classpath 
  *     refers to, iff the corresponding classpath entries are tagged as being exported 
- *     (<code>IClasspathEntry#isExported</code>). 
+ *     ({@link IClasspathEntry#isExported}). 
  *    Unless exporting some classpath entries, classpaths are not chained by default - 
  *    each project must specify its own classpath in its entirety.</li>
  * 
  *  <li> A path beginning in a classpath variable defined globally to the workspace.
- *		Entries of this kind are  associated with the <code>CPE_VARIABLE</code> constant.  
- *      Classpath variables are created using <code>JavaCore#setClasspathVariable</code>,
+ *		Entries of this kind are  associated with the {@link #CPE_VARIABLE} constant.  
+ *      Classpath variables are created using {@link JavaCore#setClasspathVariable(String, IPath, org.eclipse.core.runtime.IProgressMonitor)},
  * 		and gets resolved, to either a project or library entry, using
- *      <code>JavaCore#getResolvedClasspathVariable</code>.
- *		It is also possible to register an automatic initializer (<code>ClasspathVariableInitializer</code>),
+ *      {@link JavaCore#getResolvedClasspathEntry(IClasspathEntry)}.
+ *		It is also possible to register an automatic initializer ({@link ClasspathVariableInitializer}),
  * 	which will be invoked through the extension point "org.eclipse.jdt.core.classpathVariableInitializer".
  * 	After resolution, a classpath variable entry may either correspond to a project or a library entry. </li>
  * 
  *  <li> A named classpath container identified by its container path.
  *     A classpath container provides a way to indirectly reference a set of classpath entries through
- *     a classpath entry of kind <code>CPE_CONTAINER</code>. Typically, a classpath container can
+ *     a classpath entry of kind {@link #CPE_CONTAINER}. Typically, a classpath container can
  *     be used to describe a complex library composed of multiple JARs, projects or classpath variables,
  *     considering also that containers can be mapped differently on each project. Several projects can
  *     reference the same generic container path, but have each of them actually bound to a different
  *     container object.
  *     The container path is a formed by a first ID segment followed with extra segments, 
  *     which can be used as additional hints for resolving this container reference. If no container was ever 
- *     recorded for this container path onto this project (using <code>setClasspathContainer</code>, 
- * 	then a <code>ClasspathContainerInitializer</code> will be activated if any was registered for this 
+ *     recorded for this container path onto this project (using {@link JavaCore#setClasspathContainer}, 
+ * 	then a {@link ClasspathContainerInitializer} will be activated if any was registered for this 
  * 	container ID onto the extension point "org.eclipse.jdt.core.classpathContainerInitializer".
- * 	A classpath container entry can be resolved explicitly using <code>JavaCore#getClasspathContainer</code>
+ * 	A classpath container entry can be resolved explicitly using {@link JavaCore#getClasspathContainer}
  * 	and the resulting container entries can contain any non-container entry. In particular, it may contain variable
  *     entries, which in turn needs to be resolved before being directly used. 
  * 	<br> Also note that the container resolution APIs include an IJavaProject argument, so as to allow the same
  * 	container path to be interpreted in different ways for different projects. </li>
  * </ul>
  * </p>
- * The result of <code>IJavaProject#getResolvedClasspath</code> will have all entries of type
- * <code>CPE_VARIABLE</code> and <code>CPE_CONTAINER</code> resolved to a set of 
- * <code>CPE_SOURCE</code>, <code>CPE_LIBRARY</code> or <code>CPE_PROJECT</code>
+ * The result of {@link IJavaProject#getResolvedClasspath} will have all entries of type
+ * {@link #CPE_VARIABLE} and {@link #CPE_CONTAINER} resolved to a set of 
+ * {@link #CPE_SOURCE}, {@link #CPE_LIBRARY} or {@link #CPE_PROJECT}
  * classpath entries.
  * <p>
- * Any classpath entry other than a source folder (kind <code>CPE_SOURCE</code>) can
+ * Any classpath entry other than a source folder (kind {@link #CPE_SOURCE}) can
  * be marked as being exported. Exported entries are automatically contributed to
  * dependent projects, along with the project's default output folder, which is
  * implicitly exported, and any auxiliary output folders specified on source
@@ -100,7 +102,7 @@
  * followed by the any exported entries.
  * <p>
  * This interface is not intended to be implemented by clients.
- * Classpath entries can be created via methods on <code>JavaCore</code>.
+ * Classpath entries can be created via methods on {@link JavaCore}.
  * </p>
  *
  * @see JavaCore#newLibraryEntry(org.eclipse.core.runtime.IPath, org.eclipse.core.runtime.IPath, org.eclipse.core.runtime.IPath)
@@ -168,11 +170,11 @@
 	 * Returns the kind of files found in the package fragments identified by this
 	 * classpath entry.
 	 *
-	 * @return <code>IPackageFragmentRoot.K_SOURCE</code> for files containing
-	 *   source code, and <code>IPackageFragmentRoot.K_BINARY</code> for binary
+	 * @return {@link IPackageFragmentRoot#K_SOURCE} for files containing
+	 *   source code, and {@link IPackageFragmentRoot#K_BINARY} for binary
 	 *   class files.
-	 *   There is no specified value for an entry denoting a variable (<code>CPE_VARIABLE</code>)
-	 *   or a classpath container (<code>CPE_CONTAINER</code>).
+	 *   There is no specified value for an entry denoting a variable ({@link #CPE_VARIABLE})
+	 *   or a classpath container ({@link #CPE_CONTAINER}).
 	 */
 	int getContentKind();
 
@@ -181,16 +183,16 @@
 	 *
 	 * @return one of:
 	 * <ul>
-	 * <li><code>CPE_SOURCE</code> - this entry describes a source root in
+	 * <li>{@link #CPE_SOURCE} - this entry describes a source root in
 	 		its project
-	 * <li><code>CPE_LIBRARY</code> - this entry describes a folder or JAR
+	 * <li>{@link #CPE_LIBRARY} - this entry describes a folder or JAR
 	 		containing binaries
-	 * <li><code>CPE_PROJECT</code> - this entry describes another project
+	 * <li>{@link #CPE_PROJECT} - this entry describes another project
 	 *
-	 * <li><code>CPE_VARIABLE</code> - this entry describes a project or library
+	 * <li>{@link #CPE_VARIABLE} - this entry describes a project or library
 	 *  	indirectly via a classpath variable in the first segment of the path
 	 * *
-	 * <li><code>CPE_CONTAINER</code> - this entry describes set of entries
+	 * <li>{@link #CPE_CONTAINER} - this entry describes set of entries
 	 *  	referenced indirectly via a classpath container
 	 * </ul>
 	 */
@@ -237,13 +239,13 @@
 	 * Combinations of *'s and ?'s are allowed.
 	 * </p>
 	 * <p>
-	 * The special pattern '**' matches zero or more segments. In a source enry,
+	 * The special pattern '**' matches zero or more segments. In a source entry,
 	 * a path like <code>tests/</code> that ends in a trailing separator is interpreted
 	 * as <code>tests/&#42;&#42;</code>, and would match everything under
 	 * the folder named <code>tests</code>.
 	 * </p>
 	 * <p>
-	 * Example patterns in source entries:
+	 * Example patterns in source entries (assuming that "java" is the only {@link JavaCore#getJavaLikeExtensions() Java-like extension}):
 	 * <ul>
 	 * <li>
 	 * <code>tests/&#42;&#42;</code> (or simply <code>tests/</code>) 
@@ -342,11 +344,11 @@
 	/**
 	 * Returns the full path to the specific location where the builder writes 
 	 * <code>.class</code> files generated for this source entry 
-	 * (entry kind <code>CPE_SOURCE</code>).
+	 * (entry kind {@link #CPE_SOURCE}).
 	 * <p>
 	 * Source entries can optionally be associated with a specific output location.
 	 * If none is provided, the source entry will be implicitly associated with its project
-	 * default output location (see <code>IJavaProject#getOutputLocation</code>).
+	 * default output location (see {@link IJavaProject#getOutputLocation}).
 	 * </p><p>
 	 * NOTE: A specific output location cannot coincidate with another source/library entry.
 	 * </p>
@@ -362,24 +364,24 @@
 	 * Returns the path of this classpath entry.
 	 *
 	 * The meaning of the path of a classpath entry depends on its entry kind:<ul>
-	 *	<li>Source code in the current project (<code>CPE_SOURCE</code>) -  
+	 *	<li>Source code in the current project ({@link #CPE_SOURCE}) -  
 	 *      The path associated with this entry is the absolute path to the root folder. </li>
-	 *	<li>A binary library in the current project (<code>CPE_LIBRARY</code>) - the path
+	 *	<li>A binary library in the current project ({@link #CPE_LIBRARY}) - the path
 	 *		associated with this entry is the absolute path to the JAR (or root folder), and 
 	 *		in case it refers to an external JAR, then there is no associated resource in 
 	 *		the workbench.
-	 *	<li>A required project (<code>CPE_PROJECT</code>) - the path of the entry denotes the
+	 *	<li>A required project ({@link #CPE_PROJECT}) - the path of the entry denotes the
 	 *		path to the corresponding project resource.</li>
-	 *  <li>A variable entry (<code>CPE_VARIABLE</code>) - the first segment of the path 
+	 *  <li>A variable entry ({@link #CPE_VARIABLE}) - the first segment of the path 
 	 *      is the name of a classpath variable. If this classpath variable
-	 *		is bound to the path <it>P</it>, the path of the corresponding classpath entry
-	 *		is computed by appending to <it>P</it> the segments of the returned
+	 *		is bound to the path <i>P</i>, the path of the corresponding classpath entry
+	 *		is computed by appending to <i>P</i> the segments of the returned
 	 *		path without the variable.</li>
-	 *  <li> A container entry (<code>CPE_CONTAINER</code>) - the path of the entry
+	 *  <li> A container entry ({@link #CPE_CONTAINER}) - the path of the entry
 	 * 	is the name of the classpath container, which can be bound indirectly to a set of classpath 
 	 * 	entries after resolution. The containerPath is a formed by a first ID segment followed with 
 	 *     extra segments that can be used as additional hints for resolving this container 
-	 * 	reference (also see <code>IClasspathContainer</code>).
+	 * 	reference (also see {@link IClasspathContainer}).
 	 * </li>
 	 * </ul>
 	 *
@@ -408,7 +410,7 @@
 	 * Returns the path within the source archive or folder where package fragments
 	 * are located. An empty path indicates that packages are located at
 	 * the root of the source archive or folder. Returns a non-<code>null</code> value
-	 * if and only if <code>getSourceAttachmentPath</code> returns 
+	 * if and only if {@link #getSourceAttachmentPath} returns 
 	 * a non-<code>null</code> value.
 	 *
 	 * @return the path within the source archive or folder, or <code>null</code> if
@@ -419,7 +421,7 @@
 	/**
 	 * Returns whether this entry is exported to dependent projects.
 	 * Always returns <code>false</code> for source entries (kind
-	 * <code>CPE_SOURCE</code>), which cannot be exported.
+	 * {@link #CPE_SOURCE}), which cannot be exported.
 	 * 
 	 * @return <code>true</code> if exported, and <code>false</code> otherwise
 	 * @since 2.0
@@ -429,7 +431,7 @@
 	/**
 	 * This is a helper method, which returns the resolved classpath entry denoted 
 	 * by an entry (if it is a variable entry). It is obtained by resolving the variable 
-	 * reference in the first segment. Returns <node>null</code> if unable to resolve using 
+	 * reference in the first segment. Returns <code>null</code> if unable to resolve using 
 	 * the following algorithm:
 	 * <ul>
 	 * <li> if variable segment cannot be resolved, returns <code>null</code></li>
@@ -445,7 +447,7 @@
 	 *	<p> 
 	 * Note that this deprecated API doesn't handle CPE_CONTAINER entries.
 	 * 
-	 * @deprecated - use JavaCore.getResolvedClasspathEntry(...)
+	 * @deprecated Use {@link JavaCore#getResolvedClasspathEntry(IClasspathEntry)} instead
 	 */
 	IClasspathEntry getResolvedEntry();	
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICodeAssist.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICodeAssist.java
index 254e3a0..11410dd 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICodeAssist.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICodeAssist.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -144,15 +144,20 @@
 		throws JavaModelException;
 
 	/**
-	 * Returns the Java elements correspondiing to the given selected text in this compilation unit. 
+	 * Returns the Java elements corresponding to the given selected text in this compilation unit. 
 	 * The <code>offset</code> is the 0-based index of the first selected character. 
 	 * The <code>length</code> is the number of selected characters.
+	 * <p>
+	 * Note that if the <code>length</code> is 0 and the <code>offset</code> is inside an identifier 
+	 * or the index just after an identifier then this identifier is considered as the selection.
+	 * </p>
 	 * 
 	 * @param offset the given offset position
 	 * @param length the number of selected characters
-	 * @return the Java elements correspondiing to the given selected text
+	 * @return the Java elements corresponding to the given selected text
 	 *
 	 * @exception JavaModelException if code resolve could not be performed. Reasons include:
+	 * <ul>
 	 *  <li>This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
 	 *  <li> The range specified is not within this element's
 	 *      source range (INDEX_OUT_OF_BOUNDS)
@@ -161,13 +166,17 @@
 	 */
 	IJavaElement[] codeSelect(int offset, int length) throws JavaModelException;
 	/**
-	 * Returns the Java elements correspondiing to the given selected text in this compilation unit. 
+	 * Returns the Java elements corresponding to the given selected text in this compilation unit. 
 	 * The <code>offset</code> is the 0-based index of the first selected character. 
 	 * The <code>length</code> is the number of selected characters.
 	 * It considers types in the working copies with the given owner first. In other words, 
 	 * the owner's working copies will take precedence over their original compilation units
 	 * in the workspace.
 	 * <p>
+	 * Note that if the <code>length</code> is 0 and the <code>offset</code> is inside an identifier 
+	 * or the index just after an identifier then this identifier is considered as the selection.
+	 * </p>
+	 * <p>
 	 * Note that if a working copy is empty, it will be as if the original compilation
 	 * unit had been deleted.
 	 * </p>
@@ -175,9 +184,10 @@
 	 * @param offset the given offset position
 	 * @param length the number of selected characters
 	 * @param owner the owner of working copies that take precedence over their original compilation units
-	 * @return the Java elements correspondiing to the given selected text
+	 * @return the Java elements corresponding to the given selected text
 	 *
 	 * @exception JavaModelException if code resolve could not be performed. Reasons include:
+	 * <ul>
 	 *  <li>This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
 	 *  <li> The range specified is not within this element's
 	 *      source range (INDEX_OUT_OF_BOUNDS)
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICodeCompletionRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICodeCompletionRequestor.java
index 86ef806..90bb0e6 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICodeCompletionRequestor.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICodeCompletionRequestor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICodeFormatter.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICodeFormatter.java
index e44e348..a590fc1 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICodeFormatter.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICodeFormatter.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -18,7 +18,7 @@
  * @see ToolFactory#createCodeFormatter()
  * @see ToolFactory#createDefaultCodeFormatter(java.util.Map options)
  * @since 2.0
- * @deprecated - should use org.eclipse.jdt.core.formatter.CodeFormatter instead (note: options have changed)
+ * @deprecated Use {@link org.eclipse.jdt.core.formatter.CodeFormatter} instead (note: options have changed)
  */
 public interface ICodeFormatter {
 
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICompilationUnit.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICompilationUnit.java
index e714fac..421bc41 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICompilationUnit.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICompilationUnit.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -12,24 +12,27 @@
 package org.eclipse.jdt.core;
 
 import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jdt.core.dom.ASTParser;
 import org.eclipse.jdt.core.dom.CompilationUnit;
 import org.eclipse.jdt.core.dom.AST;
+import org.eclipse.jdt.core.dom.IBinding;
 
 
 /**
- * Represents an entire Java compilation unit (<code>.java</code> source file).
+ * Represents an entire Java compilation unit (source file with one of the
+ * {@link JavaCore#getJavaLikeExtensions() Java-like extensions}).
  * Compilation unit elements need to be opened before they can be navigated or manipulated.
  * The children are of type {@link IPackageDeclaration},
  * {@link IImportContainer}, and {@link IType},
  * and appear in the order in which they are declared in the source.
- * If a <code>.java</code> file cannot be parsed, its structure remains unknown.
- * Use {@link IJavaElement#isStructureKnown} to determine whether this is 
+ * If a source file cannot be parsed, its structure remains unknown.
+ * Use {@link IJavaElement#isStructureKnown} to determine whether this is
  * the case.
  * <p>
  * This interface is not intended to be implemented by clients.
  * </p>
  */
-public interface ICompilationUnit extends IJavaElement, ISourceReference, IParent, IOpenable, IWorkingCopy, ISourceManipulation, ICodeAssist {
+public interface ICompilationUnit extends ITypeRoot, IWorkingCopy, ISourceManipulation {
 /**
  * Constant indicating that a reconcile operation should not return an AST.
  * @since 3.0
@@ -37,11 +40,33 @@
 public static final int NO_AST = 0;
 
 /**
+ * Constant indicating that a reconcile operation should recompute the problems
+ * even if the source hasn't changed.
+ * @since 3.3
+ */
+public static final int FORCE_PROBLEM_DETECTION = 0x01;
+
+/**
+ * Constant indicating that a reconcile operation should enable the statements recovery.
+ * @see ASTParser#setStatementsRecovery(boolean)
+ * @since 3.3
+ */
+public static final int ENABLE_STATEMENTS_RECOVERY = 0x02;
+
+/**
+ * Constant indicating that a reconcile operation should enable the bindings recovery
+ * @see ASTParser#setBindingsRecovery(boolean)
+ * @see IBinding#isRecovered()
+ * @since 3.3
+ */
+public static final int ENABLE_BINDINGS_RECOVERY = 0x04;
+
+/**
  * Changes this compilation unit handle into a working copy. A new {@link IBuffer} is
- * created using this compilation unit handle's owner. Uses the primary owner is none was
+ * created using this compilation unit handle's owner. Uses the primary owner if none was
  * specified when this compilation unit handle was created.
  * <p>
- * When switching to working copy mode, problems are reported to given 
+ * When switching to working copy mode, problems are reported to given
  * {@link IProblemRequestor}. Note that once in working copy mode, the given
  * {@link IProblemRequestor} is ignored. Only the original {@link IProblemRequestor}
  * is used to report subsequent problems.
@@ -53,22 +78,51 @@
  * </p>
  * <p>
  * If this compilation unit was already in working copy mode, an internal counter is incremented and no
- * other action is taken on this compilation unit. To bring this compilation unit back into the original mode 
- * (where it reflects the underlying resource), {@link #discardWorkingCopy} must be call as many 
+ * other action is taken on this compilation unit. To bring this compilation unit back into the original mode
+ * (where it reflects the underlying resource), {@link #discardWorkingCopy} must be call as many
  * times as {@link #becomeWorkingCopy(IProblemRequestor, IProgressMonitor)}.
  * </p>
- * 
+ *
  * @param problemRequestor a requestor which will get notified of problems detected during
  * 	reconciling as they are discovered. The requestor can be set to <code>null</code> indicating
  * 	that the client is not interested in problems.
  * @param monitor a progress monitor used to report progress while opening this compilation unit
- * 	or <code>null</code> if no progress should be reported 
+ * 	or <code>null</code> if no progress should be reported
  * @throws JavaModelException if this compilation unit could not become a working copy.
  * @see #discardWorkingCopy()
  * @since 3.0
+ *
+ * @deprecated Use {@link #becomeWorkingCopy(IProgressMonitor)} instead.
+ * 	Note that if this deprecated method is used, problems will be reported to the given problem requestor
+ * 	as well as the problem requestor returned by the working copy owner (if not null).
  */
 void becomeWorkingCopy(IProblemRequestor problemRequestor, IProgressMonitor monitor) throws JavaModelException;
 /**
+ * Changes this compilation unit handle into a working copy. A new {@link IBuffer} is
+ * created using this compilation unit handle's owner. Uses the primary owner if none was
+ * specified when this compilation unit handle was created.
+ * <p>
+ * When switching to working copy mode, problems are reported to the {@link IProblemRequestor
+ * problem requestor} of the {@link WorkingCopyOwner working copy owner}.
+ * </p><p>
+ * Once in working copy mode, changes to this compilation unit or its children are done in memory.
+ * Only the new buffer is affected. Using {@link #commitWorkingCopy(boolean, IProgressMonitor)}
+ * will bring the underlying resource in sync with this compilation unit.
+ * </p><p>
+ * If this compilation unit was already in working copy mode, an internal counter is incremented and no
+ * other action is taken on this compilation unit. To bring this compilation unit back into the original mode
+ * (where it reflects the underlying resource), {@link #discardWorkingCopy} must be call as many
+ * times as {@link #becomeWorkingCopy(IProblemRequestor, IProgressMonitor)}.
+ * </p>
+ *
+ * @param monitor a progress monitor used to report progress while opening this compilation unit
+ * 	or <code>null</code> if no progress should be reported
+ * @throws JavaModelException if this compilation unit could not become a working copy.
+ * @see #discardWorkingCopy()
+ * @since 3.3
+ */
+void becomeWorkingCopy(IProgressMonitor monitor) throws JavaModelException;
+/**
  * Commits the contents of this working copy to its underlying resource.
  *
  * <p>It is possible that the contents of the original resource have changed
@@ -99,7 +153,7 @@
 void commitWorkingCopy(boolean force, IProgressMonitor monitor) throws JavaModelException;
 /**
  * Creates and returns an non-static import declaration in this compilation unit
- * with the given name. This method is equivalent to 
+ * with the given name. This method is equivalent to
  * <code>createImport(name, Flags.AccDefault, sibling, monitor)</code>.
  *
  * @param name the name of the import declaration to add as defined by JLS2 7.5. (For example: <code>"java.io.File"</code> or
@@ -182,7 +236,7 @@
  * <li> The name is not a valid package name (INVALID_NAME)
  * </ul>
  */
- IPackageDeclaration createPackageDeclaration(String name, IProgressMonitor monitor) throws JavaModelException;   
+ IPackageDeclaration createPackageDeclaration(String name, IProgressMonitor monitor) throws JavaModelException;
 /**
  * Creates and returns a type in this compilation unit with the
  * given contents. If this compilation unit does not exist, one
@@ -222,17 +276,18 @@
  * This has no effect if this compilation unit was not in working copy mode.
  * </p>
  * <p>
- * If {@link #becomeWorkingCopy} was called several times on this
- * compilation unit, {@link #discardWorkingCopy} must be called as 
- * many times before it switches back to the original mode.
+ * If {@link #becomeWorkingCopy(IProgressMonitor)} method was called several
+ * times on this compilation unit, {@link #discardWorkingCopy()} must be called
+ * as many times before it switches back to the original mode. Same as
+ * for method {@link #getWorkingCopy(IProgressMonitor)}.
  * </p>
- * 
+ *
  * @throws JavaModelException if this working copy could not return in its original mode.
  * @see #becomeWorkingCopy(IProblemRequestor, IProgressMonitor)
  * @since 3.0
  */
 void discardWorkingCopy() throws JavaModelException;
-/** 
+/**
  * Finds the elements in this compilation unit that correspond to
  * the given element.
  * An element A corresponds to an element B if:
@@ -246,27 +301,19 @@
  * </ul>
  * Returns <code>null</code> if no such java elements can be found
  * or if the given element is not included in a compilation unit.
- * 
+ *
  * @param element the given element
  * @return the found elements in this compilation unit that correspond to the given element
- * @since 3.0 
+ * @since 3.0
  */
 IJavaElement[] findElements(IJavaElement element);
 /**
- * Finds the primary type of this compilation unit (that is, the type with the same name as the
- * compilation unit), or <code>null</code> if no such a type exists.
- * 
- * @return the found primary type of this compilation unit, or <code>null</code> if no such a type exists
- * @since 3.0
- */
-IType findPrimaryType();
-/**
- * Finds the working copy for this compilation unit, given a {@link WorkingCopyOwner}. 
+ * Finds the working copy for this compilation unit, given a {@link WorkingCopyOwner}.
  * If no working copy has been created for this compilation unit associated with this
  * working copy owner, returns <code>null</code>.
  * <p>
- * Users of this method must not destroy the resulting working copy. 
- * 
+ * Users of this method must not destroy the resulting working copy.
+ *
  * @param owner the given {@link WorkingCopyOwner}
  * @return the found working copy for this compilation unit, <code>null</code> if none
  * @see WorkingCopyOwner
@@ -275,7 +322,7 @@
 ICompilationUnit findWorkingCopy(WorkingCopyOwner owner);
 /**
  * Returns all types declared in this compilation unit in the order
- * in which they appear in the source. 
+ * in which they appear in the source.
  * This includes all top-level types and nested member types.
  * It does NOT include local types (types defined in methods).
  *
@@ -285,26 +332,12 @@
  */
 IType[] getAllTypes() throws JavaModelException;
 /**
- * Returns the smallest element within this compilation unit that 
- * includes the given source position (that is, a method, field, etc.), or
- * <code>null</code> if there is no element other than the compilation
- * unit itself at the given position, or if the given position is not
- * within the source range of this compilation unit.
- *
- * @param position a source position inside the compilation unit
- * @return the innermost Java element enclosing a given source position or <code>null</code>
- *	if none (excluding the compilation unit).
- * @throws JavaModelException if the compilation unit does not exist or if an
- *		exception occurs while accessing its corresponding resource
- */
-IJavaElement getElementAt(int position) throws JavaModelException;
-/**
  * Returns the first import declaration in this compilation unit with the given name.
  * This is a handle-only method. The import declaration may or may not exist. This
  * is a convenience method - imports can also be accessed from a compilation unit's
  * import container.
  *
- * @param name the name of the import to find as defined by JLS2 7.5. (For example: <code>"java.io.File"</code> 
+ * @param name the name of the import to find as defined by JLS2 7.5. (For example: <code>"java.io.File"</code>
  * 	or <code>"java.awt.*"</code>)
  * @return a handle onto the corresponding import declaration. The import declaration may or may not exist.
  */
@@ -312,9 +345,9 @@
 /**
  * Returns the import container for this compilation unit.
  * This is a handle-only method. The import container may or
- * may not exist. The import container can used to access the 
+ * may not exist. The import container can used to access the
  * imports.
- * @return a handle onto the corresponding import container. The 
+ * @return a handle onto the corresponding import container. The
  *		import contain may or may not exist.
  */
 IImportContainer getImportContainer();
@@ -336,7 +369,7 @@
  * <p>
  * Note that the returned primary compilation unit can be in working copy mode.
  * </p>
- * 
+ *
  * @return the primary compilation unit this working copy was created from,
  * or this compilation unit if it is primary
  * @since 3.0
@@ -345,7 +378,7 @@
 /**
  * Returns the working copy owner of this working copy.
  * Returns null if it is not a working copy or if it has no owner.
- * 
+ *
  * @return WorkingCopyOwner the owner of this working copy or <code>null</code>
  * @since 3.0
  */
@@ -377,7 +410,7 @@
  *
  * @param name the simple name of the requested type in the compilation unit
  * @return a handle onto the corresponding type. The type may or may not exist.
- * @see JavaConventions#validateCompilationUnitName(String name)
+ * @see JavaConventions#validateCompilationUnitName(String name, String sourceLevel, String complianceLevel)
  */
 IType getType(String name);
 /**
@@ -390,27 +423,27 @@
  */
 IType[] getTypes() throws JavaModelException;
 /**
- * Returns a new working copy of this compilation unit if it is a primary compilation unit, 
+ * Returns a new working copy of this compilation unit if it is a primary compilation unit,
  * or this compilation unit if it is already a non-primary working copy.
  * <p>
- * Note: if intending to share a working copy amongst several clients, then 
- * {@link #getWorkingCopy(WorkingCopyOwner, IProblemRequestor, IProgressMonitor)} 
+ * Note: if intending to share a working copy amongst several clients, then
+ * {@link #getWorkingCopy(WorkingCopyOwner, IProblemRequestor, IProgressMonitor)}
  * should be used instead.
  * </p><p>
- * When the working copy instance is created, an ADDED IJavaElementDelta is 
+ * When the working copy instance is created, an ADDED IJavaElementDelta is
  * reported on this working copy.
  * </p><p>
- * Once done with the working copy, users of this method must discard it using 
+ * Once done with the working copy, users of this method must discard it using
  * {@link #discardWorkingCopy()}.
  * </p><p>
  * Since 2.1, a working copy can be created on a not-yet existing compilation
  * unit. In particular, such a working copy can then be committed in order to create
  * the corresponding compilation unit.
  * </p>
-* @param monitor a progress monitor used to report progress while opening this compilation unit
- *                 or <code>null</code> if no progress should be reported 
+ * @param monitor a progress monitor used to report progress while opening this compilation unit
+ *                 or <code>null</code> if no progress should be reported
  * @throws JavaModelException if the contents of this element can
- *   not be determined. 
+ *   not be determined.
  * @return a new working copy of this element if this element is not
  * a working copy, or this element if this element is already a working copy
  * @since 3.0
@@ -420,11 +453,11 @@
  * Returns a shared working copy on this compilation unit using the given working copy owner to create
  * the buffer, or this compilation unit if it is already a non-primary working copy.
  * This API can only answer an already existing working copy if it is based on the same
- * original compilation unit AND was using the same working copy owner (that is, as defined by {@link Object#equals}).	 
+ * original compilation unit AND was using the same working copy owner (that is, as defined by {@link Object#equals}).
  * <p>
  * The life time of a shared working copy is as follows:
  * <ul>
- * <li>The first call to {@link #getWorkingCopy(WorkingCopyOwner, IProblemRequestor, IProgressMonitor)} 
+ * <li>The first call to {@link #getWorkingCopy(WorkingCopyOwner, IProblemRequestor, IProgressMonitor)}
  * 	creates a new working copy for this element</li>
  * <li>Subsequent calls increment an internal counter.</li>
  * <li>A call to {@link #discardWorkingCopy()} decrements the internal counter.</li>
@@ -432,7 +465,7 @@
  * </ul>
  * So users of this method must discard exactly once the working copy.
  * <p>
- * Note that the working copy owner will be used for the life time of this working copy, that is if the 
+ * Note that the working copy owner will be used for the life time of this working copy, that is if the
  * working copy is closed then reopened, this owner will be used.
  * The buffer will be automatically initialized with the original's compilation unit content
  * upon creation.
@@ -444,32 +477,35 @@
  * unit. In particular, such a working copy can then be committed in order to create
  * the corresponding compilation unit.
  * </p>
- * @param owner the working copy owner that creates a buffer that is used to get the content 
+ * @param owner the working copy owner that creates a buffer that is used to get the content
  * 				of the working copy
  * @param problemRequestor a requestor which will get notified of problems detected during
  * 	reconciling as they are discovered. The requestor can be set to <code>null</code> indicating
  * 	that the client is not interested in problems.
  * @param monitor a progress monitor used to report progress while opening this compilation unit
- *                 or <code>null</code> if no progress should be reported 
+ *                 or <code>null</code> if no progress should be reported
  * @throws JavaModelException if the contents of this element can
- *   not be determined. 
+ *   not be determined.
  * @return a new working copy of this element using the given factory to create
  * the buffer, or this element if this element is already a working copy
  * @since 3.0
+ * @deprecated Use {@link ITypeRoot#getWorkingCopy(WorkingCopyOwner, IProgressMonitor)} instead.
+ * 	Note that if this deprecated method is used, problems will be reported on the passed problem requester
+ * 	as well as on the problem requestor returned by the working copy owner (if not null).
  */
 ICompilationUnit getWorkingCopy(WorkingCopyOwner owner, IProblemRequestor problemRequestor, IProgressMonitor monitor) throws JavaModelException;
 /**
  * Returns whether the resource of this working copy has changed since the
  * inception of this working copy.
  * Returns <code>false</code> if this compilation unit is not in working copy mode.
- * 
+ *
  * @return whether the resource has changed
  * @since 3.0
  */
 public boolean hasResourceChanged();
 /**
  * Returns whether this element is a working copy.
- * 
+ *
  * @return true if this element is a working copy, false otherwise
  * @since 3.0
  */
@@ -478,12 +514,12 @@
 /**
  * Reconciles the contents of this working copy, sends out a Java delta
  * notification indicating the nature of the change of the working copy since
- * the last time it was either reconciled or made consistent 
+ * the last time it was either reconciled or made consistent
  * ({@link IOpenable#makeConsistent(IProgressMonitor)}), and returns a
  * compilation unit AST if requested.
  * <p>
- * It performs the reconciliation by locally caching the contents of 
- * the working copy, updating the contents, then creating a delta 
+ * It performs the reconciliation by locally caching the contents of
+ * the working copy, updating the contents, then creating a delta
  * over the cached contents and the new contents, and finally firing
  * this delta.
  * <p>
@@ -513,15 +549,20 @@
  * API is not supported, or if the working copy was already consistent.
  * </p>
  *
+ * <p>
+ * This method doesn't perform statements recovery. To recover statements with syntax
+ * errors, {@link #reconcile(int, boolean, boolean, WorkingCopyOwner, IProgressMonitor)} must be use.
+ * </p>
+ *
  * @param astLevel either {@link #NO_AST} if no AST is wanted,
  * or the {@linkplain AST#newAST(int) AST API level} of the AST if one is wanted
- * @param forceProblemDetection boolean indicating whether problem should be 
+ * @param forceProblemDetection boolean indicating whether problem should be
  *   recomputed even if the source hasn't changed
- * @param owner the owner of working copies that take precedence over the 
+ * @param owner the owner of working copies that take precedence over the
  *   original compilation units, or <code>null</code> if the primary working
  *   copy owner should be used
  * @param monitor a progress monitor
- * @return the compilation unit AST or <code>null</code> if not requested, 
+ * @return the compilation unit AST or <code>null</code> if not requested,
  *    or if the requested level of AST API is not supported,
  *    or if the working copy was consistent
  * @throws JavaModelException if the contents of the original element
@@ -534,6 +575,146 @@
 CompilationUnit reconcile(int astLevel, boolean forceProblemDetection, WorkingCopyOwner owner, IProgressMonitor monitor) throws JavaModelException;
 
 /**
+ * Reconciles the contents of this working copy, sends out a Java delta
+ * notification indicating the nature of the change of the working copy since
+ * the last time it was either reconciled or made consistent
+ * ({@link IOpenable#makeConsistent(IProgressMonitor)}), and returns a
+ * compilation unit AST if requested.
+ * <p>
+ * It performs the reconciliation by locally caching the contents of
+ * the working copy, updating the contents, then creating a delta
+ * over the cached contents and the new contents, and finally firing
+ * this delta.
+ * <p>
+ * The boolean argument allows to force problem detection even if the
+ * working copy is already consistent.
+ * </p>
+ * <p>
+ * This functionality allows to specify a working copy owner which is used
+ * during problem detection. All references contained in the working copy are
+ * resolved against other units; for which corresponding owned working copies
+ * are going to take precedence over their original compilation units. If
+ * <code>null</code> is passed in, then the primary working copy owner is used.
+ * </p>
+ * <p>
+ * Compilation problems found in the new contents are notified through the
+ * {@link IProblemRequestor} interface which was passed at
+ * creation, and no longer as transient markers.
+ * </p>
+ * <p>
+ * Note: Since 3.0, added/removed/changed inner types generate change deltas.
+ * </p>
+ * <p>
+ * If requested, a DOM AST representing the compilation unit is returned.
+ * Its bindings are computed only if the problem requestor is active, or if the
+ * problem detection is forced. This method returns <code>null</code> if the
+ * creation of the DOM AST was not requested, or if the requested level of AST
+ * API is not supported, or if the working copy was already consistent.
+ * </p>
+ *
+ * <p>
+ * If statements recovery is enabled then this method tries to rebuild statements
+ * with syntax error. Otherwise statements with syntax error won't be present in
+ * the returning DOM AST.
+ * </p>
+ *
+ * @param astLevel either {@link #NO_AST} if no AST is wanted,
+ * or the {@linkplain AST#newAST(int) AST API level} of the AST if one is wanted
+ * @param forceProblemDetection boolean indicating whether problem should be
+ *   recomputed even if the source hasn't changed
+ * @param enableStatementsRecovery if <code>true</code> statements recovery is enabled.
+ * @param owner the owner of working copies that take precedence over the
+ *   original compilation units, or <code>null</code> if the primary working
+ *   copy owner should be used
+ * @param monitor a progress monitor
+ * @return the compilation unit AST or <code>null</code> if not requested,
+ *    or if the requested level of AST API is not supported,
+ *    or if the working copy was consistent
+ * @throws JavaModelException if the contents of the original element
+ *		cannot be accessed. Reasons include:
+ * <ul>
+ * <li> The original Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * </ul>
+ * @since 3.2
+ */
+CompilationUnit reconcile(int astLevel, boolean forceProblemDetection, boolean enableStatementsRecovery, WorkingCopyOwner owner, IProgressMonitor monitor) throws JavaModelException;
+
+/**
+ * Reconciles the contents of this working copy, sends out a Java delta
+ * notification indicating the nature of the change of the working copy since
+ * the last time it was either reconciled or made consistent
+ * ({@link IOpenable#makeConsistent(IProgressMonitor)}), and returns a
+ * compilation unit AST if requested.
+ *
+ * <p>
+ * If the problem detection is forced by passing the {@link #FORCE_PROBLEM_DETECTION} bit in the given reconcile flag,
+ * problem detection is run even if the working copy is already consistent.
+ * </p>
+ *
+ * <p>
+ * It performs the reconciliation by locally caching the contents of
+ * the working copy, updating the contents, then creating a delta
+ * over the cached contents and the new contents, and finally firing
+ * this delta.</p>
+ *
+ * <p>
+ * This functionality allows to specify a working copy owner which is used
+ * during problem detection. All references contained in the working copy are
+ * resolved against other units; for which corresponding owned working copies
+ * are going to take precedence over their original compilation units. If
+ * <code>null</code> is passed in, then the primary working copy owner is used.
+ * </p>
+ * <p>
+ * Compilation problems found in the new contents are notified through the
+ * {@link IProblemRequestor} interface which was passed at
+ * creation, and no longer as transient markers.
+ * </p>
+ * <p>
+ * Note: Since 3.0, added/removed/changed inner types generate change deltas.
+ * </p>
+ * <p>
+ * If requested, a DOM AST representing the compilation unit is returned.
+ * Its bindings are computed only if the problem requestor is active, or if the
+ * problem detection is forced. This method returns <code>null</code> if the
+ * creation of the DOM AST was not requested, or if the requested level of AST
+ * API is not supported, or if the working copy was already consistent.
+ * </p>
+ *
+ * <p>
+ * If statements recovery is enabled by passing the {@link #ENABLE_STATEMENTS_RECOVERY} bit in the given reconcile flag
+ * then this method tries to rebuild statements with syntax error. Otherwise statements with syntax error won't be
+ * present in the returning DOM AST.</p>
+ * <p>
+ * If bindings recovery is enabled by passing the {@link #ENABLE_BINDINGS_RECOVERY} bit in the given reconcile flag
+ * then this method tries to resolve bindings even if the type resolution contains errors.</p>
+ * <p>
+ * The given reconcile flags is a bit-mask of the different constants ({@link #ENABLE_BINDINGS_RECOVERY},
+ * {@link #ENABLE_STATEMENTS_RECOVERY}, {@link #FORCE_PROBLEM_DETECTION}). Unspecified values are left for future use.
+ * </p>
+ *
+ * @param astLevel either {@link #NO_AST} if no AST is wanted,
+ * or the {@linkplain AST#newAST(int) AST API level} of the AST if one is wanted
+ * @param reconcileFlags the given reconcile flags
+ * @param owner the owner of working copies that take precedence over the
+ *   original compilation units, or <code>null</code> if the primary working
+ *   copy owner should be used
+ * @param monitor a progress monitor
+ * @return the compilation unit AST or <code>null</code> if not requested,
+ *    or if the requested level of AST API is not supported,
+ *    or if the working copy was consistent
+ * @throws JavaModelException if the contents of the original element
+ *		cannot be accessed. Reasons include:
+ * <ul>
+ * <li> The original Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * </ul>
+ * @see #FORCE_PROBLEM_DETECTION
+ * @see #ENABLE_BINDINGS_RECOVERY
+ * @see #ENABLE_STATEMENTS_RECOVERY
+ * @since 3.3
+ */
+CompilationUnit reconcile(int astLevel, int reconcileFlags, WorkingCopyOwner owner, IProgressMonitor monitor) throws JavaModelException;
+
+/**
  * Restores the contents of this working copy to the current contents of
  * this working copy's original element. Has no effect if this element
  * is not a working copy.
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICompletionRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICompletionRequestor.java
index 859e9ca..ef45028 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICompletionRequestor.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICompletionRequestor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICorrectionRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICorrectionRequestor.java
index 0711231..caf903d 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICorrectionRequestor.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICorrectionRequestor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IElementChangedListener.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IElementChangedListener.java
index 64fadc8..72c068e 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IElementChangedListener.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IElementChangedListener.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IImportContainer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IImportContainer.java
index 691ab5b..f780bd7 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IImportContainer.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IImportContainer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IImportDeclaration.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IImportDeclaration.java
index 1b081f6..dd4121c 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IImportDeclaration.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IImportDeclaration.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IInitializer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IInitializer.java
index 2bf888a..6cd7627 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IInitializer.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IInitializer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJarEntryResource.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJarEntryResource.java
new file mode 100755
index 0000000..7a6e89c
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJarEntryResource.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core;
+
+import org.eclipse.core.resources.IStorage;
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * A jar entry corresponding to a non-Java resource in an archive {@link IPackageFragment} or {@link IPackageFragmentRoot}.
+ * <p>
+ * One can navigate the non-Java resource tree using the {@link #getChildren()} and {@link #getParent()} methods.
+ * Jar entry resources are either files ({@link #isFile()} returns true) or directories ({@link #isFile()} returns false).
+ * Files don't have any children and the returned array is always empty.
+ * </p><p>
+ * Jar entry resources that refer to the same element are guaranteed to be equal, but not necessarily identical.
+ * <p>
+ * 
+ * @since 3.3
+ */
+public interface IJarEntryResource extends IStorage {
+	
+	/**
+	 * Returns the list of children of this jar entry resource.
+	 * Returns an empty array if this jar entry is a file, or if this jar entry is a directory and it has no children.
+	 * 
+	 * @return the children of this jar entry resource
+	 */
+	IJarEntryResource[] getChildren();
+	
+	/**
+	 * Returns the full, absolute path of this jar entry resource relative to the archive this jar 
+	 * entry belongs to.
+	 * <p>
+	 * A jar entry resource's full path indicates the route from the root of the archive
+	 * to the jar entry resource.  Within an archive, there is exactly one such path
+	 * for any given jar entry resource. The returned path never has a trailing separator.  
+	 * </p>
+	 * 
+	 * @return the absolute path of this jar entry resource
+	 */
+	IPath getFullPath();
+	
+	/**
+	 * Returns the parent of this jar entry resource. This is either an {@link IJarEntryResource}, an {@link IPackageFragment}
+	 * or an {@link IPackageFragmentRoot}.
+	 * 
+	 * @return the parent of this jar entry resource
+	 */
+	Object getParent();
+	
+	/**
+	 * Returns the package fragment root this jar entry file belongs to.
+	 * 
+	 * @return the package fragment root this jar entry file belongs to.
+	 */
+	IPackageFragmentRoot getPackageFragmentRoot();
+	
+	/**
+	 * Returns <code>true</code> if this jar entry represents a file.
+	 * Returns <code>false</code> if it is a directory.
+	 * 
+	 * @return whether this jar entry is a file
+	 */
+	boolean isFile();
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaElement.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaElement.java
index ba23088..bdf18db 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaElement.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaElement.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -13,6 +13,7 @@
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.jobs.ISchedulingRule;
 
 /**
@@ -21,7 +22,7 @@
  * The Java model may hand out any number of handles for each element. Handles
  * that refer to the same element are guaranteed to be equal, but not necessarily identical.
  * <p>
- * Methods annotated as "handle-only" do not require underlying elements to exist. 
+ * Methods annotated as "handle-only" do not require underlying elements to exist.
  * Methods that require underlying elements to exist throw
  * a <code>JavaModelException</code> when an underlying element is missing.
  * <code>JavaModelException.isDoesNotExist</code> can be used to recognize
@@ -35,92 +36,92 @@
 
 	/**
 	 * Constant representing a Java model (workspace level object).
-	 * A Java element with this type can be safely cast to <code>IJavaModel</code>.
+	 * A Java element with this type can be safely cast to {@link IJavaModel}.
 	 */
 	int JAVA_MODEL = 1;
 
 	/**
 	 * Constant representing a Java project.
-	 * A Java element with this type can be safely cast to <code>IJavaProject</code>.
+	 * A Java element with this type can be safely cast to {@link IJavaProject}.
 	 */
 	int JAVA_PROJECT = 2;
 
 	/**
 	 * Constant representing a package fragment root.
-	 * A Java element with this type can be safely cast to <code>IPackageFragmentRoot</code>.
+	 * A Java element with this type can be safely cast to {@link IPackageFragmentRoot}.
 	 */
 	int PACKAGE_FRAGMENT_ROOT = 3;
 
 	/**
 	 * Constant representing a package fragment.
-	 * A Java element with this type can be safely cast to <code>IPackageFragment</code>.
+	 * A Java element with this type can be safely cast to {@link IPackageFragment}.
 	 */
 	int PACKAGE_FRAGMENT = 4;
 
 	/**
 	 * Constant representing a Java compilation unit.
-	 * A Java element with this type can be safely cast to <code>ICompilationUnit</code>.
+	 * A Java element with this type can be safely cast to {@link ICompilationUnit}.
 	 */
 	int COMPILATION_UNIT = 5;
 
 	/**
 	 * Constant representing a class file.
-	 * A Java element with this type can be safely cast to <code>IClassFile</code>.
+	 * A Java element with this type can be safely cast to {@link IClassFile}.
 	 */
 	int CLASS_FILE = 6;
 
 	/**
 	 * Constant representing a type (a class or interface).
-	 * A Java element with this type can be safely cast to <code>IType</code>.
+	 * A Java element with this type can be safely cast to {@link IType}.
 	 */
 	int TYPE = 7;
 
 	/**
 	 * Constant representing a field.
-	 * A Java element with this type can be safely cast to <code>IField</code>.
+	 * A Java element with this type can be safely cast to {@link IField}.
 	 */
 	int FIELD = 8;
 
 	/**
 	 * Constant representing a method or constructor.
-	 * A Java element with this type can be safely cast to <code>IMethod</code>.
+	 * A Java element with this type can be safely cast to {@link IMethod}.
 	 */
 	int METHOD = 9;
 
 	/**
 	 * Constant representing a stand-alone instance or class initializer.
-	 * A Java element with this type can be safely cast to <code>IInitializer</code>.
+	 * A Java element with this type can be safely cast to {@link IInitializer}.
 	 */
 	int INITIALIZER = 10;
 
 	/**
 	 * Constant representing a package declaration within a compilation unit.
-	 * A Java element with this type can be safely cast to <code>IPackageDeclaration</code>.
+	 * A Java element with this type can be safely cast to {@link IPackageDeclaration}.
 	 */
 	int PACKAGE_DECLARATION = 11;
 
 	/**
 	 * Constant representing all import declarations within a compilation unit.
-	 * A Java element with this type can be safely cast to <code>IImportContainer</code>.
+	 * A Java element with this type can be safely cast to {@link IImportContainer}.
 	 */
 	int IMPORT_CONTAINER = 12;
 
 	/**
 	 * Constant representing an import declaration within a compilation unit.
-	 * A Java element with this type can be safely cast to <code>IImportDeclaration</code>.
+	 * A Java element with this type can be safely cast to {@link IImportDeclaration}.
 	 */
 	int IMPORT_DECLARATION = 13;
-	
+
 	/**
 	 * Constant representing a local variable declaration.
-	 * A Java element with this type can be safely cast to <code>ILocalVariable</code>.
+	 * A Java element with this type can be safely cast to {@link ILocalVariable}.
 	 * @since 3.0
 	 */
 	int LOCAL_VARIABLE = 14;
-	
+
 	/**
 	 * Constant representing a type parameter declaration.
-	 * A Java element with this type can be safely cast to <code>ITypeParameter</code>.
+	 * A Java element with this type can be safely cast to {@link ITypeParameter}.
 	 * @since 3.1
 	 */
 	int TYPE_PARAMETER = 15;
@@ -146,12 +147,12 @@
 	 * <code>false</code> if this element does not exist
 	 */
 	boolean exists();
-	
+
 	/**
 	 * Returns the first ancestor of this Java element that has the given type.
 	 * Returns <code>null</code> if no such an ancestor can be found.
 	 * This is a handle-only method.
-	 * 
+	 *
 	 * @param ancestorType the given type
 	 * @return the first ancestor of this Java element that has the given type, null if no such an ancestor can be found
 	 * @since 2.0
@@ -159,13 +160,37 @@
 	IJavaElement getAncestor(int ancestorType);
 
 	/**
+	 * <p>Returns the Javadoc as an html source if this element has an attached javadoc,
+	 * null otherwise.</p>
+	 * <p>This should be used only for binary elements. Source elements will always return null.</p>
+	 * <p>The encoding used to read the javadoc is the one defined by the content type of the
+	 * file. If none is defined, then the project's encoding of this java element is used. If the project's
+	 * encoding cannot be retrieved, then the platform encoding is used.</p>
+	 * <p>In case of the javadoc doesn't exist for this element, null is returned.</p>
+	 *
+	 * <p>The html is extracted from the attached javadoc and provided as is. No
+	 * transformation or validation is done.</p>
+	 *
+	 * @param monitor the given progress monitor
+	 * @exception JavaModelException if:<ul>
+	 *  <li>this element does not exist</li>
+	 *  <li>retrieving the attached javadoc fails (timed-out, invalid URL, ...)</li>
+	 *  <li>the format of the javadoc doesn't match expected standards (different anchors,...)</li>
+	 *  </ul>
+	 * @return the extracted javadoc from the attached javadoc, null if none
+	 * @see IClasspathAttribute#JAVADOC_LOCATION_ATTRIBUTE_NAME
+	 * @since 3.2
+	 */
+	String getAttachedJavadoc(IProgressMonitor monitor) throws JavaModelException;
+
+	/**
 	 * Returns the resource that corresponds directly to this element,
 	 * or <code>null</code> if there is no resource that corresponds to
 	 * this element.
 	 * <p>
 	 * For example, the corresponding resource for an <code>ICompilationUnit</code>
 	 * is its underlying <code>IFile</code>. The corresponding resource for
-	 * an <code>IPackageFragment</code> that is not contained in an archive 
+	 * an <code>IPackageFragment</code> that is not contained in an archive
 	 * is its underlying <code>IFolder</code>. An <code>IPackageFragment</code>
 	 * contained in an archive has no corresponding resource. Similarly, there
 	 * are no corresponding resources for <code>IMethods</code>,
@@ -198,7 +223,7 @@
 	/**
 	 * Returns a string representation of this element handle. The format of
 	 * the string is not specified; however, the identifier is stable across
-	 * workspace sessions, and can be used to recreate this handle via the 
+	 * workspace sessions, and can be used to recreate this handle via the
 	 * <code>JavaCore.create(String)</code> method.
 	 *
 	 * @return the string handle identifier
@@ -217,7 +242,7 @@
 	/**
 	 * Returns the Java project this element is contained in,
 	 * or <code>null</code> if this element is not contained in any Java project
-	 * (for instance, the <code>IJavaModel</code> is not contained in any Java 
+	 * (for instance, the <code>IJavaModel</code> is not contained in any Java
 	 * project).
 	 * This is a handle-only method.
 	 *
@@ -231,7 +256,7 @@
 	 * itself is returned. Returns <code>null</code> if this element doesn't have
 	 * an openable parent.
 	 * This is a handle-only method.
-	 * 
+	 *
 	 * @return the first openable parent or <code>null</code> if this element doesn't have
 	 * an openable parent.
 	 * @since 2.0
@@ -248,26 +273,26 @@
 	IJavaElement getParent();
 
 	/**
-	 * Returns the path to the innermost resource enclosing this element. 
-	 * If this element is not included in an external archive, 
-	 * the path returned is the full, absolute path to the underlying resource, 
-	 * relative to the workbench. 
-	 * If this element is included in an external archive, 
+	 * Returns the path to the innermost resource enclosing this element.
+	 * If this element is not included in an external archive,
+	 * the path returned is the full, absolute path to the underlying resource,
+	 * relative to the workbench.
+	 * If this element is included in an external archive,
 	 * the path returned is the absolute path to the archive in the file system.
 	 * This is a handle-only method.
-	 * 
+	 *
 	 * @return the path to the innermost resource enclosing this element
 	 * @since 2.0
 	 */
 	IPath getPath();
-	
+
 	/**
 	 * Returns the primary element (whose compilation unit is the primary compilation unit)
 	 * this working copy element was created from, or this element if it is a descendant of a
 	 * primary compilation unit or if it is not a descendant of a working copy (e.g. it is a
 	 * binary member).
 	 * The returned element may or may not exist.
-	 * 
+	 *
 	 * @return the primary element this working copy element was created from, or this
 	 * 			element.
 	 * @since 3.0
@@ -275,23 +300,23 @@
 	IJavaElement getPrimaryElement();
 
 	/**
-	 * Returns the innermost resource enclosing this element. 
-	 * If this element is included in an archive and this archive is not external, 
-	 * this is the underlying resource corresponding to the archive. 
+	 * Returns the innermost resource enclosing this element.
+	 * If this element is included in an archive and this archive is not external,
+	 * this is the underlying resource corresponding to the archive.
 	 * If this element is included in an external archive, <code>null</code>
 	 * is returned.
 	 * This is a handle-only method.
-	 * 
-	 * @return the innermost resource enclosing this element, <code>null</code> if this 
+	 *
+	 * @return the innermost resource enclosing this element, <code>null</code> if this
 	 * element is included in an external archive
 	 * @since 2.0
 	 */
 	IResource getResource();
-	
+
 	/**
 	 * 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
 	 */
@@ -310,10 +335,10 @@
 
 	/**
 	 * Returns whether this Java element is read-only. An element is read-only
-	 * if its structure cannot be modified by the java model. 
+	 * if its structure cannot be modified by the java model.
 	 * <p>
 	 * Note this is different from IResource.isReadOnly(). For example, .jar
-	 * files are read-only as the java model doesn't know how to add/remove 
+	 * files are read-only as the java model doesn't know how to add/remove
 	 * elements in this file, but the underlying IFile can be writable.
 	 * <p>
 	 * This is a handle-only method.
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaElementDelta.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaElementDelta.java
index 98fcbf6..d08920e 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaElementDelta.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaElementDelta.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -11,6 +11,7 @@
 package org.eclipse.jdt.core;
 
 import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.jdt.core.dom.CompilationUnit;
 
 /**
  * A Java element delta describes changes in Java element between two discrete
@@ -18,45 +19,45 @@
  * changed, and any children that have changed.
  * <p>
  * Deltas have a different status depending on the kind of change they represent.  
- * The list below summarizes each status (as returned by <code>getKind</code>)
+ * The list below summarizes each status (as returned by {@link #getKind})
  * and its meaning (see individual constants for a more detailled description):
  * <ul>
- * <li><code>ADDED</code> - The element described by the delta has been added.</li>
- * <li><code>REMOVED</code> - The element described by the delta has been removed.</li>
- * <li><code>CHANGED</code> - The element described by the delta has been changed in some way.  
- * Specification of the type of change is provided by <code>getFlags</code> which returns the following values:
+ * <li>{@link #ADDED} - The element described by the delta has been added.</li>
+ * <li>{@link #REMOVED} - The element described by the delta has been removed.</li>
+ * <li>{@link #CHANGED} - The element described by the delta has been changed in some way.  
+ * Specification of the type of change is provided by {@link #getFlags} which returns the following values:
  * <ul>
- * <li><code>F_ADDED_TO_CLASSPATH</code> - A classpath entry corresponding to the element
+ * <li>{@link #F_ADDED_TO_CLASSPATH} - A classpath entry corresponding to the element
  * has been added to the project's classpath. This flag is only valid if the element is an 
- * <code>IPackageFragmentRoot</code>.</li>
- * <li><code>F_ARCHIVE_CONTENT_CHANGED</code> - The contents of an archive
- * has changed in some way. This flag is only valid if the element is an <code>IPackageFragmentRoot</code>
+ * {@link IPackageFragmentRoot}.</li>
+ * <li>{@link #F_ARCHIVE_CONTENT_CHANGED} - The contents of an archive
+ * has changed in some way. This flag is only valid if the element is an {@link IPackageFragmentRoot}
  * which is an archive.</li>
- * <li><code>F_CHILDREN</code> - A child of the element has changed in some way.  This flag
- * is only valid if the element is an <code>IParent</code>.</li>
- * <li><code>F_CLASSPATH_REORDER</code> - A classpath entry corresponding to the element
+ * <li>{@link #F_CHILDREN} - A child of the element has changed in some way.  This flag
+ * is only valid if the element is an {@link IParent}.</li>
+ * <li>{@link #F_CLASSPATH_REORDER} - A classpath entry corresponding to the element
  * has changed position in the project's classpath. This flag is only valid if the element is an 
- * <code>IPackageFragmentRoot</code>.</li>
- * <li><code>F_CLOSED</code> - The underlying <code>IProject</code>
- * has been closed. This flag is only valid if the element is an <code>IJavaProject</code>.</li>
- * <li><code>F_CONTENT</code> - The contents of the element have been altered.  This flag
+ * {@link IPackageFragmentRoot}.</li>
+ * <li>{@link #F_CLOSED} - The underlying {@link org.eclipse.core.resources.IProject}
+ * has been closed. This flag is only valid if the element is an {@link IJavaProject}.</li>
+ * <li>{@link #F_CONTENT} - The contents of the element have been altered.  This flag
  * is only valid for elements which correspond to files.</li>
- *<li><code>F_FINE_GRAINED</code> - The delta is a fine-grained delta, that is, an analysis down
+ *<li>{@link #F_FINE_GRAINED} - The delta is a fine-grained delta, that is, an analysis down
  * to the members level was done to determine if there were structural changes to members of the element.</li>
- * <li><code>F_MODIFIERS</code> - The modifiers on the element have changed in some way. 
- * This flag is only valid if the element is an <code>IMember</code>.</li>
- * <li><code>F_OPENED</code> - The underlying <code>IProject</code>
- * has been opened. This flag is only valid if the element is an <code>IJavaProject</code>.</li>
- * <li><code>F_REMOVED_FROM_CLASSPATH</code> - A classpath entry corresponding to the element 
+ * <li>{@link #F_MODIFIERS} - The modifiers on the element have changed in some way. 
+ * This flag is only valid if the element is an {@link IMember}.</li>
+ * <li>{@link #F_OPENED} - The underlying {@link org.eclipse.core.resources.IProject}
+ * has been opened. This flag is only valid if the element is an {@link IJavaProject}.</li>
+ * <li>{@link #F_REMOVED_FROM_CLASSPATH} - A classpath entry corresponding to the element 
  * has been removed from the project's classpath. This flag is only valid if the element is an 
- * <code>IPackageFragmentRoot</code>.</li>
- * <li><code>F_SOURCEATTACHED</code> - The source attachment path or the source attachment root path
+ * {@link IPackageFragmentRoot}.</li>
+ * <li>{@link #F_SOURCEATTACHED} - The source attachment path or the source attachment root path
  * of a classpath entry corresponding to the element was added. This flag is only valid if the element is an 
- * <code>IPackageFragmentRoot</code>.</li>
- * <li><code>F_SOURCEDETACHED</code> - The source attachment path or the source attachment root path
+ * {@link IPackageFragmentRoot}.</li>
+ * <li>{@link #F_SOURCEDETACHED} - The source attachment path or the source attachment root path
  * of a classpath entry corresponding to the element was removed. This flag is only valid if the element is an 
- * <code>IPackageFragmentRoot</code>.</li>
- * <li><code>F_SUPER_TYPES</code> - One of the supertypes of an <code>IType</code> has changed</li>.
+ * {@link IPackageFragmentRoot}.</li>
+ * <li>{@link #F_SUPER_TYPES} - One of the supertypes of an {@link IType} has changed</li>.
  * </ul>
  * </li>
  * </ul>
@@ -64,11 +65,11 @@
  * <p>
  * Move operations are indicated by other change flags, layered on top
  * of the change flags described above. If element A is moved to become B,
- * the delta for the  change in A will have status <code>REMOVED</code>,
- * with change flag <code>F_MOVED_TO</code>. In this case,
- * <code>getMovedToElement</code> on delta A will return the handle for B.
- * The  delta for B will have status <code>ADDED</code>, with change flag
- * <code>F_MOVED_FROM</code>, and <code>getMovedFromElement</code> on delta
+ * the delta for the  change in A will have status {@link #REMOVED},
+ * with change flag {@link #F_MOVED_TO}. In this case,
+ * {@link #getMovedToElement} on delta A will return the handle for B.
+ * The  delta for B will have status {@link #ADDED}, with change flag
+ * {@link #F_MOVED_FROM}, and {@link #getMovedFromElement} on delta
  * B will return the handle for A. (Note, the handle to A in this case represents
  * an element that no longer exists).
  * </p>
@@ -77,25 +78,25 @@
  * do not imply anything about the parent or children of the element.
  * </p>
  * <p>
- * The <code>F_ADDED_TO_CLASSPATH</code>, <code>F_REMOVED_FROM_CLASSPATH</code> and
- * <code>F_CLASSPATH_REORDER</code> flags are triggered by changes to a project's classpath. They do not mean that
+ * The {@link #F_ADDED_TO_CLASSPATH}, {@link #F_REMOVED_FROM_CLASSPATH} and
+ * {@link #F_CLASSPATH_REORDER} flags are triggered by changes to a project's classpath. They do not mean that
  * the underlying resource was added, removed or changed. For example, if a project P already contains a folder src, then 
- * adding a classpath entry with the 'P/src' path to the project's classpath will result in an <code>IJavaElementDelta</code> 
- * with the <code>F_ADDED_TO_CLASSPATH</code> flag for the <code>IPackageFragmentRoot</code> P/src.
+ * adding a classpath entry with the 'P/src' path to the project's classpath will result in an {@link IJavaElementDelta} 
+ * with the {@link #F_ADDED_TO_CLASSPATH} flag for the {@link IPackageFragmentRoot} P/src.
  * On the contrary, if a resource is physically added, removed or changed and this resource corresponds to a classpath
- * entry of the project, then an <code>IJavaElementDelta</code> with the <code>ADDED</code>, 
- * <code>REMOVED</code>, or <code>CHANGED</code> kind will be fired.
+ * entry of the project, then an {@link IJavaElementDelta} with the {@link #ADDED}, 
+ * {@link #REMOVED}, or {@link #CHANGED} kind will be fired.
  * </p>
  * <p>
  * Note that when a source attachment path or a source attachment root path is changed, then the flags of the delta contain
- * both <code>F_SOURCEATTACHED</code> and <code>F_SOURCEDETTACHED</code>.
+ * both {@link #F_SOURCEATTACHED} and {@link #F_SOURCEDETACHED}.
  * </p>
  * <p>
- * No assumptions should be made on whether the java element delta tree is rooted at the <code>IJavaModel</code>
+ * No assumptions should be made on whether the java element delta tree is rooted at the {@link IJavaModel}
  * level or not.
  * </p>
  * <p>
- * <code>IJavaElementDelta</code> object are not valid outside the dynamic scope
+ * {@link IJavaElementDelta} object are not valid outside the dynamic scope
  * of the notification.
  * </p>
  * <p>
@@ -128,90 +129,90 @@
 	 * Change flag indicating that the content of the element has changed.
 	 * This flag is only valid for elements which correspond to files.
 	 */
-	public int F_CONTENT = 0x00001;
+	public int F_CONTENT = 0x000001;
 
 	/**
 	 * Change flag indicating that the modifiers of the element have changed.
-	 * This flag is only valid if the element is an <code>IMember</code>. 
+	 * This flag is only valid if the element is an {@link IMember}. 
 	 */
-	public int F_MODIFIERS = 0x00002;
+	public int F_MODIFIERS = 0x000002;
 
 	/**
 	 * Change flag indicating that there are changes to the children of the element.
-	 * This flag is only valid if the element is an <code>IParent</code>. 
+	 * This flag is only valid if the element is an {@link IParent}. 
 	 */
-	public int F_CHILDREN = 0x00008;
+	public int F_CHILDREN = 0x000008;
 
 	/**
 	 * Change flag indicating that the element was moved from another location.
-	 * The location of the old element can be retrieved using <code>getMovedFromElement</code>.
+	 * The location of the old element can be retrieved using {@link #getMovedFromElement}.
 	 */
-	public int F_MOVED_FROM = 0x00010;
+	public int F_MOVED_FROM = 0x000010;
 
 	/**
 	 * Change flag indicating that the element was moved to another location.
-	 * The location of the new element can be retrieved using <code>getMovedToElement</code>.
+	 * The location of the new element can be retrieved using {@link #getMovedToElement}.
 	 */
-	public int F_MOVED_TO = 0x00020;
+	public int F_MOVED_TO = 0x000020;
 
 	/**
 	 * Change flag indicating that a classpath entry corresponding to the element has been added to the project's classpath. 
-	 * This flag is only valid if the element is an <code>IPackageFragmentRoot</code>.
+	 * This flag is only valid if the element is an {@link IPackageFragmentRoot}.
 	 */
-	public int F_ADDED_TO_CLASSPATH = 0x00040;
+	public int F_ADDED_TO_CLASSPATH = 0x000040;
 
 	/**
 	 * Change flag indicating that a classpath entry corresponding to the element has been removed from the project's 
-	 * classpath. This flag is only valid if the element is an <code>IPackageFragmentRoot</code>.
+	 * classpath. This flag is only valid if the element is an {@link IPackageFragmentRoot}.
 	 */
-	public int F_REMOVED_FROM_CLASSPATH = 0x00080;
+	public int F_REMOVED_FROM_CLASSPATH = 0x000080;
 
 	/**
 	 * Change flag indicating that a classpath entry corresponding to the element has changed position in the project's 
-	 * classpath. This flag is only valid if the element is an <code>IPackageFragmentRoot</code>.
-	 * @deprecated Use F_REORDER instead.
+	 * classpath. This flag is only valid if the element is an {@link IPackageFragmentRoot}.
+	 * @deprecated Use {@link #F_REORDER} instead.
 	 */
-	public int F_CLASSPATH_REORDER = 0x00100;
+	public int F_CLASSPATH_REORDER = 0x000100;
 	/**
 	 * Change flag indicating that the element has changed position relatively to its siblings. 
-	 * If the element is an <code>IPackageFragmentRoot</code>,  a classpath entry corresponding 
+	 * If the element is an {@link IPackageFragmentRoot},  a classpath entry corresponding 
 	 * to the element has changed position in the project's classpath.
 	 * 
 	 * @since 2.1
 	 */
-	public int F_REORDER = 0x00100;
+	public int F_REORDER = 0x000100;
 
 	/**
-	 * Change flag indicating that the underlying <code>IProject</code> has been
-	 * opened. This flag is only valid if the element is an <code>IJavaProject</code>. 
+	 * Change flag indicating that the underlying {@link org.eclipse.core.resources.IProject} has been
+	 * opened. This flag is only valid if the element is an {@link IJavaProject}. 
 	 */
-	public int F_OPENED = 0x00200;
+	public int F_OPENED = 0x000200;
 
 	/**
-	 * Change flag indicating that the underlying <code>IProject</code> has been
-	 * closed. This flag is only valid if the element is an <code>IJavaProject</code>. 
+	 * Change flag indicating that the underlying {@link org.eclipse.core.resources.IProject} has been
+	 * closed. This flag is only valid if the element is an {@link IJavaProject}. 
 	 */
-	public int F_CLOSED = 0x00400;
+	public int F_CLOSED = 0x000400;
 
 	/**
-	 * Change flag indicating that one of the supertypes of an <code>IType</code>
+	 * Change flag indicating that one of the supertypes of an {@link IType}
 	 * has changed.
 	 */
-	public int F_SUPER_TYPES = 0x00800;
+	public int F_SUPER_TYPES = 0x000800;
 
 	/**
 	 * Change flag indicating that the source attachment path or the source attachment root path of a classpath entry 
 	 * corresponding to the element was added. This flag is only valid if the element is an 
-	 * <code>IPackageFragmentRoot</code>.
+	 * {@link IPackageFragmentRoot}.
 	 */
-	public int F_SOURCEATTACHED = 0x01000;	
+	public int F_SOURCEATTACHED = 0x001000;	
 
 	/**
 	 * Change flag indicating that the source attachment path or the source attachment root path of a classpath entry 
 	 * corresponding to the element was removed. This flag is only valid if the element is an 
-	 * <code>IPackageFragmentRoot</code>.
+	 * {@link IPackageFragmentRoot}.
 	 */
-	public int F_SOURCEDETACHED = 0x02000;	
+	public int F_SOURCEDETACHED = 0x002000;	
 	
 	/**
 	 * Change flag indicating that this is a fine-grained delta, that is, an analysis down
@@ -219,51 +220,68 @@
 	 * members.
 	 * <p>
 	 * Clients can use this flag to find out if a compilation unit 
-     * that have a <code>F_CONTENT</code> change should assume that there are 
-     * no finer grained changes (<code>F_FINE_GRAINED</code> is set) or if 
-     * finer grained changes were not considered (<code>F_FINE_GRAINED</code> 
+     * that have a {@link #F_CONTENT} change should assume that there are 
+     * no finer grained changes ({@link #F_FINE_GRAINED} is set) or if 
+     * finer grained changes were not considered ({@link #F_FINE_GRAINED} 
      * is not set). 
      * 
      * @since 2.0
 	 */
-	public int F_FINE_GRAINED = 0x04000;
+	public int F_FINE_GRAINED = 0x004000;
 
 	/**
 	 * Change flag indicating that the element's archive content on the classpath has changed.
-	 * This flag is only valid if the element is an <code>IPackageFragmentRoot</code>
+	 * This flag is only valid if the element is an {@link IPackageFragmentRoot}
 	 * which is an archive.
 	 * 
 	 * @see IPackageFragmentRoot#isArchive()
 	 * @since 2.0
 	 */
-	public int F_ARCHIVE_CONTENT_CHANGED = 0x08000;
+	public int F_ARCHIVE_CONTENT_CHANGED = 0x008000;
 	
 	/**
 	 * Change flag indicating that a compilation unit has become a primary working copy, or that a 
 	 * primary working copy has reverted to a compilation unit.
-	 * This flag is only valid if the element is an <code>ICompilationUnit</code>.
+	 * This flag is only valid if the element is an {@link ICompilationUnit}.
 	 * 
 	 * @since 3.0
 	 */
-	public int F_PRIMARY_WORKING_COPY = 0x10000;
+	public int F_PRIMARY_WORKING_COPY = 0x010000;
 
 	/**
 	 * Change flag indicating that the raw classpath (or the output folder) of a project has changed. 
-	 * This flag is only valid if the element is an <code>IJavaProject</code>.
+	 * This flag is only valid if the element is an {@link IJavaProject}.
 	 *
 	 * @since 3.0
 	 */
-	public int F_CLASSPATH_CHANGED = 0x20000;
+	public int F_CLASSPATH_CHANGED = 0x020000;
 
 	/**
 	 * Change flag indicating that the resource of a primary compilation unit has changed.
-	 * This flag is only valid if the element is a primary <code>ICompilationUnit</code>.
+	 * This flag is only valid if the element is a primary {@link ICompilationUnit}.
 	 * 
 	 * @since 3.0
 	 */
-	public int F_PRIMARY_RESOURCE = 0x40000;
+	public int F_PRIMARY_RESOURCE = 0x040000;
 
 	/**
+	 * Change flag indicating that a reconcile operation has affected the compilation unit AST created in a 
+	 * previous reconcile operation. Use {@link #getCompilationUnitAST()} to retrieve the AST (if any is available).
+	 * This flag is only valid if the element is an {@link ICompilationUnit} in working copy mode.
+	 * 
+	 * @since 3.2
+	 */
+	public int F_AST_AFFECTED = 0x080000;
+	
+	/**
+	 * Change flag indicating that the categories of the element have changed.
+	 * This flag is only valid if the element is an {@link IMember}. 
+	 * 
+	 * @since 3.2
+	 */
+	public int F_CATEGORIES = 0x100000;
+	
+	/**
 	 * Returns deltas for the children that have been added.
 	 * @return deltas for the children that have been added
 	 */
@@ -274,6 +292,22 @@
 	 * @return deltas for the affected (added, removed, or changed) children
 	 */
 	public IJavaElementDelta[] getAffectedChildren();
+	
+	/**
+	 * Returns the compilation unit AST created by the last reconcile operation on this delta's element.
+	 * This returns a non-null value if and only if:
+	 * <ul>
+	 * <li>the last reconcile operation on this working copy requested an AST</li>
+	 * <li>this delta's element is an {@link ICompilationUnit} in working copy mode</li>
+	 * <li>the delta comes from a {@link ElementChangedEvent#POST_RECONCILE} event
+	 * </ul>
+	 * 
+	 * @return the AST created during the last reconcile operation
+	 * @see ICompilationUnit#reconcile(int, boolean, WorkingCopyOwner, org.eclipse.core.runtime.IProgressMonitor)
+	 * @see #F_AST_AFFECTED
+	 * @since 3.2
+	 */
+	public CompilationUnit getCompilationUnitAST();
 
 	/**
 	 * Returns deltas for the children which have changed.
@@ -301,8 +335,8 @@
 	public int getFlags();
 
 	/**
-	 * Returns the kind of this delta - one of <code>ADDED</code>, <code>REMOVED</code>,
-	 * or <code>CHANGED</code>.
+	 * Returns the kind of this delta - one of {@link #ADDED}, {@link #REMOVED},
+	 * or {@link #CHANGED}.
 	 * 
 	 * @return the kind of this delta
 	 */
@@ -311,21 +345,21 @@
 	/**
 	 * Returns an element describing this element before it was moved
 	 * to its current location, or <code>null</code> if the
-	 * <code>F_MOVED_FROM</code> change flag is not set. 
+	 * {@link #F_MOVED_FROM} change flag is not set. 
 	 * 
 	 * @return an element describing this element before it was moved
 	 * to its current location, or <code>null</code> if the
-	 * <code>F_MOVED_FROM</code> change flag is not set
+	 * {@link #F_MOVED_FROM} change flag is not set
 	 */
 	public IJavaElement getMovedFromElement();
 
 	/**
 	 * Returns an element describing this element in its new location,
-	 * or <code>null</code> if the <code>F_MOVED_TO</code> change
+	 * or <code>null</code> if the {@link #F_MOVED_TO} change
 	 * flag is not set.
 	 * 
 	 * @return an element describing this element in its new location,
-	 * or <code>null</code> if the <code>F_MOVED_TO</code> change
+	 * or <code>null</code> if the {@link #F_MOVED_TO} change
 	 * flag is not set
 	 */
 	public IJavaElement getMovedToElement();
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModel.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModel.java
index b646b91..f29180a 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModel.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModel.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelMarker.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelMarker.java
index a33ba49..f1e1aa5 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelMarker.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelMarker.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -20,72 +20,91 @@
 public interface IJavaModelMarker {
 
 	/**
-	 * Java model problem marker type (value <code>"org.eclipse.jdt.core.problem"</code>).
-	 * This can be used to recognize those markers in the workspace that flag problems 
-	 * detected by the Java tooling during compilation.
+	 * Java model problem marker type (value
+	 * <code>"org.eclipse.jdt.core.problem"</code>). This can be used to
+	 * recognize those markers in the workspace that flag problems detected by
+	 * the Java tooling during compilation.
 	 */
-	public static final String JAVA_MODEL_PROBLEM_MARKER = JavaCore.PLUGIN_ID + ".problem"; //$NON-NLS-1$
+	String JAVA_MODEL_PROBLEM_MARKER = JavaCore.PLUGIN_ID + ".problem"; //$NON-NLS-1$
 
 	/**
-	 * Java model transient problem marker type (value <code>"org.eclipse.jdt.core.transient_problem"</code>).
-	 * This can be used to recognize those markers in the workspace that flag transient
-	 * problems detected by the Java tooling (such as a problem
-	 * detected by the outliner, or a problem detected during a code completion)
+	 * Java model transient problem marker type (value
+	 * <code>"org.eclipse.jdt.core.transient_problem"</code>). This can be
+	 * used to recognize those markers in the workspace that flag transient
+	 * problems detected by the Java tooling (such as a problem detected by the
+	 * outliner, or a problem detected during a code completion). Since 1.0,
+	 * transient problems are reported as <code>IProblem</code> through
+	 * various API. Only the evaluation API is still producing markers for
+	 * transient problems.
+	 * 
+	 * @see org.eclipse.jdt.core.compiler.IProblem
+	 * @see org.eclipse.jdt.core.eval.ICodeSnippetRequestor#acceptProblem(org.eclipse.core.resources.IMarker,String,
+	 *      int)
 	 */
-	public static final String TRANSIENT_PROBLEM = JavaCore.PLUGIN_ID + ".transient_problem"; //$NON-NLS-1$
+	String TRANSIENT_PROBLEM = JavaCore.PLUGIN_ID + ".transient_problem"; //$NON-NLS-1$
 
 	/**
-	 * Java model task marker type (value <code>"org.eclipse.jdt.core.task"</code>).
-	 * This can be used to recognize task markers in the workspace that correspond to tasks
-	 * specified in Java source comments and detected during compilation (for example, 'TO-DO: ...').
-	 * Tasks are identified by a task tag, which can be customized through <code>JavaCore</code>
-	 * option <code>"org.eclipse.jdt.core.compiler.taskTag"</code>.
+	 * Java model task marker type (value
+	 * <code>"org.eclipse.jdt.core.task"</code>). This can be used to
+	 * recognize task markers in the workspace that correspond to tasks
+	 * specified in Java source comments and detected during compilation (for
+	 * example, 'TO-DO: ...'). Tasks are identified by a task tag, which can be
+	 * customized through <code>JavaCore</code> option
+	 * <code>"org.eclipse.jdt.core.compiler.taskTag"</code>.
+	 * 
 	 * @since 2.1
 	 */
-	public static final String TASK_MARKER = JavaCore.PLUGIN_ID + ".task"; //$NON-NLS-1$
-    
-    /** 
-	 * Id marker attribute (value <code>"arguments"</code>).
-	 * Arguments are concatenated into one String, prefixed with an argument count (followed with colon
-	 * separator) and separated with '#' characters. For example:
-	 *     { "foo", "bar" } is encoded as "2:foo#bar",     
-	 *     {  } is encoded as "0: "
-	 * @since 2.0
-	 */
-	 public static final String ARGUMENTS = "arguments"; //$NON-NLS-1$
-    
-	/** 
-	 * Id marker attribute (value <code>"id"</code>).
-	 */
-	 public static final String ID = "id"; //$NON-NLS-1$
-
-	/** 
-	 * Flags marker attribute (value <code>"flags"</code>).
-	 * Reserved for future use.
-	 */
-	 public static final String FLAGS = "flags"; //$NON-NLS-1$
-
-	/** 
-	 * Cycle detected marker attribute (value <code>"cycleDetected"</code>).
-	 * Used only on buildpath problem markers.
-	 * The value of this attribute is either "true" or "false".
-	 */
-	 public static final String CYCLE_DETECTED = "cycleDetected"; //$NON-NLS-1$
+	String TASK_MARKER = JavaCore.PLUGIN_ID + ".task"; //$NON-NLS-1$
 
 	/**
-	 * Build path problem marker type (value <code>"org.eclipse.jdt.core.buildpath_problem"</code>).
-	 * This can be used to recognize those markers in the workspace that flag problems 
-	 * detected by the Java tooling during classpath setting.
-	 */
-	public static final String BUILDPATH_PROBLEM_MARKER = JavaCore.PLUGIN_ID + ".buildpath_problem"; //$NON-NLS-1$
-	
-	/** 
-	 * Classpath file format marker attribute (value <code>"classpathFileFormat"</code>).
-	 * Used only on buildpath problem markers.
-	 * The value of this attribute is either "true" or "false".
+	 * Id marker attribute (value <code>"arguments"</code>). Arguments are
+	 * concatenated into one String, prefixed with an argument count (followed
+	 * with colon separator) and separated with '#' characters. For example: {
+	 * "foo", "bar" } is encoded as "2:foo#bar", { } is encoded as "0: "
 	 * 
 	 * @since 2.0
 	 */
-	 public static final String CLASSPATH_FILE_FORMAT = "classpathFileFormat"; //$NON-NLS-1$
-	
+	String ARGUMENTS = "arguments"; //$NON-NLS-1$
+
+	/**
+	 * ID marker attribute (value <code>"id"</code>).
+	 */
+	String ID = "id"; //$NON-NLS-1$
+
+	/**
+	 * ID category marker attribute (value <code>"categoryId"</code>)
+	 * @since 3.2
+	 */
+	String CATEGORY_ID = "categoryId"; //$NON-NLS-1$
+
+	/**
+	 * Flags marker attribute (value <code>"flags"</code>). Reserved for
+	 * future use.
+	 */
+	String FLAGS = "flags"; //$NON-NLS-1$
+
+	/**
+	 * Cycle detected marker attribute (value <code>"cycleDetected"</code>).
+	 * Used only on buildpath problem markers. The value of this attribute is
+	 * either "true" or "false".
+	 */
+	String CYCLE_DETECTED = "cycleDetected"; //$NON-NLS-1$
+
+	/**
+	 * Build path problem marker type (value
+	 * <code>"org.eclipse.jdt.core.buildpath_problem"</code>). This can be
+	 * used to recognize those markers in the workspace that flag problems
+	 * detected by the Java tooling during classpath setting.
+	 */
+	String BUILDPATH_PROBLEM_MARKER = JavaCore.PLUGIN_ID
+			+ ".buildpath_problem"; //$NON-NLS-1$
+
+	/**
+	 * Classpath file format marker attribute (value
+	 * <code>"classpathFileFormat"</code>). Used only on buildpath problem
+	 * markers. The value of this attribute is either "true" or "false".
+	 * 
+	 * @since 2.0
+	 */
+	String CLASSPATH_FILE_FORMAT = "classpathFileFormat"; //$NON-NLS-1$
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelStatus.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelStatus.java
index c90b830..84131cd 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelStatus.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelStatus.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -67,7 +67,7 @@
  *
  * @return the string culprit, or <code>null</code> if none
  * @see IJavaModelStatusConstants
- * @deprecated Use IStatus#getMessage instead
+ * @deprecated Use {@link IStatus#getMessage()} instead
  */
 String getString();
 /**
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelStatusConstants.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelStatusConstants.java
index 65b294d..ad659f6 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelStatusConstants.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelStatusConstants.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -306,5 +306,24 @@
 	 * Status constant indicating that a compiler option is invalid.
 	 * @since 3.1
 	 */
-//	public static final int INVALID_COMPILER_OPTION = 1007;	
+//	public static final int INVALID_COMPILER_OPTION = 1007;
+	/**
+	 * <p>Status constant indicating that the attached javadoc content cannot be retrieved due to multiple reasons:
+	 * invalid url, timed-out,...</p>
+	 * 
+	 * @since 3.2
+	 */
+	public static final int CANNOT_RETRIEVE_ATTACHED_JAVADOC = 1008;
+	/**
+	 * <p>Status constant indicating that the attached javadoc content format is unrecognized.</p>
+	 * 
+	 * @since 3.2
+	 */
+	public static final int UNKNOWN_JAVADOC_FORMAT = 1009;
+	/**
+	 * <p>Status constant indicating that the variable is deprecated.</p>
+	 * 
+	 * @since 3.3
+	 */
+	public static final int DEPRECATED_VARIABLE = 1010;
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaProject.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaProject.java
index c73c501..1299fda 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaProject.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaProject.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -58,6 +58,26 @@
 public interface IJavaProject extends IParent, IJavaElement, IOpenable {
 
 	/**
+	 * Decodes the classpath entry that has been encoded in the given string
+	 * in the context of this project.
+	 * Returns null if the encoded entry is malformed.
+	 * 
+	 * @param encodedEntry the encoded classpath entry
+	 * @return the decoded classpath entry, or <code>null</code> if unable to decode it
+	 * @since 3.2
+	 */
+	IClasspathEntry decodeClasspathEntry(String encodedEntry);
+	
+	/**
+	 * Encodes the given classpath entry into a string in the context of this project.
+	 * 
+	 * @param classpathEntry the classpath entry to encode
+	 * @return the encoded classpath entry
+	 * @since 3.2
+	 */
+	String encodeClasspathEntry(IClasspathEntry classpathEntry);
+	
+	/**
 	 * Returns the <code>IJavaElement</code> corresponding to the given
 	 * classpath-relative path, or <code>null</code> if no such 
 	 * <code>IJavaElement</code> is found. The result is one of an
@@ -168,8 +188,7 @@
 	 * Note that in order to be found, a type name (or its toplevel enclosing
 	 * type name) must match its corresponding compilation unit name. As a 
 	 * consequence, secondary types cannot be found using this functionality.
-	 * Secondary types can however be explicitely accessed through their enclosing
-	 * unit or found by the <code>SearchEngine</code>.
+	 * To find secondary types use {@link #findType(String, IProgressMonitor)} instead.
 	 * 
 	 * @param fullyQualifiedName the given fully qualified name
 	 * @exception JavaModelException if this project does not exist or if an
@@ -181,6 +200,21 @@
 	 */
 	IType findType(String fullyQualifiedName) throws JavaModelException;
 	/**
+	 * Same functionality as {@link #findType(String)} but also look for secondary
+	 * types if given name does not match a compilation unit name.
+	 * 
+	 * @param fullyQualifiedName the given fully qualified name
+	 * @param progressMonitor the progress monitor to report progress to,
+	 * 	or <code>null</code> if no progress monitor is provided
+	 * @exception JavaModelException if this project does not exist or if an
+	 *		exception occurs while accessing its corresponding resource
+	 * @return the first type found following this project's classpath 
+	 * with the given fully qualified name or <code>null</code> if none is found
+	 * @see IType#getFullyQualifiedName(char)
+	 * @since 3.2
+	 */
+	IType findType(String fullyQualifiedName, IProgressMonitor progressMonitor) throws JavaModelException;
+	/**
 	 * Returns the first type found following this project's classpath 
 	 * with the given fully qualified name or <code>null</code> if none is found.
 	 * The fully qualified name is a dot-separated name. For example,
@@ -192,8 +226,8 @@
 	 * Note that in order to be found, a type name (or its toplevel enclosing
 	 * type name) must match its corresponding compilation unit name. As a 
 	 * consequence, secondary types cannot be found using this functionality.
-	 * Secondary types can however be explicitely accessed through their enclosing
-	 * unit or found by the <code>SearchEngine</code>.
+	 * To find secondary types use {@link #findType(String, WorkingCopyOwner, IProgressMonitor)}
+	 * instead.
 	 * 
 	 * @param fullyQualifiedName the given fully qualified name
 	 * @param owner the owner of the returned type's compilation unit
@@ -206,6 +240,23 @@
 	 */
 	IType findType(String fullyQualifiedName, WorkingCopyOwner owner) throws JavaModelException;
 	/**
+	 * Same functionality as {@link #findType(String, WorkingCopyOwner)}
+	 * but also look for secondary types if given name does not match
+	 * a compilation unit name.
+	 * 
+	 * @param fullyQualifiedName the given fully qualified name
+	 * @param owner the owner of the returned type's compilation unit
+	 * @param progressMonitor the progress monitor to report progress to,
+	 * 	or <code>null</code> if no progress monitor is provided
+	 * @exception JavaModelException if this project does not exist or if an
+	 *		exception occurs while accessing its corresponding resource
+	 * @return the first type found following this project's classpath 
+	 * with the given fully qualified name or <code>null</code> if none is found
+	 * @see IType#getFullyQualifiedName(char)
+	 * @since 3.2
+	 */
+	IType findType(String fullyQualifiedName, WorkingCopyOwner owner, IProgressMonitor progressMonitor) throws JavaModelException;
+	/**
 	 * Returns the first type found following this project's classpath 
 	 * with the given package name and type qualified name
 	 * or <code>null</code> if none is found.
@@ -217,8 +268,8 @@
 	 * Note that in order to be found, a type name (or its toplevel enclosing
 	 * type name) must match its corresponding compilation unit name. As a 
 	 * consequence, secondary types cannot be found using this functionality.
-	 * Secondary types can however be explicitely accessed through their enclosing
-	 * unit or found by the <code>SearchEngine</code>.
+	 * To find secondary types use {@link #findType(String, String, IProgressMonitor)}
+	 * instead.
 	 * 
 	 * @param packageName the given package name
 	 * @param typeQualifiedName the given type qualified name
@@ -232,6 +283,22 @@
 	 */
 	IType findType(String packageName, String typeQualifiedName) throws JavaModelException;
 	/**
+	 * Same functionality as {@link #findType(String, String)} but also look for
+	 * secondary types if given name does not match a compilation unit name.
+	 * 
+	 * @param packageName the given package name
+	 * @param typeQualifiedName the given type qualified name
+	 * @param progressMonitor the progress monitor to report progress to,
+	 * 	or <code>null</code> if no progress monitor is provided
+	 * @exception JavaModelException if this project does not exist or if an
+	 *		exception occurs while accessing its corresponding resource
+	 * @return the first type found following this project's classpath 
+	 * with the given fully qualified name or <code>null</code> if none is found
+	 * @see IType#getFullyQualifiedName(char)
+	 * @since 3.2
+	 */
+	IType findType(String packageName, String typeQualifiedName, IProgressMonitor progressMonitor) throws JavaModelException;
+	/**
 	 * Returns the first type found following this project's classpath 
 	 * with the given package name and type qualified name
 	 * or <code>null</code> if none is found.
@@ -245,8 +312,8 @@
 	 * Note that in order to be found, a type name (or its toplevel enclosing
 	 * type name) must match its corresponding compilation unit name. As a 
 	 * consequence, secondary types cannot be found using this functionality.
-	 * Secondary types can however be explicitely accessed through their enclosing
-	 * unit or found by the <code>SearchEngine</code>.
+	 * To find secondary types use {@link #findType(String, String, WorkingCopyOwner, IProgressMonitor)}
+	 * instead.
 	 * 
 	 * @param packageName the given package name
 	 * @param typeQualifiedName the given type qualified name
@@ -260,6 +327,23 @@
 	 * @since 3.0
 	 */
 	IType findType(String packageName, String typeQualifiedName, WorkingCopyOwner owner) throws JavaModelException;
+	/**
+	 * Same functionality as {@link #findType(String, String, WorkingCopyOwner)}
+	 * but also look for secondary types if given name does not match a compilation unit name.
+	 * 
+	 * @param packageName the given package name
+	 * @param typeQualifiedName the given type qualified name
+	 * @param owner the owner of the returned type's compilation unit
+	 * @param progressMonitor the progress monitor to report progress to,
+	 * 	or <code>null</code> if no progress monitor is provided
+	 * @exception JavaModelException if this project does not exist or if an
+	 *		exception occurs while accessing its corresponding resource
+	 * @return the first type found following this project's classpath 
+	 * with the given fully qualified name or <code>null</code> if none is found
+	 * @see IType#getFullyQualifiedName(char)
+	 * @since 3.2
+	 */
+	IType findType(String packageName, String typeQualifiedName, WorkingCopyOwner owner, IProgressMonitor progressMonitor) throws JavaModelException;
 	
 	/**
 	 * Returns all of the existing package fragment roots that exist
@@ -400,7 +484,7 @@
 	 * @param entry the given entry
 	 * @return the existing package fragment roots identified by the given entry
 	 * @see IClasspathContainer
-	 * @deprecated Use IJavaProject#findPackageFragmentRoots instead
+	 * @deprecated Use {@link IJavaProject#findPackageFragmentRoots(IClasspathEntry)} instead
 	 */
 	IPackageFragmentRoot[] getPackageFragmentRoots(IClasspathEntry entry);
 
@@ -785,9 +869,88 @@
 		throws JavaModelException;
 
 	/**
+	 * Sets both the classpath of this project and its default output
+	 * location at once. The classpath is defined using a list of classpath
+	 * entries. In particular such a classpath may contain classpath variable entries. 
+	 * Classpath variable entries can be resolved individually ({@link JavaCore#getClasspathVariable(String)}),
+	 * or the full classpath can be resolved at once using the helper method {@link #getResolvedClasspath(boolean)}.
+	 * <p>
+	 * A classpath variable provides an indirection level for better sharing a classpath. As an example, it allows
+	 * a classpath to no longer refer directly to external JARs located in some user specific location. The classpath
+	 * can simply refer to some variables defining the proper locations of these external JARs.
+	 * </p><p>
+	 * If it is specified that this operation cannot modify resources, the .classpath file will not be written to disk
+	 * and no error marker will be generated. To synchronize the .classpath with the in-memory classpath,
+	 * one can use <code>setRawClasspath(readRawClasspath(), true, monitor)</code>.
+	 * </p><p>
+	 * Setting the classpath to <code>null</code> specifies a default classpath
+	 * (the project root). Setting the classpath to an empty array specifies an
+	 * empty classpath.
+	 * </p><p>
+	 * If a cycle is detected while setting this classpath (and if resources can be modified), an error marker will be added
+	 * to the project closing the cycle.
+	 * To avoid this problem, use {@link #hasClasspathCycle(IClasspathEntry[])}
+	 * before setting the classpath.
+	 * <p>
+	 * This operation acquires a lock on the workspace's root.
+	 *
+	 * @param entries a list of classpath entries
+	 * @param outputLocation the default output location
+	 * @param canModifyResources whether resources should be written to disk if needed
+	 * @param monitor the given progress monitor
+	 * @exception JavaModelException if the classpath could not be set. Reasons include:
+	 * <ul>
+	 * <li> This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+	 * <li> The classpath is being modified during resource change event notification (CORE_EXCEPTION)
+	 * <li> The classpath failed the validation check as defined by {@link JavaConventions#validateClasspath(IJavaProject, IClasspathEntry[], IPath)}
+	 * </ul>
+	 * @see IClasspathEntry
+	 * @since 3.2
+	 */
+	void setRawClasspath(IClasspathEntry[] entries, IPath outputLocation, boolean canModifyResources, IProgressMonitor monitor) throws JavaModelException;
+	
+	/**
 	 * Sets the classpath of this project using a list of classpath entries. In particular such a classpath may contain
-	 * classpath variable entries. Classpath variable entries can be resolved individually (see <code>JavaCore#getClasspathVariable</code>),
-	 * or the full classpath can be resolved at once using the helper method <code>getResolvedClasspath</code>.
+	 * classpath variable entries. Classpath variable entries can be resolved individually ({@link JavaCore#getClasspathVariable(String)}),
+	 * or the full classpath can be resolved at once using the helper method {@link #getResolvedClasspath(boolean)}.
+	 * <p>
+	 * A classpath variable provides an indirection level for better sharing a classpath. As an example, it allows
+	 * a classpath to no longer refer directly to external JARs located in some user specific location. The classpath
+	 * can simply refer to some variables defining the proper locations of these external JARs.
+	 * </p><p>
+	 * If it is specified that this operation cannot modify resources, the .classpath file will not be written to disk
+	 * and no error marker will be generated. To synchronize the .classpath with the in-memory classpath,
+	 * one can use <code>setRawClasspath(readRawClasspath(), true, monitor)</code>.
+	 * </p><p>
+	 * Setting the classpath to <code>null</code> specifies a default classpath
+	 * (the project root). Setting the classpath to an empty array specifies an
+	 * empty classpath.
+	 * </p><p>
+	 * If a cycle is detected while setting this classpath (and if resources can be modified), an error marker will be added
+	 * to the project closing the cycle.
+	 * To avoid this problem, use {@link #hasClasspathCycle(IClasspathEntry[])}
+	 * before setting the classpath.
+	 * <p>
+	 * This operation acquires a lock on the workspace's root.
+	 *
+	 * @param entries a list of classpath entries
+	 * @param canModifyResources whether resources should be written to disk if needed
+	 * @param monitor the given progress monitor
+	 * @exception JavaModelException if the classpath could not be set. Reasons include:
+	 * <ul>
+	 * <li> This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+	 * <li> The classpath is being modified during resource change event notification (CORE_EXCEPTION)
+	 * <li> The classpath failed the validation check as defined by {@link JavaConventions#validateClasspath(IJavaProject, IClasspathEntry[], IPath)}
+	 * </ul>
+	 * @see IClasspathEntry
+	 * @since 3.2
+	 */
+	void setRawClasspath(IClasspathEntry[] entries, boolean canModifyResources, IProgressMonitor monitor) throws JavaModelException;
+	
+	/**
+	 * Sets the classpath of this project using a list of classpath entries. In particular such a classpath may contain
+	 * classpath variable entries. Classpath variable entries can be resolved individually ({@link JavaCore#getClasspathVariable(String)}),
+	 * or the full classpath can be resolved at once using the helper method {@link #getResolvedClasspath(boolean)}.
 	 * <p>
 	 * A classpath variable provides an indirection level for better sharing a classpath. As an example, it allows
 	 * a classpath to no longer refer directly to external JARs located in some user specific location. The classpath
@@ -799,7 +962,7 @@
 	 * <p>
 	 * If a cycle is detected while setting this classpath, an error marker will be added
 	 * to the project closing the cycle.
-	 * To avoid this problem, use <code>hasClasspathCycle(IClasspathEntry[] entries)</code>
+	 * To avoid this problem, use {@link #hasClasspathCycle(IClasspathEntry[])}
 	 * before setting the classpath.
 	 * <p>
 	 * This operation acquires a lock on the workspace's root.
@@ -810,7 +973,7 @@
 	 * <ul>
 	 * <li> This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
 	 * <li> The classpath is being modified during resource change event notification (CORE_EXCEPTION)
-	 * <li> The classpath failed the validation check as defined by <code>JavaConventions#validateClasspath</code>
+	 * <li> The classpath failed the validation check as defined by {@link JavaConventions#validateClasspath(IJavaProject, IClasspathEntry[], IPath)}
 	 * </ul>
 	 * @see IClasspathEntry
 	 */
@@ -822,9 +985,9 @@
 	 * location at once. The classpath is defined using a list of classpath
 	 * entries. In particular, such a classpath may contain classpath variable
 	 * entries. Classpath variable entries can be resolved individually (see
-	 * <code>JavaCore#getClasspathVariable</code>), or the full classpath can be
+	 * ({@link JavaCore#getClasspathVariable(String)}), or the full classpath can be
 	 * resolved at once using the helper method
-	 * <code>getResolvedClasspath</code>.
+	 * {@link #getResolvedClasspath(boolean)}.
 	 * <p>
 	 * A classpath variable provides an indirection level for better sharing a
 	 * classpath. As an example, it allows a classpath to no longer refer
@@ -840,7 +1003,7 @@
 	 * <p>
 	 * If a cycle is detected while setting this classpath, an error marker will
 	 * be added to the project closing the cycle. To avoid this problem, use
-	 * <code>hasClasspathCycle(IClasspathEntry[] entries)</code> before setting
+	 * {@link #hasClasspathCycle(IClasspathEntry[])} before setting
 	 * the classpath.
 	 * </p>
 	 * <p>
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ILocalVariable.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ILocalVariable.java
index 1ce2918..7c0b6e1 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ILocalVariable.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ILocalVariable.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IMember.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IMember.java
index ff5cc71..59cead4 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IMember.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IMember.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -20,6 +20,17 @@
  */
 public interface IMember extends IJavaElement, ISourceReference, ISourceManipulation, IParent {
 /**
+ * Returns the categories defined by this member's Javadoc. A category is the identifier
+ * following the tag <code>@category</code> in the member's Javadoc.
+ * Returns an empty array if no category is defined in this member's Javadoc.
+ * 
+ * @return the categories defined by this member's doc
+ * @exception JavaModelException if this element does not exist or if an
+ *      exception occurs while accessing its corresponding resource.
+ *  @since 3.2
+ */
+String[] getCategories() throws JavaModelException;
+/**
  * Returns the class file in which this member is declared, or <code>null</code>
  * if this member is not declared in a class file (for example, a source type).
  * This is a handle-only method.
@@ -61,6 +72,25 @@
  */
 int getFlags() throws JavaModelException;
 /**
+ * Returns the Javadoc range if this element is from source or if this element
+ * is a binary element with an attached source, null otherwise.
+ * 
+ * <p>If this element is from source, the javadoc range is 
+ * extracted from the corresponding source.</p>
+ * <p>If this element is from a binary, the javadoc is extracted from the
+ * attached source if present.</p>
+ * <p>If this element's openable is not consistent, then null is returned.</p>
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ *      exception occurs while accessing its corresponding resource.
+ * @return a source range corresponding to the javadoc source or <code>null</code>
+ * if no source is available, this element has no javadoc comment or
+ * this element's openable is not consistent
+ * @see IOpenable#isConsistent()
+ * @since 3.2
+ */
+ISourceRange getJavadocRange() throws JavaModelException;
+/**
  * Returns the source range of this member's simple name,
  * or <code>null</code> if this member does not have a name
  * (for example, an initializer), or if this member does not have
@@ -75,6 +105,33 @@
  */
 ISourceRange getNameRange() throws JavaModelException;
 /**
+ * Returns the position relative to the order this member is defined in the source.
+ * Numbering starts at 1 (thus the first occurrence is occurrence 1, not occurrence 0).
+ * <p>
+ * Two members m1 and m2 that are equal (e.g. 2 fields with the same name in 
+ * the same type) can be distinguished using their occurrence counts. If member 
+ * m1 appears first in the source, it will have an occurrence count of 1. If member 
+ * m2 appears right after member m1, it will have an occurrence count of 2.
+ * </p><p>
+ * The occurrence count can be used to distinguish initializers inside a type
+ * or anonymous types inside a method.
+ * </p><p>
+ * This is a handle-only method.  The member may or may not be present.
+ * </p>
+ * 
+ * @return the position relative to the order this member is defined in the source
+ * @since 3.2
+ */
+int getOccurrenceCount();
+/**
+ * Returns the Java type root in which this member is declared.
+ * This is a handle-only method.
+ * 
+ * @return the Java type root in which this member is declared.
+ * @since 3.3
+ */
+ITypeRoot getTypeRoot();
+/**
  * Returns the local or anonymous type declared in this source member with the given simple name and/or
  * with the specified position relative to the order they are defined in the source.
  * The name is empty if it is an anonymous type.
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IMethod.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IMethod.java
index 92c3bd4..85e82c2 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IMethod.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IMethod.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -65,7 +65,7 @@
  * in the order declared in the source, an empty array if none
  * @see Signature
  * @since 3.0
- * @deprecated Use #getTypeParameters() instead
+ * @deprecated Use {@link #getTypeParameters()} instead
  */
 String[] getTypeParameterSignatures() throws JavaModelException;
 /**
@@ -99,8 +99,8 @@
 String getKey();
 /**
  * Returns the names of parameters in this method.
- * For binary types, these names are invented as "arg"+i, where i starts at 1 
- * (even if source is associated with the binary).
+ * For binary types, associated source or attached Javadoc are used to retrieve the names.
+ * If none can be retrieved, then these names are invented as "arg"+i, where i starts at 0.
  * Returns an empty array if this method has no parameters.
  *
  * <p>For example, a method declared as <code>public void foo(String text, int length)</code>
@@ -131,6 +131,23 @@
  */
 String[] getParameterTypes();
 /**
+ * Returns the names of parameters in this method.
+ * For binary types, these names are invented as "arg"+i, where i starts at 0 
+ * (even if source is associated with the binary or if Javdoc is attached to the binary).
+ * Returns an empty array if this method has no parameters.
+ *
+ * <p>For example, a method declared as <code>public void foo(String text, int length)</code>
+ * would return the array <code>{"text","length"}</code>. For the same method in a
+ * binary, this would return <code>{"arg0", "arg1"}</code>.
+ * </p>
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ *      exception occurs while accessing its corresponding resource.
+ * @return the names of parameters in this method, an empty array if this method has no parameters
+ * @since 3.2
+ */
+String[] getRawParameterNames() throws JavaModelException;
+/**
  * Returns the type signature of the return value of this method.
  * For constructors, this returns the signature for void.
  * <p>
@@ -196,7 +213,7 @@
  * <li>its name is equal to <code>"main"</code></li>
  * <li>its return type is <code>void</code></li>
  * <li>it is <code>static</code> and <code>public</code></li>
- * <li>it defines one parameter whose type's simple name is </code>String[]</code></li>
+ * <li>it defines one parameter whose type's simple name is <code>String[]</code></li>
  * </ul>
  * 
  * @exception JavaModelException if this element does not exist or if an
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IOpenable.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IOpenable.java
index d0f4e5d..2d1cfab 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IOpenable.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IOpenable.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -55,6 +55,19 @@
  */
 public void close() throws JavaModelException;
 /**
+ * Finds and returns the recommended line separator for this element.
+ * The element's buffer is first searched and the first line separator in this buffer is returned if any.
+ * Otherwise the preference {@link org.eclipse.core.runtime.Platform#PREF_LINE_SEPARATOR} 
+ * on this element's project or workspace is returned.
+ * Finally if no such preference is set, the system line separator is returned.
+ * 
+ * @return the recommended line separator for this element
+ * @exception JavaModelException if this element does not exist or if an
+ *		exception occurs while accessing its corresponding resource.
+ * @since 3.2
+ */
+public String findRecommendedLineSeparator() throws JavaModelException;
+/**
  * Returns the buffer opened for this element, or <code>null</code>
  * if this element does not have a buffer.
  *
@@ -110,7 +123,9 @@
  * by updating the element's structure and properties as necessary.
  *<p>
  * Note: Using this functionality on a working copy will interfere with any
- * subsequent reconciling operation. Indeed, the next {@link ICompilationUnit#reconcile}
+ * subsequent reconciling operation. Indeed, the next
+ * {@link ICompilationUnit#reconcile(int, boolean, WorkingCopyOwner, IProgressMonitor)} or
+ * {@link ICompilationUnit#reconcile(int, boolean, boolean, WorkingCopyOwner, IProgressMonitor)}
  * operation will not account for changes which occurred before an
  * explicit use of {@link #makeConsistent(IProgressMonitor)}
  * <p>
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageDeclaration.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageDeclaration.java
index 597977c..cc7f318 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageDeclaration.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageDeclaration.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragment.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragment.java
index 0ae4a74..25b7414 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragment.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragment.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -100,7 +100,7 @@
 	 * 
 	 * @param name the given name
 	 * @return the compilation unit with the specified name in this package
-	 * @see JavaConventions#validateCompilationUnitName(String)
+	 * @see JavaConventions#validateCompilationUnitName(String name, String sourceLevel, String complianceLevel)
 	 */
 	ICompilationUnit getCompilationUnit(String name);
 	/**
@@ -145,7 +145,8 @@
 	String getElementName();
 	/**
 	 * Returns this package fragment's root kind encoded as an integer.
-	 * A package fragment can contain <code>.java</code> source files,
+	 * A package fragment can contain source files (i.e. files with one of 
+	 * the {@link JavaCore#getJavaLikeExtensions() Java-like extensions}),
 	 * or <code>.class</code> files. This is a convenience method.
 	 *
 	 * @exception JavaModelException if this element does not exist or if an
@@ -164,6 +165,11 @@
 	 * inclusion/exclusion patterns on the corresponding source classpath entry
 	 * are considered non-Java resources and will appear in the result
 	 * (possibly in a folder).
+	 * </p><p>
+	 * Since 3.3, if this package fragment is inside an archive, the non-Java resources
+	 * are a tree of {@link IJarEntryResource}s. One can navigate this tree using
+	 * the {@link IJarEntryResource#getChildren()} and 
+	 * {@link IJarEntryResource#getParent()} methods.
 	 * </p>
 	 * 
 	 * @exception JavaModelException if this element does not exist or if an
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragmentRoot.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragmentRoot.java
index 527f119..e8d36dc 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragmentRoot.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragmentRoot.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -245,11 +245,12 @@
 	void delete(int updateResourceFlags, int updateModelFlags, IProgressMonitor monitor) throws JavaModelException;
 	/**
 	 * Returns this package fragment root's kind encoded as an integer.
-	 * A package fragment root can contain <code>.java</code> source files,
+	 * A package fragment root can contain source files (i.e. files with one 
+	 * of the {@link JavaCore#getJavaLikeExtensions() Java-like extensions},
 	 * or <code>.class</code> files, but not both.
 	 * If the underlying folder or archive contains other kinds of files, they are ignored.
 	 * In particular, <code>.class</code> files are ignored under a source package fragment root,
-	 * and <code>.java</code> files are ignored under a binary package fragment root.
+	 * and source files are ignored under a binary package fragment root.
 	 *
 	 * @exception JavaModelException if this element does not exist or if an
 	 *		exception occurs while accessing its corresponding resource.
@@ -269,7 +270,13 @@
 	 * entry are considered non-Java resources and will appear in the result
 	 * (possibly in a folder). Thus when a nested source folder is excluded, it will appear
 	 * in the non-Java resources of the outer folder.
+	 * </p><p>
+	 * Since 3.3, if this package fragment root is an archive, the non-Java resources
+	 * are a tree of {@link IJarEntryResource}s. One can navigate this tree using
+	 * the {@link IJarEntryResource#getChildren()} and 
+	 * {@link IJarEntryResource#getParent()} methods.
 	 * </p>
+	 * 
 	 * @return an array of non-Java resources (<code>IFile</code>s, 
 	 *              <code>IFolder</code>s, or <code>IStorage</code>s if the
 	 *              package fragment root is in archive) contained in this package 
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IParent.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IParent.java
index 66b9379..8f85575 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IParent.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IParent.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IProblemRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IProblemRequestor.java
index 2dc0c95..7781fdc 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IProblemRequestor.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IProblemRequestor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -43,7 +43,7 @@
 
 	/**
 	 * Predicate allowing the problem requestor to signal whether or not it is currently
-	 * interested by problem reports. When answering <code>false</false>, problem will
+	 * interested by problem reports. When answering <code>false</code>, problem will
 	 * not be discovered any more until the next iteration.
 	 * 
 	 * This  predicate will be invoked once prior to each problem detection iteration.
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IRegion.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IRegion.java
index b621ede..6474177 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IRegion.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IRegion.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ISourceManipulation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ISourceManipulation.java
index d19b1c7..758e818 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ISourceManipulation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ISourceManipulation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ISourceRange.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ISourceRange.java
index 468c048..a3bc9a1 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ISourceRange.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ISourceRange.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ISourceReference.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ISourceReference.java
index 3e7b79c..f005327 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ISourceReference.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ISourceReference.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -16,7 +16,6 @@
  * <code>IPackageDeclaration</code>, <code>IImportDeclaration</code>,
  * <code>IImportContainer</code>, <code>IType</code>, <code>IField</code>,
  * <code>IMethod</code>, and <code>IInitializer</code>.
- * </ul>
  * <p>
  * Note: For <code>IClassFile</code>, <code>IType</code> and other members
  * derived from a binary type, the implementation returns source iff the
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IType.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IType.java
index 95d562e..4286f85 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IType.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IType.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -345,6 +345,17 @@
 	IMethod[] findMethods(IMethod method);
 	
 	/**
+	 * Returns the children of this type that have the given category as a <code>@category</code> tag.
+	 * Returns an empty array if no children with this category exist.
+	 * 
+	 * @return the children for the given category.
+	 * @exception JavaModelException if this element does not exist or if an
+	 *      exception occurs while accessing its corresponding resource.
+	 *  @since 3.2
+	 */
+	IJavaElement[] getChildrenForCategory(String category) throws JavaModelException;
+
+	/**
 	 * Returns the simple name of this type, unqualified by package or enclosing type.
 	 * This is a handle-only method.
 	 * 
@@ -417,7 +428,7 @@
 	
 	/**
 	 * Returns this type's fully qualified name followed by its type parameters between angle brakets if it is a generic type.
-	 * For example, "p.X<T>", "java.util.Map<java.lang.String, p.X>"
+	 * For example, "p.X&lt;T&gt;", "java.util.Map&lt;java.lang.String, p.X&gt;"
 	 * 
 	 * @exception JavaModelException if this element does not exist or if an
 	 *      exception occurs while accessing its corresponding resource.
@@ -481,7 +492,7 @@
 	
 	/**
 	 * Returns the methods and constructors declared by this type.
-	 * For binary types, this may include the special <code>&lt;clinit&gt</code>; method 
+	 * For binary types, this may include the special <code>&lt;clinit&gt;</code>; method 
 	 * and synthetic methods.
 	 * If this is a source type, the results are listed in the order
 	 * in which they appear in the source, otherwise, the results are
@@ -569,7 +580,7 @@
 	/**
 	 * Returns the names of interfaces that this type implements or extends,
 	 * in the order in which they are listed in the source.
-	 * </p>
+	 * <p>
 	 * For classes, this gives the interfaces that this class implements.
 	 * For interfaces, this gives the interfaces that this interface extends.
 	 * An empty collection is returned if this type does not implement or
@@ -668,7 +679,7 @@
 	 * <li>the type qualified name of a class B defined as a member of a class A
 	 *     using the '$' separator is "A$B"</li>
 	 * <li>the type qualified name of a binary type whose class file is A$B.class
-	 *     using the '.' separator is "A.B"</li>
+	 *     using the '.' separator is "A$B"</li>
 	 * <li>the type qualified name of a binary type whose class file is A$B.class
 	 *     using the '$' separator is "A$B"</li>
 	 * <li>the type qualified name of an anonymous binary type whose class file is A$1.class
@@ -776,7 +787,7 @@
 	boolean isMember() throws JavaModelException;
 	/**
 	 * Returns whether this type represents a resolved type.
-	 * If a type is resoved, its key contains resolved information.
+	 * If a type is resolved, its key contains resolved information.
 	 * 
 	 * @return whether this type represents a resolved type.
 	 * @since 3.1
@@ -791,7 +802,7 @@
 	 * <li>IType#newSupertypeHierarchy(IProgressMonitor)</li>
 	 * <li>IType#newTypeHierarchy(IJavaProject, IProgressMonitor)</li>
 	 * <li>IType#newTypeHierarchy(IProgressMonitor)</li>
-	 * </u>
+	 * </ul>
 	 * 
 	 * @param input stream where hierarchy will be read
 	 * @param monitor the given progress monitor
@@ -850,7 +861,7 @@
 	 * @exception JavaModelException if this element does not exist or if an
 	 *		exception occurs while accessing its corresponding resource.
 	 * @since 2.0
-	 * @deprecated use #newSupertypeHierarchy(ICompilationUnit[], IProgressMonitor) instead
+	 * @deprecated Use {@link #newSupertypeHierarchy(ICompilationUnit[], IProgressMonitor)} instead
 	 */
 	ITypeHierarchy newSupertypeHierarchy(IWorkingCopy[] workingCopies, IProgressMonitor monitor)
 		throws JavaModelException;
@@ -962,7 +973,7 @@
 	 * @exception JavaModelException if this element does not exist or if an
 	 *		exception occurs while accessing its corresponding resource.
 	 * @since 2.0
-	 * @deprecated use #newTypeHierarchy(ICompilationUnit[], IProgressMonitor) instead
+	 * @deprecated Use {@link #newTypeHierarchy(ICompilationUnit[], IProgressMonitor)} instead
 	 */
 	ITypeHierarchy newTypeHierarchy(IWorkingCopy[] workingCopies, IProgressMonitor monitor) throws JavaModelException;
 	
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ITypeHierarchy.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ITypeHierarchy.java
index 64ef993..51c9732 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ITypeHierarchy.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ITypeHierarchy.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -291,7 +291,7 @@
  * <li>IType#newSupertypeHierarchy(IProgressMonitor)</li>
  * <li>IType#newTypeHierarchy(IJavaProject, IProgressMonitor)</li>
  * <li>IType#newTypeHierarchy(IProgressMonitor)</li>
- * </u>
+ * </ul>
  * 
  * @param outputStream output stream where the hierarchy will be stored
  * @param monitor the given progress monitor
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ITypeHierarchyChangedListener.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ITypeHierarchyChangedListener.java
index 335a320..5b43f1d 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ITypeHierarchyChangedListener.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ITypeHierarchyChangedListener.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ITypeParameter.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ITypeParameter.java
index 26ccbc5..12b51ef 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ITypeParameter.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ITypeParameter.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -22,6 +22,9 @@
  * of the type parameters use {@link IType#getTypeParameters()} for a type and use
  * {@link IMethod#getTypeParameters()} for a method.
  * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
  *
  * @since 3.1
  */
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ITypeRoot.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ITypeRoot.java
new file mode 100755
index 0000000..1e14fe4
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ITypeRoot.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+
+/**
+ * Represents an entire Java type root (either an <code>ICompilationUnit</code>
+ * or an <code>IClassFile</code>).
+ * 
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ *
+ * @see ICompilationUnit Note that methods {@link #findPrimaryType()} and {@link #getElementAt(int)}
+ * 	were already implemented in this interface respectively since version 3.0 and version 1.0.
+ * @see IClassFile Note that method {@link #getWorkingCopy(WorkingCopyOwner, IProgressMonitor)}
+ * 	was already implemented in this interface since version 3.0.
+ * @since 3.3
+ */
+public interface ITypeRoot extends IJavaElement, IParent, IOpenable, ISourceReference, ICodeAssist {
+
+/**
+ * Finds the primary type of this Java type root (that is, the type with the same name as the
+ * compilation unit, or the type of a class file), or <code>null</code> if no such a type exists.
+ * 
+ * @return the found primary type of this Java type root, or <code>null</code> if no such a type exists
+ */
+IType findPrimaryType();
+
+/**
+ * Returns the smallest element within this Java type root that 
+ * includes the given source position (that is, a method, field, etc.), or
+ * <code>null</code> if there is no element other than the Java type root
+ * itself at the given position, or if the given position is not
+ * within the source range of the source of this Java type root.
+ *
+ * @param position a source position inside the Java type root
+ * @return the innermost Java element enclosing a given source position or <code>null</code>
+ *	if none (excluding the Java type root).
+ * @throws JavaModelException if the Java type root does not exist or if an
+ *	exception occurs while accessing its corresponding resource
+ */
+IJavaElement getElementAt(int position) throws JavaModelException;
+	
+/**
+ * Returns a shared working copy on this compilation unit or class file using the given working copy owner to create
+ * the buffer. If this is already a working copy of the given owner, the element itself is returned.
+ * This API can only answer an already existing working copy if it is based on the same
+ * original Java type root AND was using the same working copy owner (that is, as defined by {@link Object#equals}).	 
+ * <p>
+ * The life time of a shared working copy is as follows:
+ * <ul>
+ * <li>The first call to {@link #getWorkingCopy(WorkingCopyOwner, IProgressMonitor)} 
+ * 	creates a new working copy for this element</li>
+ * <li>Subsequent calls increment an internal counter.</li>
+ * <li>A call to {@link ICompilationUnit#discardWorkingCopy()} decrements the internal counter.</li>
+ * <li>When this counter is 0, the working copy is discarded.
+ * </ul>
+ * So users of this method must discard exactly once the working copy.
+ * <p>
+ * Note that the working copy owner will be used for the life time of the shared working copy, that is if the 
+ * working copy is closed then reopened, this owner will be used.
+ * The buffer will be automatically initialized with the original's Java type root content upon creation.
+ * <p>
+ * When the shared working copy instance is created, an ADDED IJavaElementDelta is reported on this
+ * working copy.
+ * </p><p>
+ * A working copy can be created on a not-yet existing compilation unit.
+ * In particular, such a working copy can then be committed in order to create
+ * the corresponding compilation unit.
+ * </p><p>
+ * Note that possible problems of this working copy are reported using this method only
+ * if the given working copy owner returns a problem requestor for this working copy
+ * (see {@link WorkingCopyOwner#getProblemRequestor(ICompilationUnit)}).
+ * </p>
+ * 
+ * @param owner the working copy owner that creates a buffer that is used to get the content 
+ * 				of the working copy
+ * @param monitor a progress monitor used to report progress while opening this compilation unit
+ *                 or <code>null</code> if no progress should be reported 
+ * @throws JavaModelException if the contents of this element can
+ *   	not be determined. 
+ * @return a new working copy of this Java type root using the given owner to create
+ *		the buffer, or this Java type root if it is already a working copy
+ */
+ICompilationUnit getWorkingCopy(WorkingCopyOwner owner, IProgressMonitor monitor) throws JavaModelException;
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IWorkingCopy.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IWorkingCopy.java
index c034623..c3b80d1 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IWorkingCopy.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IWorkingCopy.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -49,7 +49,7 @@
  * <p>
  * This interface is not intended to be implemented by clients.
  * </p>
- * @deprecated Use <code>ICompilationUnit</code>instead
+ * @deprecated Use {@link ICompilationUnit} instead
  */
 public interface IWorkingCopy {
 	
@@ -81,6 +81,7 @@
 	 * <li> This element is not a working copy (INVALID_ELEMENT_TYPES)
 	 * <li> A update conflict (described above) (UPDATE_CONFLICT)
 	 * </ul>
+	 * @deprecated Use {@link ICompilationUnit#commitWorkingCopy(boolean, IProgressMonitor)} instead.
 	 */
 	void commit(boolean force, IProgressMonitor monitor) throws JavaModelException;
 	
@@ -97,6 +98,7 @@
 	 * When it is destroyed, a REMOVED IJavaElementDelta is reported on this 
 	 * working copy.
 	 * </p>
+	 * @deprecated Use {@link ICompilationUnit#discardWorkingCopy()} instead.
 	 */
 	void destroy();
 	
@@ -111,6 +113,8 @@
 	 * @return the found shared working copy for this element, <code>null</code> if none
 	 * @see IBufferFactory
 	 * @since 2.0
+	 * 
+	 * @deprecated Use {@link ICompilationUnit#findWorkingCopy(WorkingCopyOwner)} instead.
 	 */
 	IJavaElement findSharedWorkingCopy(IBufferFactory bufferFactory);
 
@@ -122,6 +126,8 @@
 	 * @param workingCopyElement the specified working copy element
 	 * @return the original element the specified working copy element was created from,
 	 * or <code>null</code> if this is not a working copy element
+	 * 
+	 * @deprecated Use {@link IJavaElement#getPrimaryElement()} instead.
 	 */
 	IJavaElement getOriginal(IJavaElement workingCopyElement);
 	
@@ -131,6 +137,8 @@
 	 * 
 	 * @return the original element this working copy was created from,
 	 * or <code>null</code> if this is not a working copy
+	 * 
+	 * @deprecated Use {@link ICompilationUnit#findPrimaryType()} instead.
 	 */
 	IJavaElement getOriginalElement();
 	
@@ -152,6 +160,8 @@
 	 * @param element the given element
 	 * @return the found elements in this compilation unit that correspond to the given element
 	 * @since 2.0 
+	 * 
+	 * @deprecated Use {@link ICompilationUnit#findElements(IJavaElement)} instead.
 	 */
 	IJavaElement[] findElements(IJavaElement element);
 	
@@ -161,6 +171,8 @@
 	 * 
 	 * @return the found primary type of this compilation unit, or <code>null</code> if no such a type exists
 	 * @since 2.0
+	 * 
+	 * @deprecated Use {@link ITypeRoot#findPrimaryType()} instead.
 	 */
 	IType findPrimaryType();
 	
@@ -202,6 +214,8 @@
 	 * @see IBufferFactory
 	 * @see IProblemRequestor
 	 * @since 2.0
+	 * 
+	 * @deprecated Use {@link ICompilationUnit#getWorkingCopy(WorkingCopyOwner, IProblemRequestor, IProgressMonitor)} instead.
 	 */
 	IJavaElement getSharedWorkingCopy(
 		IProgressMonitor monitor,
@@ -227,6 +241,8 @@
 	 *   not be determined. 
 	 * @return a new working copy of this element if this element is not
 	 * a working copy, or this element if this element is already a working copy
+	 * 
+	 * @deprecated Use {@link ICompilationUnit#getWorkingCopy(IProgressMonitor)} instead.
 	 */
 	IJavaElement getWorkingCopy() throws JavaModelException;
 	
@@ -260,6 +276,8 @@
 	 * @return a new working copy of this element using the given factory to create
 	 * the buffer, or this element if this element is already a working copy
 	 * @since 2.0
+	 * 
+	 * @deprecated Use {@link ICompilationUnit#getWorkingCopy(WorkingCopyOwner, IProblemRequestor, IProgressMonitor)} instead.
 	 */
 	IJavaElement getWorkingCopy(
 		IProgressMonitor monitor,
@@ -274,6 +292,8 @@
 	 * @param resource this working copy's resource
 	 * @return true if this working copy's original element's content
 	 * has not changed since the inception of this working copy, false otherwise
+	 * 
+	 * @deprecated Use {@link ICompilationUnit#hasResourceChanged()} instead.
 	 */
 	boolean isBasedOn(IResource resource);
 	
@@ -281,6 +301,8 @@
 	 * Returns whether this element is a working copy.
 	 * 
 	 * @return true if this element is a working copy, false otherwise
+	 * 
+	 * @deprecated Use {@link ICompilationUnit#isWorkingCopy()} instead.
 	 */
 	boolean isWorkingCopy();
 	
@@ -307,6 +329,8 @@
 	 * <li> The original Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
 	 * </ul>
 	 * @return <code>null</code>
+	 * 
+	 * @deprecated Use {@link ICompilationUnit#reconcile(int, boolean, WorkingCopyOwner, IProgressMonitor)} instead.
 	 */
 	IMarker[] reconcile() throws JavaModelException;
 	
@@ -336,6 +360,8 @@
 	 * <li> The original Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
 	 * </ul>
 	 * @since 2.0
+	 * 
+	 * @deprecated Use {@link ICompilationUnit#reconcile(int, boolean, WorkingCopyOwner, IProgressMonitor)} instead.
 	 */
 	void reconcile(boolean forceProblemDetection, IProgressMonitor monitor) throws JavaModelException;
 
@@ -352,6 +378,7 @@
 	 * <ul>
 	 * <li> The original Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
 	 * </ul>
+	 * @deprecated Use {@link ICompilationUnit#restore()} instead.
 	 */
 	void restore() throws JavaModelException;
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaConventions.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaConventions.java
index 9ef3ef0..b6d9ebf 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaConventions.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaConventions.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -19,8 +19,11 @@
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Status;
 import org.eclipse.jdt.core.compiler.*;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
 import org.eclipse.jdt.internal.compiler.parser.Scanner;
+import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
 import org.eclipse.jdt.internal.compiler.parser.TerminalTokens;
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
 import org.eclipse.jdt.internal.core.*;
@@ -35,10 +38,10 @@
  */
 public final class JavaConventions {
 
-	private final static char DOT= '.';
+	private static final char DOT= '.';
 	private static final String PACKAGE_INFO = new String(TypeConstants.PACKAGE_INFO_NAME);
-	private final static Scanner SCANNER = new Scanner();
-
+	private static final Scanner SCANNER = new Scanner(false /*comment*/, true /*whitespace*/, false /*nls*/, ClassFileConstants.JDK1_3 /*sourceLevel*/, null/*taskTag*/, null/*taskPriorities*/, true /*taskCaseSensitive*/);
+	
 	private JavaConventions() {
 		// Not instantiable
 	}
@@ -72,32 +75,27 @@
 
 	/*
 	 * Returns the current identifier extracted by the scanner (without unicode
-	 * escapes) from the given id.
+	 * escapes) from the given id and for the given source and compliance levels.
 	 * Returns <code>null</code> if the id was not valid
 	 */
-	private static synchronized char[] scannedIdentifier(String id) {
+	private static synchronized char[] scannedIdentifier(String id, String sourceLevel, String complianceLevel) {
 		if (id == null) {
 			return null;
 		}
-		String trimmed = id.trim();
-		if (!trimmed.equals(id)) {
-			return null;
-		}
+		// Set scanner for given source and compliance levels
+		SCANNER.sourceLevel = sourceLevel == null ? ClassFileConstants.JDK1_3 : CompilerOptions.versionToJdkLevel(sourceLevel);
+		SCANNER.complianceLevel = complianceLevel == null ? ClassFileConstants.JDK1_3 : CompilerOptions.versionToJdkLevel(complianceLevel);	
+
 		try {
 			SCANNER.setSource(id.toCharArray());
-			int token = SCANNER.getNextToken();
-			char[] currentIdentifier;
-			try {
-				currentIdentifier = SCANNER.getCurrentIdentifierSource();
-			} catch (ArrayIndexOutOfBoundsException e) {
-				return null;
-			}
-			int nextToken= SCANNER.getNextToken();
-			if (token == TerminalTokens.TokenNameIdentifier 
-				&& nextToken == TerminalTokens.TokenNameEOF
-				&& SCANNER.startPosition == SCANNER.source.length) { // to handle case where we had an ArrayIndexOutOfBoundsException 
-																     // while reading the last token
-				return currentIdentifier;
+			int token = SCANNER.scanIdentifier();
+			if (token != TerminalTokens.TokenNameIdentifier) return null; 
+			if (SCANNER.currentPosition == SCANNER.eofPosition) { // to handle case where we had an ArrayIndexOutOfBoundsException 
+				try {
+					return SCANNER.getCurrentIdentifierSource();
+				} catch (ArrayIndexOutOfBoundsException e) {
+					return null;
+				}
 			} else {
 				return null;
 			}
@@ -109,10 +107,12 @@
 
 	/**
 	 * Validate the given compilation unit name.
+	 * <p>
 	 * A compilation unit name must obey the following rules:
 	 * <ul>
 	 * <li> it must not be null
-	 * <li> it must include the <code>".java"</code> suffix
+	 * <li> it must be suffixed by a dot ('.') followed by one of the 
+	 *       {@link JavaCore#getJavaLikeExtensions() Java-like extensions}
 	 * <li> its prefix must be a valid identifier
 	 * <li> it must not contain any characters or substrings that are not valid 
 	 *		   on the file system on which workspace root is located.
@@ -122,8 +122,34 @@
 	 * @return a status object with code <code>IStatus.OK</code> if
 	 *		the given name is valid as a compilation unit name, otherwise a status 
 	 *		object indicating what is wrong with the name
+	 * @deprecated Use {@link #validateCompilationUnitName(String id, String sourceLevel, String complianceLevel)} instead
 	 */
 	public static IStatus validateCompilationUnitName(String name) {
+		return validateCompilationUnitName(name,CompilerOptions.VERSION_1_3,CompilerOptions.VERSION_1_3);
+	}
+	
+	/**
+	 * Validate the given compilation unit name for the given source and compliance levels.
+	 * <p>
+	 * A compilation unit name must obey the following rules:
+	 * <ul>
+	 * <li> it must not be null
+	 * <li> it must be suffixed by a dot ('.') followed by one of the 
+	 *       {@link JavaCore#getJavaLikeExtensions() Java-like extensions}
+	 * <li> its prefix must be a valid identifier
+	 * <li> it must not contain any characters or substrings that are not valid 
+	 *		   on the file system on which workspace root is located.
+	 * </ul>
+	 * </p>
+	 * @param name the name of a compilation unit
+	 * @param sourceLevel the source level
+	 * @param complianceLevel the compliance level
+	 * @return a status object with code <code>IStatus.OK</code> if
+	 *		the given name is valid as a compilation unit name, otherwise a status 
+	 *		object indicating what is wrong with the name
+	 * @since 3.3
+	 */
+	public static IStatus validateCompilationUnitName(String name, String sourceLevel, String complianceLevel) {
 		if (name == null) {
 			return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.convention_unit_nullName, null); 
 		}
@@ -141,7 +167,7 @@
 		// file in which to store package annotations and
 		// the package-level spec (replaces package.html)
 		if (!identifier.equals(PACKAGE_INFO)) {
-			IStatus status = validateIdentifier(identifier);
+			IStatus status = validateIdentifier(identifier, sourceLevel, complianceLevel);
 			if (!status.isOK()) {
 				return status;
 			}
@@ -155,6 +181,7 @@
 
 	/**
 	 * Validate the given .class file name.
+	 * <p>
 	 * A .class file name must obey the following rules:
 	 * <ul>
 	 * <li> it must not be null
@@ -169,8 +196,33 @@
 	 *		the given name is valid as a .class file name, otherwise a status 
 	 *		object indicating what is wrong with the name
 	 * @since 2.0
+	 * @deprecated Use {@link #validateClassFileName(String id, String sourceLevel, String complianceLevel)} instead
 	 */
 	public static IStatus validateClassFileName(String name) {
+		return validateClassFileName(name, CompilerOptions.VERSION_1_3, CompilerOptions.VERSION_1_3);
+	}
+	
+	/**
+	 * Validate the given .class file name for the given source and compliance levels.
+	 * <p>
+	 * A .class file name must obey the following rules:
+	 * <ul>
+	 * <li> it must not be null
+	 * <li> it must include the <code>".class"</code> suffix
+	 * <li> its prefix must be a valid identifier
+	 * <li> it must not contain any characters or substrings that are not valid 
+	 *		   on the file system on which workspace root is located.
+	 * </ul>
+	 * </p>
+	 * @param name the name of a .class file
+	 * @param sourceLevel the source level
+	 * @param complianceLevel the compliance level
+	 * @return a status object with code <code>IStatus.OK</code> if
+	 *		the given name is valid as a .class file name, otherwise a status 
+	 *		object indicating what is wrong with the name
+	 * @since 3.3
+	 */
+	public static IStatus validateClassFileName(String name, String sourceLevel, String complianceLevel) {
 		if (name == null) {
 			return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.convention_classFile_nullName, null);		}
 		if (!org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(name)) {
@@ -187,7 +239,7 @@
 		// file in which to store package annotations and
 		// the package-level spec (replaces package.html)
 		if (!identifier.equals(PACKAGE_INFO)) {
-			IStatus status = validateIdentifier(identifier);
+			IStatus status = validateIdentifier(identifier, sourceLevel, complianceLevel);
 			if (!status.isOK()) {
 				return status;
 			}
@@ -209,9 +261,28 @@
 	 * @return a status object with code <code>IStatus.OK</code> if
 	 *		the given name is valid as a field name, otherwise a status 
 	 *		object indicating what is wrong with the name
+	 * @deprecated Use {@link #validateFieldName(String id, String sourceLevel, String complianceLevel)} instead
 	 */
 	public static IStatus validateFieldName(String name) {
-		return validateIdentifier(name);
+		return validateIdentifier(name, CompilerOptions.VERSION_1_3,CompilerOptions.VERSION_1_3);
+	}
+	
+	/**
+	 * Validate the given field name for the given source and compliance levels.
+	 * <p>
+	 * Syntax of a field name corresponds to VariableDeclaratorId (JLS2 8.3).
+	 * For example, <code>"x"</code>.
+	 *
+	 * @param name the name of a field
+	 * @param sourceLevel the source level
+	 * @param complianceLevel the compliance level
+	 * @return a status object with code <code>IStatus.OK</code> if
+	 *		the given name is valid as a field name, otherwise a status 
+	 *		object indicating what is wrong with the name
+	 * @since 3.3
+	 */
+	public static IStatus validateFieldName(String name, String sourceLevel, String complianceLevel) {
+		return validateIdentifier(name, sourceLevel, complianceLevel);
 	}
 
 	/**
@@ -225,9 +296,29 @@
 	 * @return a status object with code <code>IStatus.OK</code> if
 	 *		the given identifier is a valid Java identifier, otherwise a status 
 	 *		object indicating what is wrong with the identifier
+	 * @deprecated Use {@link #validateIdentifier(String id, String sourceLevel, String complianceLevel)} instead
 	 */
 	public static IStatus validateIdentifier(String id) {
-		if (scannedIdentifier(id) != null) {
+		return validateIdentifier(id,CompilerOptions.VERSION_1_3,CompilerOptions.VERSION_1_3);
+	}
+	
+	/**
+	 * Validate the given Java identifier for the given source and compliance levels
+	 * The identifier must not have the same spelling as a Java keyword,
+	 * boolean literal (<code>"true"</code>, <code>"false"</code>), or null literal (<code>"null"</code>).
+	 * See section 3.8 of the <em>Java Language Specification, Second Edition</em> (JLS2).
+	 * A valid identifier can act as a simple type name, method name or field name.
+	 *
+	 * @param id the Java identifier
+	 * @param sourceLevel the source level
+	 * @param complianceLevel the compliance level
+	 * @return a status object with code <code>IStatus.OK</code> if
+	 *		the given identifier is a valid Java identifier, otherwise a status 
+	 *		object indicating what is wrong with the identifier
+	 * @since 3.3
+	 */
+	public static IStatus validateIdentifier(String id, String sourceLevel, String complianceLevel) {
+		if (scannedIdentifier(id, sourceLevel, complianceLevel) != null) {
 			return JavaModelStatus.VERIFIED_OK;
 		} else {
 			return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.bind(Messages.convention_illegalIdentifier, id), null); 
@@ -245,19 +336,39 @@
 	 * @return a status object with code <code>IStatus.OK</code> if
 	 *		the given name is valid as an import declaration, otherwise a status 
 	 *		object indicating what is wrong with the name
+	 * @deprecated Use {@link #validateImportDeclaration(String id, String sourceLevel, String complianceLevel)} instead
 	 */
 	public static IStatus validateImportDeclaration(String name) {
+		return validateImportDeclaration(name,CompilerOptions.VERSION_1_3,CompilerOptions.VERSION_1_3);
+	}
+	
+	/**
+	 * Validate the given import declaration name for the given source and compliance levels.
+	 * <p>
+	 * The name of an import corresponds to a fully qualified type name
+	 * or an on-demand package name as defined by ImportDeclaration (JLS2 7.5).
+	 * For example, <code>"java.util.*"</code> or <code>"java.util.Hashtable"</code>.
+	 *
+	 * @param name the import declaration
+	 * @param sourceLevel the source level
+	 * @param complianceLevel the compliance level
+	 * @return a status object with code <code>IStatus.OK</code> if
+	 *		the given name is valid as an import declaration, otherwise a status 
+	 *		object indicating what is wrong with the name
+	 * @since 3.3
+	 */
+	public static IStatus validateImportDeclaration(String name, String sourceLevel, String complianceLevel) {
 		if (name == null || name.length() == 0) {
 			return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.convention_import_nullImport, null); 
 		} 
 		if (name.charAt(name.length() - 1) == '*') {
 			if (name.charAt(name.length() - 2) == '.') {
-				return validatePackageName(name.substring(0, name.length() - 2));
+				return validatePackageName(name.substring(0, name.length() - 2), sourceLevel, complianceLevel);
 			} else {
 				return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.convention_import_unqualifiedImport, null); 
 			}
 		}
-		return validatePackageName(name);
+		return validatePackageName(name, sourceLevel, complianceLevel);
 	}
 
 	/**
@@ -272,8 +383,29 @@
 	 *		indicating why the given name is discouraged, 
 	 *      otherwise a status object indicating what is wrong with 
 	 *      the name
+	 * @deprecated Use {@link #validateJavaTypeName(String id, String sourceLevel, String complianceLevel)} instead
 	 */
 	public static IStatus validateJavaTypeName(String name) {
+		return validateJavaTypeName(name, CompilerOptions.VERSION_1_3,CompilerOptions.VERSION_1_3);
+	}
+	
+	/**
+	 * Validate the given Java type name, either simple or qualified, for the given source and compliance levels.
+	 * For example, <code>"java.lang.Object"</code>, or <code>"Object"</code>.
+	 * <p>
+	 *
+	 * @param name the name of a type
+	 * @param sourceLevel the source level
+	 * @param complianceLevel the compliance level
+	 * @return a status object with code <code>IStatus.OK</code> if
+	 *		the given name is valid as a Java type name, 
+	 *      a status with code <code>IStatus.WARNING</code>
+	 *		indicating why the given name is discouraged, 
+	 *      otherwise a status object indicating what is wrong with 
+	 *      the name
+	 * @since 3.3
+	 */
+	public static IStatus validateJavaTypeName(String name, String sourceLevel, String complianceLevel) {
 		if (name == null) {
 			return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.convention_type_nullName, null); 
 		}
@@ -285,16 +417,16 @@
 		char[] scannedID;
 		if (index == -1) {
 			// simple name
-			scannedID = scannedIdentifier(name);
+			scannedID = scannedIdentifier(name, sourceLevel, complianceLevel);
 		} else {
 			// qualified name
 			String pkg = name.substring(0, index).trim();
-			IStatus status = validatePackageName(pkg);
+			IStatus status = validatePackageName(pkg, sourceLevel, complianceLevel);
 			if (!status.isOK()) {
 				return status;
 			}
 			String type = name.substring(index + 1).trim();
-			scannedID = scannedIdentifier(type);
+			scannedID = scannedIdentifier(type, sourceLevel, complianceLevel);
 		}
 	
 		if (scannedID != null) {
@@ -305,7 +437,7 @@
 			if (CharOperation.contains('$', scannedID)) {
 				return new Status(IStatus.WARNING, JavaCore.PLUGIN_ID, -1, Messages.convention_type_dollarName, null); 
 			}
-			if ((scannedID.length > 0 && Character.isLowerCase(scannedID[0]))) {
+			if ((scannedID.length > 0 && ScannerHelper.isLowerCase(scannedID[0]))) {
 				return new Status(IStatus.WARNING, JavaCore.PLUGIN_ID, -1, Messages.convention_type_lowercaseName, null); 
 			}
 			return JavaModelStatus.VERIFIED_OK;
@@ -325,10 +457,29 @@
 	 * @return a status object with code <code>IStatus.OK</code> if
 	 *		the given name is valid as a method name, otherwise a status 
 	 *		object indicating what is wrong with the name
+	 * @deprecated Use {@link #validateMethodName(String id, String sourceLevel, String complianceLevel)} instead
 	 */
 	public static IStatus validateMethodName(String name) {
-
-		return validateIdentifier(name);
+		return validateMethodName(name, CompilerOptions.VERSION_1_3,CompilerOptions.VERSION_1_3);
+	}
+	
+	/**
+	 * Validate the given method name for the given source and compliance levels.
+	 * The special names "&lt;init&gt;" and "&lt;clinit&gt;" are not valid.
+	 * <p>
+	 * The syntax for a method  name is defined by Identifier
+	 * of MethodDeclarator (JLS2 8.4). For example "println".
+	 *
+	 * @param name the name of a method
+	 * @param sourceLevel the source level
+	 * @param complianceLevel the compliance level
+	 * @return a status object with code <code>IStatus.OK</code> if
+	 *		the given name is valid as a method name, otherwise a status 
+	 *		object indicating what is wrong with the name
+	 * @since 3.3
+	 */
+	public static IStatus validateMethodName(String name, String sourceLevel, String complianceLevel) {
+		return validateIdentifier(name, sourceLevel,complianceLevel);
 	}
 
 	/**
@@ -346,8 +497,32 @@
 	 * @return a status object with code <code>IStatus.OK</code> if
 	 *		the given name is valid as a package name, otherwise a status 
 	 *		object indicating what is wrong with the name
+	 * @deprecated Use {@link #validatePackageName(String id, String sourceLevel, String complianceLevel)} instead
 	 */
 	public static IStatus validatePackageName(String name) {
+		return validatePackageName(name, CompilerOptions.VERSION_1_3,CompilerOptions.VERSION_1_3);
+	}
+	
+	/**
+	 * Validate the given package name for the given source and compliance levels.
+	 * <p>
+	 * The syntax of a package name corresponds to PackageName as
+	 * defined by PackageDeclaration (JLS2 7.4). For example, <code>"java.lang"</code>.
+	 * <p>
+	 * Note that the given name must be a non-empty package name (that is, attempting to
+	 * validate the default package will return an error status.)
+	 * Also it must not contain any characters or substrings that are not valid 
+	 * on the file system on which workspace root is located.
+	 *
+	 * @param name the name of a package
+	 * @param sourceLevel the source level
+	 * @param complianceLevel the compliance level
+	 * @return a status object with code <code>IStatus.OK</code> if
+	 *		the given name is valid as a package name, otherwise a status 
+	 *		object indicating what is wrong with the name
+	 * @since 3.3
+	 */
+	public static IStatus validatePackageName(String name, String sourceLevel, String complianceLevel) {
 
 		if (name == null) {
 			return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.convention_package_nullName, null); 
@@ -375,7 +550,7 @@
 		while (st.hasMoreTokens()) {
 			String typeName = st.nextToken();
 			typeName = typeName.trim(); // grammar allows spaces
-			char[] scannedID = scannedIdentifier(typeName);
+			char[] scannedID = scannedIdentifier(typeName, sourceLevel, complianceLevel);
 			if (scannedID == null) {
 				return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.bind(Messages.convention_illegalIdentifier, typeName), null); 
 			}
@@ -383,7 +558,7 @@
 			if (!status.isOK()) {
 				return status;
 			}
-			if (firstToken && scannedID.length > 0 && Character.isUpperCase(scannedID[0])) {
+			if (firstToken && scannedID.length > 0 && ScannerHelper.isUpperCase(scannedID[0])) {
 				if (warningStatus == null) {
 					warningStatus = new Status(IStatus.WARNING, JavaCore.PLUGIN_ID, -1, Messages.convention_package_uppercaseName, null); 
 				}
@@ -444,7 +619,10 @@
 	 * @since 2.0
 	 */
 	public static IJavaModelStatus validateClasspathEntry(IJavaProject project, IClasspathEntry entry, boolean checkSourceAttachment){
-		return ClasspathEntry.validateClasspathEntry(project, entry, checkSourceAttachment, true/*recurse in container*/);
+		IJavaModelStatus status = ClasspathEntry.validateClasspathEntry(project, entry, checkSourceAttachment, true/*recurse in container*/);
+		if (status.getCode() == IJavaModelStatusConstants.INVALID_CLASSPATH && ((ClasspathEntry) entry).isOptional())
+			return JavaModelStatus.VERIFIED_OK;
+		return status;
 	}
 	
 	/**
@@ -458,11 +636,30 @@
 	 *		the given name is valid as a type variable name, otherwise a status 
 	 *		object indicating what is wrong with the name
 	 * @since 3.1
+	 * @deprecated Use {@link #validateTypeVariableName(String id, String sourceLevel, String complianceLevel)} instead
 	 */
 	public static IStatus validateTypeVariableName(String name) {
-		return validateIdentifier(name);
+		return validateIdentifier(name, CompilerOptions.VERSION_1_3,CompilerOptions.VERSION_1_3);
 	}
-
+	
+	/**
+	 * Validate the given type variable name for the given source and compliance levels.
+	 * <p>
+	 * Syntax of a type variable name corresponds to a Java identifier (JLS3 4.3).
+	 * For example, <code>"E"</code>.
+	 *
+	 * @param name the name of a type variable
+	 * @param sourceLevel the source level
+	 * @param complianceLevel the compliance level
+	 * @return a status object with code <code>IStatus.OK</code> if
+	 *		the given name is valid as a type variable name, otherwise a status 
+	 *		object indicating what is wrong with the name
+	 * @since 3.3
+	 */
+	public static IStatus validateTypeVariableName(String name, String sourceLevel, String complianceLevel) {
+		return validateIdentifier(name, sourceLevel, complianceLevel);
+	}
+	
 	/**
 	 * Validate that all compiler options of the given project match keys and values
 	 * described in {@link JavaCore#getDefaultOptions()} method.
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java
index ca7ccd5..27a3108 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -18,6 +18,7 @@
  *     IBM Corporation - added specific output location to source classpath entries
  *     IBM Corporation - added the following constants:
  *                                 CORE_JAVA_BUILD_CLEAN_OUTPUT_FOLDER
+ *                                 CORE_JAVA_BUILD_RECREATE_MODIFIED_CLASS_FILES_IN_OUTPUT_FOLDER
  *                                 CLEAN
  *     IBM Corporation - added getClasspathContainerInitializer(String)
  *     IBM Corporation - added the following constants:
@@ -54,21 +55,62 @@
  *                                 COMPILER_PB_MISSING_JAVADOC_COMMENTS_OVERRIDING
  *                                 COMPILER_PB_DEPRECATION_WHEN_OVERRIDING_DEPRECATED_METHOD
  *                                 COMPILER_PB_UNUSED_DECLARED_THROWN_EXCEPTION_WHEN_OVERRIDING
+ *     IBM Corporation - added the following constants:
+ *                                 TIMEOUT_FOR_PARAMETER_NAME_FROM_ATTACHED_JAVADOC
+ *     IBM Corporation - added the following constants:
+ *                                 COMPILER_PB_FALLTHROUGH_CASE
+ *                                 COMPILER_PB_PARAMETER_ASSIGNMENT
+ *                                 COMPILER_PB_NULL_REFERENCE
+ *     IBM Corporation - added the following constants:
+ *                                 CODEASSIST_DEPRECATION_CHECK
+ *     IBM Corporation - added the following constants:
+ *                                 COMPILER_PB_POTENTIAL_NULL_REFERENCE
+ *                                 COMPILER_PB_REDUNDANT_NULL_CHECK
+ *     IBM Corporation - added the following constants:
+ *                                 COMPILER_PB_UNUSED_PARAMETER_INCLUDE_DOC_COMMENT_REFERENCE
  *******************************************************************************/
 package org.eclipse.jdt.core;
 
 import java.io.File;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
 
-import org.eclipse.core.resources.*;
-import org.eclipse.core.runtime.*;
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IMarkerDelta;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceChangeEvent;
+import org.eclipse.core.resources.IResourceChangeListener;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.IWorkspaceRunnable;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Plugin;
+import org.eclipse.core.runtime.QualifiedName;
+import org.eclipse.core.runtime.SubProgressMonitor;
 import org.eclipse.core.runtime.jobs.ISchedulingRule;
-import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.search.IJavaSearchConstants;
 import org.eclipse.jdt.core.search.IJavaSearchScope;
 import org.eclipse.jdt.core.search.SearchEngine;
 import org.eclipse.jdt.core.search.SearchPattern;
 import org.eclipse.jdt.core.search.TypeNameRequestor;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
 import org.eclipse.jdt.internal.core.*;
 import org.eclipse.jdt.internal.core.builder.JavaBuilder;
@@ -89,14 +131,16 @@
  * </p>
  * <p>
  * The single instance of this class can be accessed from any plug-in declaring
- * the Java model plug-in as a prerequisite via 
+ * the Java model plug-in as a prerequisite via
  * <code>JavaCore.getJavaCore()</code>. The Java model plug-in will be activated
  * automatically if not already active.
  * </p>
  */
 public final class JavaCore extends Plugin {
 
-	private static Plugin JAVA_CORE_PLUGIN = null; 
+	private static final IResource[] NO_GENERATED_RESOURCES = new IResource[0];
+
+	private static Plugin JAVA_CORE_PLUGIN = null;
 	/**
 	 * The plug-in identifier of the Java core support
 	 * (value <code>"org.eclipse.jdt.core"</code>).
@@ -118,7 +162,7 @@
 	/**
 	 * The identifier for the Java nature
 	 * (value <code>"org.eclipse.jdt.core.javanature"</code>).
-	 * The presence of this nature on a project indicates that it is 
+	 * The presence of this nature on a project indicates that it is
 	 * Java-capable.
 	 *
 	 * @see org.eclipse.core.resources.IProject#hasNature(java.lang.String)
@@ -136,7 +180,7 @@
 	 * @since 3.0
 	 */
 	public static final String USER_LIBRARY_CONTAINER_ID= "org.eclipse.jdt.USER_LIBRARY"; //$NON-NLS-1$
-	
+
 	// *************** Possible IDs for configurable options. ********************
 
 	/**
@@ -245,6 +289,12 @@
 	/**
 	 * Possible  configurable option ID.
 	 * @see #getDefaultOptions()
+	 * @since 3.3
+	 */
+	public static final String COMPILER_PB_UNUSED_PARAMETER_INCLUDE_DOC_COMMENT_REFERENCE = PLUGIN_ID + ".compiler.problem.unusedParameterIncludeDocCommentReference"; //$NON-NLS-1$
+	/**
+	 * Possible  configurable option ID.
+	 * @see #getDefaultOptions()
 	 * @since 2.0
 	 */
 	public static final String COMPILER_PB_UNUSED_IMPORT = PLUGIN_ID + ".compiler.problem.unusedImport"; //$NON-NLS-1$
@@ -334,6 +384,12 @@
 	/**
 	 * Possible  configurable option ID.
 	 * @see #getDefaultOptions()
+	 * @since 3.2
+	 */
+	public static final String COMPILER_PB_FALLTHROUGH_CASE = PLUGIN_ID + ".compiler.problem.fallthroughCase"; //$NON-NLS-1$
+	/**
+	 * Possible  configurable option ID.
+	 * @see #getDefaultOptions()
 	 * @since 3.0
 	 */
 	public static final String COMPILER_PB_EMPTY_STATEMENT = PLUGIN_ID + ".compiler.problem.emptyStatement"; //$NON-NLS-1$
@@ -401,6 +457,12 @@
 	/**
 	 * Possible  configurable option ID.
 	 * @see #getDefaultOptions()
+	 * @since 3.2
+	 */
+	public static final String COMPILER_PB_RAW_TYPE_REFERENCE = PLUGIN_ID + ".compiler.problem.rawTypeReference"; //$NON-NLS-1$
+	/**
+	 * Possible  configurable option ID.
+	 * @see #getDefaultOptions()
 	 * @since 3.1
 	 */
 	public static final String COMPILER_PB_FINAL_PARAMETER_BOUND = PLUGIN_ID + ".compiler.problem.finalParameterBound"; //$NON-NLS-1$
@@ -448,13 +510,19 @@
 	public static final String COMPILER_PB_INCOMPLETE_ENUM_SWITCH = PLUGIN_ID + ".compiler.problem.incompleteEnumSwitch"; //$NON-NLS-1$
 	/**
 	 * Possible  configurable option ID.
-	 * @see #getDefaultOptions()
 	 * @since 3.1
+	 * @deprecated use {@link #COMPILER_PB_NULL_REFERENCE} instead
 	 */
 	public static final String COMPILER_PB_INCONSISTENT_NULL_CHECK = PLUGIN_ID + ".compiler.problem.inconsistentNullCheck"; //$NON-NLS-1$
 	/**
 	 * Possible  configurable option ID.
 	 * @see #getDefaultOptions()
+	 * @since 3.2
+	 */
+	public static final String COMPILER_PB_UNUSED_LABEL = PLUGIN_ID + ".compiler.problem.unusedLabel"; //$NON-NLS-1$
+	/**
+	 * Possible  configurable option ID.
+	 * @see #getDefaultOptions()
 	 * @since 3.0
 	 */
 	public static final String COMPILER_PB_INVALID_JAVADOC = PLUGIN_ID + ".compiler.problem.invalidJavadoc"; //$NON-NLS-1$
@@ -533,6 +601,18 @@
 	/**
 	 * Possible  configurable option ID.
 	 * @see #getDefaultOptions()
+	 * @since 3.2
+	 */
+	public static final String COMPILER_PB_FATAL_OPTIONAL_ERROR = PLUGIN_ID + ".compiler.problem.fatalOptionalError"; //$NON-NLS-1$
+	/**
+	 * Possible configurable option ID.
+	 * @see #getDefaultOptions()
+	 * @since 3.2
+	 */
+	public static final String COMPILER_PB_PARAMETER_ASSIGNMENT = PLUGIN_ID + ".compiler.problem.parameterAssignment"; //$NON-NLS-1$
+	/**
+	 * Possible  configurable option ID.
+	 * @see #getDefaultOptions()
 	 * @since 2.0
 	 */
 	public static final String COMPILER_SOURCE = PLUGIN_ID + ".compiler.source"; //$NON-NLS-1$
@@ -577,7 +657,7 @@
 	 * @see #getDefaultOptions()
 	 * @since 3.0
 	 */
-	public static final String COMPILER_TASK_CASE_SENSITIVE = PLUGIN_ID + ".compiler.taskCaseSensitive"; //$NON-NLS-1$	
+	public static final String COMPILER_TASK_CASE_SENSITIVE = PLUGIN_ID + ".compiler.taskCaseSensitive"; //$NON-NLS-1$
 	/**
 	 * Possible  configurable option ID.
 	 * @see #getDefaultOptions()
@@ -605,6 +685,30 @@
 	/**
 	 * Possible  configurable option ID.
 	 * @see #getDefaultOptions()
+	 * @since 3.2
+	 */
+	public static final String COMPILER_PB_NULL_REFERENCE = PLUGIN_ID + ".compiler.problem.nullReference"; //$NON-NLS-1$
+	/**
+	 * Possible  configurable option ID.
+	 * @see #getDefaultOptions()
+	 * @since 3.3
+	 */
+	public static final String COMPILER_PB_POTENTIAL_NULL_REFERENCE = PLUGIN_ID + ".compiler.problem.potentialNullReference"; //$NON-NLS-1$
+	/**
+	 * Possible  configurable option ID.
+	 * @see #getDefaultOptions()
+	 * @since 3.3
+	 */
+	public static final String COMPILER_PB_REDUNDANT_NULL_CHECK = PLUGIN_ID + ".compiler.problem.redundantNullCheck"; //$NON-NLS-1$
+	/**
+	 * Possible  configurable option ID.
+	 * @see #getDefaultOptions()
+	 * @since 3.3
+	 */
+	public static final String COMPILER_PB_OVERRIDING_METHOD_WITHOUT_SUPER_INVOCATION = PLUGIN_ID + ".compiler.problem.overridingMethodWithoutSuperInvocation"; //$NON-NLS-1$
+	/**
+	 * Possible  configurable option ID.
+	 * @see #getDefaultOptions()
 	 */
 	public static final String CORE_JAVA_BUILD_ORDER = PLUGIN_ID + ".computeJavaBuildOrder"; //$NON-NLS-1$
 	/**
@@ -624,7 +728,13 @@
 	 * @see #getDefaultOptions()
 	 * @since 2.1
 	 */
-	public static final String CORE_JAVA_BUILD_CLEAN_OUTPUT_FOLDER = PLUGIN_ID + ".builder.cleanOutputFolder"; //$NON-NLS-1$	 	
+	public static final String CORE_JAVA_BUILD_CLEAN_OUTPUT_FOLDER = PLUGIN_ID + ".builder.cleanOutputFolder"; //$NON-NLS-1$
+	/**
+	 * Possible  configurable option ID.
+	 * @see #getDefaultOptions()
+	 * @since 3.2
+	 */
+	public static final String CORE_JAVA_BUILD_RECREATE_MODIFIED_CLASS_FILES_IN_OUTPUT_FOLDER = PLUGIN_ID + ".builder.recreateModifiedClassFileInOutputFolder"; //$NON-NLS-1$
 	/**
 	 * Possible  configurable option ID.
 	 * @see #getDefaultOptions()
@@ -658,7 +768,7 @@
 	/**
 	 * Possible  configurable option ID.
 	 * @see #getDefaultOptions()
-	 * @since 2.1 
+	 * @since 2.1
 	 */
 	public static final String CORE_ENABLE_CLASSPATH_EXCLUSION_PATTERNS = PLUGIN_ID + ".classpath.exclusionPatterns"; //$NON-NLS-1$
 	/**
@@ -669,13 +779,13 @@
 	public static final String CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS = PLUGIN_ID + ".classpath.multipleOutputLocations"; //$NON-NLS-1$
 	/**
 	 * Default task tag
-	 * @deprecated - should use #DEFAULT_TASK_TAGS instead 
+	 * @deprecated Use {@link #DEFAULT_TASK_TAGS} instead
 	 * @since 2.1
 	 */
 	public static final String DEFAULT_TASK_TAG = "TODO"; //$NON-NLS-1$
 	/**
 	 * Default task priority
-	 * @deprecated - should use #DEFAULT_TASK_PRIORITIES instead 
+	 * @deprecated Use {@link #DEFAULT_TASK_PRIORITIES} instead
 	 * @since 2.1
 	 */
 	public static final String DEFAULT_TASK_PRIORITY = "NORMAL"; //$NON-NLS-1$
@@ -776,6 +886,18 @@
 	/**
 	 * Possible  configurable option ID.
 	 * @see #getDefaultOptions()
+	 * @since 3.2
+	 */
+	public static final String CODEASSIST_DEPRECATION_CHECK = PLUGIN_ID + ".codeComplete.deprecationCheck"; //$NON-NLS-1$
+	/**
+	 * Possible  configurable option ID.
+	 * @see #getDefaultOptions()
+	 * @since 3.2
+	 */
+	public static final String CODEASSIST_CAMEL_CASE_MATCH = PLUGIN_ID + ".codeComplete.camelCaseMatch"; //$NON-NLS-1$
+	/**
+	 * Possible  configurable option ID.
+	 * @see #getDefaultOptions()
 	 * @since 2.0
 	 */
 	public static final String CODEASSIST_IMPLICIT_QUALIFICATION = PLUGIN_ID + ".codeComplete.forceImplicitQualification"; //$NON-NLS-1$
@@ -839,9 +961,19 @@
 	 * @since 3.1
 	 */
 	public static final String CODEASSIST_DISCOURAGED_REFERENCE_CHECK= PLUGIN_ID + ".codeComplete.discouragedReferenceCheck"; //$NON-NLS-1$
-	
-	// *************** Possible values for configurable options. ********************
-	
+	/**
+	 * Possible  configurable option ID.
+	 * @see #getDefaultOptions()
+	 * @since 3.3
+	 */
+	public static final String CODEASSIST_SUGGEST_STATIC_IMPORTS= PLUGIN_ID + ".codeComplete.suggestStaticImports"; //$NON-NLS-1$
+	/**
+	 * Possible  configurable option ID.
+	 * @see #getDefaultOptions()
+	 * @since 3.2
+	 */
+	public static final String TIMEOUT_FOR_PARAMETER_NAME_FROM_ATTACHED_JAVADOC = PLUGIN_ID + ".timeoutForParameterNameFromAttachedJavadoc"; //$NON-NLS-1$
+
 	/**
 	 * Possible  configurable option value.
 	 * @see #getDefaultOptions()
@@ -893,6 +1025,18 @@
 	/**
 	 * Possible  configurable option value.
 	 * @see #getDefaultOptions()
+	 * @since 3.2
+	 */
+	public static final String VERSION_1_6 = "1.6"; //$NON-NLS-1$
+	/**
+	 * Possible  configurable option value.
+	 * @see #getDefaultOptions()
+	 * @since 3.3
+	 */
+	public static final String VERSION_1_7 = "1.7"; //$NON-NLS-1$
+	/**
+	 * Possible  configurable option value.
+	 * @see #getDefaultOptions()
 	 * @since 2.0
 	 */
 	public static final String ABORT = "abort"; //$NON-NLS-1$
@@ -1014,12 +1158,22 @@
 	public static final String NEVER = "never"; //$NON-NLS-1$
 
 	/**
+	 * Value of the content-type for Java source files. Use this value to retrieve the Java content type
+	 * from the content type manager, and to add new Java-like extensions to this content type.
+	 *
+	 * @see org.eclipse.core.runtime.content.IContentTypeManager#getContentType(String)
+	 * @see #getJavaLikeExtensions()
+	 * @since 3.2
+	 */
+	public static final String JAVA_SOURCE_CONTENT_TYPE = JavaCore.PLUGIN_ID+".javaSource" ; //$NON-NLS-1$
+
+	/**
 	 * Creates the Java core plug-in.
 	 * <p>
-	 * The plug-in instance is created automatically by the 
+	 * The plug-in instance is created automatically by the
 	 * Eclipse platform. Clients must not call.
 	 * </p>
-	 * 
+	 *
 	 * @since 3.0
 	 */
 	public JavaCore() {
@@ -1035,7 +1189,7 @@
 	 * and any reconcile operation (POST_RECONCILE).
 	 * For finer control of the notification, use <code>addElementChangedListener(IElementChangedListener,int)</code>,
 	 * which allows to specify a different eventMask.
-	 * 
+	 *
 	 * @param listener the listener
 	 * @see ElementChangedEvent
 	 */
@@ -1048,20 +1202,20 @@
 	 * Has no effect if an identical listener is already registered.
 	 * After completion of this method, the given listener will be registered for exactly
 	 * the specified events.  If they were previously registered for other events, they
-	 * will be deregistered.  
+	 * will be deregistered.
 	 * <p>
 	 * Once registered, a listener starts receiving notification of changes to
-	 * java elements in the model. The listener continues to receive 
-	 * notifications until it is replaced or removed. 
+	 * java elements in the model. The listener continues to receive
+	 * notifications until it is replaced or removed.
 	 * </p>
 	 * <p>
 	 * Listeners can listen for several types of event as defined in <code>ElementChangeEvent</code>.
 	 * Clients are free to register for any number of event types however if they register
 	 * for more than one, it is their responsibility to ensure they correctly handle the
-	 * case where the same java element change shows up in multiple notifications.  
+	 * case where the same java element change shows up in multiple notifications.
 	 * Clients are guaranteed to receive only the events for which they are registered.
 	 * </p>
-	 * 
+	 *
 	 * @param listener the listener
 	 * @param eventMask the bit-wise OR of all event types of interest to the listener
 	 * @see IElementChangedListener
@@ -1089,23 +1243,83 @@
 		if (attributes != null && element != null)
 			attributes.put(ATT_HANDLE_ID, element.getHandleIdentifier());
 	}
-	
+
+	private static void addNonJavaResources(Object[] nonJavaResources,
+			IContainer container,
+			int rootPathSegmentCounts,
+			ArrayList collector) {
+		for (int i = 0, max = nonJavaResources.length; i < max; i++) {
+			Object nonJavaResource = nonJavaResources[i];
+			if (nonJavaResource instanceof IFile) {
+				IFile file = (IFile) nonJavaResource;
+				IPath path = file.getFullPath().removeFirstSegments(rootPathSegmentCounts);
+				IResource member = container.findMember(path);
+				if (member != null && member.exists()) {
+					collector.add(member);
+				}
+			} else if (nonJavaResource instanceof IFolder) {
+				IFolder folder = (IFolder) nonJavaResource;
+				IResource[] members = null;
+				try {
+					members = folder.members();
+				} catch (CoreException e) {
+					// ignore
+				}
+				if (members != null) {
+					addNonJavaResources(members, container, rootPathSegmentCounts, collector);
+				}
+			}
+		}
+	}
+
 	/**
-	 * 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
+	 * Adds the given listener for POST_CHANGE resource change events to the Java core.
+	 * The listener is guaranteed to be notified of the POST_CHANGE resource change event before
 	 * the Java core starts processing the resource change event itself.
 	 * <p>
 	 * Has no effect if an identical listener is already registered.
 	 * </p>
-	 * 
+	 *
 	 * @param listener the listener
 	 * @see #removePreProcessingResourceChangedListener(IResourceChangeListener)
 	 * @since 3.0
+	 * @deprecated use addPreProcessingResourceChangedListener(listener, IResourceChangeEvent.POST_CHANGE) instead
 	 */
 	public static void addPreProcessingResourceChangedListener(IResourceChangeListener listener) {
-		JavaModelManager.getJavaModelManager().deltaState.addPreResourceChangedListener(listener);
+		addPreProcessingResourceChangedListener(listener, IResourceChangeEvent.POST_CHANGE);
 	}
-	
+
+	/**
+	 * Adds the given listener for resource change events of the given types to the Java core.
+	 * The listener is guaranteed to be notified of the resource change event before
+	 * the Java core starts processing the resource change event itself.
+	 * <p>
+	 * If an identical listener is already registered, the given event types are added to the event types
+	 * of interest to the listener.
+	 * </p>
+	 * <p>
+	 * Supported event types are:
+	 * <ul>
+	 * <li>{@link IResourceChangeEvent#PRE_BUILD}</li>
+	 * <li>{@link IResourceChangeEvent#POST_BUILD}</li>
+	 * <li>{@link IResourceChangeEvent#POST_CHANGE}</li>
+	 * <li>{@link IResourceChangeEvent#PRE_DELETE}</li>
+	 * <li>{@link IResourceChangeEvent#PRE_CLOSE}</li>
+	 * </ul>
+	 * This list may increase in the future.
+	 * </p>
+	 *
+	 * @param listener the listener
+	 * @param eventMask the bit-wise OR of all event types of interest to the
+	 * listener
+	 * @see #removePreProcessingResourceChangedListener(IResourceChangeListener)
+	 * @see IResourceChangeEvent
+	 * @since 3.2
+	 */
+	public static void addPreProcessingResourceChangedListener(IResourceChangeListener listener, int eventMask) {
+		JavaModelManager.getJavaModelManager().deltaState.addPreResourceChangedListener(listener, eventMask);
+	}
+
 	/**
 	 * Configures the given marker for the given Java element.
 	 * Used for markers, which denote a Java element rather than a resource.
@@ -1121,12 +1335,12 @@
 		if (marker != null && element != null)
 			marker.setAttribute(ATT_HANDLE_ID, element.getHandleIdentifier());
 	}
-	
+
 	/**
 	 * Returns the Java model element corresponding to the given handle identifier
 	 * generated by <code>IJavaElement.getHandleIdentifier()</code>, or
 	 * <code>null</code> if unable to create the associated element.
-	 * 
+	 *
 	 * @param handleIdentifier the given handle identifier
 	 * @return the Java element corresponding to the handle identifier
 	 */
@@ -1139,9 +1353,9 @@
 	 * generated by <code>IJavaElement.getHandleIdentifier()</code>, or
 	 * <code>null</code> if unable to create the associated element.
 	 * If the returned Java element is an <code>ICompilationUnit</code>, its owner
-	 * is the given owner if such a working copy exists, otherwise the compilation unit 
+	 * is the given owner if such a working copy exists, otherwise the compilation unit
 	 * is a primary compilation unit.
-	 * 
+	 *
 	 * @param handleIdentifier the given handle identifier
 	 * @param owner the owner of the returned compilation unit, ignored if the returned
 	 *   element is not a compilation unit
@@ -1156,21 +1370,22 @@
 		JavaModel model = JavaModelManager.getJavaModelManager().getJavaModel();
 		return model.getHandleFromMemento(memento, owner);
 	}
-	
+
 	/**
 	 * Returns the Java element corresponding to the given file, or
 	 * <code>null</code> if unable to associate the given file
 	 * with a Java element.
 	 *
 	 * <p>The file must be one of:<ul>
-	 *	<li>a <code>.java</code> file - the element returned is the corresponding <code>ICompilationUnit</code></li>
+	 *	<li>a file with one of the {@link JavaCore#getJavaLikeExtensions()
+	 *      Java-like extensions} - the element returned is the corresponding <code>ICompilationUnit</code></li>
 	 *	<li>a <code>.class</code> file - the element returned is the corresponding <code>IClassFile</code></li>
 	 *	<li>a <code>.jar</code> file - the element returned is the corresponding <code>IPackageFragmentRoot</code></li>
 	 *	</ul>
 	 * <p>
 	 * Creating a Java element has the side effect of creating and opening all of the
 	 * element's parents if they are not yet open.
-	 * 
+	 *
 	 * @param file the given file
 	 * @return the Java element corresponding to the given file, or
 	 * <code>null</code> if unable to associate the given file
@@ -1187,7 +1402,7 @@
 	 * <p>
 	 * Creating a Java element has the side effect of creating and opening all of the
 	 * element's parents if they are not yet open.
-	 * 
+	 *
 	 * @param folder the given folder
 	 * @return the package fragment or package fragment root corresponding to the given folder, or
 	 * <code>null</code> if unable to associate the given folder with a Java element
@@ -1202,7 +1417,7 @@
 	 * project's parents if they are not yet open.
 	 * <p>
 	 * Note that no check is done at this time on the existence or the java nature of this project.
-	 * 
+	 *
 	 * @param project the given project
 	 * @return the Java project corresponding to the given project, null if the given project is null
 	 */
@@ -1220,7 +1435,8 @@
 	 * <p>
 	 * The resource must be one of:<ul>
 	 *	<li>a project - the element returned is the corresponding <code>IJavaProject</code></li>
-	 *	<li>a <code>.java</code> file - the element returned is the corresponding <code>ICompilationUnit</code></li>
+	 *	<li>a file with one of the {@link JavaCore#getJavaLikeExtensions()
+	 *      Java-like extensions} - the element returned is the corresponding <code>ICompilationUnit</code></li>
 	 *	<li>a <code>.class</code> file - the element returned is the corresponding <code>IClassFile</code></li>
 	 *	<li>a <code>.jar</code> file - the element returned is the corresponding <code>IPackageFragmentRoot</code></li>
 	 *  <li>a folder - the element returned is the corresponding <code>IPackageFragmentRoot</code>
@@ -1230,7 +1446,7 @@
 	 * <p>
 	 * Creating a Java element has the side effect of creating and opening all of the
 	 * element's parents if they are not yet open.
-	 * 
+	 *
 	 * @param resource the given resource
 	 * @return the Java element corresponding to the given resource, or
 	 * <code>null</code> if unable to associate the given resource
@@ -1240,8 +1456,36 @@
 		return JavaModelManager.create(resource, null/*unknown java project*/);
 	}
 	/**
+	 * Returns the Java element corresponding to the given file, its project being the given
+	 * project. Returns <code>null</code> if unable to associate the given resource
+	 * with a Java element.
+	 *<p>
+	 * The resource must be one of:<ul>
+	 *	<li>a project - the element returned is the corresponding <code>IJavaProject</code></li>
+	 *	<li>a file with one of the {@link JavaCore#getJavaLikeExtensions()
+	 *      Java-like extensions} - the element returned is the corresponding <code>ICompilationUnit</code></li>
+	 *	<li>a <code>.class</code> file - the element returned is the corresponding <code>IClassFile</code></li>
+	 *	<li>a <code>.jar</code> file - the element returned is the corresponding <code>IPackageFragmentRoot</code></li>
+	 *  <li>a folder - the element returned is the corresponding <code>IPackageFragmentRoot</code>
+	 *    	or <code>IPackageFragment</code></li>
+	 *  <li>the workspace root resource - the element returned is the <code>IJavaModel</code></li>
+	 *	</ul>
+	 * <p>
+	 * Creating a Java element has the side effect of creating and opening all of the
+	 * element's parents if they are not yet open.
+	 *
+	 * @param resource the given resource
+	 * @return the Java element corresponding to the given file, or
+	 * <code>null</code> if unable to associate the given file
+	 * with a Java element
+	 * @since 3.3
+	 */
+	public static IJavaElement create(IResource resource, IJavaProject project) {
+		return JavaModelManager.create(resource, project);
+	}
+	/**
 	 * Returns the Java model.
-	 * 
+	 *
 	 * @param root the given root
 	 * @return the Java model, or <code>null</code> if the root is null
 	 */
@@ -1255,7 +1499,7 @@
 	 * Creates and returns a class file element for
 	 * the given <code>.class</code> file. Returns <code>null</code> if unable
 	 * to recognize the class file.
-	 * 
+	 *
 	 * @param file the given <code>.class</code> file
 	 * @return a class file element for the given <code>.class</code> file, or <code>null</code> if unable
 	 * to recognize the class file
@@ -1265,11 +1509,12 @@
 	}
 	/**
 	 * Creates and returns a compilation unit element for
-	 * the given <code>.java</code> file. Returns <code>null</code> if unable
+	 * the given source file (i.e. a file with one of the {@link JavaCore#getJavaLikeExtensions()
+	 * Java-like extensions}). Returns <code>null</code> if unable
 	 * to recognize the compilation unit.
-	 * 
-	 * @param file the given <code>.java</code> file
-	 * @return a compilation unit element for the given <code>.java</code> file, or <code>null</code> if unable
+	 *
+	 * @param file the given source file
+	 * @return a compilation unit element for the given source file, or <code>null</code> if unable
 	 * to recognize the compilation unit
 	 */
 	public static ICompilationUnit createCompilationUnitFrom(IFile file) {
@@ -1278,8 +1523,8 @@
 	/**
 	 * Creates and returns a handle for the given JAR file.
 	 * The Java model associated with the JAR's project may be
-	 * created as a side effect. 
-	 * 
+	 * created as a side effect.
+	 *
 	 * @param file the given JAR file
 	 * @return a handle for the given JAR file, or <code>null</code> if unable to create a JAR package fragment root.
 	 * (for example, if the JAR file represents a non-Java resource)
@@ -1288,33 +1533,33 @@
 		return JavaModelManager.createJarPackageFragmentRootFrom(file, null/*unknown java project*/);
 	}
 
-	/** 
+	/**
 	 * Answers the project specific value for a given classpath container.
 	 * In case this container path could not be resolved, then will answer <code>null</code>.
 	 * Both the container path and the project context are supposed to be non-null.
 	 * <p>
-	 * The containerPath is a formed by a first ID segment followed with extra segments, which can be 
-	 * used as additional hints for resolution. If no container was ever recorded for this container path 
-	 * onto this project (using <code>setClasspathContainer</code>, then a 
-	 * <code>ClasspathContainerInitializer</code> will be activated if any was registered for this container 
+	 * The containerPath is a formed by a first ID segment followed with extra segments, which can be
+	 * used as additional hints for resolution. If no container was ever recorded for this container path
+	 * onto this project (using <code>setClasspathContainer</code>, then a
+	 * <code>ClasspathContainerInitializer</code> will be activated if any was registered for this container
 	 * ID onto the extension point "org.eclipse.jdt.core.classpathContainerInitializer".
 	 * <p>
 	 * There is no assumption that the returned container must answer the exact same containerPath
-	 * when requested <code>IClasspathContainer#getPath</code>. 
+	 * when requested <code>IClasspathContainer#getPath</code>.
 	 * Indeed, the containerPath is just an indication for resolving it to an actual container object.
 	 * <p>
-	 * Classpath container values are persisted locally to the workspace, but 
-	 * are not preserved from a session to another. It is thus highly recommended to register a 
-	 * <code>ClasspathContainerInitializer</code> for each referenced container 
+	 * Classpath container values are persisted locally to the workspace, but
+	 * are not preserved from a session to another. It is thus highly recommended to register a
+	 * <code>ClasspathContainerInitializer</code> for each referenced container
 	 * (through the extension point "org.eclipse.jdt.core.ClasspathContainerInitializer").
 	 * <p>
 	 * @param containerPath the name of the container, which needs to be resolved
 	 * @param project a specific project in which the container is being resolved
 	 * @return the corresponding classpath container or <code>null</code> if unable to find one.
-	 * 
+	 *
 	 * @exception JavaModelException if an exception occurred while resolving the container, or if the resolved container
-	 *   contains illegal entries (contains CPE_CONTAINER entries or null entries).	 
-	 * 
+	 *   contains illegal entries (contains CPE_CONTAINER entries or null entries).
+	 *
 	 * @see ClasspathContainerInitializer
 	 * @see IClasspathContainer
 	 * @see #setClasspathContainer(IPath, IJavaProject[], IClasspathContainer[], IProgressMonitor)
@@ -1327,18 +1572,18 @@
 		if (container == JavaModelManager.CONTAINER_INITIALIZATION_IN_PROGRESS) {
 		    return manager.getPreviousSessionContainer(containerPath, project);
 		}
-		return container;			
+		return container;
 	}
 
 	/**
-	 * Helper method finding the classpath container initializer registered for a given classpath container ID 
+	 * Helper method finding the classpath container initializer registered for a given classpath container ID
 	 * or <code>null</code> if none was found while iterating over the contributions to extension point to
 	 * the extension point "org.eclipse.jdt.core.classpathContainerInitializer".
 	 * <p>
 	 * A containerID is the first segment of any container path, used to identify the registered container initializer.
 	 * <p>
 	 * @param containerID - a containerID identifying a registered initializer
-	 * @return ClasspathContainerInitializer - the registered classpath container initializer or <code>null</code> if 
+	 * @return ClasspathContainerInitializer - the registered classpath container initializer or <code>null</code> if
 	 * none was found.
 	 * @since 2.1
 	 */
@@ -1364,42 +1609,50 @@
 			for(int i = 0; i < extensions.length; i++){
 				IConfigurationElement [] configElements = extensions[i].getConfigurationElements();
 				for(int j = 0; j < configElements.length; j++){
-					String initializerID = configElements[j].getAttribute("id"); //$NON-NLS-1$
+					IConfigurationElement configurationElement = configElements[j];
+					String initializerID = configurationElement.getAttribute("id"); //$NON-NLS-1$
 					if (initializerID != null && initializerID.equals(containerID)){
-						if (JavaModelManager.CP_RESOLVE_VERBOSE) {
-							Util.verbose(
-								"CPContainer INIT - found initializer\n" + //$NON-NLS-1$
-								"	container ID: " + containerID + '\n' + //$NON-NLS-1$
-								"	class: " + configElements[j].getAttribute("class")); //$NON-NLS-1$ //$NON-NLS-2$
-						}						
+						if (JavaModelManager.CP_RESOLVE_VERBOSE_ADVANCED)
+							verbose_found_container_initializer(containerID, configurationElement);
 						try {
-							Object execExt = configElements[j].createExecutableExtension("class"); //$NON-NLS-1$
+							Object execExt = configurationElement.createExecutableExtension("class"); //$NON-NLS-1$
 							if (execExt instanceof ClasspathContainerInitializer){
 								return (ClasspathContainerInitializer)execExt;
 							}
 						} catch(CoreException e) {
 							// executable extension could not be created: ignore this initializer
 							if (JavaModelManager.CP_RESOLVE_VERBOSE) {
-								Util.verbose(
-									"CPContainer INIT - failed to instanciate initializer\n" + //$NON-NLS-1$
-									"	container ID: " + containerID + '\n' + //$NON-NLS-1$
-									"	class: " + configElements[j].getAttribute("class"), //$NON-NLS-1$ //$NON-NLS-2$
-									System.err); 
+								verbose_failed_to_instanciate_container_initializer(containerID, configurationElement);
 								e.printStackTrace();
-							}						
+							}
 						}
 					}
 				}
-			}	
+			}
 		}
 		return null;
 	}
 
+	private static void verbose_failed_to_instanciate_container_initializer(String containerID, IConfigurationElement configurationElement) {
+		Util.verbose(
+			"CPContainer INIT - failed to instanciate initializer\n" + //$NON-NLS-1$
+			"	container ID: " + containerID + '\n' + //$NON-NLS-1$
+			"	class: " + configurationElement.getAttribute("class"), //$NON-NLS-1$ //$NON-NLS-2$
+			System.err);
+	}
+
+	private static void verbose_found_container_initializer(String containerID, IConfigurationElement configurationElement) {
+		Util.verbose(
+			"CPContainer INIT - found initializer\n" + //$NON-NLS-1$
+			"	container ID: " + containerID + '\n' + //$NON-NLS-1$
+			"	class: " + configurationElement.getAttribute("class")); //$NON-NLS-1$ //$NON-NLS-2$
+	}
+
 	/**
 	 * Returns the path held in the given classpath variable.
-	 * Returns <node>null</code> if unable to bind.
+	 * Returns <code>null</code> if unable to bind.
 	 * <p>
-	 * Classpath variable values are persisted locally to the workspace, and 
+	 * Classpath variable values are persisted locally to the workspace, and
 	 * are preserved from session to session.
 	 * <p>
 	 * Note that classpath variables can be contributed registered initializers for,
@@ -1409,7 +1662,7 @@
 	 * each session.
 	 *
 	 * @param variableName the name of the classpath variable
-	 * @return the path, or <code>null</code> if none 
+	 * @return the path, or <code>null</code> if none
 	 * @see #setClasspathVariable(String, IPath)
 	 */
 	public static IPath getClasspathVariable(final String variableName) {
@@ -1419,73 +1672,101 @@
 		if (variablePath == JavaModelManager.VARIABLE_INITIALIZATION_IN_PROGRESS){
 		    return manager.getPreviousSessionVariable(variableName);
 		}
-		
+
 		if (variablePath != null) {
+			if (variablePath == JavaModelManager.CP_ENTRY_IGNORE_PATH)
+				return null;
 			return variablePath;
 		}
 
 		// even if persisted value exists, initializer is given priority, only if no initializer is found the persisted value is reused
 		final ClasspathVariableInitializer initializer = JavaCore.getClasspathVariableInitializer(variableName);
 		if (initializer != null){
-			if (JavaModelManager.CP_RESOLVE_VERBOSE){
-				Util.verbose(
-					"CPVariable INIT - triggering initialization\n" + //$NON-NLS-1$
-					"	variable: " + variableName + '\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$
-			}
-			JavaModelManager.getJavaModelManager().variablePut(variableName, JavaModelManager.VARIABLE_INITIALIZATION_IN_PROGRESS); // avoid initialization cycles
+			if (JavaModelManager.CP_RESOLVE_VERBOSE)
+				verbose_triggering_variable_initialization(variableName, initializer);
+			if (JavaModelManager.CP_RESOLVE_VERBOSE_ADVANCED)
+				verbose_triggering_variable_initialization_invocation_trace();
+			manager.variablePut(variableName, JavaModelManager.VARIABLE_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(variableName);
-				
-				variablePath = JavaModelManager.getJavaModelManager().variableGet(variableName); // initializer should have performed side-effect
+
+				variablePath = manager.variableGet(variableName); // initializer should have performed side-effect
 				if (variablePath == JavaModelManager.VARIABLE_INITIALIZATION_IN_PROGRESS) return null; // break cycle (initializer did not init or reentering call)
-				if (JavaModelManager.CP_RESOLVE_VERBOSE){
-					Util.verbose(
-						"CPVariable INIT - after initialization\n" + //$NON-NLS-1$
-						"	variable: " + variableName +'\n' + //$NON-NLS-1$
-						"	variable path: " + variablePath); //$NON-NLS-1$
-				}
+				if (JavaModelManager.CP_RESOLVE_VERBOSE_ADVANCED)
+					verbose_variable_value_after_initialization(variableName, variablePath);
+				manager.variablesWithInitializer.add(variableName);
 				ok = true;
 			} catch (RuntimeException e) {
-				if (JavaModelManager.CP_RESOLVE_VERBOSE) {
+				if (JavaModelManager.CP_RESOLVE_VERBOSE)
 					e.printStackTrace();
-				}
 				throw e;
 			} catch (Error e) {
-				if (JavaModelManager.CP_RESOLVE_VERBOSE) {
+				if (JavaModelManager.CP_RESOLVE_VERBOSE)
 					e.printStackTrace();
-				}
 				throw e;
 			} finally {
 				if (!ok) JavaModelManager.getJavaModelManager().variablePut(variableName, null); // flush cache
 			}
 		} else {
-			if (JavaModelManager.CP_RESOLVE_VERBOSE){
-				Util.verbose(
-					"CPVariable INIT - no initializer found\n" + //$NON-NLS-1$
-					"	variable: " + variableName); //$NON-NLS-1$
-			}
+			if (JavaModelManager.CP_RESOLVE_VERBOSE_ADVANCED)
+				verbose_no_variable_initializer_found(variableName);
 		}
 		return variablePath;
 	}
 
+	private static void verbose_no_variable_initializer_found(String variableName) {
+		Util.verbose(
+			"CPVariable INIT - no initializer found\n" + //$NON-NLS-1$
+			"	variable: " + variableName); //$NON-NLS-1$
+	}
+
+	private static void verbose_variable_value_after_initialization(String variableName, IPath variablePath) {
+		Util.verbose(
+			"CPVariable INIT - after initialization\n" + //$NON-NLS-1$
+			"	variable: " + variableName +'\n' + //$NON-NLS-1$
+			"	variable path: " + variablePath); //$NON-NLS-1$
+	}
+
+	private static void verbose_triggering_variable_initialization(String variableName, ClasspathVariableInitializer initializer) {
+		Util.verbose(
+			"CPVariable INIT - triggering initialization\n" + //$NON-NLS-1$
+			"	variable: " + variableName + '\n' + //$NON-NLS-1$
+			"	initializer: " + initializer); //$NON-NLS-1$
+	}
+
+	private static void verbose_triggering_variable_initialization_invocation_trace() {
+		Util.verbose(
+			"CPVariable INIT - triggering initialization\n" + //$NON-NLS-1$
+			"	invocation trace:"); //$NON-NLS-1$
+		new Exception("<Fake exception>").printStackTrace(System.out); //$NON-NLS-1$
+	}
+
 	/**
-	 * Helper method finding the classpath variable initializer registered for a given classpath variable name 
+	 * Returns deprecation message of a given classpath variable.
+	 *
+	 * @param variableName
+	 * @return A string if the classpath variable is deprecated, <code>null</code> otherwise.
+	 * @since 3.3
+	 */
+	public static String getClasspathVariableDeprecationMessage(String variableName) {
+	    return (String) JavaModelManager.getJavaModelManager().deprecatedVariables.get(variableName);
+	}
+
+	/**
+	 * Helper method finding the classpath variable initializer registered for a given classpath variable name
 	 * or <code>null</code> if none was found while iterating over the contributions to extension point to
 	 * the extension point "org.eclipse.jdt.core.classpathVariableInitializer".
 	 * <p>
  	 * @param variable the given variable
- 	 * @return ClasspathVariableInitializer - the registered classpath variable initializer or <code>null</code> if 
+ 	 * @return ClasspathVariableInitializer - the registered classpath variable initializer or <code>null</code> if
 	 * none was found.
 	 * @since 2.1
  	 */
 	public static ClasspathVariableInitializer getClasspathVariableInitializer(String variable){
-		
+
 		Plugin jdtCorePlugin = JavaCore.getPlugin();
 		if (jdtCorePlugin == null) return null;
 
@@ -1495,41 +1776,58 @@
 			for(int i = 0; i < extensions.length; i++){
 				IConfigurationElement [] configElements = extensions[i].getConfigurationElements();
 				for(int j = 0; j < configElements.length; j++){
+					IConfigurationElement configElement = configElements[j];
 					try {
-						String varAttribute = configElements[j].getAttribute("variable"); //$NON-NLS-1$
+						String varAttribute = configElement.getAttribute("variable"); //$NON-NLS-1$
 						if (variable.equals(varAttribute)) {
-							if (JavaModelManager.CP_RESOLVE_VERBOSE) {
-								Util.verbose(
-									"CPVariable INIT - found initializer\n" + //$NON-NLS-1$
-									"	variable: " + variable + '\n' + //$NON-NLS-1$
-									"	class: " + configElements[j].getAttribute("class")); //$NON-NLS-1$ //$NON-NLS-2$
-							}						
-							Object execExt = configElements[j].createExecutableExtension("class"); //$NON-NLS-1$
+							if (JavaModelManager.CP_RESOLVE_VERBOSE_ADVANCED)
+								verbose_found_variable_initializer(variable, configElement);
+							Object execExt = configElement.createExecutableExtension("class"); //$NON-NLS-1$
 							if (execExt instanceof ClasspathVariableInitializer){
-								return (ClasspathVariableInitializer)execExt;
+								ClasspathVariableInitializer initializer = (ClasspathVariableInitializer)execExt;
+								String deprecatedAttribute = configElement.getAttribute("deprecated"); //$NON-NLS-1$
+								if (deprecatedAttribute != null) {
+									JavaModelManager.getJavaModelManager().deprecatedVariables.put(variable, deprecatedAttribute);
+								}
+								String readOnlyAttribute = configElement.getAttribute("readOnly"); //$NON-NLS-1$
+								if (JavaModelManager.TRUE.equals(readOnlyAttribute)) {
+									JavaModelManager.getJavaModelManager().readOnlyVariables.add(variable);
+								}
+								return initializer;
 							}
 						}
 					} catch(CoreException e){
 						// executable extension could not be created: ignore this initializer
 						if (JavaModelManager.CP_RESOLVE_VERBOSE) {
-							Util.verbose(
-								"CPContainer INIT - failed to instanciate initializer\n" + //$NON-NLS-1$
-								"	variable: " + variable + '\n' + //$NON-NLS-1$
-								"	class: " + configElements[j].getAttribute("class"), //$NON-NLS-1$ //$NON-NLS-2$
-								System.err); 
+							verbose_failed_to_instanciate_variable_initializer(variable, configElement);
 							e.printStackTrace();
-						}						
+						}
 					}
 				}
-			}	
+			}
 		}
 		return null;
-	}	
-	
+	}
+
+	private static void verbose_failed_to_instanciate_variable_initializer(String variable, IConfigurationElement configElement) {
+		Util.verbose(
+			"CPContainer INIT - failed to instanciate initializer\n" + //$NON-NLS-1$
+			"	variable: " + variable + '\n' + //$NON-NLS-1$
+			"	class: " + configElement.getAttribute("class"), //$NON-NLS-1$ //$NON-NLS-2$
+			System.err);
+	}
+
+	private static void verbose_found_variable_initializer(String variable, IConfigurationElement configElement) {
+		Util.verbose(
+			"CPVariable INIT - found initializer\n" + //$NON-NLS-1$
+			"	variable: " + variable + '\n' + //$NON-NLS-1$
+			"	class: " + configElement.getAttribute("class")); //$NON-NLS-1$ //$NON-NLS-2$
+	}
+
 	/**
 	 * Returns the names of all known classpath variables.
 	 * <p>
-	 * Classpath variable values are persisted locally to the workspace, and 
+	 * Classpath variable values are persisted locally to the workspace, and
 	 * are preserved from session to session.
 	 * <p>
 	 *
@@ -1545,21 +1843,21 @@
 	 * These options allow to configure the behaviour of the underlying components.
 	 * The client may safely use the result as a template that they can modify and
 	 * then pass to <code>setOptions</code>.
-	 * 
-	 * Helper constants have been defined on JavaCore for each of the option ID and 
+	 *
+	 * Helper constants have been defined on JavaCore for each of the option ID and
 	 * their possible constant values.
-	 * 
+	 *
 	 * Note: more options might be added in further releases.
 	 * <pre>
 	 * RECOGNIZED OPTIONS:
-	 * 
+	 *
 	 * COMPILER / Setting Compliance Level
 	 *    Select the compliance level for the compiler. In "1.3" mode, source and target settings
 	 *    should not go beyond "1.3" level.
 	 *     - option id:         "org.eclipse.jdt.core.compiler.compliance"
-	 *     - possible values:   { "1.3", "1.4", "1.5" }
+	 *     - possible values:   { "1.3", "1.4", "1.5", "1.6", "1.7" }
 	 *     - default:           "1.4"
-	 * 
+	 *
 	 * COMPILER / Setting Source Compatibility Mode
 	 *    Specify whether which source level compatibility is used. From 1.4 on, 'assert' is a keyword
 	 *    reserved for assertion support. Also note, than when toggling to 1.4 mode, the target VM
@@ -1567,58 +1865,63 @@
 	 *   Source level 1.5 is necessary to enable generics, autoboxing, covariance, annotations, enumerations
 	 *   enhanced for loop, static imports and varargs. Once toggled, the target VM level should be set to "1.5"
 	 *   and the compliance mode should be "1.5".
+	 *   Source level 1.6 is necessary to enable the computation of stack map tables. Once toggled, the target
+	 *   VM level should be set to "1.6" and the compliance mode should be "1.6".
+	 *   Once the source level 1.7 is toggled, the target VM level should be set to "1.7" and the compliance mode
+	 *   should be "1.7".
 	 *     - option id:         "org.eclipse.jdt.core.compiler.source"
-	 *     - possible values:   { "1.3", "1.4", "1.5" }
+	 *     - possible values:   { "1.3", "1.4", "1.5", "1.6", "1.7" }
 	 *     - default:           "1.3"
-	 * 
+	 *
 	 * COMPILER / Defining Target Java Platform
 	 *    For binary compatibility reason, .class files can be tagged to with certain VM versions and later.
-	 *    Note that "1.4" target require to toggle compliance mode to "1.4" too. Similarily, "1.5" target require
-	 *    to toggle compliance mode to "1.5".
+	 *    Note that "1.4" target requires to toggle compliance mode to "1.4", "1.5" target requires
+	 *    to toggle compliance mode to "1.5", "1.6" target requires to toggle compliance mode to "1.6" and
+	 *    "1.7" target requires to toggle compliance mode to "1.7".
 	 *     - option id:         "org.eclipse.jdt.core.compiler.codegen.targetPlatform"
-	 *     - possible values:   { "1.1", "1.2", "1.3", "1.4", "1.5" }
+	 *     - possible values:   { "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7" }
 	 *     - default:           "1.2"
 	 *
 	 * COMPILER / Generating Local Variable Debug Attribute
- 	 *    When generated, this attribute will enable local variable names 
-	 *    to be displayed in debugger, only in place where variables are 
+ 	 *    When generated, this attribute will enable local variable names
+	 *    to be displayed in debugger, only in place where variables are
 	 *    definitely assigned (.class file is then bigger)
 	 *     - option id:         "org.eclipse.jdt.core.compiler.debug.localVariable"
 	 *     - possible values:   { "generate", "do not generate" }
 	 *     - default:           "generate"
 	 *
-	 * COMPILER / Generating Line Number Debug Attribute 
-	 *    When generated, this attribute will enable source code highlighting in debugger 
+	 * COMPILER / Generating Line Number Debug Attribute
+	 *    When generated, this attribute will enable source code highlighting in debugger
 	 *    (.class file is then bigger).
 	 *     - option id:         "org.eclipse.jdt.core.compiler.debug.lineNumber"
 	 *     - possible values:   { "generate", "do not generate" }
 	 *     - default:           "generate"
-	 *    
-	 * COMPILER / Generating Source Debug Attribute 
-	 *    When generated, this attribute will enable the debugger to present the 
+	 *
+	 * COMPILER / Generating Source Debug Attribute
+	 *    When generated, this attribute will enable the debugger to present the
 	 *    corresponding source code.
 	 *     - option id:         "org.eclipse.jdt.core.compiler.debug.sourceFile"
 	 *     - possible values:   { "generate", "do not generate" }
 	 *     - default:           "generate"
-	 *    
+	 *
 	 * COMPILER / Preserving Unused Local Variables
-	 *    Unless requested to preserve unused local variables (that is, never read), the 
+	 *    Unless requested to preserve unused local variables (that is, never read), the
 	 *    compiler will optimize them out, potentially altering debugging
 	 *     - option id:         "org.eclipse.jdt.core.compiler.codegen.unusedLocal"
 	 *     - possible values:   { "preserve", "optimize out" }
 	 *     - default:           "preserve"
-	 * 
+	 *
 	 * 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. 
+	 *   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.
 	 *  Note that JSR inlining is optional only for target platform lesser than 1.5. From 1.5 on, the JSR
 	 *  inlining is mandatory (also see related setting "org.eclipse.jdt.core.compiler.codegen.targetPlatform").
 	 *     - option id:         "org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode"
 	 *     - possible values:   { "enabled", "disabled" }
 	 *     - default:           "disabled"
-	 * 
+	 *
 	 * 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
@@ -1628,23 +1931,23 @@
 	 *     - default:           "enabled"
 	 *
 	 * COMPILER / Reporting Attempt to Override Package-Default Method
-	 *    A package default method is not visible in a different package, and thus 
-	 *    cannot be overridden. When enabling this option, the compiler will signal 
+	 *    A package default method is not visible in a different package, and thus
+	 *    cannot be overridden. When enabling this option, the compiler will signal
 	 *    such scenarii either as an error or a warning.
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod"
 	 *     - possible values:   { "error", "warning", "ignore" }
 	 *     - default:           "warning"
 	 *
 	 * COMPILER / Reporting Method With Constructor Name
-	 *    Naming a method with a constructor name is generally considered poor 
-	 *    style programming. When enabling this option, the compiler will signal such 
+	 *    Naming a method with a constructor name is generally considered poor
+	 *    style programming. When enabling this option, the compiler will signal such
 	 *    scenarii either as an error or a warning.
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.methodWithConstructorName"
 	 *     - possible values:   { "error", "warning", "ignore" }
 	 *     - default:           "warning"
 	 *
 	 * COMPILER / Reporting Deprecation
-	 *    When enabled, the compiler will signal use of deprecated API either as an 
+	 *    When enabled, the compiler will signal use of deprecated API either as an
 	 *    error or a warning.
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.deprecation"
 	 *     - possible values:   { "error", "warning", "ignore" }
@@ -1668,22 +1971,22 @@
 	 *    Locally to a try statement, some catch blocks may hide others . For example,
 	 *      try {  throw new java.io.CharConversionException();
 	 *      } catch (java.io.CharConversionException e) {
-	 *      } catch (java.io.IOException e) {}. 
-	 *    When enabling this option, the compiler will issue an error or a warning for hidden 
+	 *      } catch (java.io.IOException e) {}.
+	 *    When enabling this option, the compiler will issue an error or a warning for hidden
 	 *    catch blocks corresponding to checked exceptions
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock"
 	 *     - possible values:   { "error", "warning", "ignore" }
 	 *     - default:           "warning"
 	 *
 	 * COMPILER / Reporting Unused Local
-	 *    When enabled, the compiler will issue an error or a warning for unused local 
+	 *    When enabled, the compiler will issue an error or a warning for unused local
 	 *    variables (that is, variables never read from)
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.unusedLocal"
 	 *     - possible values:   { "error", "warning", "ignore" }
 	 *     - default:           "ignore"
 	 *
 	 * COMPILER / Reporting Unused Parameter
-	 *    When enabled, the compiler will issue an error or a warning for unused method 
+	 *    When enabled, the compiler will issue an error or a warning for unused method
 	 *    parameters (that is, parameters never read from)
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.unusedParameter"
 	 *     - possible values:   { "error", "warning", "ignore" }
@@ -1703,15 +2006,25 @@
 	 *     - possible values:   { "enabled", "disabled" }
 	 *     - default:           "disabled"
 	 *
+	 * COMPILER / Consider Reference in Doc Comment for Unused Parameter Check
+	 *    When enabled, the compiler will consider doc comment references to parameters (i.e. @param clauses) for the unused
+	 *    parameter check. Thus, documented parameters will be considered as mandated as per doc contract.
+	 *    The severity of the unused parameter problem is controlled with option "org.eclipse.jdt.core.compiler.problem.unusedParameter".
+	 *    Note: this option has no effect until the doc comment support is enabled according to the 
+	 *    option "org.eclipse.jdt.core.compiler.doc.comment.support".
+	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocReference"
+	 *     - possible values:   { "enabled", "disabled" }
+	 *     - default:           "enabled"
+	 *
 	 * COMPILER / Reporting Unused Import
-	 *    When enabled, the compiler will issue an error or a warning for unused import 
-	 *    reference 
+	 *    When enabled, the compiler will issue an error or a warning for unused import
+	 *    reference
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.unusedImport"
 	 *     - possible values:   { "error", "warning", "ignore" }
 	 *     - default:           "warning"
 	 *
 	 * COMPILER / Reporting Unused Private Members
-	 *    When enabled, the compiler will issue an error or a warning whenever a private 
+	 *    When enabled, the compiler will issue an error or a warning whenever a private
 	 *    method or field is declared but never used within the same unit.
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.unusedPrivateMember"
 	 *     - possible values:   { "error", "warning", "ignore" }
@@ -1723,30 +2036,30 @@
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.noEffectAssignment"
 	 *     - possible values:   { "error", "warning", "ignore" }
 	 *     - default:           "warning"
-	 * 
+	 *
 	 * 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"
-	 * 
+	 *
 	 * COMPILER / Reporting Unnecessary Type Check
-	 *    When enabled, the compiler will issue an error or a warning when a cast or an instanceof operation 
+	 *    When enabled, the compiler will issue an error or a warning when a cast or an instanceof operation
 	 *    is unnecessary.
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck"
 	 *     - possible values:   { "error", "warning", "ignore" }
 	 *     - default:           "ignore"
-	 * 
+	 *
 	 * 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"
-	 * 
+	 *
 	 * COMPILER / Reporting Synthetic Access Emulation
-	 *    When enabled, the compiler will issue an error or a warning whenever it emulates 
+	 *    When enabled, the compiler will issue an error or a warning whenever it emulates
 	 *    access to a non-accessible member of an enclosing type. Such access can have
 	 *    performance implications.
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation"
@@ -1754,26 +2067,26 @@
 	 *     - default:           "ignore"
 	 *
 	 * COMPILER / Reporting Non-Externalized String Literal
-	 *    When enabled, the compiler will issue an error or a warning for non externalized 
-	 *    String literal (that is, not tagged with //$NON-NLS-&lt;n&gt;$). 
+	 *    When enabled, the compiler will issue an error or a warning for non externalized
+	 *    String literal (that is, not tagged with //$NON-NLS-&lt;n&gt;$).
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral"
 	 *     - possible values:   { "error", "warning", "ignore" }
 	 *     - default:           "ignore"
-	 * 
+	 *
 	 * COMPILER / Reporting Usage of 'assert' Identifier
-	 *    When enabled, the compiler will issue an error or a warning whenever 'assert' is 
+	 *    When enabled, the compiler will issue an error or a warning whenever 'assert' is
 	 *    used as an identifier (reserved keyword in 1.4)
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.assertIdentifier"
 	 *     - possible values:   { "error", "warning", "ignore" }
 	 *     - default:           "warning"
-	 * 
+	 *
 	 * COMPILER / Reporting Usage of 'enum' Identifier
-	 *    When enabled, the compiler will issue an error or a warning whenever 'enum' is 
+	 *    When enabled, the compiler will issue an error or a warning whenever 'enum' is
 	 *    used as an identifier (reserved keyword in 1.5)
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.enumIdentifier"
 	 *     - possible values:   { "error", "warning", "ignore" }
 	 *     - default:           "warning"
-	 * 
+	 *
 	 * COMPILER / Reporting Non-Static Reference to a Static Member
 	 *    When enabled, the compiler will issue an error or a warning whenever a static field
 	 *    or method is accessed with an expression receiver. A reference to a static member should
@@ -1781,7 +2094,7 @@
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.staticAccessReceiver"
 	 *     - possible values:   { "error", "warning", "ignore" }
 	 *     - default:           "warning"
-	 * 
+	 *
 	 * COMPILER / Reporting Indirect Reference to a Static Member
 	 *    When enabled, the compiler will issue an error or a warning whenever a static field
 	 *    or method is accessed in an indirect way. A reference to a static member should
@@ -1789,18 +2102,18 @@
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.indirectStaticAccess"
 	 *     - possible values:   { "error", "warning", "ignore" }
 	 *     - default:           "ignore"
-	 * 
+	 *
 	 * COMPILER / Reporting Interface Method not Compatible with non-Inherited Methods
 	 *    When enabled, the compiler will issue an error or a warning whenever an interface
 	 *    defines a method incompatible with a non-inherited Object method. Until this conflict
-	 *    is resolved, such an interface cannot be implemented, For example, 
-	 *      interface I { 
+	 *    is resolved, such an interface cannot be implemented, For example,
+	 *      interface I {
 	 *         int clone();
-	 *      } 
+	 *      }
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod"
 	 *     - possible values:   { "error", "warning", "ignore" }
 	 *     - default:           "warning"
-	 * 
+	 *
 	 * COMPILER / Reporting Usage of char[] Expressions in String Concatenations
 	 *    When enabled, the compiler will issue an error or a warning whenever a char[] expression
 	 *    is used in String concatenations (for example, "hello" + new char[]{'w','o','r','l','d'}).
@@ -1823,16 +2136,17 @@
 	 *     - default:           "ignore"
 	 *
 	 * COMPILER / Reporting Special Parameter Hiding another Field
-	 *    When enabled, the compiler will signal cases where a constructor or setter method parameter declaration 
+	 *    When enabled, the compiler will signal cases where a constructor or setter method parameter declaration
 	 *    is hiding some field (either locally, inherited or defined in enclosing type).
 	 *    The severity of the problem is controlled with option "org.eclipse.jdt.core.compiler.problem.localVariableHiding".
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.specialParameterHidingField"
 	 *     - possible values:   { "enabled", "disabled" }
 	 *     - default:           "disabled"
-	 * 
-	 * COMPILER / Reporting Type Parameter Declaration Hiding another Type
-	 *    When enabled, the compiler will issue an error or a warning whenever a type parameter
-	 *    declaration is hiding some type.
+	 *
+	 * COMPILER / Reporting Type Declaration Hiding another Type
+	 *    When enabled, the compiler will issue an error or a warning in situations where a type parameter
+	 *    declaration is hiding some type, when a nested type is hiding some type parameter, or when
+	 *    a nested type is hiding another nested type defined in same unit.
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.typeParameterHiding"
 	 *     - possible values:   { "error", "warning", "ignore" }
 	 *     - default:           "warning"
@@ -1843,7 +2157,7 @@
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment"
 	 *     - possible values:   { "error", "warning", "ignore" }
 	 *     - default:           "ignore"
-	 * 
+	 *
 	 * COMPILER / Reporting Undocumented Empty Block
 	 *    When enabled, the compiler will issue an error or a warning when an empty block is detected and it is not
 	 *    documented with any comment.
@@ -1872,7 +2186,7 @@
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding"
 	 *     - possible values:   { "enabled", "disabled" }
 	 *     - default:           "disabled"
-	 * 
+	 *
 	 * COMPILER / Reporting Unqualified Access to Field
 	 *    When enabled, the compiler will issue an error or a warning when a field is access without any qualification.
 	 *    In order to improve code readability, it should be qualified, e.g. 'x' should rather be written 'this.x'.
@@ -1886,76 +2200,101 @@
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation"
 	 *     - possible values:   { "error", "warning", "ignore" }
 	 *     - default:           "warning"
-	 * 
+	 *
+	 * COMPILER / Reporting Raw Type Reference
+	 *    When enabled, the compiler will issue an error or a warning when detecting references to raw types. Raw types are
+	 *    discouraged, and are intended to help interfacing with legacy code. In the future, the language specification may
+	 *    reject raw references to generic types.
+	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.rawTypeReference"
+	 *     - possible values:   { "error", "warning", "ignore" }
+	 *     - default:           "warning"
+	 *
 	 * COMPILER / Reporting final Bound for Type Parameter
-	 *    When enabled, the compiler will issue an error or a warning whenever a generic type parameter is associated with a 
+	 *    When enabled, the compiler will issue an error or a warning whenever a generic type parameter is associated with a
 	 *    bound corresponding to a final type; since final types cannot be further extended, the parameter is pretty useless.
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.finalParameterBound"
 	 *     - possible values:   { "error", "warning", "ignore" }
 	 *     - default:           "warning"
-	 * 
+	 *
 	 * COMPILER / Reporting Missing Declaration of serialVersionUID Field on Serializable Class
-	 *    When enabled, the compiler will issue an error or a warning whenever a serializable class is missing a local declaration 
+	 *    When enabled, the compiler will issue an error or a warning whenever a serializable class is missing a local declaration
 	 *    of a serialVersionUID field. This field must be declared as static final and be of type long.
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.missingSerialVersion"
 	 *     - possible values:   { "error", "warning", "ignore" }
 	 *     - default:           "warning"
-	 * 
+	 *
 	 * COMPILER / Reporting Varargs Argument Needing a Cast in Method/Constructor Invocation
 	 *    When enabled, the compiler will issue an error or a warning whenever a varargs arguments should be cast
-	 *    when passed to a method/constructor invocation. (e.g. Class.getMethod(String name, Class ... args )  
+	 *    when passed to a method/constructor invocation. (e.g. Class.getMethod(String name, Class ... args )
 	 *    invoked with arguments ("foo", null)).
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast"
 	 *     - possible values:   { "error", "warning", "ignore" }
 	 *     - default:           "warning"
-	 * 
-	 * COMPILER / Reporting Null Reference or Dereference
-	 *    When enabled, the compiler will issue an error or a warning whenever assumption were made on a variable
-	 *    with respect to holding null/non-null values, but the assumption is not followed in a consistent manner.
-	 *    Situations include:
-	 *         - if variable was assumed to be null and further used to access field or methods
-	 *         - if variable was assumed to be null or non-null and further tested for null cases.
-	 *         
+	 *
+	 * COMPILER / Reporting Null Dereference
+	 *    When enabled, the compiler will issue an error or a warning whenever a
+	 *    variable that is statically known to hold a null value is used to
+	 *    access a field or method.
+	 *
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.nullReference"
 	 *     - possible values:   { "error", "warning", "ignore" }
-	 *     - default:           "warning"
-	 * 
+	 *     - default:           "ignore"
+	 *
+	 * COMPILER / Reporting Potential Null Dereference
+	 *    When enabled, the compiler will issue an error or a warning whenever a
+	 *    variable that has formerly been tested against null but is not (no more)
+	 *    statically known to hold a non-null value is used to access a field or
+	 *    method.
+	 *
+	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.potentialNullReference"
+	 *     - possible values:   { "error", "warning", "ignore" }
+	 *     - default:           "ignore"
+	 *
+	 * COMPILER / Reporting Redundant Null Check
+	 *    When enabled, the compiler will issue an error or a warning whenever a
+	 *    variable that is statically known to hold a null or a non-null value
+	 *    is tested against null.
+	 *
+	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.redundantNullCheck"
+	 *     - possible values:   { "error", "warning", "ignore" }
+	 *     - default:           "ignore"
+	 *
 	 * COMPILER / Reporting Use of Annotation Type as Super Interface
 	 *    When enabled, the compiler will issue an error or a warning whenever an annotation type is used
 	 *    as a super-interface. Though legal, this is discouraged.
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.annotationSuperInterface"
 	 *     - possible values:   { "error", "warning", "ignore" }
 	 *     - default:           "warning"
-	 * 
+	 *
 	 * COMPILER / Reporting Missing @Override Annotation
 	 *    When enabled, the compiler will issue an error or a warning whenever encountering a method
 	 *    declaration which overrides a superclass method but has no @Override annotation.
 	 *     - option id:        "org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation"
 	 *     - possible values:   { "error", "warning", "ignore" }
-	 *     - default:           "ignore"                               
-	 * 
+	 *     - default:           "ignore"
+	 *
 	 * COMPILER / Reporting Missing @Deprecated Annotation
 	 *    When enabled, the compiler will issue an error or a warning whenever encountering a declaration
-	 *    carrying a @deprecated doc tag but has no corresponding @Deprecated annotation.
+	 *    carrying a @deprecated doc tag but having no corresponding @Deprecated annotation.
 	 *     - option id:        "org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation"
 	 *     - possible values:   { "error", "warning", "ignore" }
-	 *     - default:           "ignore"                               
-	 * 
+	 *     - default:           "ignore"
+	 *
 	 * COMPILER / Reporting Incomplete Enum Switch
-	 *    When enabled, the compiler will issue an error or a warning whenever an enum constant has
-	 *    no corresponding case label in an enum switch statement
-	 *    type has no case label matching an enum constant.
+	 *    When enabled, the compiler will issue an error or a warning whenever
+	 *    an enum constant has no corresponding case label in an enum switch
+	 *    statement.
 	 *     - option id:        "org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch"
 	 *     - possible values:   { "error", "warning", "ignore" }
-	 *     - default:           "ignore"                               
-	 * 	
+	 *     - default:           "ignore"
+	 *
 	 * COMPILER / Reporting Boxing/Unboxing Conversion
 	 *    When enabled, the compiler will issue an error or a warning whenever a boxing or an unboxing
 	 *    conversion is performed.
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.autoboxing"
 	 *     - possible values:   { "error", "warning", "ignore" }
 	 *     - default:           "ignore"
-	 * 
+	 *
 	 * COMPILER / Reporting Invalid Javadoc Comment
 	 *    This is the generic control for the severity of Javadoc problems.
 	 *    When enabled, the compiler will issue an error or a warning for a problem in Javadoc.
@@ -1967,8 +2306,8 @@
 	 *    Set the minimum visibility level for Javadoc tag problems. Below this level problems will be ignored.
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility"
 	 *     - possible values:   { "public", "protected", "default", "private" }
-	 *     - default:           "private"
-	 * 
+	 *     - default:           "public"
+	 *
 	 * COMPILER / Reporting Invalid Javadoc Tags
 	 *    When enabled, the compiler will signal unbound or unexpected reference tags in Javadoc.
 	 *    A 'throws' tag referencing an undeclared exception would be considered as unexpected.
@@ -1978,24 +2317,24 @@
 	 *    The severity of the problem is controlled with option "org.eclipse.jdt.core.compiler.problem.invalidJavadoc".
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.invalidJavadocTags"
 	 *     - possible values:   { "disabled", "enabled" }
-	 *     - default:           "enabled"
-	 * 
+	 *     - default:           "disabled"
+	 *
 	 * COMPILER / Reporting Invalid Javadoc Tags with Deprecated References
 	 *    Specify whether the compiler will report deprecated references used in Javadoc tags.
 	 *    <br>Note that this diagnosis can be enabled based on the visibility of the construct associated with the Javadoc;
 	 *    also see the setting "org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility".
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef"
 	 *     - possible values:   { "enabled", "disabled" }
-	 *     - default:           "enabled"
-	 * 
+	 *     - default:           "disabled"
+	 *
 	 * COMPILER / Reporting Invalid Javadoc Tags with Not Visible References
 	 *    Specify whether the compiler will report non-visible references used in Javadoc tags.
 	 *    <br>Note that this diagnosis can be enabled based on the visibility of the construct associated with the Javadoc;
 	 *    also see the setting "org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility".
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef"
 	 *     - possible values:   { "enabled", "disabled" }
-	 *     - default:           "enabled"
-	 * 
+	 *     - default:           "disabled"
+	 *
 	 * COMPILER / Reporting Missing Javadoc Tags
 	 *    This is the generic control for the severity of Javadoc missing tag problems.
 	 *    When enabled, the compiler will issue an error or a warning when tags are missing in Javadoc comments.
@@ -2005,19 +2344,19 @@
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.missingJavadocTags"
 	 *     - possible values:   { "error", "warning", "ignore" }
 	 *     - default:           "ignore"
-	 * 
+	 *
 	 * COMPILER / Visibility Level For Missing Javadoc Tags
 	 *    Set the minimum visibility level for Javadoc missing tag problems. Below this level problems will be ignored.
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility"
 	 *     - possible values:   { "public", "protected", "default", "private" }
-	 *     - default:           "private"
-	 * 
+	 *     - default:           "public"
+	 *
 	 * COMPILER / Reporting Missing Javadoc Tags on Overriding Methods
 	 *    Specify whether the compiler will verify overriding methods in order to report Javadoc missing tag problems.
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding"
 	 *     - possible values:   { "enabled", "disabled" }
 	 *     - default:           "disabled"
-	 * 
+	 *
 	 * COMPILER / Reporting Missing Javadoc Comments
 	 *    This is the generic control for the severity of missing Javadoc comment problems.
 	 *    When enabled, the compiler will issue an error or a warning when Javadoc comments are missing.
@@ -2027,39 +2366,51 @@
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.missingJavadocComments"
 	 *     - possible values:   { "error", "warning", "ignore" }
 	 *     - default:           "ignore"
-	 * 
+	 *
 	 * COMPILER / Visibility Level For Missing Javadoc Comments
 	 *    Set the minimum visibility level for missing Javadoc problems. Below this level problems will be ignored.
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility"
 	 *     - possible values:   { "public", "protected", "default", "private" }
 	 *     - default:           "public"
-	 * 
+	 *
 	 * COMPILER / Reporting Missing Javadoc Comments on Overriding Methods
 	 *    Specify whether the compiler will verify overriding methods in order to report missing Javadoc comment problems.
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding"
 	 *     - possible values:   { "enabled", "disabled" }
 	 *     - default:           "disabled"
-	 * 
-	 * COMPILER / Maximum number of problems reported per compilation unit
+	 *
+	 * COMPILER / Maximum Number of Problems Reported per Compilation Unit
 	 *    Specify the maximum number of problems reported on each compilation unit.
 	 *     - option id:         "org.eclipse.jdt.core.compiler.maxProblemPerUnit"
 	 *     - possible values:	"&lt;n&gt;" where &lt;n&gt; is zero or a positive integer (if zero then all problems are reported).
 	 *     - default:           "100"
-	 * 
+	 *
+	 * COMPILER / Treating Optional Error as Fatal
+	 *    When enabled, optional errors (i.e. optional problems which severity is set to "error") will be treated as standard
+	 *    compiler errors, yielding problem methods/types preventing from running offending code until the issue got resolved.
+	 *    When disabled, optional errors are only considered as warnings, still carrying an error indication to make them more
+	 *    severe. Note that by default, errors are fatal, whether they are optional or not.
+	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.fatalOptionalError"
+	 *     - possible values:   { "enabled", "disabled" }
+	 *     - default:           "enabled"
+	 *
 	 * COMPILER / Defining the Automatic Task Tags
 	 *    When the tag list is not empty, the compiler will issue a task marker whenever it encounters
-	 *    one of the corresponding tag inside any comment in Java source code.
-	 *    Generated task messages will include the tag, and range until the next line separator or comment ending.
+	 *    one of the corresponding tags inside any comment in Java source code.
+	 *    Generated task messages will start with the tag, and range until the next line separator,
+	 *    comment ending, or tag.
+	 *    When a given line of code bears multiple tags, each tag will be reported separately.
+	 *    Moreover, a tag immediately followed by another tag will be reported using the contents of the
+	 *    next non-empty tag of the line, if any.
 	 *    Note that tasks messages are trimmed. If a tag is starting with a letter or digit, then it cannot be leaded by
 	 *    another letter or digit to be recognized ("fooToDo" will not be recognized as a task for tag "ToDo", but "foo#ToDo"
 	 *    will be detected for either tag "ToDo" or "#ToDo"). Respectively, a tag ending with a letter or digit cannot be followed
 	 *    by a letter or digit to be recognized ("ToDofoo" will not be recognized as a task for tag "ToDo", but "ToDo:foo" will
 	 *    be detected either for tag "ToDo" or "ToDo:").
-	 *    Note: the tasks are ordered, and the first matching tag will be selected; e.g. "TODO,TODO!" will match "TODO!" against "TODO" first.
 	 *     - option id:         "org.eclipse.jdt.core.compiler.taskTags"
-	 *     - possible values:   { "&lt;tag&gt;[,&lt;tag&gt;]*" } where &lt;tag&gt; is a String without any wild-card or leading/trailing spaces 
+	 *     - possible values:   { "&lt;tag&gt;[,&lt;tag&gt;]*" } where &lt;tag&gt; is a String without any wild-card or leading/trailing spaces
 	 *     - default:           "TODO,FIXME,XXX"
-	 * 
+	 *
 	 * COMPILER / Defining the Automatic Task Priorities
 	 *    In parallel with the Automatic Task Tags, this list defines the priorities (high, normal or low)
 	 *    of the task markers issued by the compiler.
@@ -2067,7 +2418,7 @@
 	 *     - option id:         "org.eclipse.jdt.core.compiler.taskPriorities"
 	 *     - possible values:   { "&lt;priority&gt;[,&lt;priority&gt;]*" } where &lt;priority&gt; is one of "HIGH", "NORMAL" or "LOW"
 	 *     - default:           "NORMAL,HIGH,NORMAL"
-	 * 
+	 *
 	 * COMPILER / Determining 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"
@@ -2089,7 +2440,7 @@
 	 *     - default:           "warning"
 	 *
 	 * COMPILER / Determining Effect of @SuppressWarnings
-	 *    When enabled, the @SuppressWarnings annotation can be used to suppress some compiler warnings. 
+	 *    When enabled, the @SuppressWarnings annotation can be used to suppress some compiler warnings.
 	 *    When disabled, all @SupressWarnings annotations are ignored; i.e., warnings are reported.
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.suppressWarnings"
 	 *     - possible values:   { "enabled", "disabled" }
@@ -2102,236 +2453,300 @@
 	 *     - possible values:   { "error", "warning", "ignore" }
 	 *     - default:           "warning"
 	 *
+	 * COMPILER / Reporting Unreferenced Label
+	 *    When enabled, the compiler will issue an error or a warning when encountering a labeled statement which label
+	 *    is never explicitly referenced. A label is considered to be referenced if its name explicitly appears behind a break
+	 *    or continue statement; for instance the following label would be considered unreferenced;   LABEL: { break; }
+	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.unusedLabel"
+	 *     - possible values:   { "error", "warning", "ignore" }
+	 *     - default:           "warning"
+	 *
+	 * COMPILER / Reporting Parameter Assignment
+	 *    When enabled, the compiler will issue an error or a warning if a parameter is
+	 *    assigned to.
+	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.parameterAssignment"
+	 *     - possible values:   { "error", "warning", "ignore" }
+	 *     - default:           "ignore"
+	 *
+	 * COMPILER / Reporting Switch Fall-Through Case
+	 *    When enabled, the compiler will issue an error or a warning if a case may be
+	 *    entered by falling through previous case. Empty cases are allowed.
+	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.fallthroughCase"
+	 *     - possible values:   { "error", "warning", "ignore" }
+	 *     - default:           "ignore"
+	 *
+	 * COMPILER / Reporting Overriding method that doesn't call the super method invocation
+	 *    When enabled, the compiler will issue an error or a warning if a method is overriding a method without calling
+	 *    the super invocation.
+	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.overridingMethodWithoutSuperInvocation"
+	 *     - possible values:   { "error", "warning", "ignore" }
+	 *     - default:           "ignore"
+	 *
 	 * BUILDER / Specifying Filters for Resource Copying Control
 	 *    Allow to specify some filters to control the resource copy process.
 	 *     - option id:         "org.eclipse.jdt.core.builder.resourceCopyExclusionFilter"
 	 *     - possible values:   { "&lt;name&gt;[,&lt;name&gt;]* } where &lt;name&gt; is a file name pattern (* and ? wild-cards allowed)
 	 *       or the name of a folder which ends with '/'
 	 *     - default:           ""
-	 * 
+	 *
 	 * BUILDER / Abort if Invalid Classpath
 	 *    Allow to toggle the builder to abort if the classpath is invalid
 	 *     - option id:         "org.eclipse.jdt.core.builder.invalidClasspath"
 	 *     - possible values:   { "abort", "ignore" }
 	 *     - default:           "abort"
-	 * 
+	 *
 	 * BUILDER / Cleaning Output Folder(s)
 	 *    Indicate whether the JavaBuilder is allowed to clean the output folders
 	 *    when performing full build operations.
 	 *     - option id:         "org.eclipse.jdt.core.builder.cleanOutputFolder"
 	 *     - possible values:   { "clean", "ignore" }
 	 *     - default:           "clean"
-	 * 
+	 *
+	 * BUILDER / Recreate Modified class files in Output Folder
+	 *    Indicate whether the JavaBuilder should check for any changes to .class files
+	 *    in the output folders while performing incremental build operations. If changes
+	 *    are detected to managed .class files, then a full build is performed, otherwise
+	 *    the changes are left as is. Tools further altering generated .class files, like optimizers,
+	 *    should ensure this option remains set in its default state of ignore.
+	 *     - option id:         "org.eclipse.jdt.core.builder.recreateModifiedClassFileInOutputFolder"
+	 *     - possible values:   { "enabled", "ignore" }
+	 *     - default:           "ignore"
+	 *
 	 * BUILDER / Reporting Duplicate Resources
 	 *    Indicate the severity of the problem reported when more than one occurrence
 	 *    of a resource is to be copied into the output location.
 	 *     - option id:         "org.eclipse.jdt.core.builder.duplicateResourceTask"
 	 *     - possible values:   { "error", "warning" }
 	 *     - default:           "warning"
-	 * 
+	 *
 	 * JAVACORE / Computing Project Build Order
 	 *    Indicate whether JavaCore should enforce the project build order to be based on
 	 *    the classpath prerequisite chain. When requesting to compute, this takes over
 	 *    the platform default order (based on project references).
 	 *     - option id:         "org.eclipse.jdt.core.computeJavaBuildOrder"
 	 *     - possible values:   { "compute", "ignore" }
-	 *     - default:           "ignore"	 
-	 * 
-	 * JAVACORE / Specify Default Source Encoding Format
-	 *    Get the encoding format for compiled sources. This setting is read-only, it is equivalent
-	 *    to 'ResourcesPlugin.getEncoding()'.
+	 *     - default:           "ignore"
+	 *
+	 * JAVACORE / Default Source Encoding Format
+	 *    Get the default encoding format of source files. This value is
+	 *    immutable and preset to the result of ResourcesPlugin.getEncoding().
+	 *    It is offered as a convenience shortcut only.
 	 *     - option id:         "org.eclipse.jdt.core.encoding"
-	 *     - possible values:   { any of the supported encoding name}.
-	 *     - default:           &lt;platform default&gt;
-	 * 
+	 *     - value:           &lt;immutable, platform default value&gt;
+	 *
 	 * JAVACORE / Reporting Incomplete Classpath
-	 *    Indicate the severity of the problem reported when an entry on the classpath does not exist, 
+	 *    Indicate the severity of the problem reported when an entry on the classpath does not exist,
 	 *    is not legite or is not visible (for example, a referenced project is closed).
 	 *     - option id:         "org.eclipse.jdt.core.incompleteClasspath"
 	 *     - possible values:   { "error", "warning"}
 	 *     - default:           "error"
-	 * 
+	 *
 	 * JAVACORE / Reporting Classpath Cycle
 	 *    Indicate the severity of the problem reported when a project is involved in a cycle.
 	 *     - option id:         "org.eclipse.jdt.core.circularClasspath"
 	 *     - possible values:   { "error", "warning" }
 	 *     - default:           "error"
-	 * 
+	 *
 	 * JAVACORE / Reporting Incompatible JDK Level for Required Binaries
-	 *    Indicate the severity of the problem reported when a project prerequisites another project 
+	 *    Indicate the severity of the problem reported when a project prerequisites another project
 	 *    or library with an incompatible target JDK level (e.g. project targeting 1.1 vm, but compiled against 1.4 libraries).
 	 *     - option id:         "org.eclipse.jdt.core.incompatibleJDKLevel"
 	 *     - possible values:   { "error", "warning", "ignore" }
 	 *     - default:           "ignore"
-	 * 
+	 *
 	 * JAVACORE / Enabling Usage of Classpath Exclusion Patterns
 	 *    When disabled, no entry on a project classpath can be associated with
 	 *    an exclusion pattern.
 	 *     - option id:         "org.eclipse.jdt.core.classpath.exclusionPatterns"
 	 *     - possible values:   { "enabled", "disabled" }
 	 *     - default:           "enabled"
-	 * 
+	 *
 	 * JAVACORE / Enabling Usage of Classpath Multiple Output Locations
 	 *    When disabled, no entry on a project classpath can be associated with
 	 *    a specific output location, preventing thus usage of multiple output locations.
 	 *     - option id:         "org.eclipse.jdt.core.classpath.multipleOutputLocations"
 	 *     - possible values:   { "enabled", "disabled" }
 	 *     - default:           "enabled"
-	 * 
-	 *	FORMATTER / Inserting New Line Before Opening Brace
+	 *
+	 * JAVACORE / Set the timeout value for retrieving the method's parameter names from javadoc
+	 *    Timeout in milliseconds to retrieve the method's parameter names from javadoc.
+	 *    If the value is 0, the parameter names are not fetched and the raw names are returned.
+	 *     - option id:         "org.eclipse.jdt.core.timeoutForParameterNameFromAttachedJavadoc"
+	 *     - possible values:	"&lt;n&gt;", where n is an integer greater than or equal to 0
+	 *     - default:           "50"
+	 *
+	 * DEPRECATED SEE DefaultCodeFormatterOptions: FORMATTER / Inserting New Line Before Opening Brace
 	 *    When Insert, a new line is inserted before an opening brace, otherwise nothing
 	 *    is inserted
 	 *     - option id:         "org.eclipse.jdt.core.formatter.newline.openingBrace"
 	 *     - possible values:   { "insert", "do not insert" }
 	 *     - default:           "do not insert"
-	 * 
-	 *	FORMATTER / Inserting New Line Inside Control Statement
+	 *
+	 * DEPRECATED SEE DefaultCodeFormatterOptions: FORMATTER / Inserting New Line Inside Control Statement
 	 *    When Insert, a new line is inserted between } and following else, catch, finally
 	 *     - option id:         "org.eclipse.jdt.core.formatter.newline.controlStatement"
 	 *     - possible values:   { "insert", "do not insert" }
 	 *     - default:           "do not insert"
-	 * 
-	 *	FORMATTER / Clearing Blank Lines
+	 *
+	 * DEPRECATED SEE DefaultCodeFormatterOptions: Clearing Blank Lines
 	 *    When Clear all, all blank lines are removed. When Preserve one, only one is kept
 	 *    and all others removed.
 	 *     - option id:         "org.eclipse.jdt.core.formatter.newline.clearAll"
 	 *     - possible values:   { "clear all", "preserve one" }
 	 *     - default:           "preserve one"
-	 * 
-	 *	FORMATTER / Inserting New Line Between Else/If 
-	 *    When Insert, a blank line is inserted between an else and an if when they are 
+	 *
+	 * DEPRECATED SEE DefaultCodeFormatterOptions: Inserting New Line Between Else/If
+	 *    When Insert, a blank line is inserted between an else and an if when they are
 	 *    contiguous. When choosing to not insert, else-if will be kept on the same
 	 *    line when possible.
 	 *     - option id:         "org.eclipse.jdt.core.formatter.newline.elseIf"
 	 *     - possible values:   { "insert", "do not insert" }
 	 *     - default:           "do not insert"
-	 * 
-	 *	FORMATTER / Inserting New Line In Empty Block
+	 *
+	 * DEPRECATED SEE DefaultCodeFormatterOptions: Inserting New Line In Empty Block
 	 *    When insert, a line break is inserted between contiguous { and }, if } is not followed
 	 *    by a keyword.
 	 *     - option id:         "org.eclipse.jdt.core.formatter.newline.emptyBlock"
 	 *     - possible values:   { "insert", "do not insert" }
 	 *     - default:           "insert"
-	 * 
-	 *	FORMATTER / Splitting Lines Exceeding Length
+	 *
+	 * DEPRECATED SEE DefaultCodeFormatterOptions: Splitting Lines Exceeding Length
 	 *    Enable splitting of long lines (exceeding the configurable length). Length of 0 will
 	 *    disable line splitting
 	 *     - option id:         "org.eclipse.jdt.core.formatter.lineSplit"
 	 *     - possible values:	"&lt;n&gt;", where n is zero or a positive integer
 	 *     - default:           "80"
-	 * 
-	 *	FORMATTER / Compacting Assignment
+	 *
+	 * DEPRECATED SEE DefaultCodeFormatterOptions: Compacting Assignment
 	 *    Assignments can be formatted asymmetrically, for example 'int x= 2;', when Normal, a space
 	 *    is inserted before the assignment operator
 	 *     - option id:         "org.eclipse.jdt.core.formatter.style.assignment"
 	 *     - possible values:   { "compact", "normal" }
 	 *     - default:           "normal"
-	 * 
-	 *	FORMATTER / Defining Indentation Character
+	 *
+	 * DEPRECATED SEE DefaultCodeFormatterOptions: Defining Indentation Character
 	 *    Either choose to indent with tab characters or spaces
 	 *     - option id:         "org.eclipse.jdt.core.formatter.tabulation.char"
 	 *     - possible values:   { "tab", "space" }
 	 *     - default:           "tab"
-	 * 
-	 *	FORMATTER / Defining Space Indentation Length
-	 *    When using spaces, set the amount of space characters to use for each 
+	 *
+	 * DEPRECATED SEE DefaultCodeFormatterOptions: Defining Space Indentation Length
+	 *    When using spaces, set the amount of space characters to use for each
 	 *    indentation mark.
 	 *     - option id:         "org.eclipse.jdt.core.formatter.tabulation.size"
 	 *     - possible values:	"&lt;n&gt;", where n is a positive integer
 	 *     - default:           "4"
-	 * 
-	 *	FORMATTER / Inserting space in cast expression
+	 *
+	 * DEPRECATED SEE DefaultCodeFormatterOptions: Inserting space in cast expression
 	 *    When Insert, a space is added between the type and the expression in a cast expression.
 	 *     - option id:         "org.eclipse.jdt.core.formatter.space.castexpression"
 	 *     - possible values:   { "insert", "do not insert" }
 	 *     - default:           "insert"
-	 * 
-	 *	CODEASSIST / Activate Visibility Sensitive Completion
+	 *
+	 * CODEASSIST / Activate Visibility Sensitive Completion
 	 *    When active, completion doesn't show that you can not see
 	 *    (for example, you can not see private methods of a super class).
 	 *     - option id:         "org.eclipse.jdt.core.codeComplete.visibilityCheck"
 	 *     - possible values:   { "enabled", "disabled" }
 	 *     - default:           "disabled"
-	 * 
-	 *	CODEASSIST / Automatic Qualification of Implicit Members
+	 *
+	 * CODEASSIST / Activate Deprecation Sensitive Completion
+	 *    When enabled, completion doesn't propose deprecated members and types.
+	 *     - option id:         "org.eclipse.jdt.core.codeComplete.deprecationCheck"
+	 *     - possible values:   { "enabled", "disabled" }
+	 *     - default:           "disabled"
+	 *
+	 * CODEASSIST / Automatic Qualification of Implicit Members
 	 *    When active, completion automatically qualifies completion on implicit
 	 *    field references and message expressions.
 	 *     - option id:         "org.eclipse.jdt.core.codeComplete.forceImplicitQualification"
 	 *     - possible values:   { "enabled", "disabled" }
 	 *     - default:           "disabled"
-	 * 
-	 *  CODEASSIST / Define the Prefixes for Field Name
+	 *
+	 * CODEASSIST / Define the Prefixes for Field Name
 	 *    When the prefixes is non empty, completion for field name will begin with
 	 *    one of the proposed prefixes.
 	 *     - option id:         "org.eclipse.jdt.core.codeComplete.fieldPrefixes"
-	 *     - possible values:   { "&lt;prefix&gt;[,&lt;prefix&gt;]*" } where &lt;prefix&gt; is a String without any wild-card 
+	 *     - possible values:   { "&lt;prefix&gt;[,&lt;prefix&gt;]*" } where &lt;prefix&gt; is a String without any wild-card
 	 *     - default:           ""
-	 * 
-	 *  CODEASSIST / Define the Prefixes for Static Field Name
+	 *
+	 * CODEASSIST / Define the Prefixes for Static Field Name
 	 *    When the prefixes is non empty, completion for static field name will begin with
 	 *    one of the proposed prefixes.
 	 *     - option id:         "org.eclipse.jdt.core.codeComplete.staticFieldPrefixes"
-	 *     - possible values:   { "&lt;prefix&gt;[,&lt;prefix&gt;]*" } where &lt;prefix&gt; is a String without any wild-card 
+	 *     - possible values:   { "&lt;prefix&gt;[,&lt;prefix&gt;]*" } where &lt;prefix&gt; is a String without any wild-card
 	 *     - default:           ""
-	 * 
-	 *  CODEASSIST / Define the Prefixes for Local Variable Name
+	 *
+	 * CODEASSIST / Define the Prefixes for Local Variable Name
 	 *    When the prefixes is non empty, completion for local variable name will begin with
 	 *    one of the proposed prefixes.
 	 *     - option id:         "org.eclipse.jdt.core.codeComplete.localPrefixes"
-	 *     - possible values:   { "&lt;prefix&gt;[,&lt;prefix&gt;]*" } where &lt;prefix&gt; is a String without any wild-card 
+	 *     - possible values:   { "&lt;prefix&gt;[,&lt;prefix&gt;]*" } where &lt;prefix&gt; is a String without any wild-card
 	 *     - default:           ""
-	 * 
-	 *  CODEASSIST / Define the Prefixes for Argument Name
+	 *
+	 * CODEASSIST / Define the Prefixes for Argument Name
 	 *    When the prefixes is non empty, completion for argument name will begin with
 	 *    one of the proposed prefixes.
 	 *     - option id:         "org.eclipse.jdt.core.codeComplete.argumentPrefixes"
-	 *     - possible values:   { "&lt;prefix&gt;[,&lt;prefix&gt;]*" } where &lt;prefix&gt; is a String without any wild-card 
+	 *     - possible values:   { "&lt;prefix&gt;[,&lt;prefix&gt;]*" } where &lt;prefix&gt; is a String without any wild-card
 	 *     - default:           ""
-	 * 
-	 *  CODEASSIST / Define the Suffixes for Field Name
+	 *
+	 * CODEASSIST / Define the Suffixes for Field Name
 	 *    When the suffixes is non empty, completion for field name will end with
 	 *    one of the proposed suffixes.
 	 *     - option id:         "org.eclipse.jdt.core.codeComplete.fieldSuffixes"
-	 *     - possible values:   { "&lt;suffix&gt;[,&lt;suffix&gt;]*" } where &lt;suffix&gt; is a String without any wild-card 
+	 *     - possible values:   { "&lt;suffix&gt;[,&lt;suffix&gt;]*" } where &lt;suffix&gt; is a String without any wild-card
 	 *     - default:           ""
-	 * 
-	 *  CODEASSIST / Define the Suffixes for Static Field Name
+	 *
+	 * CODEASSIST / Define the Suffixes for Static Field Name
 	 *    When the suffixes is non empty, completion for static field name will end with
 	 *    one of the proposed suffixes.
 	 *     - option id:         "org.eclipse.jdt.core.codeComplete.staticFieldSuffixes"
-	 *     - possible values:   { "&lt;suffix&gt;[,&lt;suffix&gt;]*" } where &lt;suffix&gt; is a String without any wild-card 
+	 *     - possible values:   { "&lt;suffix&gt;[,&lt;suffix&gt;]*" } where &lt;suffix&gt; is a String without any wild-card
 	 *     - default:           ""
-	 * 
-	 *  CODEASSIST / Define the Suffixes for Local Variable Name
+	 *
+	 * CODEASSIST / Define the Suffixes for Local Variable Name
 	 *    When the suffixes is non empty, completion for local variable name will end with
 	 *    one of the proposed suffixes.
 	 *     - option id:         "org.eclipse.jdt.core.codeComplete.localSuffixes"
-	 *     - possible values:   { "&lt;suffix&gt;[,&lt;suffix&gt;]*" } where &lt;suffix&gt; is a String without any wild-card 
+	 *     - possible values:   { "&lt;suffix&gt;[,&lt;suffix&gt;]*" } where &lt;suffix&gt; is a String without any wild-card
 	 *     - default:           ""
-	 * 
-	 *  CODEASSIST / Define the Suffixes for Argument Name
+	 *
+	 * CODEASSIST / Define the Suffixes for Argument Name
 	 *    When the suffixes is non empty, completion for argument name will end with
 	 *    one of the proposed suffixes.
 	 *     - option id:         "org.eclipse.jdt.core.codeComplete.argumentSuffixes"
-	 *     - possible values:   { "&lt;suffix&gt;[,&lt;suffix&gt;]*" } where &lt;suffix&gt; is a String without any wild-card 
+	 *     - possible values:   { "&lt;suffix&gt;[,&lt;suffix&gt;]*" } where &lt;suffix&gt; is a String without any wild-card
 	 *     - default:           ""
-	 * 
-	 *  CODEASSIST / Activate Forbidden Reference Sensitive Completion
-	 *    When active, completion doesn't show that have forbidden reference.
+	 *
+	 * CODEASSIST / Activate Forbidden Reference Sensitive Completion
+	 *    When enabled, completion doesn't propose elements which match a
+  	 *    forbidden reference rule.
 	 *     - option id:         "org.eclipse.jdt.core.codeComplete.forbiddenReferenceCheck"
 	 *     - possible values:   { "enabled", "disabled" }
 	 *     - default:           "enabled"
-	 * 
-	 *  CODEASSIST / Activate Discouraged Reference Sensitive Completion
-	 *    When active, completion doesn't show that have discouraged reference.
+	 *
+	 * CODEASSIST / Activate Discouraged Reference Sensitive Completion
+	 *    When enabled, completion doesn't propose elements which match a
+  	 *    discouraged reference rule.
 	 *     - option id:         "org.eclipse.jdt.core.codeComplete.discouragedReferenceCheck"
 	 *     - possible values:   { "enabled", "disabled" }
 	 *     - default:           "disabled"
+	 *
+	 * CODEASSIST / Activate Camel Case Sensitive Completion
+	 *    When enabled, completion shows proposals whose name match the CamelCase
+	 *    pattern.
+	 *     - option id:         "org.eclipse.jdt.core.codeComplete.camelCaseMatch"
+	 *     - possible values:   { "enabled", "disabled" }
+	 *     - default:           "enabled"
+	 *
+	 * CODEASSIST / Activate Suggestion of Static Import
+	 *    When enabled, completion proposals can contain static import
+	 *    pattern.
+	 *     - option id:         "org.eclipse.jdt.core.codeComplete.suggestStaticImports"
+	 *     - possible values:   { "enabled", "disabled" }
+	 *     - default:           "enabled"
 	 * </pre>
-	 * 
-	 * @return a mutable table containing the default settings of all known options
-	 *   (key type: <code>String</code>; value type: <code>String</code>)
-	 * @see #setOptions(Hashtable)
 	 */
  	public static Hashtable getDefaultOptions(){
  		return JavaModelManager.getJavaModelManager().getDefaultOptions();
@@ -2339,7 +2754,7 @@
 
 	/**
 	 * Returns the workspace root default charset encoding.
-	 * 
+	 *
 	 * @return the name of the default charset encoding for workspace root.
 	 * @see IContainer#getDefaultCharset()
 	 * @see ResourcesPlugin#getEncoding()
@@ -2359,22 +2774,226 @@
 	}
 
 	/**
+	 * Returns an array that contains the resources generated by the Java builder when building the
+	 * compilation units contained in the given region.
+	 * <p>The contents of the array is accurate only if the elements of the given region have been built.</p>
+	 * <p>The given region can contain instances of:</p>
+	 * <ul>
+	 * <li><code>org.eclipse.jdt.core.ICompilationUnit</code></li>
+	 * <li><code>org.eclipse.jdt.core.IPackageFragment</code></li>
+	 * <li><code>org.eclipse.jdt.core.IPackageFragmentRoot</code></li>
+	 * <li><code>org.eclipse.jdt.core.IJavaProject</code></li>
+	 * </ul>
+	 * <p>All other types of <code>org.eclipse.jdt.core.IJavaElement</code> are ignored.</p>
+	 *
+	 * @param region the given region
+	 * @param includesNonJavaResources a flag that indicates if non-java resources should be included
+	 *
+	 * @return an array that contains the resources generated by the Java builder when building the
+	 * compilation units contained in the given region, an empty array if none
+	 * @exception IllegalArgumentException if the given region is <code>null</code>
+	 * @since 3.3
+	 */
+	public static IResource[] getGeneratedResources(IRegion region, boolean includesNonJavaResources) {
+		if (region == null) throw new IllegalArgumentException("region cannot be null"); //$NON-NLS-1$
+		IJavaElement[] elements = region.getElements();
+		HashMap projectsStates = new HashMap();
+		ArrayList collector = new ArrayList();
+		for (int i = 0, max = elements.length; i < max; i++) {
+			// collect all the java project
+			IJavaElement element = elements[i];
+			IJavaProject javaProject = element.getJavaProject();
+			IProject project = javaProject.getProject();
+			State state = null;
+			State currentState = (State) projectsStates.get(project);
+			if (currentState != null) {
+				state = currentState;
+			} else {
+				state = (State) JavaModelManager.getJavaModelManager().getLastBuiltState(project, null);
+				if (state != null) {
+					projectsStates.put(project, state);
+				}
+			}
+			if (state == null) continue;
+			if (element.getElementType() == IJavaElement.JAVA_PROJECT) {
+				IPackageFragmentRoot[] roots = null;
+				try {
+					roots = javaProject.getPackageFragmentRoots();
+				} catch (JavaModelException e) {
+					// ignore
+				}
+				if (roots == null) continue;
+				IRegion region2 = JavaCore.newRegion();
+				for (int j = 0; j < roots.length; j++) {
+					region2.add(roots[j]);
+				}
+				IResource[] res = getGeneratedResources(region2, includesNonJavaResources);
+				for (int j = 0, max2 = res.length; j < max2; j++) {
+					collector.add(res[j]);
+				}
+				continue;
+			}
+			IPath outputLocation = null;
+			try {
+				outputLocation = javaProject.getOutputLocation();
+			} catch (JavaModelException e) {
+				// ignore
+			}
+			IJavaElement root = element;
+			while (root != null && root.getElementType() != IJavaElement.PACKAGE_FRAGMENT_ROOT) {
+				root = root.getParent();
+			}
+			if (root == null) continue;
+			IPackageFragmentRoot packageFragmentRoot = (IPackageFragmentRoot) root;
+			int rootPathSegmentCounts = packageFragmentRoot.getPath().segmentCount();
+			try {
+				IClasspathEntry entry = packageFragmentRoot.getRawClasspathEntry();
+				IPath entryOutputLocation = entry.getOutputLocation();
+				if (entryOutputLocation != null) {
+					outputLocation = entryOutputLocation;
+				}
+			} catch (JavaModelException e) {
+				e.printStackTrace();
+			}
+			if (outputLocation == null) continue;
+			IContainer container = (IContainer) project.getWorkspace().getRoot().findMember(outputLocation);
+			switch(element.getElementType()) {
+				case IJavaElement.COMPILATION_UNIT :
+					// get the .class files generated when this element was built
+					ICompilationUnit unit = (ICompilationUnit) element;
+					getGeneratedResource(unit, container, state, rootPathSegmentCounts, collector);
+					break;
+				case IJavaElement.PACKAGE_FRAGMENT :
+					// collect all the .class files generated when all the units in this package were built
+					IPackageFragment fragment = (IPackageFragment) element;
+					ICompilationUnit[] compilationUnits = null;
+					try {
+						compilationUnits = fragment.getCompilationUnits();
+					} catch (JavaModelException e) {
+						// ignore
+					}
+					if (compilationUnits == null) continue;
+					for (int j = 0, max2 = compilationUnits.length; j < max2; j++) {
+						getGeneratedResource(compilationUnits[j], container, state, rootPathSegmentCounts, collector);
+					}
+					if (includesNonJavaResources) {
+						// retrieve all non-java resources from the output location using the package fragment path
+						Object[] nonJavaResources = null;
+						try {
+							nonJavaResources = fragment.getNonJavaResources();
+						} catch (JavaModelException e) {
+							// ignore
+						}
+						if (nonJavaResources != null) {
+							addNonJavaResources(nonJavaResources, container, rootPathSegmentCounts, collector);
+						}
+					}
+					break;
+				case IJavaElement.PACKAGE_FRAGMENT_ROOT :
+					// collect all the .class files generated when all the units in this package were built
+					IPackageFragmentRoot fragmentRoot = (IPackageFragmentRoot) element;
+					if (fragmentRoot.isArchive()) continue;
+					IJavaElement[] children = null;
+					try {
+						children = fragmentRoot.getChildren();
+					} catch (JavaModelException e) {
+						// ignore
+					}
+					if (children == null) continue;
+					for (int j = 0, max2 = children.length; j < max2; j++) {
+						fragment = (IPackageFragment) children[j];
+						ICompilationUnit[] units = null;
+						try {
+							units = fragment.getCompilationUnits();
+						} catch (JavaModelException e) {
+							// ignore
+						}
+						if (units == null) continue;
+						for (int n = 0, max3 = units.length; n < max3; n++) {
+							getGeneratedResource(units[n], container, state, rootPathSegmentCounts, collector);
+						}
+						if (includesNonJavaResources) {
+							// retrieve all non-java resources from the output location using the package fragment path
+							Object[] nonJavaResources = null;
+							try {
+								nonJavaResources = fragment.getNonJavaResources();
+							} catch (JavaModelException e) {
+								// ignore
+							}
+							if (nonJavaResources != null) {
+								addNonJavaResources(nonJavaResources, container, rootPathSegmentCounts, collector);
+							}
+						}
+					}
+					break;
+			}
+		}
+		int size = collector.size();
+		if (size != 0) {
+			IResource[] result = new IResource[size];
+			collector.toArray(result);
+			return result;
+		}
+		return NO_GENERATED_RESOURCES;
+	}
+
+	private static void getGeneratedResource(ICompilationUnit unit,
+			IContainer container,
+			State state,
+			int rootPathSegmentCounts,
+			ArrayList collector) {
+		IResource resource = unit.getResource();
+		char[][] typeNames = state.getDefinedTypeNamesFor(resource.getProjectRelativePath().toString());
+		if (typeNames != null) {
+			IPath path = unit.getPath().removeFirstSegments(rootPathSegmentCounts).removeLastSegments(1);
+			for (int j = 0, max2 = typeNames.length; j < max2; j++) {
+				IPath localPath = path.append(new String(typeNames[j]) + ".class"); //$NON-NLS-1$
+				IResource member = container.findMember(localPath);
+				if (member != null && member.exists()) {
+					collector.add(member);
+				}
+			}
+		} else {
+			IPath path = unit.getPath().removeFirstSegments(rootPathSegmentCounts).removeLastSegments(1);
+			path = path.append(Util.getNameWithoutJavaLikeExtension(unit.getElementName()) + ".class"); //$NON-NLS-1$
+			IResource member = container.findMember(path);
+			if (member != null && member.exists()) {
+				collector.add(member);
+			}
+		}
+	}
+
+	/**
 	 * Returns the single instance of the Java core plug-in runtime class.
 	 * Equivalent to <code>(JavaCore) getPlugin()</code>.
-	 * 
+	 *
 	 * @return the single instance of the Java core plug-in runtime class
 	 */
 	public static JavaCore getJavaCore() {
 		return (JavaCore) getPlugin();
 	}
-	
+
+	/**
+	 * Returns the list of known Java-like extensions.
+	 * Java like extension are defined in the {@link org.eclipse.core.runtime.Platform#getContentTypeManager()
+	 * content type manager} for the {@link #JAVA_SOURCE_CONTENT_TYPE}.
+	 * Note that a Java-like extension doesn't include the leading dot ('.').
+	 * Also note that the "java" extension is always defined as a Java-like extension.
+	 *
+	 * @return the list of known Java-like extensions.
+	 * @since 3.2
+	 */
+	public static String[] getJavaLikeExtensions() {
+		return CharOperation.toStrings(Util.getJavaLikeExtensions());
+	}
+
 	/**
 	 * Helper method for returning one option value only. Equivalent to <code>(String)JavaCore.getOptions().get(optionName)</code>
 	 * Note that it may answer <code>null</code> if this option does not exist.
 	 * <p>
 	 * For a complete description of the configurable options, see <code>getDefaultOptions</code>.
 	 * </p>
-	 * 
+	 *
 	 * @param optionName the name of an option
 	 * @return the String value of a given option
 	 * @see JavaCore#getDefaultOptions()
@@ -2384,15 +3003,14 @@
 	public static String getOption(String optionName) {
 		return JavaModelManager.getJavaModelManager().getOption(optionName);
 	}
-	
+
 	/**
 	 * Returns the table of the current options. Initially, all options have their default values,
 	 * and this method returns a table that includes all known options.
-	 * <p>
-	 * For a complete description of the configurable options, see <code>getDefaultOptions</code>.
-	 * </p>
-	 * 
-	 * @return table of current settings of all options 
+	 * <p>For a complete description of the configurable options, see <code>getDefaultOptions</code>.</p>
+	 * <p>Returns a default set of options even if the platform is not running.</p>
+	 *
+	 * @return table of current settings of all options
 	 *   (key type: <code>String</code>; value type: <code>String</code>)
 	 * @see #getDefaultOptions()
 	 * @see JavaCorePreferenceInitializer for changing default settings
@@ -2403,7 +3021,7 @@
 
 	/**
 	 * Returns the single instance of the Java core plug-in runtime class.
-	 * 
+	 *
 	 * @return the single instance of the Java core plug-in runtime class
 	 */
 	public static Plugin getPlugin() {
@@ -2411,9 +3029,9 @@
 	}
 
 	/**
-	 * This is a helper method, which returns the resolved classpath entry denoted 
-	 * by a given entry (if it is a variable entry). It is obtained by resolving the variable 
-	 * reference in the first segment. Returns <node>null</code> if unable to resolve using 
+	 * This is a helper method, which returns the resolved classpath entry denoted
+	 * by a given entry (if it is a variable entry). It is obtained by resolving the variable
+	 * reference in the first segment. Returns <code>null</code> if unable to resolve using
 	 * the following algorithm:
 	 * <ul>
 	 * <li> if variable segment cannot be resolved, returns <code>null</code></li>
@@ -2427,62 +3045,60 @@
 	 * NOTE: This helper method does not handle classpath containers, for which should rather be used
 	 * <code>JavaCore#getClasspathContainer(IPath, IJavaProject)</code>.
 	 * <p>
-	 * 
+	 *
 	 * @param entry the given variable entry
 	 * @return the resolved library or project classpath entry, or <code>null</code>
 	 *   if the given variable entry could not be resolved to a valid classpath entry
 	 */
 	public static IClasspathEntry getResolvedClasspathEntry(IClasspathEntry entry) {
-	
+
 		if (entry.getEntryKind() != IClasspathEntry.CPE_VARIABLE)
 			return entry;
-	
+
 		IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
 		IPath resolvedPath = JavaCore.getResolvedVariablePath(entry.getPath());
 		if (resolvedPath == null)
 			return null;
-	
+
 		Object target = JavaModel.getTarget(workspaceRoot, resolvedPath, false);
 		if (target == null)
 			return null;
-	
+
 		// inside the workspace
 		if (target instanceof IResource) {
 			IResource resolvedResource = (IResource) target;
-			if (resolvedResource != null) {
-				switch (resolvedResource.getType()) {
-					
-					case IResource.PROJECT :  
-						// internal project
-						return JavaCore.newProjectEntry(
-								resolvedPath, 
-								entry.getAccessRules(),
-								entry.combineAccessRules(), 
-								entry.getExtraAttributes(), 
-								entry.isExported());
-					case IResource.FILE : 
-						if (org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(resolvedResource.getName())) {
-							// internal binary archive
-							return JavaCore.newLibraryEntry(
-									resolvedPath,
-									getResolvedVariablePath(entry.getSourceAttachmentPath()),
-									getResolvedVariablePath(entry.getSourceAttachmentRootPath()),
-									entry.getAccessRules(), 
-									entry.getExtraAttributes(), 
-									entry.isExported());
-						}
-						break;
-						
-					case IResource.FOLDER : 
-						// internal binary folder
+			switch (resolvedResource.getType()) {
+
+				case IResource.PROJECT :
+					// internal project
+					return JavaCore.newProjectEntry(
+							resolvedPath,
+							entry.getAccessRules(),
+							entry.combineAccessRules(),
+							entry.getExtraAttributes(),
+							entry.isExported());
+				case IResource.FILE :
+					if (org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(resolvedResource.getName())) {
+						// internal binary archive
 						return JavaCore.newLibraryEntry(
 								resolvedPath,
 								getResolvedVariablePath(entry.getSourceAttachmentPath()),
 								getResolvedVariablePath(entry.getSourceAttachmentRootPath()),
-								entry.getAccessRules(), 
-								entry.getExtraAttributes(), 
+								entry.getAccessRules(),
+								entry.getExtraAttributes(),
 								entry.isExported());
-				}
+					}
+					break;
+
+				case IResource.FOLDER :
+					// internal binary folder
+					return JavaCore.newLibraryEntry(
+							resolvedPath,
+							getResolvedVariablePath(entry.getSourceAttachmentPath()),
+							getResolvedVariablePath(entry.getSourceAttachmentRootPath()),
+							entry.getAccessRules(),
+							entry.getExtraAttributes(),
+							entry.isExported());
 			}
 		}
 		// outside the workspace
@@ -2490,7 +3106,7 @@
 			File externalFile = JavaModel.getFile(target);
 			if (externalFile != null) {
 				String fileName = externalFile.getName().toLowerCase();
-				if (fileName.endsWith(SuffixConstants.SUFFIX_STRING_jar) || fileName.endsWith(SuffixConstants.SUFFIX_STRING_zip)) { 
+				if (fileName.endsWith(SuffixConstants.SUFFIX_STRING_jar) || fileName.endsWith(SuffixConstants.SUFFIX_STRING_zip)) {
 					// external binary archive
 					return JavaCore.newLibraryEntry(
 							resolvedPath,
@@ -2518,211 +3134,275 @@
 
 	/**
 	 * Resolve a variable path (helper method).
-	 * 
+	 *
 	 * @param variablePath the given variable path
 	 * @return the resolved variable path or <code>null</code> if none
 	 */
 	public static IPath getResolvedVariablePath(IPath variablePath) {
-	
+
 		if (variablePath == null)
 			return null;
 		int count = variablePath.segmentCount();
 		if (count == 0)
 			return null;
-	
-		// lookup variable	
+
+		// lookup variable
 		String variableName = variablePath.segment(0);
 		IPath resolvedPath = JavaCore.getClasspathVariable(variableName);
 		if (resolvedPath == null)
 			return null;
-	
+
 		// append path suffix
 		if (count > 1) {
 			resolvedPath = resolvedPath.append(variablePath.removeFirstSegments(1));
 		}
-		return resolvedPath; 
+		return resolvedPath;
 	}
 
 	/**
-	 * Answers the shared working copies currently registered for this buffer factory. 
-	 * Working copies can be shared by several clients using the same buffer factory,see 
+	 * Answers the shared working copies currently registered for this buffer factory.
+	 * Working copies can be shared by several clients using the same buffer factory,see
 	 * <code>IWorkingCopy.getSharedWorkingCopy</code>.
-	 * 
+	 *
 	 * @param factory the given buffer factory
 	 * @return the list of shared working copies for a given buffer factory
-	 * @see IWorkingCopy
 	 * @since 2.0
-	 * @deprecated - should use #getWorkingCopies(WorkingCopyOwner) instead
+	 * @deprecated Use {@link #getWorkingCopies(WorkingCopyOwner)} instead
 	 */
 	public static IWorkingCopy[] getSharedWorkingCopies(IBufferFactory factory){
-		
+
 		// if factory is null, default factory must be used
 		if (factory == null) factory = BufferManager.getDefaultBufferManager().getDefaultBufferFactory();
 
 		return getWorkingCopies(BufferFactoryWrapper.create(factory));
 	}
-	
+
 	/**
 	 * Returns the names of all defined user libraries. The corresponding classpath container path
-	 * is the name appended to the USER_LIBRARY_CONTAINER_ID.  
+	 * is the name appended to the USER_LIBRARY_CONTAINER_ID.
 	 * @return Return an array containing the names of all known user defined.
 	 * @since 3.0
 	 */
 	public static String[] getUserLibraryNames() {
-		 return UserLibraryManager.getUserLibraryNames();
+		 return JavaModelManager.getUserLibraryManager().getUserLibraryNames();
 	}
 
 	/**
-	 * Returns the working copies that have the given owner. 
+	 * Returns the working copies that have the given owner.
 	 * Only compilation units in working copy mode are returned.
 	 * If the owner is <code>null</code>, primary working copies are returned.
-	 * 
-	 * @param owner the given working copy owner or <null> for primary working copy owner
+	 *
+	 * @param owner the given working copy owner or <code>null</code> for primary working copy owner
 	 * @return the list of working copies for a given owner
 	 * @since 3.0
 	 */
 	public static ICompilationUnit[] getWorkingCopies(WorkingCopyOwner owner){
-		
+
 		JavaModelManager manager = JavaModelManager.getJavaModelManager();
 		if (owner == null) owner = DefaultWorkingCopyOwner.PRIMARY;
 		ICompilationUnit[] result = manager.getWorkingCopies(owner, false/*don't add primary WCs*/);
 		if (result == null) return JavaModelManager.NO_WORKING_COPY;
 		return result;
 	}
-	
+
 	/**
-	 * Initializes JavaCore internal structures to allow subsequent operations (such 
-	 * as the ones that need a resolved classpath) to run full speed. A client may 
-	 * choose to call this method in a background thread early after the workspace 
+	 * Initializes JavaCore internal structures to allow subsequent operations (such
+	 * as the ones that need a resolved classpath) to run full speed. A client may
+	 * choose to call this method in a background thread early after the workspace
 	 * has started so that the initialization is transparent to the user.
 	 * <p>
-	 * However calling this method is optional. Services will lazily perform 
-	 * initialization when invoked. This is only a way to reduce initialization 
-	 * overhead on user actions, if it can be performed before at some 
+	 * However calling this method is optional. Services will lazily perform
+	 * initialization when invoked. This is only a way to reduce initialization
+	 * overhead on user actions, if it can be performed before at some
 	 * appropriate moment.
 	 * </p><p>
 	 * This initialization runs accross all Java projects in the workspace. Thus the
 	 * workspace root scheduling rule is used during this operation.
 	 * </p><p>
-	 * This method may return before the initialization is complete. The 
+	 * This method may return before the initialization is complete. The
 	 * initialization will then continue in a background thread.
 	 * </p><p>
 	 * This method can be called concurrently.
 	 * </p>
-	 * 
+	 *
 	 * @param monitor a progress monitor, or <code>null</code> if progress
 	 *    reporting and cancellation are not desired
-	 * @exception CoreException if the initialization fails, 
+	 * @exception CoreException if the initialization fails,
 	 * 		the status of the exception indicates the reason of the failure
 	 * @since 3.1
 	 */
 	public static void initializeAfterLoad(IProgressMonitor monitor) throws CoreException {
-		Job job = new Job(Messages.javamodel_initialization) {
-			protected IStatus run(IProgressMonitor progressMonitor) {
-				// dummy query for waiting until the indexes are ready and classpath containers/variables are initialized
-				SearchEngine engine = new SearchEngine();
-				IJavaSearchScope scope = SearchEngine.createWorkspaceScope(); // initialize all containers and variables
-				try {
-					engine.searchAllTypeNames(
-						null,
-						"!@$#!@".toCharArray(), //$NON-NLS-1$
-						SearchPattern.R_PATTERN_MATCH | SearchPattern.R_CASE_SENSITIVE,
-						IJavaSearchConstants.CLASS,
-						scope, 
-						new TypeNameRequestor() {
-							public void acceptType(
-								int modifiers,
-								char[] packageName,
-								char[] simpleTypeName,
-								char[][] enclosingTypeNames,
-								String path) {
-								// no type to accept
-							}
-						},
-						// will not activate index query caches if indexes are not ready, since it would take to long
-						// to wait until indexes are fully rebuild
-						IJavaSearchConstants.CANCEL_IF_NOT_READY_TO_SEARCH,
-						progressMonitor == null ? null : new SubProgressMonitor(progressMonitor, 99) // 99% of the time is spent in the dummy search
-					); 
-				} catch (JavaModelException e) {
-					// /search failed: ignore
-				} catch (OperationCanceledException e) {
-					if (progressMonitor != null && progressMonitor.isCanceled())
-						throw e;
-					// else indexes were not ready: catch the exception so that jars are still refreshed
+		try {
+			if (monitor != null) 	monitor.beginTask(Messages.javamodel_initialization, 100);
+
+			// initialize all containers and variables
+			JavaModelManager manager = JavaModelManager.getJavaModelManager();
+			try {
+				if (monitor != null) {
+					monitor.subTask(Messages.javamodel_configuring_classpath_containers);
+					manager.batchContainerInitializationsProgress.set(new SubProgressMonitor(monitor, 50)); // 50% of the time is spent in initializing containers and variables
 				}
 				
-				// check if the build state version number has changed since last session
-				// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=98969)
-				QualifiedName qName = new QualifiedName(JavaCore.PLUGIN_ID, "stateVersionNumber"); //$NON-NLS-1$
-				IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
-				String versionNumber = null;
-				try {
-					versionNumber = root.getPersistentProperty(qName);
-				} catch (CoreException e) {
-					// could not read version number: consider it is new
+				// all classpaths in the workspace are going to be resolved, ensure that containers are initialized in one batch
+				manager.batchContainerInitializations = true; 
+				
+				// avoid leaking source attachment properties (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=183413)
+				IJavaProject[] projects = manager.getJavaModel().getJavaProjects();
+				for (int i = 0, length = projects.length; i < length; i++) {
+					IClasspathEntry[] classpath;
+					try {
+						classpath = ((JavaProject) projects[i]).getResolvedClasspath();
+					} catch (JavaModelException e) {
+						// project no longer exist: ignore
+						continue;
+					}
+					if (classpath != null) {
+						for (int j = 0, length2 = classpath.length; j < length2; j++) {
+							IClasspathEntry entry = classpath[j];
+							if (entry.getSourceAttachmentPath() != null)
+								Util.setSourceAttachmentProperty(entry.getPath(), null);
+							// else source might have been attached by IPackageFragmentRoot#attachSource(...), we keep it
+						}
+					}
 				}
-				final JavaModel model = JavaModelManager.getJavaModelManager().getJavaModel();
-				String newVersionNumber = Byte.toString(State.VERSION);
-				if (!newVersionNumber.equals(versionNumber)) {
-					// build state version number has changed: touch every projects to force a rebuild
-					if (JavaBuilder.DEBUG)
-						System.out.println("Build state version number has changed"); //$NON-NLS-1$
-					IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
-						public void run(IProgressMonitor progressMonitor2) throws CoreException {
-							IJavaProject[] projects = null;
-							try {
-								projects = model.getJavaProjects();
-							} catch (JavaModelException e) {
-								// could not get Java projects: ignore
-							}
-							if (projects != null) {
-								for (int i = 0, length = projects.length; i < length; i++) {
-									IJavaProject project = projects[i];
-									try {
-										if (JavaBuilder.DEBUG)
-											System.out.println("Touching " + project.getElementName()); //$NON-NLS-1$
-										project.getProject().touch(progressMonitor2);
-									} catch (CoreException e) {
-										// could not touch this project: ignore
-									}
+				
+				// initialize delta state
+				manager.deltaState.rootsAreStale = true; // in case it was already initialized before we cleaned up the source attachment proprties
+				manager.deltaState.initializeRoots();
+			} finally {
+				manager.batchContainerInitializationsProgress.set(null);
+			}
+
+			// dummy query for waiting until the indexes are ready
+			SearchEngine engine = new SearchEngine();
+			IJavaSearchScope scope = SearchEngine.createWorkspaceScope();
+			try {
+				if (monitor != null)
+					monitor.subTask(Messages.javamodel_configuring_searchengine);
+				engine.searchAllTypeNames(
+					null,
+					SearchPattern.R_EXACT_MATCH,
+					"!@$#!@".toCharArray(), //$NON-NLS-1$
+					SearchPattern.R_PATTERN_MATCH | SearchPattern.R_CASE_SENSITIVE,
+					IJavaSearchConstants.CLASS,
+					scope,
+					new TypeNameRequestor() {
+						public void acceptType(
+							int modifiers,
+							char[] packageName,
+							char[] simpleTypeName,
+							char[][] enclosingTypeNames,
+							String path) {
+							// no type to accept
+						}
+					},
+					// will not activate index query caches if indexes are not ready, since it would take to long
+					// to wait until indexes are fully rebuild
+					IJavaSearchConstants.CANCEL_IF_NOT_READY_TO_SEARCH,
+					monitor == null ? null : new SubProgressMonitor(monitor, 49) // 49% of the time is spent in the dummy search
+				);
+			} catch (JavaModelException e) {
+				// /search failed: ignore
+			} catch (OperationCanceledException e) {
+				if (monitor != null && monitor.isCanceled())
+					throw e;
+				// else indexes were not ready: catch the exception so that jars are still refreshed
+			}
+
+			// check if the build state version number has changed since last session
+			// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=98969)
+			if (monitor != null)
+				monitor.subTask(Messages.javamodel_getting_build_state_number);
+			QualifiedName qName = new QualifiedName(JavaCore.PLUGIN_ID, "stateVersionNumber"); //$NON-NLS-1$
+			IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+			String versionNumber = null;
+			try {
+				versionNumber = root.getPersistentProperty(qName);
+			} catch (CoreException e) {
+				// could not read version number: consider it is new
+			}
+			final JavaModel model = manager.getJavaModel();
+			String newVersionNumber = Byte.toString(State.VERSION);
+			if (!newVersionNumber.equals(versionNumber)) {
+				// build state version number has changed: touch every projects to force a rebuild
+				if (JavaBuilder.DEBUG)
+					System.out.println("Build state version number has changed"); //$NON-NLS-1$
+				IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
+					public void run(IProgressMonitor progressMonitor2) throws CoreException {
+						IJavaProject[] projects = null;
+						try {
+							projects = model.getJavaProjects();
+						} catch (JavaModelException e) {
+							// could not get Java projects: ignore
+						}
+						if (projects != null) {
+							for (int i = 0, length = projects.length; i < length; i++) {
+								IJavaProject project = projects[i];
+								try {
+									if (JavaBuilder.DEBUG)
+										System.out.println("Touching " + project.getElementName()); //$NON-NLS-1$
+									project.getProject().touch(progressMonitor2);
+								} catch (CoreException e) {
+									// could not touch this project: ignore
 								}
 							}
 						}
-					};
-					try {
-						ResourcesPlugin.getWorkspace().run(runnable, progressMonitor);
-					} catch (CoreException e) {
-						// could not touch all projects
 					}
-					try {
-						root.setPersistentProperty(qName, newVersionNumber);
-					} catch (CoreException e) {
-						Util.log(e, "Could not persist build state version number"); //$NON-NLS-1$
-					}
-				}
-				
-				// ensure external jars are refreshed (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=93668)
+				};
+				if (monitor != null)
+					monitor.subTask(Messages.javamodel_building_after_upgrade);
 				try {
-					model.refreshExternalArchives(
-						null/*refresh all projects*/, 
-						progressMonitor == null ? null : new SubProgressMonitor(progressMonitor, 1) // 1% of the time is spent in jar refresh
-					);
-				} catch (JavaModelException e) {
-					// refreshing failed: ignore
+					ResourcesPlugin.getWorkspace().run(runnable, monitor);
+				} catch (CoreException e) {
+					// could not touch all projects
 				}
-				
-				return Status.OK_STATUS;
+				try {
+					root.setPersistentProperty(qName, newVersionNumber);
+				} catch (CoreException e) {
+					Util.log(e, "Could not persist build state version number"); //$NON-NLS-1$
+				}
 			}
-			public boolean belongsTo(Object family) {
-				return PLUGIN_ID.equals(family);
+
+			// ensure external jars are refreshed (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=93668)
+			try {
+				if (monitor != null)
+					monitor.subTask(Messages.javamodel_refreshing_external_jars);
+				model.refreshExternalArchives(
+					null/*refresh all projects*/,
+					monitor == null ? null : new SubProgressMonitor(monitor, 1) // 1% of the time is spent in jar refresh
+				);
+			} catch (JavaModelException e) {
+				// refreshing failed: ignore
 			}
-		};
-		job.setPriority(Job.SHORT);
-		job.schedule(2000);	 // wait for the startup activity to calm down
-		
+			
+		} finally {
+			if (monitor != null) monitor.done();
+		}
 	}
-	
+
+	/**
+	 * Returns whether a given classpath variable is read-only or not.
+	 *
+	 * @param variableName
+	 * @return <code>true</code> if the classpath variable is read-only,
+	 * 	<code>false</code> otherwise.
+	 * @since 3.3
+	 */
+	public static boolean isClasspathVariableReadOnly(String variableName) {
+	    return JavaModelManager.getJavaModelManager().readOnlyVariables.contains(variableName);
+	}
+
+	/**
+	 * Returns whether the given file name's extension is a Java-like extension.
+	 *
+	 * @return whether the given file name's extension is a Java-like extension
+	 * @see #getJavaLikeExtensions()
+	 * @since 3.2
+	 */
+	public static boolean isJavaLikeFileName(String fileName) {
+		return Util.isJavaLikeFileName(fileName);
+	}
+
 	/**
 	 * Returns whether the given marker references the given Java element.
 	 * Used for markers, which denote a Java element rather than a resource.
@@ -2730,10 +3410,10 @@
 	 * @param element the element
 	 * @param marker the marker
 	 * @return <code>true</code> if the marker references the element, false otherwise
-	 * @exception CoreException if the <code>IMarker.getAttribute</code> on the marker fails 	 
+	 * @exception CoreException if the <code>IMarker.getAttribute</code> on the marker fails
 	 */
 	public static boolean isReferencedBy(IJavaElement element, IMarker marker) throws CoreException {
-		
+
 		// only match units or classfiles
 		if (element instanceof IMember){
 			IMember member = (IMember) element;
@@ -2743,16 +3423,16 @@
 				element = member.getCompilationUnit();
 			}
 		}
-		if (element == null) return false;			
+		if (element == null) return false;
 		if (marker == null) return false;
 
 		String markerHandleId = (String)marker.getAttribute(ATT_HANDLE_ID);
 		if (markerHandleId == null) return false;
-		
+
 		IJavaElement markerElement = JavaCore.create(markerHandleId);
 		while (true){
 			if (element.equals(markerElement)) return true; // external elements may still be equal with different handleIDs.
-			
+
 			// cycle through enclosing types in case marker is associated with a classfile (15568)
 			if (markerElement instanceof IClassFile){
 				IType enclosingType = ((IClassFile)markerElement).getType().getDeclaringType();
@@ -2773,10 +3453,10 @@
 	 * @param element the element
 	 * @param markerDelta the marker delta
 	 * @return <code>true</code> if the marker delta references the element
-	 * @exception CoreException if the  <code>IMarkerDelta.getAttribute</code> on the marker delta fails 	 
+	 * @exception CoreException if the  <code>IMarkerDelta.getAttribute</code> on the marker delta fails
 	 */
 	public static boolean isReferencedBy(IJavaElement element, IMarkerDelta markerDelta) throws CoreException {
-		
+
 		// only match units or classfiles
 		if (element instanceof IMember){
 			IMember member = (IMember) element;
@@ -2786,16 +3466,16 @@
 				element = member.getCompilationUnit();
 			}
 		}
-		if (element == null) return false;			
+		if (element == null) return false;
 		if (markerDelta == null) return false;
 
 		String markerDeltarHandleId = (String)markerDelta.getAttribute(ATT_HANDLE_ID);
 		if (markerDeltarHandleId == null) return false;
-		
+
 		IJavaElement markerElement = JavaCore.create(markerDeltarHandleId);
 		while (true){
 			if (element.equals(markerElement)) return true; // external elements may still be equal with different handleIDs.
-			
+
 			// cycle through enclosing types in case marker is associated with a classfile (15568)
 			if (markerElement instanceof IClassFile){
 				IType enclosingType = ((IClassFile)markerElement).getType().getDeclaringType();
@@ -2808,22 +3488,29 @@
 		}
 		return false;
 	}
-	
+
 	/**
 	 * Creates and returns a new access rule with the given file pattern and kind.
-	 * 
+	 * <p>
+	 * The rule kind is one of {@link IAccessRule#K_ACCESSIBLE}, {@link IAccessRule#K_DISCOURAGED},
+	 * or {@link IAccessRule#K_NON_ACCESSIBLE}, optionally combined with {@link IAccessRule#IGNORE_IF_BETTER},
+	 * e..g. <code>IAccessRule.K_NON_ACCESSIBLE | IAccessRule.IGNORE_IF_BETTER</code>.
+	 * </p>
+	 *
 	 * @param filePattern the file pattern this access rule should match
-	 * @param kind one of IAccessRule#K_ACCESSIBLE, IAcccessRule#K_STRICTLY_NON_ACCESSIBLE, or IAcccessRule#K_LOOSELY_NON_ACCESSIBLE
+	 * @param kind one of {@link IAccessRule#K_ACCESSIBLE}, {@link IAccessRule#K_DISCOURAGED},
+	 *                     or {@link IAccessRule#K_NON_ACCESSIBLE}, optionally combined with
+	 *                     {@link IAccessRule#IGNORE_IF_BETTER}
 	 * @return a new access rule
 	 * @since 3.1
 	 */
 	public static IAccessRule newAccessRule(IPath filePattern, int kind) {
 		return new ClasspathAccessRule(filePattern, kind);
 	}
-	
+
 	/**
 	 * Creates and returns a new classpath attribute with the given name and the given value.
-	 * 
+	 *
 	 * @return a new classpath attribute
 	 * @since 3.1
 	 */
@@ -2840,7 +3527,7 @@
 	 * @param containerPath the path identifying the container, it must be formed of two
 	 * 	segments
 	 * @return a new container classpath entry
-	 * 
+	 *
 	 * @see JavaCore#getClasspathContainer(IPath, IJavaProject)
 	 * @since 2.0
 	 */
@@ -2856,14 +3543,14 @@
 	 * Creates and returns a new classpath entry of kind <code>CPE_CONTAINER</code>
 	 * for the given path. This method is fully equivalent to calling
 	 * {@link #newContainerEntry(IPath, IAccessRule[], IClasspathAttribute[], boolean)
-	 * newContainerEntry(containerPath, new IAccessRule[0], new IClasspathAttribute[0], isExported)}. 
-	 * 
+	 * newContainerEntry(containerPath, new IAccessRule[0], new IClasspathAttribute[0], isExported)}.
+	 *
 	 * @param containerPath the path identifying the container, it must be formed of at least
 	 * 	one segment (ID+hints)
 	 * @param isExported a boolean indicating whether this entry is contributed to dependent
 	 *    projects in addition to the output location
 	 * @return a new container classpath entry
-	 * 
+	 *
 	 * @see JavaCore#getClasspathContainer(IPath, IJavaProject)
 	 * @see JavaCore#setClasspathContainer(IPath, IJavaProject[], IClasspathContainer[], IProgressMonitor)
 	 * @since 2.0
@@ -2899,12 +3586,12 @@
 	 * Example of an ClasspathContainerInitializer for a classpath container denoting a default JDK container:
 	 * <pre>
 	 * containerEntry = JavaCore.newContainerEntry(new Path("MyProvidedJDK/default"));
-	 * 
+	 *
 	 * &lt;extension
 	 *    point="org.eclipse.jdt.core.classpathContainerInitializer"&gt;
 	 *    &lt;containerInitializer
 	 *       id="MyProvidedJDK"
-	 *       class="com.example.MyInitializer"/&gt; 
+	 *       class="com.example.MyInitializer"/&gt;
 	 * </pre>
 	 * <p>
 	 * The access rules determine the set of accessible source and class files
@@ -2913,7 +3600,7 @@
 	 * See {@link IAccessRule} for a detailed description of access
 	 * rules. Note that if an entry defined by the container defines access rules,
 	 * then these access rules are combined with the given access rules.
-	 * The given access rules are considered first, then the entry's access rules are 
+	 * The given access rules are considered first, then the entry's access rules are
 	 * considered.
 	 * </p>
 	 * <p>
@@ -2926,13 +3613,13 @@
 	 * projects. If not exported, dependent projects will not see any of the classes from this entry.
 	 * If exported, dependent projects will concatenate the accessible files patterns of this entry with the
 	 * accessible files patterns of the projects, and they will concatenate the non accessible files patterns of this entry
-	 * with the non accessible files patterns of the project. 
+	 * with the non accessible files patterns of the project.
 	 * </p>
 	 * <p>
 	 * Note that this operation does not attempt to validate classpath containers
 	 * or access the resources at the given paths.
 	 * </p>
-	 * 
+	 *
 	 * @param containerPath the path identifying the container, it must be formed of at least
 	 * 	one segment (ID+hints)
 	 * @param accessRules the possibly empty list of access rules for this entry
@@ -2940,21 +3627,22 @@
 	 * @param isExported a boolean indicating whether this entry is contributed to dependent
 	 *    projects in addition to the output location
 	 * @return a new container classpath entry
-	 * 
+	 *
 	 * @see JavaCore#getClasspathContainer(IPath, IJavaProject)
 	 * @see JavaCore#setClasspathContainer(IPath, IJavaProject[], IClasspathContainer[], IProgressMonitor)
 	 * @see JavaCore#newContainerEntry(IPath, boolean)
 	 * @see JavaCore#newAccessRule(IPath, int)
 	 * @since 3.1
-	 */	
+	 */
 	public static IClasspathEntry newContainerEntry(
-			IPath containerPath, 
-			IAccessRule[] accessRules, 
+			IPath containerPath,
+			IAccessRule[] accessRules,
 			IClasspathAttribute[] extraAttributes,
 			boolean isExported) {
-			
-		if (containerPath == null) Assert.isTrue(false, "Container path cannot be null"); //$NON-NLS-1$
-		if (containerPath.segmentCount() < 1) {
+
+		if (containerPath == null) {
+			Assert.isTrue(false, "Container path cannot be null"); //$NON-NLS-1$
+		} else if (containerPath.segmentCount() < 1) {
 			Assert.isTrue(
 				false,
 				"Illegal classpath container path: \'" + containerPath.makeRelative().toString() + "\', must have at least one segment (containerID+hints)"); //$NON-NLS-1$//$NON-NLS-2$
@@ -2972,13 +3660,13 @@
 			accessRules,
 			true, // combine access rules
 			extraAttributes);
-	}	
-	
+	}
+
 	/**
 	 * Creates and returns a type hierarchy for all types in the given
-	 * region, considering subtypes within that region and considering types in the 
-	 * working copies with the given owner. 
-	 * In other words, the owner's working copies will take 
+	 * region, considering subtypes within that region and considering types in the
+	 * working copies with the given owner.
+	 * In other words, the owner's working copies will take
 	 * precedence over their original compilation units in the workspace.
 	 * <p>
 	 * Note that if a working copy is empty, it will be as if the original compilation
@@ -3006,20 +3694,20 @@
 		op.runOperation(monitor);
 		return op.getResult();
 	}
-	
+
 	/**
-	 * Creates and returns a new non-exported classpath entry of kind <code>CPE_LIBRARY</code> for the 
-	 * JAR or folder identified by the given absolute path. This specifies that all package fragments 
+	 * Creates and returns a new non-exported classpath entry of kind <code>CPE_LIBRARY</code> for the
+	 * JAR or folder identified by the given absolute path. This specifies that all package fragments
 	 * within the root will have children of type <code>IClassFile</code>.
 	 * This method is fully equivalent to calling
 	 * {@link #newLibraryEntry(IPath, IPath, IPath, IAccessRule[], IClasspathAttribute[], boolean)
 	 * newLibraryEntry(path, sourceAttachmentPath, sourceAttachmentRootPath, new IAccessRule[0], new IClasspathAttribute[0], false)}.
 	 *
 	 * @param path the absolute path of the binary archive
-	 * @param sourceAttachmentPath the absolute path of the corresponding source archive or folder, 
+	 * @param sourceAttachmentPath the absolute path of the corresponding source archive or folder,
 	 *    or <code>null</code> if none. Note, since 3.0, an empty path is allowed to denote no source attachment.
 	 *   and will be automatically converted to <code>null</code>.
-	 * @param sourceAttachmentRootPath the location of the root within the source archive or folder
+	 * @param sourceAttachmentRootPath the location of the root of the source files within the source archive or folder
 	 *    or <code>null</code> if this location should be automatically detected.
 	 * @return a new library classpath entry
 	 */
@@ -3027,9 +3715,9 @@
 		IPath path,
 		IPath sourceAttachmentPath,
 		IPath sourceAttachmentRootPath) {
-			
+
 		return newLibraryEntry(
-			path, 
+			path,
 			sourceAttachmentPath,
 			sourceAttachmentRootPath,
 			ClasspathEntry.NO_ACCESS_RULES,
@@ -3039,17 +3727,17 @@
 
 	/**
 	 * Creates and returns a new classpath entry of kind <code>CPE_LIBRARY</code> for the JAR or folder
-	 * identified by the given absolute path. This specifies that all package fragments within the root 
+	 * identified by the given absolute path. This specifies that all package fragments within the root
 	 * will have children of type <code>IClassFile</code>.
 	 * This method is fully equivalent to calling
 	 * {@link #newLibraryEntry(IPath, IPath, IPath, IAccessRule[], IClasspathAttribute[], boolean)
 	 * newLibraryEntry(path, sourceAttachmentPath, sourceAttachmentRootPath, new IAccessRule[0], new IClasspathAttribute[0], isExported)}.
-	 * 
+	 *
 	 * @param path the absolute path of the binary archive
-	 * @param sourceAttachmentPath the absolute path of the corresponding source archive or folder, 
+	 * @param sourceAttachmentPath the absolute path of the corresponding source archive or folder,
 	 *    or <code>null</code> if none. Note, since 3.0, an empty path is allowed to denote no source attachment.
 	 *   and will be automatically converted to <code>null</code>.
-	 * @param sourceAttachmentRootPath the location of the root within the source archive or folder
+	 * @param sourceAttachmentRootPath the location of the root of the source files within the source archive or folder
 	 *    or <code>null</code> if this location should be automatically detected.
 	 * @param isExported indicates whether this entry is contributed to dependent
 	 * 	  projects in addition to the output location
@@ -3061,9 +3749,9 @@
 		IPath sourceAttachmentPath,
 		IPath sourceAttachmentRootPath,
 		boolean isExported) {
-			
+
 		return newLibraryEntry(
-			path, 
+			path,
 			sourceAttachmentPath,
 			sourceAttachmentRootPath,
 			ClasspathEntry.NO_ACCESS_RULES,
@@ -3073,7 +3761,7 @@
 
 	/**
 	 * Creates and returns a new classpath entry of kind <code>CPE_LIBRARY</code> for the JAR or folder
-	 * identified by the given absolute path. This specifies that all package fragments within the root 
+	 * identified by the given absolute path. This specifies that all package fragments within the root
 	 * will have children of type <code>IClassFile</code>.
 	 * <p>
 	 * A library entry is used to denote a prerequisite JAR or root folder containing binaries.
@@ -3084,13 +3772,19 @@
 	 * linked (see IFolder#createLink(...)).
 	 * <p>
 	 * e.g. Here are some examples of binary path usage<ul>
-	 *	<li><code> "c:/jdk1.2.2/jre/lib/rt.jar" </code> - reference to an external JAR</li>
-	 *	<li><code> "/Project/someLib.jar" </code> - reference to an internal JAR </li>
-	 *	<li><code> "/Project/classes/" </code> - reference to an internal binary folder</li>
+	 *	<li><code> "c:\jdk1.2.2\jre\lib\rt.jar" </code> - reference to an external JAR on Windows</li>
+	 *	<li><code> "/Project/someLib.jar" </code> - reference to an internal JAR on Windows or Linux</li>
+	 *	<li><code> "/Project/classes/" </code> - reference to an internal binary folder on Windows or Linux</li>
 	 * </ul>
-	 * Note that this operation does not attempt to validate or access the 
+	 * Note that on non-Windows platform, a path <code>"/some/lib.jar"</code> is ambiguous.
+	 * It can be a path to an external JAR (its file system path being <code>"/some/lib.jar"</code>)
+	 * or it can be a path to an internal JAR (<code>"some"</code> being a project in the workspace).
+	 * Such an ambiguity is solved when the classpath entry is used (e.g. in {@link IJavaProject#getPackageFragmentRoots()}).
+	 * If the resource <code>"lib.jar"</code> exists in project <code>"some"</code>, then it is considered an
+	 * internal JAR. Otherwise it is an external JAR.
+	 * <p>Also note that this operation does not attempt to validate or access the
 	 * resources at the given paths.
-	 * <p>
+	 * </p><p>
 	 * The access rules determine the set of accessible class files
 	 * in the library. If the list of access rules is empty then all files
 	 * in this library are accessible.
@@ -3107,14 +3801,14 @@
 	 * projects. If not exported, dependent projects will not see any of the classes from this entry.
 	 * If exported, dependent projects will concatenate the accessible files patterns of this entry with the
 	 * accessible files patterns of the projects, and they will concatenate the non accessible files patterns of this entry
-	 * with the non accessible files patterns of the project. 
+	 * with the non accessible files patterns of the project.
 	 * </p>
-	 * 
+	 *
 	 * @param path the absolute path of the binary archive
-	 * @param sourceAttachmentPath the absolute path of the corresponding source archive or folder, 
+	 * @param sourceAttachmentPath the absolute path of the corresponding source archive or folder,
 	 *    or <code>null</code> if none. Note, since 3.0, an empty path is allowed to denote no source attachment.
 	 *   and will be automatically converted to <code>null</code>.
-	 * @param sourceAttachmentRootPath the location of the root within the source archive or folder
+	 * @param sourceAttachmentRootPath the location of the root of the source files within the source archive or folder
 	 *    or <code>null</code> if this location should be automatically detected.
 	 * @param accessRules the possibly empty list of access rules for this entry
 	 * @param extraAttributes the possibly empty list of extra attributes to persist with this entry
@@ -3127,10 +3821,10 @@
 			IPath path,
 			IPath sourceAttachmentPath,
 			IPath sourceAttachmentRootPath,
-			IAccessRule[] accessRules, 
+			IAccessRule[] accessRules,
 			IClasspathAttribute[] extraAttributes,
 			boolean isExported) {
-			
+
 		if (path == null) Assert.isTrue(false, "Library path cannot be null"); //$NON-NLS-1$
 		if (!path.isAbsolute()) Assert.isTrue(false, "Path for IClasspathEntry must be absolute"); //$NON-NLS-1$
 		if (sourceAttachmentPath != null) {
@@ -3156,28 +3850,28 @@
 			false, // no access rules to combine
 			extraAttributes);
 	}
-	
+
 	/**
 	 * Creates and returns a new non-exported classpath entry of kind <code>CPE_PROJECT</code>
 	 * for the project identified by the given absolute path.
 	 * This method is fully equivalent to calling
 	 * {@link #newProjectEntry(IPath, IAccessRule[], boolean, IClasspathAttribute[], boolean)
 	 * newProjectEntry(path, new IAccessRule[0], true, new IClasspathAttribute[0], false)}.
-	 * 
+	 *
 	 * @param path the absolute path of the binary archive
 	 * @return a new project classpath entry
 	 */
 	public static IClasspathEntry newProjectEntry(IPath path) {
 		return newProjectEntry(path, false);
 	}
-	
+
 	/**
 	 * Creates and returns a new classpath entry of kind <code>CPE_PROJECT</code>
 	 * for the project identified by the given absolute path.
 	 * This method is fully equivalent to calling
 	 * {@link #newProjectEntry(IPath, IAccessRule[], boolean, IClasspathAttribute[], boolean)
 	 * newProjectEntry(path, new IAccessRule[0], true, new IClasspathAttribute[0], isExported)}.
-	 * 
+	 *
 	 * @param path the absolute path of the prerequisite project
 	 * @param isExported indicates whether this entry is contributed to dependent
 	 * 	  projects in addition to the output location
@@ -3185,9 +3879,9 @@
 	 * @since 2.0
 	 */
 	public static IClasspathEntry newProjectEntry(IPath path, boolean isExported) {
-		
+
 		if (!path.isAbsolute()) Assert.isTrue(false, "Path for IClasspathEntry must be absolute"); //$NON-NLS-1$
-		
+
 		return newProjectEntry(
 			path,
 			ClasspathEntry.NO_ACCESS_RULES,
@@ -3202,11 +3896,11 @@
 	 * <p>
 	 * A project entry is used to denote a prerequisite project on a classpath.
 	 * The referenced project will be contributed as a whole, either as sources (in the Java Model, it
-	 * contributes all its package fragment roots) or as binaries (when building, it contributes its 
+	 * contributes all its package fragment roots) or as binaries (when building, it contributes its
 	 * whole output location).
 	 * </p>
 	 * <p>
-	 * A project reference allows to indirect through another project, independently from its internal layout. 
+	 * A project reference allows to indirect through another project, independently from its internal layout.
 	 * </p><p>
 	 * The prerequisite project is referred to using an absolute path relative to the workspace root.
 	 * </p>
@@ -3219,7 +3913,7 @@
 	 * <p>
 	 * The <code>combineAccessRules</code> flag indicates whether access rules of one (or more)
 	 * exported entry of the project should be combined with the given access rules. If they should
-	 * be combined, the given access rules are considered first, then the entry's access rules are 
+	 * be combined, the given access rules are considered first, then the entry's access rules are
 	 * considered.
 	 * </p>
 	 * <p>
@@ -3232,9 +3926,9 @@
 	 * projects. If not exported, dependent projects will not see any of the classes from this entry.
 	 * If exported, dependent projects will concatenate the accessible files patterns of this entry with the
 	 * accessible files patterns of the projects, and they will concatenate the non accessible files patterns of this entry
-	 * with the non accessible files patterns of the project. 
+	 * with the non accessible files patterns of the project.
 	 * </p>
-	 * 
+	 *
 	 * @param path the absolute path of the prerequisite project
 	 * @param accessRules the possibly empty list of access rules for this entry
 	 * @param combineAccessRules whether the access rules of the project's exported entries should be combined with the given access rules
@@ -3245,14 +3939,14 @@
 	 * @since 3.1
 	 */
 	public static IClasspathEntry newProjectEntry(
-			IPath path, 
-			IAccessRule[] accessRules, 
+			IPath path,
+			IAccessRule[] accessRules,
 			boolean combineAccessRules,
 			IClasspathAttribute[] extraAttributes,
 			boolean isExported) {
-		
+
 		if (!path.isAbsolute()) Assert.isTrue(false, "Path for IClasspathEntry must be absolute"); //$NON-NLS-1$
-		
+
 		return new ClasspathEntry(
 			IPackageFragmentRoot.K_SOURCE,
 			IClasspathEntry.CPE_PROJECT,
@@ -3270,7 +3964,7 @@
 
 	/**
 	 * Returns a new empty region.
-	 * 
+	 *
 	 * @return a new empty region
 	 */
 	public static IRegion newRegion() {
@@ -3287,7 +3981,7 @@
 	 * newSourceEntry(path, new IPath[] {}, new IPath[] {}, null);
 	 * </pre>
 	 * </p>
-	 * 
+	 *
 	 * @param path the absolute workspace-relative path of a source folder
 	 * @return a new source classpath entry
 	 * @see #newSourceEntry(IPath, IPath[], IPath[], IPath)
@@ -3296,10 +3990,10 @@
 
 		return newSourceEntry(path, ClasspathEntry.INCLUDE_ALL, ClasspathEntry.EXCLUDE_NONE, null /*output location*/);
 	}
-	
+
 	/**
 	 * Creates and returns a new classpath entry of kind <code>CPE_SOURCE</code>
-	 * for the project's source folder identified by the given absolute 
+	 * for the project's source folder identified by the given absolute
 	 * workspace-relative path but excluding all source files with paths
 	 * matching any of the given patterns.
 	 * <p>
@@ -3318,15 +4012,15 @@
 	 */
 	public static IClasspathEntry newSourceEntry(IPath path, IPath[] exclusionPatterns) {
 
-		return newSourceEntry(path, ClasspathEntry.INCLUDE_ALL, exclusionPatterns, null /*output location*/); 
+		return newSourceEntry(path, ClasspathEntry.INCLUDE_ALL, exclusionPatterns, null /*output location*/);
 	}
 
 	/**
 	 * Creates and returns a new classpath entry of kind <code>CPE_SOURCE</code>
-	 * for the project's source folder identified by the given absolute 
+	 * for the project's source folder identified by the given absolute
 	 * workspace-relative path but excluding all source files with paths
 	 * matching any of the given patterns, and associated with a specific output location
-	 * (that is, ".class" files are not going to the project default output location). 
+	 * (that is, ".class" files are not going to the project default output location).
 	 * <p>
 	 * The convenience method is fully equivalent to:
 	 * <pre>
@@ -3346,13 +4040,13 @@
 
 	    return newSourceEntry(path, ClasspathEntry.INCLUDE_ALL, exclusionPatterns, specificOutputLocation);
 	}
-		
+
 	/**
 	 * Creates and returns a new classpath entry of kind <code>CPE_SOURCE</code>
-	 * for the project's source folder identified by the given absolute 
+	 * for the project's source folder identified by the given absolute
 	 * workspace-relative path but excluding all source files with paths
 	 * matching any of the given patterns, and associated with a specific output location
-	 * (that is, ".class" files are not going to the project default output location). 
+	 * (that is, ".class" files are not going to the project default output location).
 	 * <p>
 	 * The convenience method is fully equivalent to:
 	 * <pre>
@@ -3373,16 +4067,16 @@
 	public static IClasspathEntry newSourceEntry(IPath path, IPath[] inclusionPatterns, IPath[] exclusionPatterns, IPath specificOutputLocation) {
 		return newSourceEntry(path, inclusionPatterns, exclusionPatterns, specificOutputLocation, ClasspathEntry.NO_EXTRA_ATTRIBUTES);
 	}
-	
+
 	/**
 	 * Creates and returns a new classpath entry of kind <code>CPE_SOURCE</code>
-	 * for the project's source folder identified by the given absolute 
+	 * for the project's source folder identified by the given absolute
 	 * workspace-relative path using the given inclusion and exclusion patterns
 	 * to determine which source files are included, and the given output path
 	 * to control the output location of generated files.
 	 * <p>
 	 * The source folder is referred to using an absolute path relative to the
-	 * workspace root, e.g. <code>/Project/src</code>. A project's source 
+	 * workspace root, e.g. <code>/Project/src</code>. A project's source
 	 * folders are located with that project. That is, a source classpath
 	 * entry specifying the path <code>/P1/src</code> is only usable for
 	 * project <code>P1</code>.
@@ -3394,11 +4088,11 @@
 	 * includes all relevent files in the resource tree rooted at the source
 	 * entry's path. On the other hand, specifying one or more inclusion
 	 * patterns means that all <b>and only</b> files matching at least one of
-	 * the specified patterns are to be included. If exclusion patterns are 
+	 * the specified patterns are to be included. If exclusion patterns are
 	 * specified, the initial set of files is then reduced by eliminating files
 	 * matched by at least one of the exclusion patterns. Inclusion and
 	 * exclusion patterns look like relative file paths with wildcards and are
-	 * interpreted relative to the source entry's path. File patterns are 
+	 * interpreted relative to the source entry's path. File patterns are
 	 * case-sensitive can contain '**', '*' or '?' wildcards (see
 	 * {@link IClasspathEntry#getExclusionPatterns()} for the full description
 	 * of their syntax and semantics). The resulting set of files are included
@@ -3406,24 +4100,24 @@
 	 * the root will have children of type <code>ICompilationUnit</code>.
 	 * </p>
 	 * <p>
-	 * For example, if the source folder path is 
+	 * For example, if the source folder path is
 	 * <code>/Project/src</code>, there are no inclusion filters, and the
-	 * exclusion pattern is 
+	 * exclusion pattern is
 	 * <code>com/xyz/tests/&#42;&#42;</code>, then source files
 	 * like <code>/Project/src/com/xyz/Foo.java</code>
 	 * and <code>/Project/src/com/xyz/utils/Bar.java</code> would be included,
 	 * whereas <code>/Project/src/com/xyz/tests/T1.java</code>
 	 * and <code>/Project/src/com/xyz/tests/quick/T2.java</code> would be
-	 * excluded. 
+	 * excluded.
 	 * </p>
 	 * <p>
-	 * Additionally, a source entry can be associated with a specific output location. 
-	 * By doing so, the Java builder will ensure that the generated ".class" files will 
-	 * be issued inside this output location, as opposed to be generated into the 
-	 * project default output location (when output location is <code>null</code>). 
+	 * Additionally, a source entry can be associated with a specific output location.
+	 * By doing so, the Java builder will ensure that the generated ".class" files will
+	 * be issued inside this output location, as opposed to be generated into the
+	 * project default output location (when output location is <code>null</code>).
 	 * Note that multiple source entries may target the same output location.
-	 * The output location is referred to using an absolute path relative to the 
-	 * workspace root, e.g. <code>"/Project/bin"</code>, it must be located inside 
+	 * The output location is referred to using an absolute path relative to the
+	 * workspace root, e.g. <code>"/Project/bin"</code>, it must be located inside
 	 * the same project as the source folder.
 	 * </p>
 	 * <p>
@@ -3470,7 +4164,7 @@
 			false,
 			null,
 			false, // no access rules to combine
-			extraAttributes); 
+			extraAttributes);
 	}
 
 	/**
@@ -3478,15 +4172,15 @@
 	 * for the given path. This method is fully equivalent to calling
 	 * {@link #newVariableEntry(IPath, IPath, IPath, IAccessRule[], IClasspathAttribute[], boolean)
 	 * newVariableEntry(variablePath, variableSourceAttachmentPath, sourceAttachmentRootPath, new IAccessRule[0], new IClasspathAttribute[0], false)}.
-	 * 
+	 *
 	 * @param variablePath the path of the binary archive; first segment is the
 	 *   name of a classpath variable
-	 * @param variableSourceAttachmentPath the path of the corresponding source archive, 
+	 * @param variableSourceAttachmentPath the path of the corresponding source archive,
 	 *    or <code>null</code> if none; if present, the first segment is the
 	 *    name of a classpath variable (not necessarily the same variable
 	 *    as the one that begins <code>variablePath</code>)
-	 * @param sourceAttachmentRootPath the location of the root within the source archive
-	 *    or <code>null</code> if <code>archivePath</code> is also <code>null</code>
+	 * @param sourceAttachmentRootPath the location of the root of the source files within the source archive
+	 *    or <code>null</code> if <code>variableSourceAttachmentPath</code> is also <code>null</code>
 	 * @return a new library classpath entry
 	 */
 	public static IClasspathEntry newVariableEntry(
@@ -3502,15 +4196,15 @@
 	 * for the given path. This method is fully equivalent to calling
 	 * {@link #newVariableEntry(IPath, IPath, IPath, IAccessRule[], IClasspathAttribute[], boolean)
 	 * newVariableEntry(variablePath, variableSourceAttachmentPath, sourceAttachmentRootPath, new IAccessRule[0], new IClasspathAttribute[0], isExported)}.
-	 * 
+	 *
 	 * @param variablePath the path of the binary archive; first segment is the
 	 *   name of a classpath variable
-	 * @param variableSourceAttachmentPath the path of the corresponding source archive, 
+	 * @param variableSourceAttachmentPath the path of the corresponding source archive,
 	 *    or <code>null</code> if none; if present, the first segment is the
 	 *    name of a classpath variable (not necessarily the same variable
 	 *    as the one that begins <code>variablePath</code>)
-	 * @param variableSourceAttachmentRootPath the location of the root within the source archive
-	 *    or <code>null</code> if <code>archivePath</code> is also <code>null</code>
+	 * @param variableSourceAttachmentRootPath the location of the root of the source files within the source archive
+	 *    or <code>null</code> if <code>variableSourceAttachmentPath</code> is also <code>null</code>
 	 * @param isExported indicates whether this entry is contributed to dependent
 	 * 	  projects in addition to the output location
 	 * @return a new variable classpath entry
@@ -3532,7 +4226,7 @@
 	}
 
 	/**
-	 * Creates and returns a new non-exported classpath entry of kind <code>CPE_VARIABLE</code>
+	 * Creates and returns a new classpath entry of kind <code>CPE_VARIABLE</code>
 	 * for the given path. The first segment of the path is the name of a classpath variable.
 	 * The trailing segments of the path will be appended to resolved variable path.
 	 * <p>
@@ -3541,15 +4235,15 @@
 	 * <p>
 	 *	It is possible to register an automatic initializer (<code>ClasspathVariableInitializer</code>),
 	 * which will be invoked through the extension point "org.eclipse.jdt.core.classpathVariableInitializer".
-	 * After resolution, a classpath variable entry may either correspond to a project or a library entry. </li>	 
+	 * After resolution, a classpath variable entry may either correspond to a project or a library entry.
 	 * <p>
 	 * e.g. Here are some examples of variable path usage<ul>
-	 * <li> "JDTCORE" where variable <code>JDTCORE</code> is 
+	 * <li> "JDTCORE" where variable <code>JDTCORE</code> is
 	 *		bound to "c:/jars/jdtcore.jar". The resolved classpath entry is denoting the library "c:\jars\jdtcore.jar"</li>
-	 * <li> "JDTCORE" where variable <code>JDTCORE</code> is 
+	 * <li> "JDTCORE" where variable <code>JDTCORE</code> is
 	 *		bound to "/Project_JDTCORE". The resolved classpath entry is denoting the project "/Project_JDTCORE"</li>
 	 * <li> "PLUGINS/com.example/example.jar" where variable <code>PLUGINS</code>
-	 *      is bound to "c:/eclipse/plugins". The resolved classpath entry is denoting the library "c:/eclipse/plugins/com.example/example.jar"</li>
+	 *      is bound to "c:/eclipse/plugins". The resolved classpath entry is denoting the library "c:\eclipse\plugins\com.example\example.jar"</li>
 	 * </ul>
 	 * <p>
 	 * The access rules determine the set of accessible class files
@@ -3567,7 +4261,7 @@
 	 * projects. If not exported, dependent projects will not see any of the classes from this entry.
 	 * If exported, dependent projects will concatenate the accessible files patterns of this entry with the
 	 * accessible files patterns of the projects, and they will concatenate the non accessible files patterns of this entry
-	 * with the non accessible files patterns of the project. 
+	 * with the non accessible files patterns of the project.
 	 * </p>
 	 * <p>
 	 * Note that this operation does not attempt to validate classpath variables
@@ -3576,24 +4270,24 @@
 	 *
 	 * @param variablePath the path of the binary archive; first segment is the
 	 *   name of a classpath variable
-	 * @param variableSourceAttachmentPath the path of the corresponding source archive, 
+	 * @param variableSourceAttachmentPath the path of the corresponding source archive,
 	 *    or <code>null</code> if none; if present, the first segment is the
 	 *    name of a classpath variable (not necessarily the same variable
 	 *    as the one that begins <code>variablePath</code>)
-	 * @param variableSourceAttachmentRootPath the location of the root within the source archive
-	 *    or <code>null</code> if <code>archivePath</code> is also <code>null</code>
+	 * @param variableSourceAttachmentRootPath the location of the root of the source files within the source archive
+	 *    or <code>null</code> if <code>variableSourceAttachmentPath</code> is also <code>null</code>
 	 * @param accessRules the possibly empty list of access rules for this entry
 	 * @param extraAttributes the possibly empty list of extra attributes to persist with this entry
 	 * @param isExported indicates whether this entry is contributed to dependent
 	 * 	  projects in addition to the output location
 	 * @return a new variable classpath entry
 	 * @since 3.1
-	 */	
+	 */
 	public static IClasspathEntry newVariableEntry(
 			IPath variablePath,
 			IPath variableSourceAttachmentPath,
 			IPath variableSourceAttachmentRootPath,
-			IAccessRule[] accessRules, 
+			IAccessRule[] accessRules,
 			IClasspathAttribute[] extraAttributes,
 			boolean isExported) {
 
@@ -3603,7 +4297,7 @@
 				false,
 				"Illegal classpath variable path: \'" + variablePath.makeRelative().toString() + "\', must have at least one segment"); //$NON-NLS-1$//$NON-NLS-2$
 		}
-	
+
 		return new ClasspathEntry(
 			IPackageFragmentRoot.K_SOURCE,
 			IClasspathEntry.CPE_VARIABLE,
@@ -3611,27 +4305,27 @@
 			ClasspathEntry.INCLUDE_ALL, // inclusion patterns
 			ClasspathEntry.EXCLUDE_NONE, // exclusion patterns
 			variableSourceAttachmentPath, // source attachment
-			variableSourceAttachmentRootPath, // source attachment root			
+			variableSourceAttachmentRootPath, // source attachment root
 			null, // specific output folder
 			isExported,
 			accessRules,
 			false, // no access rules to combine
 			extraAttributes);
-	}	
+	}
 	/**
 	 * Removed the given classpath variable. Does nothing if no value was
 	 * set for this classpath variable.
 	 * <p>
 	 * This functionality cannot be used while the resource tree is locked.
 	 * <p>
-	 * Classpath variable values are persisted locally to the workspace, and 
+	 * Classpath variable values are persisted locally to the workspace, and
 	 * are preserved from session to session.
 	 * <p>
 	 *
 	 * @param variableName the name of the classpath variable
 	 * @see #setClasspathVariable(String, IPath)
 	 *
-	 * @deprecated - use version with extra IProgressMonitor
+	 * @deprecated Use {@link #removeClasspathVariable(String, IProgressMonitor)} instead
 	 */
 	public static void removeClasspathVariable(String variableName) {
 		removeClasspathVariable(variableName, null);
@@ -3643,7 +4337,7 @@
 	 * <p>
 	 * This functionality cannot be used while the resource tree is locked.
 	 * <p>
-	 * Classpath variable values are persisted locally to the workspace, and 
+	 * Classpath variable values are persisted locally to the workspace, and
 	 * are preserved from session to session.
 	 * <p>
 	 *
@@ -3651,14 +4345,12 @@
 	 * @param monitor the progress monitor to report progress
 	 * @see #setClasspathVariable(String, IPath)
 	 */
-	public static void removeClasspathVariable(
-		String variableName,
-		IProgressMonitor monitor) {
-
+	public static void removeClasspathVariable(String variableName, IProgressMonitor monitor) {
 		try {
-			JavaModelManager.getJavaModelManager().updateVariableValues(new String[]{ variableName}, new IPath[]{ null }, monitor);
+			SetVariablesOperation operation = new SetVariablesOperation(new String[]{ variableName}, new IPath[]{ null }, true/*update preferences*/);
+			operation.runOperation(monitor);
 		} catch (JavaModelException e) {
-			// cannot happen: ignore
+			Util.log(e, "Exception while removing variable " + variableName); //$NON-NLS-1$
 		}
 	}
 
@@ -3673,6 +4365,19 @@
 	}
 
 	/**
+	 * Removes the file extension from the given file name, if it has a Java-like file
+	 * extension. Otherwise the file name itself is returned.
+	 * Note this removes the dot ('.') before the extension as well.
+	 *
+	 * @param fileName the name of a file
+	 * @return the fileName without the Java-like extension
+	 * @since 3.2
+	 */
+	public static String removeJavaLikeExtension(String fileName) {
+		return Util.getNameWithoutJavaLikeExtension(fileName);
+	}
+
+	/**
 	 * Removes the given pre-processing resource changed listener.
 	 * <p>
 	 * Has no affect if an identical listener is not registered.
@@ -3683,9 +4388,9 @@
 	public static void removePreProcessingResourceChangedListener(IResourceChangeListener listener) {
 		JavaModelManager.getJavaModelManager().deltaState.removePreResourceChangedListener(listener);
 	}
-	
 
-	
+
+
 	/**
 	 * Runs the given action as an atomic Java model operation.
 	 * <p>
@@ -3740,7 +4445,7 @@
 	 * </p>
 	 * <p>
  	 * The supplied scheduling rule is used to determine whether this operation can be
-	 * run simultaneously with workspace changes in other threads. See 
+	 * run simultaneously with workspace changes in other threads. See
 	 * <code>IWorkspace.run(...)</code> for more details.
  	 * </p>
 	 *
@@ -3760,37 +4465,37 @@
 			// use IWorkspace.run(...) to ensure that a build will be done in autobuild mode
 			workspace.run(new BatchOperation(action), rule, IWorkspace.AVOID_UPDATE, monitor);
 		}
-	}	
-	/** 
+	}
+	/**
 	 * Bind a container reference path to some actual containers (<code>IClasspathContainer</code>).
 	 * This API must be invoked whenever changes in container need to be reflected onto the JavaModel.
 	 * Containers can have distinct values in different projects, therefore this API considers a
 	 * set of projects with their respective containers.
 	 * <p>
 	 * <code>containerPath</code> is the path under which these values can be referenced through
-	 * container classpath entries (<code>IClasspathEntry#CPE_CONTAINER</code>). A container path 
+	 * container classpath entries (<code>IClasspathEntry#CPE_CONTAINER</code>). A container path
 	 * is formed by a first ID segment followed with extra segments, which can be used as additional hints
-	 * for the resolution. The container ID is used to identify a <code>ClasspathContainerInitializer</code> 
+	 * for the resolution. The container ID is used to identify a <code>ClasspathContainerInitializer</code>
 	 * registered on the extension point "org.eclipse.jdt.core.classpathContainerInitializer".
 	 * <p>
-	 * There is no assumption that each individual container value passed in argument 
-	 * (<code>respectiveContainers</code>) must answer the exact same path when requested 
-	 * <code>IClasspathContainer#getPath</code>. 
-	 * Indeed, the containerPath is just an indication for resolving it to an actual container object. It can be 
+	 * There is no assumption that each individual container value passed in argument
+	 * (<code>respectiveContainers</code>) must answer the exact same path when requested
+	 * <code>IClasspathContainer#getPath</code>.
+	 * Indeed, the containerPath is just an indication for resolving it to an actual container object. It can be
 	 * delegated to a <code>ClasspathContainerInitializer</code>, which can be activated through the extension
-	 * point "org.eclipse.jdt.core.ClasspathContainerInitializer"). 
+	 * point "org.eclipse.jdt.core.ClasspathContainerInitializer").
 	 * <p>
 	 * In reaction to changing container values, the JavaModel will be updated to reflect the new
-	 * state of the updated container. A combined Java element delta will be notified to describe the corresponding 
+	 * state of the updated container. A combined Java element delta will be notified to describe the corresponding
 	 * classpath changes resulting from the container update. This operation is batched, and automatically eliminates
 	 * unnecessary updates (new container is same as old one). This operation acquires a lock on the workspace's root.
 	 * <p>
 	 * This functionality cannot be used while the workspace is locked, since
 	 * it may create/remove some resource markers.
 	 * <p>
-	 * Classpath container values are persisted locally to the workspace, but 
-	 * are not preserved from a session to another. It is thus highly recommended to register a 
-	 * <code>ClasspathContainerInitializer</code> for each referenced container 
+	 * Classpath container values are persisted locally to the workspace, but
+	 * are not preserved from a session to another. It is thus highly recommended to register a
+	 * <code>ClasspathContainerInitializer</code> for each referenced container
 	 * (through the extension point "org.eclipse.jdt.core.ClasspathContainerInitializer").
 	 * <p>
 	 * Note: setting a container to <code>null</code> will cause it to be lazily resolved again whenever
@@ -3807,182 +4512,11 @@
 	 * @see IClasspathContainer
 	 * @since 2.0
 	 */
-	public static void setClasspathContainer(final IPath containerPath, IJavaProject[] affectedProjects, IClasspathContainer[] respectiveContainers, IProgressMonitor monitor) throws JavaModelException {
-
-		if (affectedProjects.length != respectiveContainers.length) Assert.isTrue(false, "Projects and containers collections should have the same size"); //$NON-NLS-1$
-	
-		if (monitor != null && monitor.isCanceled()) return;
-	
-		if (JavaModelManager.CP_RESOLVE_VERBOSE){
-			Util.verbose(
-				"CPContainer SET  - setting container\n" + //$NON-NLS-1$
-				"	container path: " + containerPath + '\n' + //$NON-NLS-1$
-				"	projects: {" +//$NON-NLS-1$
-				org.eclipse.jdt.internal.compiler.util.Util.toString(
-					affectedProjects, 
-					new org.eclipse.jdt.internal.compiler.util.Util.Displayable(){ 
-						public String displayString(Object o) { return ((IJavaProject) o).getElementName(); }
-					}) +
-				"}\n	values: {\n"  +//$NON-NLS-1$
-				org.eclipse.jdt.internal.compiler.util.Util.toString(
-					respectiveContainers, 
-					new org.eclipse.jdt.internal.compiler.util.Util.Displayable(){ 
-						public String displayString(Object o) { 
-							StringBuffer buffer = new StringBuffer("		"); //$NON-NLS-1$
-							if (o == null) {
-								buffer.append("<null>"); //$NON-NLS-1$
-								return buffer.toString();
-							}
-							IClasspathContainer container = (IClasspathContainer) o;
-							buffer.append(container.getDescription());
-							buffer.append(" {\n"); //$NON-NLS-1$
-							IClasspathEntry[] entries = container.getClasspathEntries();
-							if (entries != null){
-								for (int i = 0; i < entries.length; i++){
-									buffer.append(" 			"); //$NON-NLS-1$
-									buffer.append(entries[i]); 
-									buffer.append('\n'); 
-								}
-							}
-							buffer.append(" 		}"); //$NON-NLS-1$
-							return buffer.toString();
-						}
-					}) +
-				"\n	}\n	invocation stack trace:"); //$NON-NLS-1$
-				new Exception("<Fake exception>").printStackTrace(System.out); //$NON-NLS-1$
-		}
-		
-		JavaModelManager manager = JavaModelManager.getJavaModelManager();
-		if (manager.containerPutIfInitializingWithSameEntries(containerPath, affectedProjects, respectiveContainers))
-			return;
-
-		final int projectLength = affectedProjects.length;	
-		final IJavaProject[] modifiedProjects;
-		System.arraycopy(affectedProjects, 0, modifiedProjects = new IJavaProject[projectLength], 0, projectLength);
-		final IClasspathEntry[][] oldResolvedPaths = new IClasspathEntry[projectLength][];
-			
-		// filter out unmodified project containers
-		int remaining = 0;
-		for (int i = 0; i < projectLength; i++){
-	
-			if (monitor != null && monitor.isCanceled()) return;
-	
-			JavaProject affectedProject = (JavaProject) affectedProjects[i];
-			IClasspathContainer newContainer = respectiveContainers[i];
-			if (newContainer == null) newContainer = JavaModelManager.CONTAINER_INITIALIZATION_IN_PROGRESS; // 30920 - prevent infinite loop
-			boolean found = false;
-			if (JavaProject.hasJavaNature(affectedProject.getProject())){
-				IClasspathEntry[] rawClasspath = affectedProject.getRawClasspath();
-				for (int j = 0, cpLength = rawClasspath.length; j <cpLength; j++) {
-					IClasspathEntry entry = rawClasspath[j];
-					if (entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER && entry.getPath().equals(containerPath)){
-						found = true;
-						break;
-					}
-				}
-			}
-			if (!found){
-				modifiedProjects[i] = null; // filter out this project - does not reference the container path, or isnt't yet Java project
-				manager.containerPut(affectedProject, containerPath, newContainer);
-				continue;
-			}
-			IClasspathContainer oldContainer = manager.containerGet(affectedProject, containerPath);
-			if (oldContainer == JavaModelManager.CONTAINER_INITIALIZATION_IN_PROGRESS) {
-//				Map previousContainerValues = (Map)JavaModelManager.getJavaModelManager().previousSessionContainers.get(affectedProject);
-//				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: " + affectedProject.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());
-//						}
-//						JavaModelManager.getJavaModelManager().containerPut(affectedProject, containerPath, previousContainer); 
-//					}
-//					oldContainer = null; //33695 - cannot filter out restored container, must update affected project to reset cached CP
-//				} else {
-					oldContainer = null;
-//				}
-			}
-			if (oldContainer != null && oldContainer.equals(respectiveContainers[i])){
-				modifiedProjects[i] = null; // filter out this project - container did not change
-				continue;
-			}
-			remaining++; 
-			oldResolvedPaths[i] = affectedProject.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
-			manager.containerPut(affectedProject, containerPath, newContainer);
-		}
-		
-		if (remaining == 0) return;
-		
-		// trigger model refresh
-		try {
-			final boolean canChangeResources = !ResourcesPlugin.getWorkspace().isTreeLocked();
-			JavaCore.run(new IWorkspaceRunnable() {
-				public void run(IProgressMonitor progressMonitor) throws CoreException {
-					for(int i = 0; i < projectLength; i++){
-		
-						if (progressMonitor != null && progressMonitor.isCanceled()) return;
-		
-						JavaProject affectedProject = (JavaProject)modifiedProjects[i];
-						if (affectedProject == null) continue; // was filtered out
-						
-						if (JavaModelManager.CP_RESOLVE_VERBOSE){
-							Util.verbose(
-								"CPContainer SET  - updating affected project due to setting container\n" + //$NON-NLS-1$
-								"	project: " + affectedProject.getElementName() + '\n' + //$NON-NLS-1$
-								"	container path: " + containerPath); //$NON-NLS-1$
-						}
-
-						// force a refresh of the affected project (will compute deltas)
-						affectedProject.setRawClasspath(
-								affectedProject.getRawClasspath(),
-								SetClasspathOperation.DO_NOT_SET_OUTPUT,
-								progressMonitor,
-								canChangeResources,
-								oldResolvedPaths[i],
-								false, // updating - no need for early validation
-								false); // updating - no need to save
-					}
-				}
-			},
-			null/*no need to lock anything*/,
-			monitor);
-		} catch(CoreException e) {
-			if (JavaModelManager.CP_RESOLVE_VERBOSE){
-				Util.verbose(
-					"CPContainer SET  - FAILED DUE TO EXCEPTION\n" + //$NON-NLS-1$
-					"	container path: " + containerPath, //$NON-NLS-1$
-					System.err);
-				e.printStackTrace();
-			}
-			if (e instanceof JavaModelException) {
-				throw (JavaModelException)e;
-			} else {
-				throw new JavaModelException(e);
-			}
-		} finally {
-			for (int i = 0; i < projectLength; i++) {
-				if (respectiveContainers[i] == null) {
-					manager.containerPut(affectedProjects[i], containerPath, null); // reset init in progress marker
-				}
-			}
-		}
-					
+	public static void setClasspathContainer(IPath containerPath, IJavaProject[] affectedProjects, IClasspathContainer[] respectiveContainers, IProgressMonitor monitor) throws JavaModelException {
+		if (affectedProjects.length != respectiveContainers.length)
+			Assert.isTrue(false, "Projects and containers collections should have the same size"); //$NON-NLS-1$
+		SetContainerOperation operation = new SetContainerOperation(containerPath, affectedProjects, respectiveContainers);
+		operation.runOperation(monitor);
 	}
 
 	/**
@@ -3991,7 +4525,7 @@
 	 * <p>
 	 * This functionality cannot be used while the resource tree is locked.
 	 * <p>
-	 * Classpath variable values are persisted locally to the workspace, and 
+	 * Classpath variable values are persisted locally to the workspace, and
 	 * are preserved from session to session.
 	 * <p>
 	 *
@@ -4000,7 +4534,7 @@
 	 * @throws JavaModelException
 	 * @see #getClasspathVariable(String)
 	 *
-	 * @deprecated - use API with IProgressMonitor
+	 * @deprecated Use {@link #setClasspathVariable(String, IPath, IProgressMonitor)} instead
 	 */
 	public static void setClasspathVariable(String variableName, IPath path)
 		throws JavaModelException {
@@ -4014,7 +4548,7 @@
 	 * <p>
 	 * This functionality cannot be used while the resource tree is locked.
 	 * <p>
-	 * Classpath variable values are persisted locally to the workspace, and 
+	 * Classpath variable values are persisted locally to the workspace, and
 	 * are preserved from session to session.
 	 * <p>
 	 * Updating a variable with the same value has no effect.
@@ -4039,19 +4573,19 @@
 	 * Sets the values of all the given classpath variables at once.
 	 * Null paths can be used to request corresponding variable removal.
 	 * <p>
-	 * A combined Java element delta will be notified to describe the corresponding 
-	 * classpath changes resulting from the variables update. This operation is batched, 
-	 * and automatically eliminates unnecessary updates (new variable is same as old one). 
+	 * A combined Java element delta will be notified to describe the corresponding
+	 * classpath changes resulting from the variables update. This operation is batched,
+	 * and automatically eliminates unnecessary updates (new variable is same as old one).
 	 * This operation acquires a lock on the workspace's root.
 	 * <p>
 	 * This functionality cannot be used while the workspace is locked, since
 	 * it may create/remove some resource markers.
 	 * <p>
-	 * Classpath variable values are persisted locally to the workspace, and 
+	 * Classpath variable values are persisted locally to the workspace, and
 	 * are preserved from session to session.
 	 * <p>
 	 * Updating a variable with the same value has no effect.
-	 * 
+	 *
 	 * @param variableNames an array of names for the updated classpath variables
 	 * @param paths an array of path updates for the modified classpath variables (null
 	 *       meaning that the corresponding value will be removed
@@ -4067,19 +4601,87 @@
 		throws JavaModelException {
 
 		if (variableNames.length != paths.length)	Assert.isTrue(false, "Variable names and paths collections should have the same size"); //$NON-NLS-1$
-		JavaModelManager.getJavaModelManager().updateVariableValues(variableNames, paths, monitor);
+		SetVariablesOperation operation = new SetVariablesOperation(variableNames, paths, true/*update preferences*/);
+		operation.runOperation(monitor);
 	}
 
 	/**
-	 * Sets the current table of options. All and only the options explicitly included in the given table 
-	 * are remembered; all previous option settings are forgotten, including ones not explicitly
-	 * mentioned.
+	 * Sets the default's compiler options inside the given options map according
+	 * to the given compliance.
+	 *
+	 * <p>The given compliance must be one of the compliance supported by the compiler.
+	 * See {@link #getDefaultOptions()} for a list of compliance values.</p>
+	 *
+	 * <p>The list of modified options is:</p>
+	 * <ul>
+	 * <li>{@link #COMPILER_CODEGEN_TARGET_PLATFORM}</li>
+	 * <li>{@link #COMPILER_SOURCE}</li>
+	 * <li>{@link #COMPILER_COMPLIANCE}</li>
+	 * <li>{@link #COMPILER_PB_ASSERT_IDENTIFIER}</li>
+	 * <li>{@link #COMPILER_PB_ENUM_IDENTIFIER}</li>
+	 * </ul>
+	 *
+	 * <p>If the given compliance is unknown, the given map is unmodified.</p>
+	 *
+	 * @param compliance the given compliance
+	 * @param options the given options map
+	 * @since 3.3
+	 */
+	public static void setComplianceOptions(String compliance, Map options) {
+		switch((int) (CompilerOptions.versionToJdkLevel(compliance) >>> 16)) {
+			case ClassFileConstants.MAJOR_VERSION_1_3:
+				options.put(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_3);
+				options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_3);
+				options.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_1);
+				options.put(JavaCore.COMPILER_PB_ASSERT_IDENTIFIER, JavaCore.IGNORE);
+				options.put(JavaCore.COMPILER_PB_ENUM_IDENTIFIER, JavaCore.IGNORE);
+				break;
+			case ClassFileConstants.MAJOR_VERSION_1_4:
+				options.put(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_4);
+				options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_3);
+				options.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_2);
+				options.put(JavaCore.COMPILER_PB_ASSERT_IDENTIFIER, JavaCore.WARNING);
+				options.put(JavaCore.COMPILER_PB_ENUM_IDENTIFIER, JavaCore.WARNING);
+				break;
+			case ClassFileConstants.MAJOR_VERSION_1_5:
+				options.put(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_5);
+				options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_5);
+				options.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_5);
+				options.put(JavaCore.COMPILER_PB_ASSERT_IDENTIFIER, JavaCore.ERROR);
+				options.put(JavaCore.COMPILER_PB_ENUM_IDENTIFIER, JavaCore.ERROR);
+				options.put(JavaCore.COMPILER_CODEGEN_INLINE_JSR_BYTECODE, JavaCore.ENABLED);
+				break;
+			case ClassFileConstants.MAJOR_VERSION_1_6:
+				options.put(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_6);
+				options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_6);
+				options.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_6);
+				options.put(JavaCore.COMPILER_PB_ASSERT_IDENTIFIER, JavaCore.ERROR);
+				options.put(JavaCore.COMPILER_PB_ENUM_IDENTIFIER, JavaCore.ERROR);
+				options.put(JavaCore.COMPILER_CODEGEN_INLINE_JSR_BYTECODE, JavaCore.ENABLED);
+				break;
+			case ClassFileConstants.MAJOR_VERSION_1_7:
+				options.put(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_7);
+				options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_7);
+				options.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_7);
+				options.put(JavaCore.COMPILER_PB_ASSERT_IDENTIFIER, JavaCore.ERROR);
+				options.put(JavaCore.COMPILER_PB_ENUM_IDENTIFIER, JavaCore.ERROR);
+				options.put(JavaCore.COMPILER_CODEGEN_INLINE_JSR_BYTECODE, JavaCore.ENABLED);
+		}
+	}
+
+	/**
+	 * Sets the current table of options. All and only the options explicitly
+	 * included in the given table are remembered; all previous option settings
+	 * are forgotten, including ones not explicitly mentioned.
 	 * <p>
-	 * For a complete description of the configurable options, see <code>getDefaultOptions</code>.
+	 * For a complete description of the configurable options, see
+	 * <code>getDefaultOptions</code>.
 	 * </p>
-	 * 
-	 * @param newOptions the new options (key type: <code>String</code>; value type: <code>String</code>),
-	 *   or <code>null</code> to reset all options to their default values
+	 *
+	 * @param newOptions
+	 *            the new options (key type: <code>String</code>; value type:
+	 *            <code>String</code>), or <code>null</code> to reset all
+	 *            options to their default values
 	 * @see JavaCore#getDefaultOptions()
 	 * @see JavaCorePreferenceInitializer for changing default settings
 	 */
@@ -4116,4 +4718,4 @@
 		super.start(context);
 		JavaModelManager.getJavaModelManager().startup();
 	}
-}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaModelException.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaModelException.java
index 5e20900..ed7842c 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaModelException.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaModelException.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/NamingConventions.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/NamingConventions.java
index 19cac72..c4d42a9 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/NamingConventions.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/NamingConventions.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -12,6 +12,7 @@
 
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.codeassist.impl.AssistOptions;
+import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
 import org.eclipse.jdt.internal.core.INamingRequestor;
 import org.eclipse.jdt.internal.core.InternalNamingConventions;
 
@@ -23,14 +24,14 @@
  * <p>
  * The possible options are :
  * <ul>
- * <li>CODEASSIST_FIELD_PREFIXES : Define the Prefixes for Field Name.</li>
- * <li>CODEASSIST_STATIC_FIELD_PREFIXES : Define the Prefixes for Static Field Name.</li>
- * <li>CODEASSIST_LOCAL_PREFIXES : Define the Prefixes for Local Variable Name.</li>
- * <li>CODEASSIST_ARGUMENT_PREFIXES : Define the Prefixes for Argument Name.</li>
- * <li>CODEASSIST_FIELD_SUFFIXES : Define the Suffixes for Field Name.</li>
- * <li>CODEASSIST_STATIC_FIELD_SUFFIXES : Define the Suffixes for Static Field Name.</li>
- * <li>CODEASSIST_LOCAL_SUFFIXES : Define the Suffixes for Local Variable Name.</li>
- * <li>CODEASSIST_ARGUMENT_SUFFIXES : Define the Suffixes for Argument Name.</li>
+ * <li> {@link JavaCore#CODEASSIST_FIELD_PREFIXES} : Define the Prefixes for Field Name.</li>
+ * <li> {@link JavaCore#CODEASSIST_STATIC_FIELD_PREFIXES} : Define the Prefixes for Static Field Name.</li>
+ * <li> {@link JavaCore#CODEASSIST_LOCAL_PREFIXES} : Define the Prefixes for Local Variable Name.</li>
+ * <li> {@link JavaCore#CODEASSIST_ARGUMENT_PREFIXES} : Define the Prefixes for Argument Name.</li>
+ * <li> {@link JavaCore#CODEASSIST_FIELD_SUFFIXES} : Define the Suffixes for Field Name.</li>
+ * <li> {@link JavaCore#CODEASSIST_STATIC_FIELD_SUFFIXES} : Define the Suffixes for Static Field Name.</li>
+ * <li> {@link JavaCore#CODEASSIST_LOCAL_SUFFIXES} : Define the Suffixes for Local Variable Name.</li>
+ * <li> {@link JavaCore#CODEASSIST_ARGUMENT_SUFFIXES} : Define the Suffixes for Argument Name.</li>
  * </ul>
  * </p>
  * <p>
@@ -51,7 +52,7 @@
 	private static final char[] GETTER_NAME = "get".toCharArray(); //$NON-NLS-1$
 	private static final char[] SETTER_NAME = "set".toCharArray(); //$NON-NLS-1$
 	
-	private static class NamingRequestor implements INamingRequestor {
+	static class NamingRequestor implements INamingRequestor {
 		private final static int SIZE = 10;
 		
 		// for acceptNameWithPrefixAndSuffix
@@ -79,7 +80,7 @@
 		// for acceptNameWithoutPrefixAndSuffix
 		private char[][] otherResults = new char[SIZE][];
 		private int otherResultsCount = 0;
-		public void acceptNameWithPrefixAndSuffix(char[] name, boolean isFirstPrefix, boolean isFirstSuffix) {
+		public void acceptNameWithPrefixAndSuffix(char[] name, boolean isFirstPrefix, boolean isFirstSuffix, int reusedCharacters) {
 			if(isFirstPrefix && isFirstSuffix) {
 				int length = this.firstPrefixAndFirstSuffixResults.length;
 				if(length == this.firstPrefixAndFirstSuffixResultsCount) {
@@ -127,7 +128,7 @@
 			}
 		}
 
-		public void acceptNameWithPrefix(char[] name, boolean isFirstPrefix) {
+		public void acceptNameWithPrefix(char[] name, boolean isFirstPrefix, int reusedCharacters) {
 			if(isFirstPrefix) {
 				int length = this.firstPrefixResults.length;
 				if(length == this.firstPrefixResultsCount) {
@@ -153,7 +154,7 @@
 			}
 		}
 
-		public void acceptNameWithSuffix(char[] name, boolean isFirstSuffix) {
+		public void acceptNameWithSuffix(char[] name, boolean isFirstSuffix, int reusedCharacters) {
 			if(isFirstSuffix) {
 				int length = this.firstSuffixResults.length;
 				if(length == this.firstSuffixResultsCount) {
@@ -179,7 +180,7 @@
 			}
 		}
 
-		public void acceptNameWithoutPrefixAndSuffix(char[] name) {
+		public void acceptNameWithoutPrefixAndSuffix(char[] name, int reusedCharacters) {
 			int length = this.otherResults.length;
 			if(length == this.otherResultsCount) {
 				System.arraycopy(
@@ -242,8 +243,8 @@
 				char[] prefix = prefixes[i];
 				if (CharOperation.prefixEquals(prefix, name)) {
 					int currLen = prefix.length;
-					boolean lastCharIsLetter = Character.isLetter(prefix[currLen - 1]);
-					if(!lastCharIsLetter || (lastCharIsLetter && name.length > currLen && Character.isUpperCase(name[currLen]))) {
+					boolean lastCharIsLetter = ScannerHelper.isLetter(prefix[currLen - 1]);
+					if(!lastCharIsLetter || (lastCharIsLetter && name.length > currLen && ScannerHelper.isUpperCase(name[currLen]))) {
 						if (bestLength < currLen && name.length != currLen) {
 							withoutPrefixName = CharOperation.subarray(name, currLen, name.length);
 							bestLength = currLen;
@@ -269,7 +270,7 @@
 			}
 		}
 		
-		withoutSuffixName[0] = Character.toLowerCase(withoutSuffixName[0]);
+		withoutSuffixName[0] = ScannerHelper.toLowerCase(withoutSuffixName[0]);
 		return withoutSuffixName;
 	}
 
@@ -282,8 +283,8 @@
 	 * name <code>preArgsuf</code>.
 	 * </p>
 	 * <p>
-	 * This method is affected by the following JavaCore options : CODEASSIST_ARGUMENT_PREFIXES and
-	 * CODEASSIST_ARGUMENT_SUFFIXES.
+	 * This method is affected by the following JavaCore options :  {@link JavaCore#CODEASSIST_ARGUMENT_PREFIXES} and
+	 *  {@link JavaCore#CODEASSIST_ARGUMENT_SUFFIXES}.
 	 * </p>
 	 * <p>
 	 * For a complete description of these configurable options, see <code>getDefaultOptions</code>.
@@ -313,8 +314,8 @@
 	 * name <code>preArgsuf</code>.
 	 * </p>
 	 * <p>
-	 * This method is affected by the following JavaCore options : CODEASSIST_ARGUMENT_PREFIXES and
-	 * CODEASSIST_ARGUMENT_SUFFIXES.
+	 * This method is affected by the following JavaCore options :  {@link JavaCore#CODEASSIST_ARGUMENT_PREFIXES} and
+	 *  {@link JavaCore#CODEASSIST_ARGUMENT_SUFFIXES}.
 	 * </p>
 	 * <p>
 	 * For a complete description of these configurable options, see <code>getDefaultOptions</code>.
@@ -340,9 +341,9 @@
 	 * name <code>preFieldsuf</code>.
 	 * </p>
 	 * <p>
-	 * This method is affected by the following JavaCore options : CODEASSIST_FIELD_PREFIXES, 
-	 * CODEASSIST_FIELD_SUFFIXES for instance field and CODEASSIST_STATIC_FIELD_PREFIXES,
-	 * CODEASSIST_STATIC_FIELD_SUFFIXES for static field.
+	 * This method is affected by the following JavaCore options : {@link JavaCore#CODEASSIST_FIELD_PREFIXES} } , 
+	 *  {@link JavaCore#CODEASSIST_FIELD_SUFFIXES} for instance field and  {@link JavaCore#CODEASSIST_STATIC_FIELD_PREFIXES},
+	 *  {@link JavaCore#CODEASSIST_STATIC_FIELD_SUFFIXES} for static field.
 	 * </p>
 	 * <p>
 	 * For a complete description of these configurable options, see <code>getDefaultOptions</code>.
@@ -376,9 +377,9 @@
 	 * name <code>preFieldsuf</code>.
 	 * </p>
 	 * <p>
-	 * This method is affected by the following JavaCore options : CODEASSIST_FIELD_PREFIXES, 
-	 * CODEASSIST_FIELD_SUFFIXES for instance field and CODEASSIST_STATIC_FIELD_PREFIXES,
-	 * CODEASSIST_STATIC_FIELD_SUFFIXES for static field.
+	 * This method is affected by the following JavaCore options :  {@link JavaCore#CODEASSIST_FIELD_PREFIXES}, 
+	 *  {@link JavaCore#CODEASSIST_FIELD_SUFFIXES} for instance field and  {@link JavaCore#CODEASSIST_STATIC_FIELD_PREFIXES},
+	 *  {@link JavaCore#CODEASSIST_STATIC_FIELD_SUFFIXES} for static field.
 	 * </p>
 	 * <p>
 	 * For a complete description of these configurable options, see <code>getDefaultOptions</code>.
@@ -406,8 +407,8 @@
 	 * name <code>preLocalsuf</code>.
 	 * </p>
 	 * <p>
-	 * This method is affected by the following JavaCore options : CODEASSIST_LOCAL_PREFIXES and 
-	 * CODEASSIST_LOCAL_SUFFIXES.
+	 * This method is affected by the following JavaCore options :  {@link JavaCore#CODEASSIST_LOCAL_PREFIXES} and 
+	 *  {@link JavaCore#CODEASSIST_LOCAL_SUFFIXES}.
 	 * </p>
 	 * <p>
 	 * For a complete description of these configurable options, see <code>getDefaultOptions</code>.
@@ -437,8 +438,8 @@
 	 * name <code>preLocalsuf</code>.
 	 * </p>
 	 * <p>
-	 * This method is affected by the following JavaCore options : CODEASSIST_LOCAL_PREFIXES and 
-	 * CODEASSIST_LOCAL_SUFFIXES.
+	 * This method is affected by the following JavaCore options :  {@link JavaCore#CODEASSIST_LOCAL_PREFIXES} and 
+	 *  {@link JavaCore#CODEASSIST_LOCAL_SUFFIXES}.
 	 * </p>
 	 * <p>
 	 * For a complete description of these configurable options, see <code>getDefaultOptions</code>.
@@ -465,8 +466,8 @@
 	 * and <code>name</code>.
 	 * </p>
 	 * <p>
-	 * This method is affected by the following JavaCore options : CODEASSIST_ARGUMENT_PREFIXES and 
-	 * CODEASSIST_ARGUMENT_SUFFIXES.
+	 * This method is affected by the following JavaCore options :  {@link JavaCore#CODEASSIST_ARGUMENT_PREFIXES} and 
+	 *  {@link JavaCore#CODEASSIST_ARGUMENT_SUFFIXES}.
 	 * </p>
 	 * <p>
 	 * For a complete description of these configurable options, see <code>getDefaultOptions</code>.
@@ -490,6 +491,7 @@
 			packageName,
 			qualifiedTypeName,
 			dim,
+			null,
 			excludedNames,
 			requestor);
 
@@ -506,8 +508,8 @@
 	 * and <code>name</code>.
 	 * </p>
 	 * <p>
-	 * This method is affected by the following JavaCore options : CODEASSIST_ARGUMENT_PREFIXES and 
-	 * CODEASSIST_ARGUMENT_SUFFIXES.
+	 * This method is affected by the following JavaCore options :  {@link JavaCore#CODEASSIST_ARGUMENT_PREFIXES} and 
+	 *  {@link JavaCore#CODEASSIST_ARGUMENT_SUFFIXES}.
 	 * </p>
 	 * <p>
 	 * For a complete description of these configurable options, see <code>getDefaultOptions</code>.
@@ -543,9 +545,9 @@
 	 * and <code>name</code>.
 	 * </p>
 	 * <p>
-	 * This method is affected by the following JavaCore options : CODEASSIST_FIELD_PREFIXES, 
-	 * CODEASSIST_FIELD_SUFFIXES and for instance field and CODEASSIST_STATIC_FIELD_PREFIXES,
-	 * CODEASSIST_STATIC_FIELD_SUFFIXES for static field.
+	 * This method is affected by the following JavaCore options :  {@link JavaCore#CODEASSIST_FIELD_PREFIXES}, 
+	 *  {@link JavaCore#CODEASSIST_FIELD_SUFFIXES} and for instance field and  {@link JavaCore#CODEASSIST_STATIC_FIELD_PREFIXES},
+	 *  {@link JavaCore#CODEASSIST_STATIC_FIELD_SUFFIXES} for static field.
 	 * </p>
 	 * <p>
 	 * For a complete description of these configurable options, see <code>getDefaultOptions</code>.
@@ -573,6 +575,7 @@
 			qualifiedTypeName,
 			dim,
 			modifiers,
+			null,
 			excludedNames,
 			requestor);
 
@@ -589,9 +592,9 @@
 	 * and <code>name</code>.
 	 * </p>
 	 * <p>
-	 * This method is affected by the following JavaCore options : CODEASSIST_FIELD_PREFIXES, 
-	 * CODEASSIST_FIELD_SUFFIXES and for instance field and CODEASSIST_STATIC_FIELD_PREFIXES,
-	 * CODEASSIST_STATIC_FIELD_SUFFIXES for static field.
+	 * This method is affected by the following JavaCore options :  {@link JavaCore#CODEASSIST_FIELD_PREFIXES}, 
+	 *  {@link JavaCore#CODEASSIST_FIELD_SUFFIXES} and for instance field and  {@link JavaCore#CODEASSIST_STATIC_FIELD_PREFIXES},
+	 *  {@link JavaCore#CODEASSIST_STATIC_FIELD_SUFFIXES} for static field.
 	 * </p>
 	 * <p>
 	 * For a complete description of these configurable options, see <code>getDefaultOptions</code>.
@@ -632,8 +635,8 @@
 	 * and <code>name</code>.
 	 * </p>
 	 * <p>
-	 * This method is affected by the following JavaCore options : CODEASSIST_LOCAL_PREFIXES and
-	 * CODEASSIST_LOCAL_SUFFIXES.
+	 * This method is affected by the following JavaCore options :  {@link JavaCore#CODEASSIST_LOCAL_PREFIXES} and
+	 *  {@link JavaCore#CODEASSIST_LOCAL_SUFFIXES}.
 	 * </p>
 	 * <p>
 	 * For a complete description of these configurable options, see <code>getDefaultOptions</code>.
@@ -657,6 +660,7 @@
 			packageName,
 			qualifiedTypeName,
 			dim,
+			null,
 			excludedNames,
 			requestor);
 
@@ -673,8 +677,8 @@
 	 * and <code>name</code>.
 	 * </p>
 	 * <p>
-	 * This method is affected by the following JavaCore options : CODEASSIST_LOCAL_PREFIXES and
-	 * CODEASSIST_LOCAL_SUFFIXES.
+	 * This method is affected by the following JavaCore options :  {@link JavaCore#CODEASSIST_LOCAL_PREFIXES} and
+	 *  {@link JavaCore#CODEASSIST_LOCAL_SUFFIXES}.
 	 * </p>
 	 * <p>
 	 * For a complete description of these configurable options, see <code>getDefaultOptions</code>.
@@ -711,9 +715,9 @@
 	 * for boolean field or <code>getPreFieldNamesuf</code> for others.
 	 * </p>
 	 * <p>
-	 * This method is affected by the following JavaCore options : CODEASSIST_FIELD_PREFIXES, 
-	 * CODEASSIST_FIELD_SUFFIXES for instance field and CODEASSIST_STATIC_FIELD_PREFIXES,
-	 * CODEASSIST_STATIC_FIELD_SUFFIXES for static field.
+	 * This method is affected by the following JavaCore options :  {@link JavaCore#CODEASSIST_FIELD_PREFIXES}, 
+	 *  {@link JavaCore#CODEASSIST_FIELD_SUFFIXES} for instance field and  {@link JavaCore#CODEASSIST_STATIC_FIELD_PREFIXES},
+	 *  {@link JavaCore#CODEASSIST_STATIC_FIELD_SUFFIXES} for static field.
 	 * </p>
 	 * <p>
 	 * For a complete description of these configurable options, see <code>getDefaultOptions</code>.
@@ -737,7 +741,7 @@
 			char[] name = removePrefixAndSuffixForFieldName(project, fieldName, modifiers);
 			int prefixLen =  GETTER_BOOL_NAME.length;
 			if (CharOperation.prefixEquals(GETTER_BOOL_NAME, name) 
-				&& name.length > prefixLen && Character.isUpperCase(name[prefixLen])) {
+				&& name.length > prefixLen && ScannerHelper.isUpperCase(name[prefixLen])) {
 				return suggestNewName(name, excludedNames);
 			} else {
 				return suggestNewName(
@@ -763,9 +767,9 @@
 	 * for boolean field or <code>getPreFieldNamesuf</code> for others.
 	 * </p>
 	 * <p>
-	 * This method is affected by the following JavaCore options : CODEASSIST_FIELD_PREFIXES, 
-	 * CODEASSIST_FIELD_SUFFIXES for instance field and CODEASSIST_STATIC_FIELD_PREFIXES,
-	 * CODEASSIST_STATIC_FIELD_SUFFIXES for static field.
+	 * This method is affected by the following JavaCore options :  {@link JavaCore#CODEASSIST_FIELD_PREFIXES}, 
+	 *  {@link JavaCore#CODEASSIST_FIELD_SUFFIXES} for instance field and  {@link JavaCore#CODEASSIST_STATIC_FIELD_PREFIXES},
+	 *  {@link JavaCore#CODEASSIST_STATIC_FIELD_SUFFIXES} for static field.
 	 * </p>
 	 * <p>
 	 * For a complete description of these configurable options, see <code>getDefaultOptions</code>.
@@ -803,9 +807,9 @@
 	 * If there is no prefix and suffix the proposal is <code>setPreFieldNamesuf</code>.
 	 * </p>
 	 * <p>
-	 * This method is affected by the following JavaCore options : CODEASSIST_FIELD_PREFIXES, 
-	 * CODEASSIST_FIELD_SUFFIXES for instance field and CODEASSIST_STATIC_FIELD_PREFIXES,
-	 * CODEASSIST_STATIC_FIELD_SUFFIXES for static field.
+	 * This method is affected by the following JavaCore options :  {@link JavaCore#CODEASSIST_FIELD_PREFIXES}, 
+	 *  {@link JavaCore#CODEASSIST_FIELD_SUFFIXES} for instance field and  {@link JavaCore#CODEASSIST_STATIC_FIELD_PREFIXES},
+	 *  {@link JavaCore#CODEASSIST_STATIC_FIELD_SUFFIXES} for static field.
 	 * </p>
 	 * <p>
 	 * For a complete description of these configurable options, see <code>getDefaultOptions</code>.
@@ -830,7 +834,7 @@
 			char[] name = removePrefixAndSuffixForFieldName(project, fieldName, modifiers);
 			int prefixLen =  GETTER_BOOL_NAME.length;
 			if (CharOperation.prefixEquals(GETTER_BOOL_NAME, name) 
-				&& name.length > prefixLen && Character.isUpperCase(name[prefixLen])) {
+				&& name.length > prefixLen && ScannerHelper.isUpperCase(name[prefixLen])) {
 				name = CharOperation.subarray(name, prefixLen, name.length);
 				return suggestNewName(
 					CharOperation.concat(SETTER_NAME, suggestAccessorName(project, name, modifiers)),
@@ -859,9 +863,9 @@
 	 * If there is no prefix and suffix the proposal is <code>setPreFieldNamesuf</code>.
 	 * </p>
 	 * <p>
-	 * This method is affected by the following JavaCore options : CODEASSIST_FIELD_PREFIXES, 
-	 * CODEASSIST_FIELD_SUFFIXES for instance field and CODEASSIST_STATIC_FIELD_PREFIXES,
-	 * CODEASSIST_STATIC_FIELD_SUFFIXES for static field.
+	 * This method is affected by the following JavaCore options :  {@link JavaCore#CODEASSIST_FIELD_PREFIXES}, 
+	 *  {@link JavaCore#CODEASSIST_FIELD_SUFFIXES} for instance field and  {@link JavaCore#CODEASSIST_STATIC_FIELD_PREFIXES},
+	 *  {@link JavaCore#CODEASSIST_STATIC_FIELD_SUFFIXES} for static field.
 	 * </p>
 	 * <p>
 	 * For a complete description of these configurable options, see <code>getDefaultOptions</code>.
@@ -892,8 +896,8 @@
 	
 	private static char[] suggestAccessorName(IJavaProject project, char[] fieldName, int modifiers) {
 		char[] name = removePrefixAndSuffixForFieldName(project, fieldName, modifiers);
-		if (name.length > 0 && Character.isLowerCase(name[0])) {
-			name[0] = Character.toUpperCase(name[0]);
+		if (name.length > 0 && ScannerHelper.isLowerCase(name[0])) {
+			name[0] = ScannerHelper.toUpperCase(name[0]);
 		}
 		return name;
 	}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/Signature.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/Signature.java
index b2fac6f..680eab7 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/Signature.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/Signature.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -14,14 +14,16 @@
 import java.util.ArrayList;
 
 import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
 import org.eclipse.jdt.internal.core.util.Util;
 
 
 /**
  * Provides methods for encoding and decoding type and method signature strings.
  * <p>
- * Signatures obtained from parsing source (".java") files differ subtly from
- * ones obtained from pre-compiled binary (".class") files in class names are
+ * Signatures obtained from parsing source files (i.e. files with one of the 
+ * {@link JavaCore#getJavaLikeExtensions() Java-like extensions}) differ subtly 
+ * from ones obtained from pre-compiled binary (".class") files in class names are
  * usually left unresolved in the former. For example, the normal resolved form
  * of the type "String" embeds the class's package name ("Ljava.lang.String;"
  * or "Ljava/lang/String;"), whereas the unresolved form contains only what is
@@ -30,10 +32,10 @@
  * <p>
  * Generic types introduce to the Java language in J2SE 1.5 add three new
  * facets to signatures: type variables, parameterized types with type arguments,
- * and formal type parameters. <it>Rich</it> signatures containing these facets
+ * and formal type parameters. <i>Rich</i> signatures containing these facets
  * only occur when dealing with code that makes overt use of the new language
  * features. All other code, and certainly all Java code written or compiled
- * with J2SE 1.4 or earlier, involved only <it>simple</it> signatures.
+ * with J2SE 1.4 or earlier, involved only <i>simple</i> signatures.
  * </p>
  * <p>
  * Note that the "Q" and "!" formats are specific to Eclipse; the remainder
@@ -61,10 +63,14 @@
  * ResolvedClassTypeSignature ::= // resolved named type (in compiled code)
  *     "L" + Identifier + OptionalTypeArguments
  *           ( ( "." | "/" ) + Identifier + OptionalTypeArguments )* + ";"
+ *     | OptionalTypeParameters + "L" + Identifier +
+ *           ( ( "." | "/" ) + Identifier )* + ";"
  * 
  * UnresolvedClassTypeSignature ::= // unresolved named type (in source code)
  *     "Q" + Identifier + OptionalTypeArguments
  *           ( ( "." | "/" ) + Identifier + OptionalTypeArguments )* + ";"
+ *     | OptionalTypeParameters "Q" + Identifier +
+ *           ( ( "." | "/" ) + Identifier )* + ";"
  * 
  * OptionalTypeArguments ::=
  *     "&lt;" + TypeArgument+ + "&gt;" 
@@ -75,6 +81,10 @@
  *   | "*" // wildcard ?
  *   | "+" TypeSignature // wildcard ? extends X
  *   | "-" TypeSignature // wildcard ? super X
+ *   
+ * OptionalTypeParameters ::=
+ *     "&lt;" + FormalTypeParameterSignature+ + "&gt;" 
+ *   |
  * </pre>
  * </p>
  * <p>
@@ -85,14 +95,15 @@
  *   <li><code>"QString;"</code> denotes <code>String</code> in source code</li>
  *   <li><code>"Qjava.lang.String;"</code> denotes <code>java.lang.String</code> in source code</li>
  *   <li><code>"[QString;"</code> denotes <code>String[]</code> in source code</li>
- *   <li><code>"QMap&lt;QString;&ast;&gt;;"</code> denotes <code>Map&lt;String,?&gt;</code> in source code</li>
+ *   <li><code>"QMap&lt;QString;*&gt;;"</code> denotes <code>Map&lt;String,?&gt;</code> in source code</li>
  *   <li><code>"Qjava.util.List&ltTV;&gt;;"</code> denotes <code>java.util.List&lt;V&gt;</code> in source code</li>
+ *   <li><code>"&ltE;&gt;Ljava.util.List;"</code> denotes <code>&lt;E&gt;java.util.List</code> in source code</li>
  * </ul>
  * </p>
  * <p>
  * The syntax for a method signature is: 
  * <pre>
- * MethodSignature ::= "(" + ParamTypeSignature* + ")" + ReturnTypeSignature
+ * MethodSignature ::= OptionalTypeParameters + "(" + ParamTypeSignature* + ")" + ReturnTypeSignature
  * ParamTypeSignature ::= TypeSignature
  * ReturnTypeSignature ::= TypeSignature
  * </pre>
@@ -208,7 +219,7 @@
 	/**
 	 * Character constant indicating an unbound wildcard type argument 
 	 * in a signature.
-	 * Value is <code>'&ast;'</code>.
+	 * Value is <code>'*'</code>.
 	 * @since 3.0
 	 */
 	public static final char C_STAR	= '*';
@@ -300,7 +311,7 @@
 
 	/**
 	 * Character constant indicating a capture of a wildcard type in a 
-	 * signature.Value is <code>'!'</code>.
+	 * signature. Value is <code>'!'</code>.
 	 * @since 3.1
 	 */
 	public static final char C_CAPTURE	= '!';
@@ -413,8 +424,6 @@
 	private static final char[] EXTENDS = "extends".toCharArray(); //$NON-NLS-1$
 	private static final char[] SUPER = "super".toCharArray(); //$NON-NLS-1$
 	private static final char[] CAPTURE = "capture-of".toCharArray(); //$NON-NLS-1$
-	
-	private static final String EMPTY = new String(CharOperation.NO_CHAR);
 		
 private Signature() {
 	// Not instantiable
@@ -434,7 +443,7 @@
             case ',' :
                 return pos;
 			default:
-			    if (Character.isWhitespace(currentChar))
+			    if (ScannerHelper.isWhitespace(currentChar))
 			    	return pos;
 			    
         }
@@ -652,7 +661,7 @@
 			    count++;
 			    break;
 			default:
-			    if (currentChar == ' ' || Character.isWhitespace(currentChar)) {
+			    if (currentChar == ' ' || ScannerHelper.isWhitespace(currentChar)) {
 			        if (lastAppendedChar == C_DOT) { // allow spaces after a dot
 			            pos = consumeWhitespace(typeName, pos, length) - 1; // will be incremented
 			            break; 
@@ -1409,7 +1418,7 @@
 			if (i < 0 || i >= length) 
 				throw new IllegalArgumentException();
 			// iterate over bounds
-			nextBound: while (methodOrTypeSignature[i] == ':') {
+			while (methodOrTypeSignature[i] == ':') {
 				i++; // skip colon
 				switch (methodOrTypeSignature[i]) {
 					case ':':
@@ -1597,9 +1606,9 @@
  * For example:
  * <pre>
  * <code>
- * getQualifier("java.lang.Object") -> "java.lang"
- * getQualifier("Outer.Inner") -> "Outer"
- * getQualifier("java.util.List<java.lang.String>") -> "java.util"
+ * getQualifier("java.lang.Object") -&gt; "java.lang"
+ * getQualifier("Outer.Inner") -&gt; "Outer"
+ * getQualifier("java.util.List&lt;java.lang.String&gt;") -&gt; "java.util"
  * </code>
  * </pre>
  * </p>
@@ -1611,7 +1620,7 @@
  */
 public static String getQualifier(String name) {
 	char[] qualifier = getQualifier(name.toCharArray());
-	if (qualifier.length == 0) return EMPTY;
+	if (qualifier.length == 0) return org.eclipse.jdt.internal.compiler.util.Util.EMPTY_STRING;
 	return new String(qualifier);
 }
 /**
@@ -1840,10 +1849,10 @@
  * For example:
  * <pre>
  * <code>
- * getSimpleName("java.lang.Object") -> "Object"
+ * getSimpleName("java.lang.Object") -&gt; "Object"
  * </code>
  * <code>
- * getSimpleName("java.util.Map<java.lang.String, java.lang.Object>") -> "Map<String,Object>"
+ * getSimpleName("java.util.Map&lt;java.lang.String, java.lang.Object&gt;") -&gt; "Map&lt;String,Object&gt;"
  * </code>
  * </pre>
  * </p>
@@ -1918,6 +1927,10 @@
 			case '.':
 				if (depth == 0) {
 					lastDot = i;
+					char c = name[start];
+					if (c == C_EXTENDS || c == C_SUPER) {
+						buffer.append(c);
+					}
 					break lastDotLookup;
 				}
 				break;
@@ -2034,10 +2047,11 @@
  * For example:
  * <pre>
  * <code>
- * getSimpleNames("java.lang.Object") -> {"java", "lang", "Object"}
- * getSimpleNames("Object") -> {"Object"}
- * getSimpleNames("") -> {}
- * getSimpleNames("java.util.List<java.lang.String>") -> {"java", "lang", "List<java.lang.String"}
+ * getSimpleNames("java.lang.Object") -&gt; {"java", "lang", "Object"}
+ * getSimpleNames("Object") -&gt; {"Object"}
+ * getSimpleNames("") -&gt; {}
+ * getSimpleNames("java.util.List&lt;java.lang.String&gt;") -&gt; 
+ *   {"java", "util", "List&lt;java.lang.String&gt;"}
  * </code>
  * </pre>
  *
@@ -2058,8 +2072,8 @@
  * For example (using equivalent string-based method):
  * <pre>
  * <code>
- * removeCapture("LTest<!+Ljava.lang.Throwable;>;")
- * will return: "LTest<+Ljava.lang.Throwable;>;"
+ * removeCapture("LTest&lt;!+Ljava.lang.Throwable;&gt;;")
+ * will return: "LTest&lt;+Ljava.lang.Throwable;&gt;;"
  * </code>
  * </pre>
  * </p>
@@ -2072,25 +2086,7 @@
  * @since 3.1
  */
 public static char[] removeCapture(char[] methodOrTypeSignature) {
-		
-// TODO (frederic) Create remove(char[], char) method on CharOperation and call it from here
-	char[] result = null;
-	int count = 0;
-	for (int i = 0, length = methodOrTypeSignature.length; i < length; i++) {
-		char c = methodOrTypeSignature[i];
-		if (c == C_CAPTURE) {
-			if (result == null) {
-				result = new char[length];
-				System.arraycopy(methodOrTypeSignature, 0, result, 0, i);
-				count = i;
-			}
-		} else if (result != null) {
-			result[count++] = c;
-		}
-	}
-	if (result == null) return methodOrTypeSignature;
-	System.arraycopy(result, 0, result = new char[count], 0, count);
-	return result;
+	return CharOperation.remove(methodOrTypeSignature, C_CAPTURE);
 }
 	
 /**
@@ -2102,8 +2098,8 @@
  * For example:
  * <pre>
  * <code>
- * removeCapture("LTest<!+Ljava.lang.Throwable;>;")
- * will return: "LTest<+Ljava.lang.Throwable;>;"
+ * removeCapture("LTest&lt;!+Ljava.lang.Throwable;&gt;;")
+ * will return: "LTest&lt;+Ljava.lang.Throwable;&gt;;"
  * </code>
  * </pre>
  * </p>
@@ -2411,7 +2407,7 @@
 		throw new IllegalArgumentException();
 	}
 	char c = string[start];
-	if (c != C_CAPTURE) { //$NON-NLS-1$
+	if (c != C_CAPTURE) {
 		throw new IllegalArgumentException();
 	}
 	buffer.append(CAPTURE).append(' ');
@@ -2440,7 +2436,7 @@
 		throw new IllegalArgumentException();
 	}
 	char c = string[start];
-	if (c != C_ARRAY) { //$NON-NLS-1$
+	if (c != C_ARRAY) {
 		throw new IllegalArgumentException();
 	}
 	
@@ -2499,6 +2495,8 @@
 	}
 	int p = start + 1;
 	int checkpoint = buffer.length();
+	int innerTypeStart = -1;
+	boolean inAnonymousType = false;
 	while (true) {
 		if (p >= string.length) {
 			throw new IllegalArgumentException();
@@ -2531,6 +2529,8 @@
 				}
 				break;
 			 case C_DOLLAR :
+			 	innerTypeStart = buffer.length();
+			 	inAnonymousType = false;
 			 	if (resolved) {
 					// once we hit "$" there are no more package prefixes
 					removePackageQualifiers = false;
@@ -2544,7 +2544,15 @@
 			 	}
 			 	break;
 			 default :
-				buffer.append(c);
+				if (innerTypeStart != -1 && !inAnonymousType && Character.isDigit(c)) {
+					inAnonymousType = true;
+					buffer.setLength(innerTypeStart); // remove '.'
+					buffer.insert(checkpoint, "new "); //$NON-NLS-1$
+					buffer.append("(){}"); //$NON-NLS-1$
+				}
+			 	if (!inAnonymousType)
+					buffer.append(c);
+				innerTypeStart = -1;
 		}
 		p++;
 	}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ToolFactory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ToolFactory.java
index 0416797..d8db37b 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ToolFactory.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ToolFactory.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -12,14 +12,17 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
 import java.util.Map;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
+import org.eclipse.core.resources.IFile;
 import org.eclipse.core.runtime.*;
-import org.eclipse.core.runtime.CoreException;
 import org.eclipse.jdt.core.compiler.IScanner;
 import org.eclipse.jdt.core.formatter.CodeFormatter;
+import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants;
 import org.eclipse.jdt.core.util.ClassFileBytesDisassembler;
 import org.eclipse.jdt.core.util.ClassFormatException;
 import org.eclipse.jdt.core.util.IClassFileReader;
@@ -44,6 +47,33 @@
  * @since 2.0
  */
 public class ToolFactory {
+	
+	/**
+	 * This mode is used for formatting new code when some formatter options should not be used. 
+	 * In particular, options that preserve the indentation of comments are not used. 
+	 * In the future,  newly added options may be ignored as well.
+	 * <p>Clients that are formatting new code are recommended to use this mode.
+	 * </p>
+	 * 
+	 * @see DefaultCodeFormatterConstants#FORMATTER_NEVER_INDENT_BLOCK_COMMENTS_ON_FIRST_COLUMN
+	 * @see DefaultCodeFormatterConstants#FORMATTER_NEVER_INDENT_LINE_COMMENTS_ON_FIRST_COLUMN
+	 * @see #createCodeFormatter(Map, int)
+	 * @since 3.3
+	 */
+	public static final int M_FORMAT_NEW = new Integer(0).intValue();
+	
+	/**
+	 * This mode is used for formatting existing code when all formatter options should be used. 
+	 * In particular, options that preserve the indentation of comments are used. 
+	 * <p>Clients that are formatting existing code are recommended to use this mode.
+	 * </p>
+	 *
+	 * @see DefaultCodeFormatterConstants#FORMATTER_NEVER_INDENT_BLOCK_COMMENTS_ON_FIRST_COLUMN
+	 * @see DefaultCodeFormatterConstants#FORMATTER_NEVER_INDENT_LINE_COMMENTS_ON_FIRST_COLUMN
+	 * @see #createCodeFormatter(Map, int)
+	 * @since 3.3
+	 */
+	public static final int M_FORMAT_EXISTING = new Integer(1).intValue();
 
 	/**
 	 * Create an instance of a code formatter. A code formatter implementation can be contributed via the 
@@ -53,7 +83,7 @@
 	 * @return an instance of a code formatter
 	 * @see ICodeFormatter
 	 * @see ToolFactory#createDefaultCodeFormatter(Map)
-	 * @deprecated - should use #createCodeFormatter(Map) instead. Extension point is discontinued
+	 * @deprecated Use {@link #createCodeFormatter(Map)} instead. Extension point is discontinued
 	 */
 	public static ICodeFormatter createCodeFormatter(){
 		
@@ -83,7 +113,15 @@
 	}
 
 	/**
-	 * Create an instance of the built-in code formatter. 
+	 * Create an instance of the built-in code formatter.
+	 * <p>The given options should at least provide the source level ({@link JavaCore#COMPILER_SOURCE}),
+	 * the  compiler compliance level ({@link JavaCore#COMPILER_COMPLIANCE}) and the target platform
+	 * ({@link JavaCore#COMPILER_CODEGEN_TARGET_PLATFORM}).
+	 * Without these options, it is not possible for the code formatter to know what kind of source it needs to format.
+	 * </p><p>
+	 * Note this is equivalent to <code>createCodeFormatter(options, M_FORMAT_NEW)</code>. Thus some code formatter options
+	 * may be ignored. See @{link {@link #M_FORMAT_NEW} for more details.
+	 * </p>
 	 * @param options - the options map to use for formatting with the default code formatter. Recognized options
 	 * 	are documented on <code>JavaCore#getDefaultOptions()</code>. If set to <code>null</code>, then use 
 	 * 	the current settings from <code>JavaCore#getOptions</code>.
@@ -93,43 +131,41 @@
 	 * @since 3.0
 	 */
 	public static CodeFormatter createCodeFormatter(Map options){
-		if (options == null) options = JavaCore.getOptions();
-		return new DefaultCodeFormatter(options);
+		return createCodeFormatter(options, M_FORMAT_NEW);
 	}
 
 	/**
-	 * Create an instance of the built-in code formatter. A code formatter implementation can be contributed via the 
-	 * extension point "org.eclipse.jdt.core.codeFormatter". If unable to find a registered extension, the factory will 
-	 * default to using the default code formatter.
+	 * Create an instance of the built-in code formatter.
+	 * <p>The given options should at least provide the source level ({@link JavaCore#COMPILER_SOURCE}),
+	 * the  compiler compliance level ({@link JavaCore#COMPILER_COMPLIANCE}) and the target platform
+	 * ({@link JavaCore#COMPILER_CODEGEN_TARGET_PLATFORM}).
+	 * Without these options, it is not possible for the code formatter to know what kind of source it needs to format.
+	 * </p>
+	 * <p>The given mode determines what options should be enabled when formatting the code. It can have the following
+	 * values: {@link #M_FORMAT_NEW}, {@link #M_FORMAT_EXISTING}, but other values may be added in the future.
+	 * </p>
 	 * 
-	 * @param options - the options map to use for formatting with the default code formatter. Recognized options
+	 * @param options the options map to use for formatting with the default code formatter. Recognized options
 	 * 	are documented on <code>JavaCore#getDefaultOptions()</code>. If set to <code>null</code>, then use 
 	 * 	the current settings from <code>JavaCore#getOptions</code>.
+	 * @param mode the given mode to modify the given options.
+	 *
 	 * @return an instance of the built-in code formatter
-	 * @see ICodeFormatter
-	 * @see ToolFactory#createCodeFormatter()
+	 * @see CodeFormatter
 	 * @see JavaCore#getOptions()
-	 * @deprecated - use #createCodeFormatter(Map) instead
+	 * @since 3.3
 	 */
-	public static ICodeFormatter createDefaultCodeFormatter(Map options){
+	public static CodeFormatter createCodeFormatter(Map options, int mode) {
 		if (options == null) options = JavaCore.getOptions();
-		return new org.eclipse.jdt.internal.formatter.old.CodeFormatter(options);
-	}
-	
-	/**
-	 * Create a classfile bytecode disassembler, able to produce a String representation of a given classfile.
-	 * 
-	 * @return a classfile bytecode disassembler
-	 * @see org.eclipse.jdt.core.util.IClassFileDisassembler
-	 * @deprecated - should use factory method creating ClassFileBytesDisassembler instead 
-	 */
-	public static org.eclipse.jdt.core.util.IClassFileDisassembler createDefaultClassFileDisassembler(){
-		class DeprecatedDisassembler extends Disassembler implements org.eclipse.jdt.core.util.IClassFileDisassembler {
-			// for backward compatibility, defines a disassembler which implements IClassFileDisassembler
+		Map currentOptions = new HashMap(options);
+		if (mode == M_FORMAT_NEW) {
+			// disable the option for not indenting comments starting on first column
+			currentOptions.put(DefaultCodeFormatterConstants.FORMATTER_NEVER_INDENT_BLOCK_COMMENTS_ON_FIRST_COLUMN, DefaultCodeFormatterConstants.FALSE);
+			currentOptions.put(DefaultCodeFormatterConstants.FORMATTER_NEVER_INDENT_LINE_COMMENTS_ON_FIRST_COLUMN, DefaultCodeFormatterConstants.FALSE);
 		}
-		return new DeprecatedDisassembler();
+		return new DefaultCodeFormatter(currentOptions);
 	}
-	
+
 	/**
 	 * Create a classfile bytecode disassembler, able to produce a String representation of a given classfile.
 	 * 
@@ -140,30 +176,20 @@
 	public static ClassFileBytesDisassembler createDefaultClassFileBytesDisassembler(){
 		return new Disassembler();
 	}
-
+	
 	/**
-	 * Create a default classfile reader, able to expose the internal representation of a given classfile
-	 * according to the decoding flag used to initialize the reader.
-	 * Answer null if the file named fileName doesn't represent a valid .class file.
-	 * The fileName has to be an absolute OS path to the given .class file.
+	 * Create a classfile bytecode disassembler, able to produce a String representation of a given classfile.
 	 * 
-	 * The decoding flags are described in IClassFileReader.
-	 * 
-	 * @param fileName the name of the file to be read
-	 * @param decodingFlag the flag used to decode the class file reader.
-	 * @return a default classfile reader
-	 * 
-	 * @see IClassFileReader
+	 * @return a classfile bytecode disassembler
+	 * @see org.eclipse.jdt.core.util.IClassFileDisassembler
+	 * @deprecated Use {@link #createDefaultClassFileBytesDisassembler()} instead 
 	 */
-	public static IClassFileReader createDefaultClassFileReader(String fileName, int decodingFlag){
-		try {
-			return new ClassFileReader(Util.getFileByteContent(new File(fileName)), decodingFlag);
-		} catch(ClassFormatException e) {
-			return null;
-		} catch(IOException e) {
-			return null;
+	public static org.eclipse.jdt.core.util.IClassFileDisassembler createDefaultClassFileDisassembler(){
+		class DeprecatedDisassembler extends Disassembler implements org.eclipse.jdt.core.util.IClassFileDisassembler {
+			// for backward compatibility, defines a disassembler which implements IClassFileDisassembler
 		}
-	}	
+		return new DeprecatedDisassembler();
+	}
 	
 	/**
 	 * Create a classfile reader onto a classfile Java element.
@@ -198,9 +224,18 @@
 					String entryName = org.eclipse.jdt.internal.core.util.Util.concatWith(packageFragment.names, classFileName, '/');
 					return createDefaultClassFileReader(archiveName, entryName, decodingFlag);
 				} else {
-					IPath location = classfile.getResource().getLocation();
-					if (location == null) return null;
-					return createDefaultClassFileReader(location.toOSString(), decodingFlag);
+					InputStream in = null;
+					try {
+						in = ((IFile) classfile.getResource()).getContents();
+						return createDefaultClassFileReader(in, decodingFlag);
+					} finally {
+						if (in != null)
+							try {
+								in.close();
+							} catch (IOException e) {
+								// ignore
+							}
+					}
 				}
 			} catch(CoreException e){
 				// unable to read
@@ -212,6 +247,54 @@
 	/**
 	 * Create a default classfile reader, able to expose the internal representation of a given classfile
 	 * according to the decoding flag used to initialize the reader.
+	 * Answer null if the input stream contents cannot be retrieved
+	 * 
+	 * The decoding flags are described in IClassFileReader.
+	 * 
+	 * @param stream the given input stream to read
+	 * @param decodingFlag the flag used to decode the class file reader.
+	 * @return a default classfile reader
+	 * 
+	 * @see IClassFileReader
+	 * @since 3.2
+	 */
+	public static IClassFileReader createDefaultClassFileReader(InputStream stream, int decodingFlag) {
+		try {
+			return new ClassFileReader(Util.getInputStreamAsByteArray(stream, -1), decodingFlag);
+		} catch(ClassFormatException e) {
+			return null;
+		} catch(IOException e) {
+			return null;
+		}
+	}
+	
+	/**
+	 * Create a default classfile reader, able to expose the internal representation of a given classfile
+	 * according to the decoding flag used to initialize the reader.
+	 * Answer null if the file named fileName doesn't represent a valid .class file.
+	 * The fileName has to be an absolute OS path to the given .class file.
+	 * 
+	 * The decoding flags are described in IClassFileReader.
+	 * 
+	 * @param fileName the name of the file to be read
+	 * @param decodingFlag the flag used to decode the class file reader.
+	 * @return a default classfile reader
+	 * 
+	 * @see IClassFileReader
+	 */
+	public static IClassFileReader createDefaultClassFileReader(String fileName, int decodingFlag){
+		try {
+			return new ClassFileReader(Util.getFileByteContent(new File(fileName)), decodingFlag);
+		} catch(ClassFormatException e) {
+			return null;
+		} catch(IOException e) {
+			return null;
+		}
+	}
+
+	/**
+	 * Create a default classfile reader, able to expose the internal representation of a given classfile
+	 * according to the decoding flag used to initialize the reader.
 	 * Answer null if the file named zipFileName doesn't represent a valid zip file or if the zipEntryName
 	 * is not a valid entry name for the specified zip file or if the bytes don't represent a valid
 	 * .class file according to the JVM specifications.
@@ -253,7 +336,26 @@
 				}
 			}
 		}
-	}	
+	}
+	
+	/**
+	 * Create an instance of the built-in code formatter. A code formatter implementation can be contributed via the 
+	 * extension point "org.eclipse.jdt.core.codeFormatter". If unable to find a registered extension, the factory will 
+	 * default to using the default code formatter.
+	 * 
+	 * @param options - the options map to use for formatting with the default code formatter. Recognized options
+	 * 	are documented on <code>JavaCore#getDefaultOptions()</code>. If set to <code>null</code>, then use 
+	 * 	the current settings from <code>JavaCore#getOptions</code>.
+	 * @return an instance of the built-in code formatter
+	 * @see ICodeFormatter
+	 * @see ToolFactory#createCodeFormatter()
+	 * @see JavaCore#getOptions()
+	 * @deprecated Use {@link #createCodeFormatter(Map)} instead
+	 */
+	public static ICodeFormatter createDefaultCodeFormatter(Map options){
+		if (options == null) options = JavaCore.getOptions();
+		return new org.eclipse.jdt.internal.formatter.old.CodeFormatter(options);
+	}
 	
 	/**
 	 * Create a scanner, indicating the level of detail requested for tokenizing. The scanner can then be
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/WorkingCopyOwner.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/WorkingCopyOwner.java
index 24e5ece..e9ac262 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/WorkingCopyOwner.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/WorkingCopyOwner.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,61 +10,182 @@
  *******************************************************************************/
 package org.eclipse.jdt.core;
 
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Path;
 import org.eclipse.jdt.internal.core.BufferManager;
+import org.eclipse.jdt.internal.core.CompilationUnit;
 import org.eclipse.jdt.internal.core.DefaultWorkingCopyOwner;
+import org.eclipse.jdt.internal.core.ExternalJavaProject;
+import org.eclipse.jdt.internal.core.PackageFragment;
 
 /**
- * The owner of an <code>ICompilationUnit</code> handle in working copy mode. 
+ * The owner of an {@link ICompilationUnit} handle in working copy mode.
  * An owner is used to identify a working copy and to create its buffer.
  * <p>
  * Clients should subclass this class to instantiate a working copy owner that is specific to their need and that
- * they can pass in to various APIs (e.g. <code>IType.resolveType(String, WorkingCopyOwner)</code>.
- * Clients can also override the default implementation of <code>createBuffer(ICompilationUnit)</code>.
+ * they can pass in to various APIs (e.g. {@link IType#resolveType(String, WorkingCopyOwner)}.
+ * Clients can also override the default implementation of {@link #createBuffer(ICompilationUnit)}.
  * </p><p>
  * Note: even though this class has no abstract method, which means that it provides functional default behavior,
  * it is still an abstract class, as clients are intended to own their owner implementation.
  * </p>
- * @see ICompilationUnit#becomeWorkingCopy(IProblemRequestor, org.eclipse.core.runtime.IProgressMonitor)
+ * @see ICompilationUnit#becomeWorkingCopy(org.eclipse.core.runtime.IProgressMonitor)
  * @see ICompilationUnit#discardWorkingCopy()
  * @see ICompilationUnit#getWorkingCopy(org.eclipse.core.runtime.IProgressMonitor)
  * @since 3.0
  */
 public abstract class WorkingCopyOwner {
-	
+
 	/**
 	 * Sets the buffer provider of the primary working copy owner. Note that even if the
 	 * buffer provider is a working copy owner, only its <code>createBuffer(ICompilationUnit)</code>
-	 * method is used by the primary working copy owner. It doesn't replace the internal primary 
+	 * method is used by the primary working copy owner. It doesn't replace the internal primary
 	 * working owner.
  	 * <p>
 	 * This method is for internal use by the jdt-related plug-ins.
 	 * Clients outside of the jdt should not reference this method.
 	 * </p>
-	 * 
+	 *
 	 * @param primaryBufferProvider the primary buffer provider
 	 */
 	public static void setPrimaryBufferProvider(WorkingCopyOwner primaryBufferProvider) {
 		DefaultWorkingCopyOwner.PRIMARY.primaryBufferProvider = primaryBufferProvider;
 	}
-	
+
 	/**
 	 * Creates a buffer for the given working copy.
 	 * The new buffer will be initialized with the contents of the underlying file
-	 * if and only if it was not already initialized by the compilation owner (a buffer is 
+	 * if and only if it was not already initialized by the compilation owner (a buffer is
 	 * uninitialized if its content is <code>null</code>).
 	 * <p>
 	 * Note: This buffer will be associated to the working copy for its entire life-cycle. Another
 	 * working copy on same unit but owned by a different owner would not share the same buffer
 	 * unless its owner decided to implement such a sharing behaviour.
 	 * </p>
-	 * 
+	 *
 	 * @param workingCopy the working copy of the buffer
 	 * @return IBuffer the created buffer for the given working copy
 	 * @see IBuffer
 	 */
 	public IBuffer createBuffer(ICompilationUnit workingCopy) {
 
-		return BufferManager.getDefaultBufferManager().createBuffer(workingCopy);
+		return BufferManager.createBuffer(workingCopy);
+	}
+
+	/**
+	 * Returns the problem requestor used by a working copy of this working copy owner.
+	 * <p>
+	 * By default, no problem requestor is configured. Clients can override this
+	 * method to provide a requestor.
+	 * </p>
+	 *
+	 * @param workingCopy The problem requestor used for the given working copy.
+	 * @return the problem requestor to be used by working copies of this working
+	 * copy owner or <code>null</code> if no problem requestor is configured.
+	 *
+	 * @since 3.3
+	 */
+	public IProblemRequestor getProblemRequestor(ICompilationUnit workingCopy) {
+		return null;
+	}
+
+	/**
+	 * Returns a new working copy with the given name using this working copy owner to
+	 * create its buffer.
+	 * <p>
+	 * This working copy always belongs to the default package in a package
+	 * fragment root that corresponds to its Java project, and this Java project never exists.
+	 * However this Java project has the given classpath that is used when resolving names
+	 * in this working copy.
+	 * </p><p>
+	 * A DOM AST created using this working copy will have bindings resolved using the given
+	 * classpath, and problem are reported to the given problem requestor.
+	 * <p></p>
+	 * <code>JavaCore#getOptions()</code> is used to create the DOM AST as it is not
+	 * possible to set the options on the non-existing Java project.
+	 * </p><p>
+	 * When the working copy instance is created, an {@link IJavaElementDelta#ADDED added delta} is
+	 * reported on this working copy.
+	 * </p><p>
+	 * Once done with the working copy, users of this method must discard it using
+	 * {@link ICompilationUnit#discardWorkingCopy()}.
+	 * </p><p>
+	 * Note that when such working copy is committed, only its buffer is saved (see
+	 * {@link IBuffer#save(IProgressMonitor, boolean)}) but no resource is created.
+	 * </p><p>
+	 * This method is not intended to be overriden by clients.
+	 * </p>
+	 *
+	 * @param name the name of the working copy (e.g. "X.java")
+	 * @param classpath the classpath used to resolve names in this working copy
+	 * @param problemRequestor a requestor which will get notified of problems detected during
+	 * 	reconciling as they are discovered. The requestor can be set to <code>null</code> indicating
+	 * 	that the client is not interested in problems.
+	 * @param monitor a progress monitor used to report progress while opening the working copy
+	 * 	or <code>null</code> if no progress should be reported
+	 * @throws JavaModelException if the contents of this working copy can
+	 *   not be determined.
+	 * @return a new working copy
+	 * @see ICompilationUnit#becomeWorkingCopy(IProblemRequestor, IProgressMonitor)
+	 * @since 3.2
+	 *
+	 * @deprecated Use {@link #newWorkingCopy(String, IClasspathEntry[], IProgressMonitor)} instead.
+	 * 	Note that if this deprecated method is used, problems may be reported twice
+	 * 	if the given requestor is not the same as the current working copy owner one.
+	 */
+	public final ICompilationUnit newWorkingCopy(String name, IClasspathEntry[] classpath, IProblemRequestor problemRequestor, IProgressMonitor monitor) throws JavaModelException {
+		ExternalJavaProject project = new ExternalJavaProject(classpath);
+		IPackageFragment parent = project.getPackageFragmentRoot(Path.EMPTY).getPackageFragment(IPackageFragment.DEFAULT_PACKAGE_NAME);
+		CompilationUnit result = new CompilationUnit((PackageFragment) parent, name, this);
+		result.becomeWorkingCopy(problemRequestor, monitor);
+		return result;
+	}
+
+	/**
+	 * Returns a new working copy with the given name using this working copy owner to
+	 * create its buffer.
+	 * <p>
+	 * This working copy always belongs to the default package in a package
+	 * fragment root that corresponds to its Java project, and this Java project never exists.
+	 * However this Java project has the given classpath that is used when resolving names
+	 * in this working copy.
+	 * </p><p>
+	 * If a DOM AST is created using this working copy, then given classpath will be used
+	 *  if bindings need to be resolved. Problems will be reported to the problem requestor
+	 * of the current working copy owner problem if it is not <code>null</code>.
+	 * <p></p>
+	 * Options used to create the DOM AST are got from {@link JavaCore#getOptions()}
+	 * as it is not possible to set the options on a non-existing Java project.
+	 * </p><p>
+	 * When the working copy instance is created, an {@link IJavaElementDelta#ADDED added delta} is
+	 * reported on this working copy.
+	 * </p><p>
+	 * Once done with the working copy, users of this method must discard it using
+	 * {@link ICompilationUnit#discardWorkingCopy()}.
+	 * </p><p>
+	 * Note that when such working copy is committed, only its buffer is saved (see
+	 * {@link IBuffer#save(IProgressMonitor, boolean)}) but no resource is created.
+	 * </p><p>
+	 * This method is not intended to be overriden by clients.
+	 * </p>
+	 *
+	 * @param name the name of the working copy (e.g. "X.java")
+	 * @param classpath the classpath used to resolve names in this working copy
+	 * @param monitor a progress monitor used to report progress while opening the working copy
+	 * 	or <code>null</code> if no progress should be reported
+	 * @throws JavaModelException if the contents of this working copy can
+	 *   not be determined.
+	 * @return a new working copy
+	 * @see ICompilationUnit#becomeWorkingCopy(IProgressMonitor)
+	 *
+	 * @since 3.3
+	 */
+	public final ICompilationUnit newWorkingCopy(String name, IClasspathEntry[] classpath, IProgressMonitor monitor) throws JavaModelException {
+		ExternalJavaProject project = new ExternalJavaProject(classpath);
+		IPackageFragment parent = project.getPackageFragmentRoot(Path.EMPTY).getPackageFragment(IPackageFragment.DEFAULT_PACKAGE_NAME);
+		CompilationUnit result = new CompilationUnit((PackageFragment) parent, name, this);
+		result.becomeWorkingCopy(getProblemRequestor(result), monitor);
+		return result;
 	}
 
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/BuildContext.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/BuildContext.java
new file mode 100755
index 0000000..24fa223
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/BuildContext.java
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * Copyright (c) 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    IBM Corporation - initial API and implementation
+ *    
+ *******************************************************************************/
+
+package org.eclipse.jdt.core.compiler;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.jdt.internal.core.builder.CompilationParticipantResult;
+import org.eclipse.jdt.internal.core.builder.SourceFile;
+
+/**
+ * The context of a build event that is notified to interested compilation 
+ * participants when {@link CompilationParticipant#buildStarting(BuildContext[], boolean) a build is starting},
+ * or to annotations processors when {@link CompilationParticipant#processAnnotations(BuildContext[]) a source file has annotations}.
+ * <p>
+ * This class is not intended to be instanciated or subclassed by clients.
+ * </p>
+ * @since 3.2
+ */
+public class BuildContext extends CompilationParticipantResult {
+
+/**
+ * Creates a build context for the given source file.
+ * <p>
+ * This constructor is not intended to be called by clients.
+ * </p>
+ * 
+ * @param sourceFile the source file being built
+ */
+public BuildContext(SourceFile sourceFile) {
+	super(sourceFile);
+}
+
+/**
+ * Returns the contents of the compilation unit.
+ * 
+ * @return the contents of the compilation unit
+ */
+public char[] getContents() {
+	return this.sourceFile.getContents();
+}
+
+/**
+ * Returns the <code>IFile</code> representing the compilation unit.
+ * 
+ * @return the <code>IFile</code> representing the compilation unit
+ */
+public IFile getFile() {
+	return this.sourceFile.resource;
+}
+
+/**
+ * Returns whether the compilation unit contained any annotations when it was compiled.
+ * 
+ * NOTE: This is only valid during {@link CompilationParticipant#processAnnotations(BuildContext[])}.
+ * 
+ * @return whether the compilation unit contained any annotations when it was compiled
+ */
+public boolean hasAnnotations() {
+	return this.hasAnnotations; // only set during processAnnotations
+}
+
+/**
+ * Record the added/changed generated files that need to be compiled.
+ * 
+ * @param addedGeneratedFiles the added/changed files
+ */
+public void recordAddedGeneratedFiles(IFile[] addedGeneratedFiles) {
+	int length2 = addedGeneratedFiles.length;
+	if (length2 == 0) return;
+
+	int length1 = this.addedFiles == null ? 0 : this.addedFiles.length;
+	IFile[] merged = new IFile[length1 + length2];
+	if (length1 > 0) // always make a copy even if currently empty
+		System.arraycopy(this.addedFiles, 0, merged, 0, length1);
+	System.arraycopy(addedGeneratedFiles, 0, merged, length1, length2);
+	this.addedFiles = merged;
+}
+
+/**
+ * Record the generated files that need to be deleted.
+ * 
+ * @param deletedGeneratedFiles the files that need to be deleted
+ */
+public void recordDeletedGeneratedFiles(IFile[] deletedGeneratedFiles) {
+	int length2 = deletedGeneratedFiles.length;
+	if (length2 == 0) return;
+
+	int length1 = this.deletedFiles == null ? 0 : this.deletedFiles.length;
+	IFile[] merged = new IFile[length1 + length2];
+	if (length1 > 0) // always make a copy even if currently empty
+		System.arraycopy(this.deletedFiles, 0, merged, 0, length1);
+	System.arraycopy(deletedGeneratedFiles, 0, merged, length1, length2);
+	this.deletedFiles = merged;
+}
+
+/**
+ * Record the fully-qualified type names of any new dependencies, each name is of the form "p1.p2.A.B".
+ * 
+ * @param typeNameDependencies the fully-qualified type names of new dependencies
+ */
+public void recordDependencies(String[] typeNameDependencies) {
+	int length2 = typeNameDependencies.length;
+	if (length2 == 0) return;
+
+	int length1 = this.dependencies == null ? 0 : this.dependencies.length;
+	String[] merged = new String[length1 + length2];
+	if (length1 > 0) // always make a copy even if currently empty
+		System.arraycopy(this.dependencies, 0, merged, 0, length1);
+	System.arraycopy(typeNameDependencies, 0, merged, length1, length2);
+	this.dependencies = merged;
+}
+
+/**
+ * Record new problems to report against this compilationUnit.
+ * Markers are persisted for these problems only for the declared managed marker type
+ * (see the 'compilationParticipant' extension point).
+ * 
+ * @param newProblems the problems to report
+ */
+public void recordNewProblems(CategorizedProblem[] newProblems) {
+	int length2 = newProblems.length;
+	if (length2 == 0) return;
+
+	int length1 = this.problems == null ? 0 : this.problems.length;
+	CategorizedProblem[] merged = new CategorizedProblem[length1 + length2];
+	if (length1 > 0) // always make a copy even if currently empty
+		System.arraycopy(this.problems, 0, merged, 0, length1);	
+	System.arraycopy(newProblems, 0, merged, length1, length2);	
+	this.problems = merged;
+}
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/CompilationParticipant.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/CompilationParticipant.java
new file mode 100755
index 0000000..c27ab15
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/CompilationParticipant.java
@@ -0,0 +1,134 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    mkaufman@bea.com - initial API as ICompilationParticipant
+ *    IBM - changed from interface ICompilationParticipant to abstract class CompilationParticipant
+ *    IBM - rewrote spec
+ *    
+ *******************************************************************************/
+
+package org.eclipse.jdt.core.compiler;
+
+import org.eclipse.jdt.core.IJavaProject;
+
+/**
+ * A compilation participant is notified of events occuring during the compilation process.
+ * The compilation process not only involves generating .class files (i.e. building), it also involves
+ * cleaning the output directory, reconciling a working copy, etc.
+ * So the notified events are the result of a build action, a clean action, a reconcile operation 
+ * (for a working copy), etc.
+ * <p>
+ * Code that participates in the build should in general be implemented with a separate Builder,
+ * rather than a CompilationParticipant. It is only necessary to use a CompilationParticipant if 
+ * the build step needs to interact with the Java build, for instance by creating additional 
+ * Java source files that must themselves in turn be compiled. 
+ * <p>
+ * Clients wishing to participate in the compilation process must suclass this class, and implement
+ * {@link #isActive(IJavaProject)}, {@link #aboutToBuild(IJavaProject)}, 
+ * {@link #reconcile(ReconcileContext)}, etc.
+* </p><p>
+ * This class is intended to be subclassed by clients.
+ * </p>
+ * @since 3.2
+ */
+public abstract class CompilationParticipant {
+
+public static int READY_FOR_BUILD = 1;
+public static int NEEDS_FULL_BUILD = 2;
+
+/**
+ * Notifies this participant that a build is about to start and provides it the opportunity to
+ * create missing source folders for generated source files. Additional source folders
+ * should be marked as optional so the project can be built when the folders do not exist.
+ * Only sent to participants interested in the project.
+ * <p>
+ * Default is to return <code>READY_FOR_BUILD</code>.
+ * </p>
+ * @param project the project about to build
+ * @return READY_FOR_BUILD or NEEDS_FULL_BUILD
+ */
+public int aboutToBuild(IJavaProject project) {
+	return READY_FOR_BUILD;
+}
+
+/**
+ * Notifies this participant that a compile operation is about to start and provides it the opportunity to
+ * generate source files based on the source files about to be compiled.
+ * When isBatchBuild is true, then files contains all source files in the project.
+ * Only sent to participants interested in the current build project.
+ *
+ * @param files is an array of BuildContext
+ * @param isBatch identifies when the build is a batch build
+  */
+public void buildStarting(BuildContext[] files, boolean isBatch) {
+	// do nothing by default
+}
+
+/**
+ * Notifies this participant that a clean is about to start and provides it the opportunity to
+ * delete generated source files.
+ * Only sent to participants interested in the project.
+ * @param project the project about to be cleaned
+ */
+public void cleanStarting(IJavaProject project) {
+	// do nothing by default
+}
+
+/**
+ * Returns whether this participant is active for a given project.
+ * <p>
+ * Default is to return <code>false</code>.
+ * </p><p>
+ * For efficiency, participants that are not interested in the 
+ * given project should return <code>false</code> for that project.
+ * </p>
+ * @param project the project to participate in
+ * @return whether this participant is active for a given project
+ */
+public boolean isActive(IJavaProject project) {
+	return false;
+}
+
+/**
+ * Returns whether this participant is interested in only Annotations.
+ * <p>
+ * Default is to return <code>false</code>.
+ * </p>
+ * @return whether this participant is interested in only Annotations.
+ */
+public boolean isAnnotationProcessor() {
+	return false;
+}
+
+/**
+ * Notifies this participant that a compile operation has found source files using Annotations.
+ * Only sent to participants interested in the current build project that answer true to isAnnotationProcessor().
+ * Each BuildContext was informed whether its source file currently hasAnnotations().
+ *
+ * @param files is an array of BuildContext
+  */
+public void processAnnotations(BuildContext[] files) {
+	// do nothing by default
+}
+
+/**
+ * Notifies this participant that a reconcile operation is happening. The participant can act on this reconcile
+ * operation by using the given context. Other participant can then see the result of this participation
+ * on this context.
+ * <p>
+ * Note that a participant should not modify the buffer of the working copy that is being reconciled.
+ * </p><p>
+ * Default is to do nothing.
+ * </p>
+ * @param context the reconcile context to act on
+  */
+public void reconcile(ReconcileContext context) {
+	// do nothing by default
+}
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/IScanner.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/IScanner.java
index 2036684..0e1d57b 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/IScanner.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/IScanner.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -17,11 +17,14 @@
   * Definition of a Java scanner, as returned by the <code>ToolFactory</code>.
   * The scanner is responsible for tokenizing a given source, providing information about
   * the nature of the token read, its positions and source equivalent.
-  * 
+  * <p>
   * When the scanner has finished tokenizing, it answers an EOF token (<code>
   * ITerminalSymbols#TokenNameEOF</code>.
-  * 
+  * </p><p>
   * When encountering lexical errors, an <code>InvalidInputException</code> is thrown.
+ * </p><p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
   * 
   * @see org.eclipse.jdt.core.ToolFactory
   * @see ITerminalSymbols
@@ -140,6 +143,7 @@
 	/**
 	 * Set the scanner source to process. By default, the scanner will consider starting at the beginning of the
 	 * source until it reaches its end.
+	 * If the given source is <code>null</code>, this clears the source.
 	 * 
 	 * @param source the given source
 	 */
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/ITerminalSymbols.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/ITerminalSymbols.java
index 3cdf047..7e500bf 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/ITerminalSymbols.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/ITerminalSymbols.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -14,6 +14,9 @@
 /**
  * Maps each terminal symbol in the java-grammar into a unique integer. 
  * This integer is used to represent the terminal when computing a parsing action. 
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
  * 
  * @see IScanner
  * @since 2.0
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/ReconcileContext.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/ReconcileContext.java
new file mode 100755
index 0000000..474cd00
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/ReconcileContext.java
@@ -0,0 +1,194 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    mkaufman@bea.com - initial API and implementation
+ *    IBM - renamed from PreReconcileCompilationResult to ReconcileContext
+ *    IBM - rewrote spec
+ *    
+ *******************************************************************************/
+
+package org.eclipse.jdt.core.compiler;
+
+import java.util.HashMap;
+
+import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IJavaElementDelta;
+import org.eclipse.jdt.core.IJavaModelMarker;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.dom.AST;
+import org.eclipse.jdt.core.dom.ASTParser;
+import org.eclipse.jdt.internal.core.CompilationUnit;
+import org.eclipse.jdt.internal.core.JavaProject;
+import org.eclipse.jdt.internal.core.ReconcileWorkingCopyOperation;
+
+/**
+ * The context of a reconcile event that is notified to interested compilation 
+ * participants while a reconcile operation is running.
+ * <p>
+ * A reconcile participant can get the AST for the reconcile-operation using
+ * {@link #getAST3()}. If the participant modifies in any way the AST 
+ * (either by modifying the source of the working copy, or modifying another entity 
+ * that would result in different bindings for the AST), it is expected to reset the 
+ * AST in the context using {@link #resetAST()}.
+ * </p><p>
+ * A reconcile participant can also create and return problems using 
+ * {@link #putProblems(String, CategorizedProblem[])}. These problems are then reported 
+ * to the problem requestor of the reconcile operation.
+ * </p><p>
+ * This class is not intended to be instanciated or subclassed by clients.
+ * </p>
+ * 
+ * @see CompilationParticipant#reconcile(ReconcileContext)
+ * @since 3.2
+ */
+public class ReconcileContext {
+	
+	private ReconcileWorkingCopyOperation operation;
+	private CompilationUnit workingCopy;
+
+/**
+ * Creates a reconcile context for the given reconcile operation.
+ * <p>
+ * This constructor is not intended to be called by clients.
+ * </p>
+ * 
+ * @param operation the reconcile operation
+ */
+public ReconcileContext(ReconcileWorkingCopyOperation operation, CompilationUnit workingCopy) {
+	this.operation = operation;
+	this.workingCopy = workingCopy;
+}
+
+/**
+ * Returns a resolved AST with {@link AST#JLS3 JLS3} level.
+ * It is created from the current state of the working copy.
+ * Creates one if none exists yet.
+ * Returns <code>null</code> if the current state of the working copy
+ * doesn't allow the AST to be created (e.g. if the working copy's content 
+ * cannot be parsed).
+ * <p>
+ * If the AST level requested during reconciling is not {@link AST#JLS3}
+ * or if binding resolutions was not requested, then a different AST is created. 
+ * Note that this AST does not become the current AST and it is only valid for 
+ * the requestor.
+ * </p>
+ * 
+ * @return the AST created from the current state of the working copy,
+ *   or <code>null</code> if none could be created
+ * @exception JavaModelException  if the contents of the working copy
+ *		cannot be accessed. Reasons include:
+ * <ul>
+ * <li> The working copy does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * </ul>
+ */
+public org.eclipse.jdt.core.dom.CompilationUnit getAST3() throws JavaModelException {
+	if (this.operation.astLevel != AST.JLS3 || !this.operation.resolveBindings) {
+		// create AST (optionally resolving bindings)
+		ASTParser parser = ASTParser.newParser(AST.JLS3);
+		parser.setCompilerOptions(workingCopy.getJavaProject().getOptions(true));
+		if (JavaProject.hasJavaNature(workingCopy.getJavaProject().getProject()))
+			parser.setResolveBindings(true);
+		parser.setStatementsRecovery((this.operation.reconcileFlags & ICompilationUnit.ENABLE_STATEMENTS_RECOVERY) != 0);
+		parser.setBindingsRecovery((this.operation.reconcileFlags & ICompilationUnit.ENABLE_BINDINGS_RECOVERY) != 0);
+		parser.setSource(workingCopy);
+		return (org.eclipse.jdt.core.dom.CompilationUnit) parser.createAST(this.operation.progressMonitor);		
+	}
+	return this.operation.makeConsistent(this.workingCopy);
+}
+
+/**
+ * Returns the AST level requested by the reconcile operation.
+ * It is either {@link ICompilationUnit#NO_AST}, or one of the JLS constants defined on {@link AST}.
+ * 
+ * @return the AST level requested by the reconcile operation
+ */
+public int getASTLevel() {
+	return this.operation.astLevel;
+}
+
+/**
+ * Returns whether the reconcile operation is resolving bindings.
+ * 
+ * @return whether the reconcile operation is resolving bindings
+ */
+public boolean isResolvingBindings() {
+	return this.operation.resolveBindings;
+}
+
+/**
+ * Returns the delta describing the change to the working copy being reconciled.
+ * Returns <code>null</code> if there is no change.
+ * Note that the delta's AST is not yet positionnned at this stage. Use {@link #getAST3()}
+ * to get the current AST.
+ *
+ * @return the delta describing the change, or <code>null</code> if none
+ */
+public IJavaElementDelta getDelta() {
+	return this.operation.deltaBuilder.delta;
+}
+
+/**
+ * Returns the problems to be reported to the problem requestor of the reconcile operation
+ * for the given marker type.
+ * Returns <code>null</code> if no problems need to be reported for this marker type.
+ * 
+ * @param markerType the given marker type
+ * @return problems to be reported to the problem requesto
+ */
+public CategorizedProblem[] getProblems(String markerType) {
+	if (this.operation.problems == null) return null;
+	return (CategorizedProblem[]) this.operation.problems.get(markerType);
+}
+
+/**
+ * Returns the working copy this context refers to.
+ * 
+ * @return the working copy this context refers to
+ */
+public ICompilationUnit getWorkingCopy() {
+	return this.workingCopy;
+}
+
+/**
+ * Resets the AST carried by this context.
+ * A compilation participant that modifies the environment that would result in different 
+ * bindings for the AST is expected to reset the AST on this context, so that other 
+ * participants don't get a stale AST.
+ * <p>
+ * Note that resetting the AST will not restart the reconcile process. Only further 
+ * participants will see the new AST. Thus participants running before the one that
+ * resets the AST will have a stale view of the AST and its problems. Use 
+ * the compilation participant extension point to order the participants.
+ * </p>
+ */
+public void resetAST() {
+	this.operation.ast = null;
+	putProblems(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, null);
+	putProblems(IJavaModelMarker.TASK_MARKER, null);
+}
+
+/**
+ * Sets the problems to be reported to the problem requestor of the reconcile operation
+ * for the given marker type.
+ * <code>null</code> indicates that no problems need to be reported.
+ * <p>
+ * Using this functionality, a participant that resolves problems for a given marker type 
+ * can hide those problems since they don't exist any longer.
+ * </p>
+ * 
+ * @param markerType the marker type of the given problems
+ * @param problems  the problems to be reported to the problem requestor of the reconcile operation,
+ *   or <code>null</code> if none
+ */
+public void putProblems(String markerType, CategorizedProblem[] problems) {
+	if (this.operation.problems == null)
+		this.operation.problems = new HashMap();
+	this.operation.problems.put(markerType, problems);
+}
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/eval/ICodeSnippetRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/eval/ICodeSnippetRequestor.java
index 03bba9c..d9be4b1 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/eval/ICodeSnippetRequestor.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/eval/ICodeSnippetRequestor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/eval/IEvaluationContext.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/eval/IEvaluationContext.java
index fe44004..1f44230 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/eval/IEvaluationContext.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/eval/IEvaluationContext.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -342,7 +342,7 @@
 		throws JavaModelException;
 	/**
 	 * Evaluates the given global variable. During this operation, 
-	 * this context's package declaration, imports, and <it>all</it> its declared 
+	 * this context's package declaration, imports, and <i>all</i> its declared 
 	 * variables are verified. The given requestor's <code>acceptProblem</code>
 	 * method will be called for each problem that is detected.
 	 * <p>
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/eval/IGlobalVariable.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/eval/IGlobalVariable.java
index 5195648..0a57fa8 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/eval/IGlobalVariable.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/eval/IGlobalVariable.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/DOMException.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/DOMException.java
index f8ba578..5add075 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/DOMException.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/DOMException.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/DOMFactory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/DOMFactory.java
index c0737f6..775d2dd 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/DOMFactory.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/DOMFactory.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMCompilationUnit.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMCompilationUnit.java
index cb2dfc2..ba8da3e 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMCompilationUnit.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMCompilationUnit.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -11,7 +11,9 @@
 package org.eclipse.jdt.core.jdom;
 
 /**
- * Represents a Java compilation unit (<code>.java</code> source file). 
+ * Represents a Java compilation unit (source file with one of the 
+ * {@link org.eclipse.jdt.core.JavaCore#getJavaLikeExtensions() 
+ * Java-like extensions}). 
  * The corresponding syntactic unit is CompilationUnit (JLS2 7.3).  
  * Allowable child types for a compilation unit are <code>IDOMPackage</code>, <code>IDOMImport</code>,
  * and <code>IDOMType</code>.
@@ -38,7 +40,9 @@
  * method returns the name of this compilation unit.
  *
  * <p>The name of a compilation unit is the name of the first top-level public type
- * defined in the compilation unit, suffixed with ".java". For example, if the first
+ * defined in the compilation unit, suffixed with one of the 
+ * {@link org.eclipse.jdt.core.JavaCore#getJavaLikeExtensions() 
+ * Java-like extensions}. For example, if the first
  * top-level public type defined in this compilation unit has the name "Hanoi",
  * then name of this compilation unit is "Hanoi.java".</p>
  *
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMFactory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMFactory.java
index f4eedbf..3b84062 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMFactory.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMFactory.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -13,7 +13,9 @@
 /**
  * A factory used to create document fragment (DF) nodes. An 
  * <code>IDOMCompilationUnit</code> represents the root of a complete JDOM (that
- * is, a ".java" file). Other node types represent fragments of a compilation
+ * is, a source file with one of the 
+ * {@link org.eclipse.jdt.core.JavaCore#getJavaLikeExtensions() 
+ * Java-like extensions}). Other node types represent fragments of a compilation
  * unit.
  * <p>
  * The factory can be used to create empty DFs or it can create DFs from source
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMField.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMField.java
index 2ec880d..9c37dda 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMField.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMField.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMImport.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMImport.java
index 913009a..fbb62ca 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMImport.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMImport.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMInitializer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMInitializer.java
index bb9b028..7ff9752 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMInitializer.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMInitializer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMMember.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMMember.java
index a031200..1f7165d 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMMember.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMMember.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMMethod.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMMethod.java
index c1f3fc7..18d9bc3 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMMethod.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMMethod.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMNode.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMNode.java
index 525105d..ce7469b 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMNode.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMNode.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -144,7 +144,7 @@
 /**
  * Returns the current contents of this document fragment as a character array.
  * <p>
- * Note: To obtain complete source for the ".java" file, ask a compilation unit
+ * Note: To obtain complete source for the source file, ask a compilation unit
  * node for its contents.
  * </p>
  *
@@ -169,7 +169,7 @@
 /**
  * Returns the current contents of this document fragment.
  * <p>
- * Note: To obtain complete source for the ".java" file, ask a compilation unit
+ * Note: To obtain complete source for the source file, ask a compilation unit
  * node for its contents.
  * </p>
  *
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMPackage.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMPackage.java
index 674cb0d..445d5c6 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMPackage.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMPackage.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMType.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMType.java
index 9e559a7..ed97e90 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMType.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/jdom/IDOMType.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ByteCodeVisitorAdapter.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ByteCodeVisitorAdapter.java
index 7689012..386c049 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ByteCodeVisitorAdapter.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ByteCodeVisitorAdapter.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ClassFileBytesDisassembler.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ClassFileBytesDisassembler.java
index 2453dcd..374361d 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ClassFileBytesDisassembler.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ClassFileBytesDisassembler.java
@@ -43,6 +43,12 @@
 	public final static int COMPACT = 8;
 
 	/**
+	 * This mode is used to retrive a pseudo code for working copy purpose.
+	 * @since 3.2
+	 */
+	public final static int WORKING_COPY = 16;
+
+	/**
 	 * Answers back the disassembled string of the classfile bytes using the default
 	 * mode.
 	 * This is an output quite similar to the javap tool, using DEFAULT mode.
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ClassFormatException.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ClassFormatException.java
index a76ac8d..bb7a3c1 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ClassFormatException.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ClassFormatException.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/CompilationUnitSorter.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/CompilationUnitSorter.java
index 2bba98d..0946d9b 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/CompilationUnitSorter.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/CompilationUnitSorter.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -7,6 +7,7 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ *     Alex Blewitt - alex_blewitt@yahoo.com https://bugs.eclipse.org/bugs/show_bug.cgi?id=171066
  *******************************************************************************/
 
 package org.eclipse.jdt.core.util;
@@ -15,9 +16,13 @@
 
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.dom.AST;
+import org.eclipse.jdt.core.dom.CompilationUnit;
 import org.eclipse.jdt.internal.core.SortElementsOperation;
+import org.eclipse.text.edits.TextEdit;
+import org.eclipse.text.edits.TextEditGroup;
 
 /**
  * Operation for sorting members within a compilation unit.
@@ -37,6 +42,19 @@
 		// Not instantiable
 	} 
 	
+    /**
+     * @deprecated marking deprecated as it is using deprecated code
+     */
+    private static void checkASTLevel(int level) {
+        switch (level) {
+        case AST.JLS2 :
+        case AST.JLS3 :
+            break;
+        default :
+            throw new IllegalArgumentException();
+        }
+    }
+
 	/**
 	 * Name of auxillary property whose value can be used to determine the
 	 * original relative order of two body declarations. This allows a
@@ -310,15 +328,129 @@
         if (compilationUnit == null || comparator == null) {
             throw new IllegalArgumentException();
         }
-        switch (level) {
-        case AST.JLS2 :
-        case AST.JLS3 :
-            break;
-        default :
-            throw new IllegalArgumentException();
-        }
+        checkASTLevel(level);
         ICompilationUnit[] compilationUnits = new ICompilationUnit[] { compilationUnit };
         SortElementsOperation operation = new SortElementsOperation(level, compilationUnits, positions, comparator);
         operation.runOperation(monitor);
     }
+    
+	/**
+	 * Reorders the declarations in the given compilation unit according to the
+	 * specified comparator. The caller is responsible for arranging in advance
+	 * that the given compilation unit is a working copy, and for applying the
+	 * returned TextEdit afterwards.
+	 * <p>
+	 * <b>Note:</b> Reordering the members within a type declaration might be
+	 * more than a cosmetic change and could have potentially serious
+	 * repercussions. Firstly, the order in which the fields of a type are
+	 * initialized is significant in the Java language; reordering fields and
+	 * initializers may result in compilation errors or change the execution
+	 * behavior of the code. Secondly, reordering a class's members may affect
+	 * how its instances are serialized. This operation should therefore be used
+	 * with caution and due concern for potential negative side effects.
+	 * </p>
+	 * <p>
+	 * The <code>compare</code> method of the given comparator is passed pairs
+	 * of body declarations (subclasses of <code>BodyDeclaration</code>)
+	 * representing body declarations at the same level. 
+	 * The comparator is called on body declarations of nested classes,
+	 * including anonymous and local classes, but always at the same level.
+	 * Clients need to provide a comparator implementation (there is no standard
+	 * comparator). The <code>RELATIVE_ORDER</code> property attached to these
+	 * AST nodes affords the comparator a way to preserve the original relative
+	 * order.
+	 * </p>
+	 * <p>
+	 * The body declarations passed as parameters to the comparator always carry
+	 * at least the following minimal signature information: <br>
+	 * <table border="1" width="80%" cellpadding="5">
+	 * <tr>
+	 * <td width="20%"><code>TypeDeclaration</code></td>
+	 * <td width="50%"><code>modifiers, isInterface, name, superclass,
+	 *        superInterfaces, typeParameters<br>
+	 *        RELATIVE_ORDER property</code></td>
+	 * </tr>
+	 * <tr>
+	 * <td width="20%"><code>FieldDeclaration</code></td>
+	 * <td width="50%"><code>modifiers, type, fragments
+	 *        (VariableDeclarationFragments
+	 *        with name only)<br>
+	 *        RELATIVE_ORDER property</code></td>
+	 * </tr>
+	 * <tr>
+	 * <td width="20%"><code>MethodDeclaration</code></td>
+	 * <td width="50%"><code>modifiers, isConstructor, returnType, name,
+	 *        typeParameters, parameters
+	 *        (SingleVariableDeclarations with name, type, and modifiers only),
+	 *        thrownExceptions<br>
+	 *        RELATIVE_ORDER property</code></td>
+	 * </tr>
+	 * <tr>
+	 * <td width="20%"><code>Initializer</code></td>
+	 * <td width="50%"><code>modifiers<br>
+	 *        RELATIVE_ORDER property</code></td>
+	 * </tr>
+	 * <tr>
+	 * <td width="20%"><code>AnnotationTypeDeclaration</code></td>
+	 * <td width="50%"><code>modifiers, name<br>
+	 *        RELATIVE_ORDER property</code></td>
+	 * </tr>
+	 * <tr>
+	 * <td width="20%"><code>AnnotationTypeMemberDeclaration</code></td>
+	 * <td width="50%"><code>modifiers, name, type, default<br>
+	 *        RELATIVE_ORDER property</code></td>
+	 * </tr>
+	 * <tr>
+	 * <td width="20%"><code>EnumDeclaration</code></td>
+	 * <td width="50%"><code>modifiers, name, superInterfaces<br>
+	 *        RELATIVE_ORDER property</code></td>
+	 * </tr>
+	 * <tr>
+	 * <td width="20%"><code>EnumConstantDeclaration</code></td>
+	 * <td width="50%"><code>modifiers, name, arguments<br>
+	 *        RELATIVE_ORDER property</code></td>
+	 * </tr>
+	 * </table>
+	 * </p>
+	 * 
+	 * @param unit
+	 *            the CompilationUnit to sort
+	 * @param comparator
+	 *            the comparator capable of ordering
+	 *            <code>BodyDeclaration</code>s; this comparator is passed
+	 *            AST nodes from an AST of the specified AST level
+	 * @param options
+	 *            bitwise-or of option flags; <code>0</code> for default
+	 *            behavior (reserved for future growth)
+	 * @param group
+	 *            the text edit group to use when generating text edits, or <code>null</code>
+	 * @param monitor
+	 *            the progress monitor to notify, or <code>null</code> if none
+	 * @return a TextEdit describing the required edits to do the sort, or <code>null</code> 
+	 *            if sorting is not required
+	 * @exception JavaModelException
+	 *                if the compilation unit could not be sorted. Reasons
+	 *                include:
+	 *                <ul>
+	 *                <li> The given unit was not created from a ICompilationUnit (INVALID_ELEMENT_TYPES)</li>
+	 *                </ul>
+	 * @exception IllegalArgumentException
+	 *                if the given compilation unit is null or if the given
+	 *                comparator is null, or if <code>options</code> is not one
+	 *                of the supported levels.
+	 * @see org.eclipse.jdt.core.dom.BodyDeclaration
+	 * @see #RELATIVE_ORDER
+	 * @since 3.3
+	 */
+	public static TextEdit sort(CompilationUnit unit,
+			Comparator comparator,
+			int options,
+			TextEditGroup group,
+			IProgressMonitor monitor) throws JavaModelException {
+		if (unit == null || comparator == null) {
+			throw new IllegalArgumentException();
+		}
+		SortElementsOperation operation = new SortElementsOperation(AST.JLS3, new IJavaElement[] { unit.getJavaElement() }, null, comparator);
+		return operation.calculateEdit(unit, group);
+	}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IAnnotation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IAnnotation.java
index c7fe6f9..7655b47 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IAnnotation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IAnnotation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IAnnotationComponent.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IAnnotationComponent.java
index 1e1bd2b..3ddb2e5 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IAnnotationComponent.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IAnnotationComponent.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IAnnotationDefaultAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IAnnotationDefaultAttribute.java
index 0093a66..335ddf1 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IAnnotationDefaultAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IAnnotationDefaultAttribute.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IAttributeNamesConstants.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IAttributeNamesConstants.java
index 0bdc102..386bf0c 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IAttributeNamesConstants.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IAttributeNamesConstants.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -129,4 +129,16 @@
 	 * @since 3.0
 	 */
 	char[] ANNOTATION_DEFAULT = "AnnotationDefault".toCharArray(); //$NON-NLS-1$
+	
+	/**
+	 * "StackMapTable" attribute (added in J2SE 1.6).
+	 * @since 3.2
+	 */
+	char[] STACK_MAP_TABLE = "StackMapTable".toCharArray(); //$NON-NLS-1$
+	
+	/**
+	 * "StackMap" attribute (added in cldc1.0).
+	 * @since 3.2
+	 */
+	char[] STACK_MAP = "StackMap".toCharArray(); //$NON-NLS-1$
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IBytecodeVisitor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IBytecodeVisitor.java
index a2c23ee..b1dbbe3 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IBytecodeVisitor.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IBytecodeVisitor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IClassFileAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IClassFileAttribute.java
index c3b5948..5beeed2 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IClassFileAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IClassFileAttribute.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IClassFileDisassembler.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IClassFileDisassembler.java
index 7805f76..afd1b97 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IClassFileDisassembler.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IClassFileDisassembler.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -15,7 +15,7 @@
  * IClassFileReader onto a String using the proper line separator.
  * 
  * @since 2.0
- * @deprecated - should use ClassFileBytesDisassembler instead
+ * @deprecated Use {@link ClassFileBytesDisassembler} instead
  */
 public interface IClassFileDisassembler {
 	
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IClassFileReader.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IClassFileReader.java
index 69acad3..1d73ec4 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IClassFileReader.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IClassFileReader.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ICodeAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ICodeAttribute.java
index 94d6a7f..28d5bb9 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ICodeAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ICodeAttribute.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantPool.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantPool.java
index d536a57..b06d30c 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantPool.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantPool.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantPoolConstant.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantPoolConstant.java
index e7bd618..7c15431 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantPoolConstant.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantPoolConstant.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantValueAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantValueAttribute.java
index 4849dcb..594eb05 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantValueAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantValueAttribute.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IEnclosingMethodAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IEnclosingMethodAttribute.java
index 0088464..b7fe519 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IEnclosingMethodAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IEnclosingMethodAttribute.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IExceptionAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IExceptionAttribute.java
index c3d9c20..3a610bb 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IExceptionAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IExceptionAttribute.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IExceptionTableEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IExceptionTableEntry.java
index decb049..7cce15c 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IExceptionTableEntry.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IExceptionTableEntry.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IFieldInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IFieldInfo.java
index ebabb40..71b8fb2 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IFieldInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IFieldInfo.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IInnerClassesAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IInnerClassesAttribute.java
index e89e12e..b370218 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IInnerClassesAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IInnerClassesAttribute.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IInnerClassesAttributeEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IInnerClassesAttributeEntry.java
index dc90439..da8e9b5 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IInnerClassesAttributeEntry.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IInnerClassesAttributeEntry.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ILineNumberAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ILineNumberAttribute.java
index c91f409..8ecc48d 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ILineNumberAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ILineNumberAttribute.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ILocalVariableAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ILocalVariableAttribute.java
index 676d8ff..9e3eec2 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ILocalVariableAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ILocalVariableAttribute.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ILocalVariableTableEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ILocalVariableTableEntry.java
index 8b2fbf0..55fdee4 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ILocalVariableTableEntry.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ILocalVariableTableEntry.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ILocalVariableTypeTableAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ILocalVariableTypeTableAttribute.java
index fdc0eda..0a32839 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ILocalVariableTypeTableAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ILocalVariableTypeTableAttribute.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ILocalVariableTypeTableEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ILocalVariableTypeTableEntry.java
index 4c4a3ba..19be343 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ILocalVariableTypeTableEntry.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ILocalVariableTypeTableEntry.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IMethodInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IMethodInfo.java
index 4fa8072..7eac9e1 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IMethodInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IMethodInfo.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IModifierConstants.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IModifierConstants.java
index dc59354..3658379 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IModifierConstants.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IModifierConstants.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IOpcodeMnemonics.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IOpcodeMnemonics.java
index 73b0721..bbbbe2a 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IOpcodeMnemonics.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IOpcodeMnemonics.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IParameterAnnotation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IParameterAnnotation.java
index 1016077..0b3303d 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IParameterAnnotation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IParameterAnnotation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IRuntimeInvisibleAnnotationsAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IRuntimeInvisibleAnnotationsAttribute.java
index 6a6fe94..3e78cf2 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IRuntimeInvisibleAnnotationsAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IRuntimeInvisibleAnnotationsAttribute.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IRuntimeInvisibleParameterAnnotationsAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IRuntimeInvisibleParameterAnnotationsAttribute.java
index aa5797d..fadb4dd 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IRuntimeInvisibleParameterAnnotationsAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IRuntimeInvisibleParameterAnnotationsAttribute.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IRuntimeVisibleAnnotationsAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IRuntimeVisibleAnnotationsAttribute.java
index f70ac57..3f9a0b0 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IRuntimeVisibleAnnotationsAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IRuntimeVisibleAnnotationsAttribute.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IRuntimeVisibleParameterAnnotationsAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IRuntimeVisibleParameterAnnotationsAttribute.java
index 433fd41..979ac3b 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IRuntimeVisibleParameterAnnotationsAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IRuntimeVisibleParameterAnnotationsAttribute.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ISignatureAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ISignatureAttribute.java
index 46c1779..dd487c3 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ISignatureAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ISignatureAttribute.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ISourceAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ISourceAttribute.java
index 2bdd925..73a5f7a 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ISourceAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ISourceAttribute.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IStackMapAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IStackMapAttribute.java
new file mode 100755
index 0000000..ec5060d
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IStackMapAttribute.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.util;
+
+/**
+ * This class represents a stack map attribute.
+ * 
+ * This interface may be implemented by clients.
+ *  
+ * @since 3.2
+ */
+public interface IStackMapAttribute extends IClassFileAttribute {
+	
+	/**
+	 * Answer back the number of stack map frames of this atribute as specified in
+	 * the JVM specifications.
+	 * 
+	 * @return the number of stack map frames of this atribute as specified in
+	 * the JVM specifications
+	 */
+	int getNumberOfEntries();
+
+	/**
+	 * Answer back the stack map frames for this attribute as specified
+	 * in the JVM specifications.
+	 * 
+	 * @return the stack map frames for this attribute as specified
+	 * in the JVM specifications
+	 */
+	IStackMapFrame[] getStackMapFrame();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IStackMapFrame.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IStackMapFrame.java
new file mode 100755
index 0000000..52c43a5
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IStackMapFrame.java
@@ -0,0 +1,102 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.util;
+
+/**
+ * Description of a stack map frame as specified in the JVM specifications.
+ * 
+ * This interface may be implemented by clients. 
+ * 
+ * @since 3.2
+ */
+public interface IStackMapFrame {
+	
+	/**
+	 * Answer back the frame type for this entry.
+	 * <table>
+	 * <tr>
+	 * <th align="left">Type</th>
+	 * <th align="left">Range</th>
+	 * </tr>
+	 * <tr>
+	 * <td>SAME</td>
+	 * <td>0-63</td>
+	 * </tr>
+	 * <tr>
+	 * <td>SAME_LOCALS_1_STACK_ITEM</td>
+	 * <td>64-127</td>
+	 * </tr>
+	 * <tr>
+	 * <td>SAME_LOCALS_1_STACK_ITEM_EXTENDED</td>
+	 * <td>247</td>
+	 * </tr>
+	 * <tr>
+	 * <td>CHOP</td>
+	 * <td>248-250</td>
+	 * </tr>
+	 * <tr>
+	 * <td>SAME_FRAME_EXTENDED</td>
+	 * <td>251</td>
+	 * </tr>
+	 * <tr>
+	 * <td>APPEND</td>
+	 * <td>252-254</td>
+	 * </tr>
+	 * <tr>
+	 * <td>FULL_FRAME</td>
+	 * <td>255</td>
+	 * </tr>
+	 * </table> 
+	 * 
+	 * @return the frame type for this entry
+	 */
+	int getFrameType();
+
+	/**
+	 * Answer back the offset delta.
+	 * <p>This is not defined only for the frame types SAME and SAME_LOCALS_1_STACK_ITEM.</p>  
+	 * 
+	 * @return the offset delta
+	 */
+	int getOffsetDelta();
+
+	/**
+	 * Answer back the number of locals.
+	 * <p>This is defined only for the frame type FULL_FRAME.</p>
+	 * 
+	 * @return the number of locals
+	 */
+	int getNumberOfLocals();
+
+	/**
+	 * Answer back verification infos for the defined locals.
+	 * <p>This is defined only for frame types APPEND and FULL_FRAME.
+	 * 
+	 * @return verification infos for the defined locals
+	 */
+	IVerificationTypeInfo[] getLocals();
+
+	/**
+	 * Answer back the number of stack items
+	 * <p>This is defined only for the frame types SAME_LOCALS_1_STACK_ITEM, SAME_LOCALS_1_STACK_ITEM_EXTENDED and FULL_FRAME.
+	 * For SAME_LOCALS_1_STACK_ITEM and SAME_LOCALS_1_STACK_ITEM_EXTENDED, the answer is implicitely 1.</p>
+	 * 
+	 * @return the number of stack items
+	 */
+	int getNumberOfStackItems();
+	
+	/**
+	 * Answer back the verification infos for the stack items.
+	 * 
+	 * @return the verification infos for the stack items
+	 */
+	IVerificationTypeInfo[] getStackItems();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IStackMapTableAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IStackMapTableAttribute.java
new file mode 100755
index 0000000..067cd86
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IStackMapTableAttribute.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.util;
+
+/**
+ * This class represents a stack map table attribute.
+ * 
+ * This interface may be implemented by clients.
+ *  
+ * @since 3.2
+ */
+public interface IStackMapTableAttribute extends IClassFileAttribute {
+	
+	/**
+	 * Answer back the number of stack map frames of this atribute as specified in
+	 * the JVM specifications.
+	 * 
+	 * @return the number of stack map frames of this atribute as specified in
+	 * the JVM specifications
+	 */
+	int getNumberOfEntries();
+
+	/**
+	 * Answer back the stack map frames for this attribute as specified
+	 * in the JVM specifications.
+	 * 
+	 * @return the stack map frames for this attribute as specified
+	 * in the JVM specifications
+	 */
+	IStackMapFrame[] getStackMapFrame();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IVerificationTypeInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IVerificationTypeInfo.java
index e78fcbb..8300d47 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IVerificationTypeInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IVerificationTypeInfo.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -19,6 +19,52 @@
  */
 public interface IVerificationTypeInfo {
 	/**
+	 * The tag value representing top variable info
+	 * @since 3.2
+	 */
+	public static final int ITEM_TOP = 0;
+	/**
+	 * The tag value representing integer variable info
+	 * @since 3.2
+	 */
+	public static final int ITEM_INTEGER = 1;
+	/**
+	 * The tag value representing float variable info
+	 * @since 3.2
+	 */
+	public static final int ITEM_FLOAT = 2;
+	/**
+	 * The tag value representing double variable info
+	 * @since 3.2
+	 */
+	public static final int ITEM_DOUBLE = 3;
+	/**
+	 * The tag value representing long variable info
+	 * @since 3.2
+	 */
+	public static final int ITEM_LONG = 4;
+	/**
+	 * The tag value representing null variable info
+	 * @since 3.2
+	 */
+	public static final int ITEM_NULL = 5;
+	/**
+	 * The tag value representing uninitialized this variable info
+	 * @since 3.2
+	 */
+	public static final int ITEM_UNINITIALIZED_THIS = 6;
+	/**
+	 * The tag value representing object variable info
+	 * @since 3.2
+	 */
+	public static final int ITEM_OBJECT = 7;
+	/**
+	 * The tag value representing uninitialized variable info
+	 * @since 3.2
+	 */
+	public static final int ITEM_UNINITIALIZED = 8;
+	
+	/**
 	 * Answer back the tag of this verification type info as described in the JVM specifications.
 	 * <ul>
 	 * <li>0 for the top type</li>
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/OpcodeStringValues.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/OpcodeStringValues.java
index b1fa9d1..dc60807 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/OpcodeStringValues.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/OpcodeStringValues.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/DocumentElementParser.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/DocumentElementParser.java
index a7a3cce..d732132 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/DocumentElementParser.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/DocumentElementParser.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,21 +10,7 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler;
 
-/*
- * A document element parser extracts structural information
- * from a piece of source, providing detailed source positions info.
- *
- * also see @IDocumentElementRequestor
- *
- * The structural investigation includes:
- * - the package statement
- * - import statements
- * - top-level types: package member, member types (member types of member types...)
- * - fields
- * - methods
- *
- * Any (parsing) problem encountered is also provided.
- */
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
 import org.eclipse.jdt.internal.compiler.env.*;
 
 import org.eclipse.jdt.internal.compiler.impl.*;
@@ -48,8 +34,6 @@
 	int[][] intArrayStack;
 	int intArrayPtr;
 	
-	CompilerOptions options;
-	
 public DocumentElementParser(
 	final IDocumentElementRequestor requestor, 
 	IProblemFactory problemFactory,
@@ -63,6 +47,9 @@
 	intArrayStack = new int[30][];
 	this.options = options;
 	this.javadocParser.checkDocComment = false;
+	
+	this.setMethodsFullRecovery(false);
+	this.setStatementsRecovery(false);
 }
 /*
  * Will clear the comment stack when looking
@@ -95,7 +82,7 @@
 		break nextComment;
 	}
 	if (deprecated) {
-		checkAndSetModifiers(AccDeprecated);
+		checkAndSetModifiers(ClassFileConstants.AccDeprecated);
 	}
 	// modify the modifier source start to point at the first comment
 	if (commentPtr >= 0) {
@@ -210,11 +197,11 @@
 	TypeDeclaration typeDecl = new TypeDeclaration(this.compilationUnit.compilationResult);
 	if (nestedMethod[nestedType] == 0) {
 		if (nestedType != 0) {
-			typeDecl.bits |= ASTNode.IsMemberTypeMASK;
+			typeDecl.bits |= ASTNode.IsMemberType;
 		}
 	} else {
 		// Record that the block has a declaration for local types
-		typeDecl.bits |= ASTNode.IsLocalTypeMASK;
+		typeDecl.bits |= ASTNode.IsLocalType;
 		markEnclosingMemberWithLocalType();
 		blockReal();
 	}
@@ -474,6 +461,11 @@
 		declaration.declarationSourceStart = previousVariable.declarationSourceStart;
 		declaration.modifiers = previousVariable.modifiers;
 		declaration.modifiersSourceStart = previousVariable.modifiersSourceStart;
+		final Annotation[] annotations = previousVariable.annotations;
+		if (annotations != null) {
+			final int annotationsLength = annotations.length;
+			System.arraycopy(annotations, 0, declaration.annotations = new Annotation[annotationsLength], 0, annotationsLength);
+		}
 	}
 
 	localIntPtr = intPtr;
@@ -663,11 +655,11 @@
 	TypeDeclaration typeDecl = new TypeDeclaration(this.compilationUnit.compilationResult);
 	if (nestedMethod[nestedType] == 0) {
 		if (nestedType != 0) {
-			typeDecl.bits |= ASTNode.IsMemberTypeMASK;
+			typeDecl.bits |= ASTNode.IsMemberType;
 		}
 	} else {
 		// Record that the block has a declaration for local types
-		typeDecl.bits |= ASTNode.IsLocalTypeMASK;
+		typeDecl.bits |= ASTNode.IsLocalType;
 		markEnclosingMemberWithLocalType();
 		blockReal();
 	}
@@ -685,7 +677,7 @@
 	intPtr--;
 	int declSourceStart = intStack[intPtr--];
 	typeDecl.modifiersSourceStart = intStack[intPtr--];
-	typeDecl.modifiers = this.intStack[this.intPtr--] | AccInterface;
+	typeDecl.modifiers = this.intStack[this.intPtr--] | ClassFileConstants.AccInterface;
 	if (typeDecl.declarationSourceStart > declSourceStart) {
 		typeDecl.declarationSourceStart = declSourceStart;
 	}
@@ -975,7 +967,7 @@
 		CharOperation.concatWith(importReference.getImportName(), '.'),
 		importReference.sourceStart,
 		false,
-		AccStatic);
+		ClassFileConstants.AccStatic);
 }
 /*
  *
@@ -996,7 +988,7 @@
 		CharOperation.concatWith(importReference.getImportName(), '.'),
 		importReference.sourceStart,
 		false,
-		AccDefault);
+		ClassFileConstants.AccDefault);
 }
 protected void consumeStaticImportOnDemandDeclarationName() {
 	// SingleTypeImportDeclarationName ::= 'import' 'static' Name '.' '*'
@@ -1013,7 +1005,7 @@
 		CharOperation.concatWith(importReference.getImportName(), '.'),
 		importReference.sourceStart,
 		true,
-		AccStatic);
+		ClassFileConstants.AccStatic);
 }
 /*
  *
@@ -1029,7 +1021,7 @@
 		initializer.declarationSourceStart,
 		initializer.declarationSourceEnd,
 		intArrayStack[intArrayPtr--],
-		AccStatic, 
+		ClassFileConstants.AccStatic, 
 		intStack[intPtr--], 
 		initializer.block.sourceStart,
 		initializer.declarationSourceEnd);
@@ -1064,7 +1056,7 @@
 		CharOperation.concatWith(importReference.getImportName(), '.'), 
 		importReference.sourceStart,
 		true,
-		AccDefault);
+		ClassFileConstants.AccDefault);
 }
 /*
  * Flush javadocs defined prior to a given positions.
@@ -1089,7 +1081,12 @@
 	}
 	return super.endParse(act);
 }
-
+public void initialize(boolean initializeNLS) {
+	//positionning the parser for a new compilation unit
+	//avoiding stack reallocation and all that....
+	super.initialize(initializeNLS);
+	intArrayPtr = -1;
+}
 public void initialize() {
 	//positionning the parser for a new compilation unit
 	//avoiding stack reallocation and all that....
@@ -1120,15 +1117,14 @@
 public void parseCompilationUnit(ICompilationUnit unit) {
 	char[] regionSource = unit.getContents();
 	try {
-		initialize();
+		initialize(true);
 		goForCompilationUnit();
 		referenceContext =
 			compilationUnit = 
-				compilationUnit = 
-					new CompilationUnitDeclaration(
-						problemReporter(), 
-						new CompilationResult(unit, 0, 0, this.options.maxProblemsPerUnit), 
-						regionSource.length); 
+				new CompilationUnitDeclaration(
+					problemReporter(), 
+					new CompilationResult(unit, 0, 0, this.options.maxProblemsPerUnit), 
+					regionSource.length); 
 		scanner.resetTo(0, regionSource.length);
 		scanner.setSource(regionSource);
 		parse();
@@ -1145,11 +1141,10 @@
 		goForClassBodyDeclarations();
 		referenceContext = 
 			compilationUnit = 
-				compilationUnit = 
-					new CompilationUnitDeclaration(
-						problemReporter(), 
-						new CompilationResult(regionSource, 0, 0, this.options.maxProblemsPerUnit), 
-						regionSource.length); 
+				new CompilationUnitDeclaration(
+					problemReporter(), 
+					new CompilationResult(regionSource, 0, 0, this.options.maxProblemsPerUnit), 
+					regionSource.length); 
 		scanner.resetTo(0, regionSource.length);
 		scanner.setSource(regionSource);
 		parse();
@@ -1166,11 +1161,10 @@
 		goForFieldDeclaration();
 		referenceContext = 
 			compilationUnit = 
-				compilationUnit = 
-					new CompilationUnitDeclaration(
-						problemReporter(), 
-						new CompilationResult(regionSource, 0, 0, this.options.maxProblemsPerUnit), 
-						regionSource.length); 
+				new CompilationUnitDeclaration(
+					problemReporter(), 
+					new CompilationResult(regionSource, 0, 0, this.options.maxProblemsPerUnit), 
+					regionSource.length); 
 		scanner.resetTo(0, regionSource.length);
 		scanner.setSource(regionSource);
 		parse();
@@ -1188,11 +1182,10 @@
 		goForImportDeclaration();
 		referenceContext = 
 			compilationUnit = 
-				compilationUnit = 
-					new CompilationUnitDeclaration(
-						problemReporter(), 
-						new CompilationResult(regionSource, 0, 0, this.options.maxProblemsPerUnit), 
-						regionSource.length); 
+				new CompilationUnitDeclaration(
+					problemReporter(), 
+					new CompilationResult(regionSource, 0, 0, this.options.maxProblemsPerUnit), 
+					regionSource.length); 
 		scanner.resetTo(0, regionSource.length);
 		scanner.setSource(regionSource);
 		parse();
@@ -1213,11 +1206,10 @@
 		goForInitializer();
 		referenceContext = 
 			compilationUnit = 
-				compilationUnit = 
-					new CompilationUnitDeclaration(
-						problemReporter(), 
-						new CompilationResult(regionSource, 0, 0, this.options.maxProblemsPerUnit), 
-						regionSource.length); 
+				new CompilationUnitDeclaration(
+					problemReporter(), 
+					new CompilationResult(regionSource, 0, 0, this.options.maxProblemsPerUnit), 
+					regionSource.length); 
 		scanner.resetTo(0, regionSource.length);
 		scanner.setSource(regionSource);
 		parse();
@@ -1235,18 +1227,16 @@
 		goForGenericMethodDeclaration();
 		referenceContext = 
 			compilationUnit = 
-				compilationUnit = 
-					new CompilationUnitDeclaration(
-						problemReporter(), 
-						new CompilationResult(regionSource, 0, 0, this.options.maxProblemsPerUnit), 
-						regionSource.length); 
+				new CompilationUnitDeclaration(
+					problemReporter(), 
+					new CompilationResult(regionSource, 0, 0, this.options.maxProblemsPerUnit), 
+					regionSource.length); 
 		scanner.resetTo(0, regionSource.length);
 		scanner.setSource(regionSource);
 		parse();
 	} catch (AbortCompilation ex) {
 		// ignore this exception
 	}
-
 }
 /*
  * Investigate one package statement declaration.
@@ -1257,11 +1247,10 @@
 		goForPackageDeclaration();
 		referenceContext = 
 			compilationUnit = 
-				compilationUnit = 
-					new CompilationUnitDeclaration(
-						problemReporter(), 
-						new CompilationResult(regionSource, 0, 0, this.options.maxProblemsPerUnit), 
-						regionSource.length); 
+				new CompilationUnitDeclaration(
+					problemReporter(), 
+					new CompilationResult(regionSource, 0, 0, this.options.maxProblemsPerUnit), 
+					regionSource.length); 
 		scanner.resetTo(0, regionSource.length);
 		scanner.setSource(regionSource);
 		parse();
@@ -1279,11 +1268,10 @@
 		goForTypeDeclaration();
 		referenceContext = 
 			compilationUnit = 
-				compilationUnit = 
-					new CompilationUnitDeclaration(
-						problemReporter(), 
-						new CompilationResult(regionSource, 0, 0, this.options.maxProblemsPerUnit), 
-						regionSource.length); 
+				new CompilationUnitDeclaration(
+					problemReporter(), 
+					new CompilationResult(regionSource, 0, 0, this.options.maxProblemsPerUnit), 
+					regionSource.length); 
 		scanner.resetTo(0, regionSource.length);
 		scanner.setSource(regionSource);
 		parse();
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/IDocumentElementRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/IDocumentElementRequestor.java
index de28a29..cb16a7d 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/IDocumentElementRequestor.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/IDocumentElementRequestor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,7 +10,7 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler;
 
-import org.eclipse.jdt.core.compiler.IProblem;
+import org.eclipse.jdt.core.compiler.CategorizedProblem;
 
 /**
  * Part of the source element parser responsible for building the output.
@@ -121,7 +121,7 @@
 /**
  * @param problem - Used to report a problem while running the JDOM
  */
-void acceptProblem(IProblem problem);
+void acceptProblem(CategorizedProblem problem);
 /**
  * @param declarationStart - a source position corresponding to the start
  *  of this class.
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/ISourceElementRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/ISourceElementRequestor.java
index 253a680..21ecce6 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/ISourceElementRequestor.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/ISourceElementRequestor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,7 +10,7 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler;
 
-import org.eclipse.jdt.core.compiler.IProblem;
+import org.eclipse.jdt.core.compiler.CategorizedProblem;
 
 /*
  * Part of the source element parser responsible for building the output. It
@@ -39,7 +39,6 @@
 public interface ISourceElementRequestor {
 	
 	public static class TypeInfo {
-		public int kind;
 		public int declarationStart;
 		public int modifiers;
 		public char[] name;
@@ -49,6 +48,9 @@
 		public char[][] superinterfaces;
 		public TypeParameterInfo[] typeParameters;
 		public long[] annotationPositions;
+		public char[][] categories;
+		public boolean secondary;
+		public boolean anonymousMember;
 	}
 	
 	public static class TypeParameterInfo {
@@ -75,6 +77,7 @@
 		public char[][] exceptionTypes;
 		public TypeParameterInfo[] typeParameters;
 		public long[] annotationPositions;
+		public char[][] categories;
 	}
 	
 	public static class FieldInfo {
@@ -85,6 +88,7 @@
 		public int nameSourceStart; 
 		public int nameSourceEnd;
 		public long[] annotationPositions;
+		public char[][] categories;
 	}
 	
 	void acceptConstructorReference(char[] typeName, int argCount, int sourcePosition);
@@ -97,16 +101,15 @@
 	 * @param declarationEnd
 	 *                   This is the position of the ';' ending the import statement or
 	 *                   the end of the comment following the import.
-	 * @param name
-	 *                   This is the name of the import like specified in the source
-	 *                   including the dots. The '.*' is never included in the name.
+	 * @param tokens
+	 *                   This are the tokens of the import like specified in the source.
 	 * @param onDemand
 	 *                   set to true if the import is an import on demand (e.g. import
 	 *                   java.io.*). False otherwise.
 	 * @param modifiers
 	 *                   can be set to static from 1.5 on.
 	 */
-	void acceptImport(int declarationStart, int declarationEnd, char[] name, boolean onDemand, int modifiers);
+	void acceptImport(int declarationStart, int declarationEnd, char[][] tokens, boolean onDemand, int modifiers);
 
 	/*
 	 * Table of line separator position. This table is passed once at the end of
@@ -121,7 +124,7 @@
 	
 	void acceptPackage(int declarationStart, int declarationEnd, char[] name);
 
-	void acceptProblem(IProblem problem);
+	void acceptProblem(CategorizedProblem problem);
 
 	void acceptTypeReference(char[][] typeName, int sourceStart, int sourceEnd);
 
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/SourceElementParser.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/SourceElementParser.java
index 79b2023..b8ee845 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/SourceElementParser.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/SourceElementParser.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -11,7 +11,9 @@
 package org.eclipse.jdt.internal.compiler;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
 import org.eclipse.jdt.internal.compiler.env.*;
 import org.eclipse.jdt.internal.compiler.impl.*;
 import org.eclipse.jdt.core.compiler.*;
@@ -42,18 +44,17 @@
  */
 public class SourceElementParser extends CommentRecorderParser {
 	
-	ISourceElementRequestor requestor;
-	int fieldCount;
+	public ISourceElementRequestor requestor;
 	ISourceType sourceType;
 	boolean reportReferenceInfo;
 	char[][] typeNames;
 	char[][] superTypeNames;
 	int nestedTypeIndex;
-	NameReference[] unknownRefs;
-	int unknownRefsCounter;
 	LocalDeclarationVisitor localDeclarationVisitor = null;
 	CompilerOptions options;
 	HashtableOfObjectToInt sourceEnds = new HashtableOfObjectToInt();
+	HashMap nodesToCategories = new HashMap(); // a map from ASTNode to char[][]
+	boolean useSourceJavadocParser = true;
 	
 /**
  * An ast visitor that visits local type declarations.
@@ -91,18 +92,35 @@
 		CompilerOptions options,
 		boolean reportLocalDeclarations,
 		boolean optimizeStringLiterals) {
+	this(requestor, problemFactory, options, reportLocalDeclarations, optimizeStringLiterals, true/* use SourceJavadocParser */);
+}
+
+public SourceElementParser(
+		ISourceElementRequestor requestor, 
+		IProblemFactory problemFactory,
+		CompilerOptions options,
+		boolean reportLocalDeclarations,
+		boolean optimizeStringLiterals,
+		boolean useSourceJavadocParser) {
+	
+	super(
+		new ProblemReporter(
+			DefaultErrorHandlingPolicies.exitAfterAllProblems(),
+			options, 
+			problemFactory),
+		optimizeStringLiterals);
+	
 	// we want to notify all syntax error with the acceptProblem API
 	// To do so, we define the record method of the ProblemReporter
-	super(new ProblemReporter(
+	this.problemReporter = new ProblemReporter(
 		DefaultErrorHandlingPolicies.exitAfterAllProblems(),
 		options, 
 		problemFactory) {
-		public void record(IProblem problem, CompilationResult unitResult, ReferenceContext context) {
+		public void record(CategorizedProblem problem, CompilationResult unitResult, ReferenceContext context) {
 			unitResult.record(problem, context); // TODO (jerome) clients are trapping problems either through factory or requestor... is result storing needed?
-			requestor.acceptProblem(problem);
+			SourceElementParser.this.requestor.acceptProblem(problem);
 		}
-	},
-	optimizeStringLiterals);
+	};
 	this.requestor = requestor;
 	typeNames = new char[4][];
 	superTypeNames = new char[4][];
@@ -111,8 +129,35 @@
 	if (reportLocalDeclarations) {
 		this.localDeclarationVisitor = new LocalDeclarationVisitor();
 	}
+	// set specific javadoc parser
+	this.useSourceJavadocParser = useSourceJavadocParser;
+	if (useSourceJavadocParser) {
+		this.javadocParser = new SourceJavadocParser(this);
+	}
 }
-
+private void acceptJavadocTypeReference(Expression expression) {
+	if (expression instanceof JavadocSingleTypeReference) {
+		JavadocSingleTypeReference singleRef = (JavadocSingleTypeReference) expression;
+		this.requestor.acceptTypeReference(singleRef.token, singleRef.sourceStart);
+	} else if (expression instanceof JavadocQualifiedTypeReference) {
+		JavadocQualifiedTypeReference qualifiedRef = (JavadocQualifiedTypeReference) expression;
+		this.requestor.acceptTypeReference(qualifiedRef.tokens, qualifiedRef.sourceStart, qualifiedRef.sourceEnd);
+	}
+}
+public void addUnknownRef(NameReference nameRef) {
+	// Note that:
+	// - the only requestor interested in references is the SourceIndexerRequestor
+	// - a name reference can become a type reference only during the cast case, it is then tagged later with the Binding.TYPE bit
+	// However since the indexer doesn't make the distinction between name reference and type reference, there is no need
+	// to report a type reference in the SourceElementParser.
+	// This gained 3.7% in the indexing performance test.
+	if (nameRef instanceof SingleNameReference) {
+		requestor.acceptUnknownReference(((SingleNameReference) nameRef).token, nameRef.sourceStart);
+	} else {
+		//QualifiedNameReference
+		requestor.acceptUnknownReference(((QualifiedNameReference) nameRef).tokens, nameRef.sourceStart, nameRef.sourceEnd);
+	}
+}
 public void checkComment() {
 	// discard obsolete comments while inside methods or fields initializer (see bug 74369)
 	if (!(this.diet && this.dietInt==0) && this.scanner.commentPtr >= 0) {
@@ -136,7 +181,7 @@
 			// do not report problem before last parsed comment while recovering code...
 			this.javadocParser.reportProblems = this.currentElement == null || commentEnd > this.lastJavadocEnd;
 			if (this.javadocParser.checkDeprecation(lastComment)) {
-				checkAndSetModifiers(AccDeprecated);
+				checkAndSetModifiers(ClassFileConstants.AccDeprecated);
 			}
 			this.javadoc = this.javadocParser.docComment;	// null if check javadoc is not activated
 			if (currentElement == null) this.lastJavadocEnd = commentEnd;
@@ -146,61 +191,54 @@
 	if (this.reportReferenceInfo && this.javadocParser.checkDocComment && this.javadoc != null) {
 		// Report reference info in javadoc comment @throws/@exception tags
 		TypeReference[] thrownExceptions = this.javadoc.exceptionReferences;
-		int throwsTagsNbre = thrownExceptions == null ? 0 : thrownExceptions.length;
-		for (int i = 0; i < throwsTagsNbre; i++) {
-			TypeReference typeRef = thrownExceptions[i];
-			if (typeRef instanceof JavadocSingleTypeReference) {
-				JavadocSingleTypeReference singleRef = (JavadocSingleTypeReference) typeRef;
-				this.requestor.acceptTypeReference(singleRef.token, singleRef.sourceStart);
-			} else if (typeRef instanceof JavadocQualifiedTypeReference) {
-				JavadocQualifiedTypeReference qualifiedRef = (JavadocQualifiedTypeReference) typeRef;
-				this.requestor.acceptTypeReference(qualifiedRef.tokens, qualifiedRef.sourceStart, qualifiedRef.sourceEnd);
+		if (thrownExceptions != null) {
+			for (int i = 0, max=thrownExceptions.length; i < max; i++) {
+				TypeReference typeRef = thrownExceptions[i];
+				if (typeRef instanceof JavadocSingleTypeReference) {
+					JavadocSingleTypeReference singleRef = (JavadocSingleTypeReference) typeRef;
+					this.requestor.acceptTypeReference(singleRef.token, singleRef.sourceStart);
+				} else if (typeRef instanceof JavadocQualifiedTypeReference) {
+					JavadocQualifiedTypeReference qualifiedRef = (JavadocQualifiedTypeReference) typeRef;
+					this.requestor.acceptTypeReference(qualifiedRef.tokens, qualifiedRef.sourceStart, qualifiedRef.sourceEnd);
+				}
 			}
 		}
 
 		// Report reference info in javadoc comment @see tags
 		Expression[] references = this.javadoc.seeReferences;
-		int seeTagsNbre = references == null ? 0 : references.length;
-		for (int i = 0; i < seeTagsNbre; i++) {
-			Expression reference = references[i];
-			acceptJavadocTypeReference(reference);
-			if (reference instanceof JavadocFieldReference) {
-				JavadocFieldReference fieldRef = (JavadocFieldReference) reference;
-				this.requestor.acceptFieldReference(fieldRef.token, fieldRef.sourceStart);
-				if (fieldRef.receiver != null && !fieldRef.receiver.isThis()) {
-					acceptJavadocTypeReference(fieldRef.receiver);
-				}
-			} else if (reference instanceof JavadocMessageSend) {
-				JavadocMessageSend messageSend = (JavadocMessageSend) reference;
-				int argCount = messageSend.arguments == null ? 0 : messageSend.arguments.length;
-				this.requestor.acceptMethodReference(messageSend.selector, argCount, messageSend.sourceStart);
-				this.requestor.acceptConstructorReference(messageSend.selector, argCount, messageSend.sourceStart);
-				if (messageSend.receiver != null && !messageSend.receiver.isThis()) {
-					acceptJavadocTypeReference(messageSend.receiver);
-				}
-			} else if (reference instanceof JavadocAllocationExpression) {
-				JavadocAllocationExpression constructor = (JavadocAllocationExpression) reference;
-				int argCount = constructor.arguments == null ? 0 : constructor.arguments.length;
-				if (constructor.type != null) {
-					char[][] compoundName = constructor.type.getParameterizedTypeName();
-					this.requestor.acceptConstructorReference(compoundName[compoundName.length-1], argCount, constructor.sourceStart);
-					if (!constructor.type.isThis()) {
-						acceptJavadocTypeReference(constructor.type);
+		if (references != null) {
+			for (int i = 0, max=references.length; i < max; i++) {
+				Expression reference = references[i];
+				acceptJavadocTypeReference(reference);
+				if (reference instanceof JavadocFieldReference) {
+					JavadocFieldReference fieldRef = (JavadocFieldReference) reference;
+					this.requestor.acceptFieldReference(fieldRef.token, fieldRef.sourceStart);
+					if (fieldRef.receiver != null && !fieldRef.receiver.isThis()) {
+						acceptJavadocTypeReference(fieldRef.receiver);
+					}
+				} else if (reference instanceof JavadocMessageSend) {
+					JavadocMessageSend messageSend = (JavadocMessageSend) reference;
+					int argCount = messageSend.arguments == null ? 0 : messageSend.arguments.length;
+					this.requestor.acceptMethodReference(messageSend.selector, argCount, messageSend.sourceStart);
+					this.requestor.acceptConstructorReference(messageSend.selector, argCount, messageSend.sourceStart);
+					if (messageSend.receiver != null && !messageSend.receiver.isThis()) {
+						acceptJavadocTypeReference(messageSend.receiver);
+					}
+				} else if (reference instanceof JavadocAllocationExpression) {
+					JavadocAllocationExpression constructor = (JavadocAllocationExpression) reference;
+					int argCount = constructor.arguments == null ? 0 : constructor.arguments.length;
+					if (constructor.type != null) {
+						char[][] compoundName = constructor.type.getParameterizedTypeName();
+						this.requestor.acceptConstructorReference(compoundName[compoundName.length-1], argCount, constructor.sourceStart);
+						if (!constructor.type.isThis()) {
+							acceptJavadocTypeReference(constructor.type);
+						}
 					}
 				}
 			}
 		}
 	}
 }
-private void acceptJavadocTypeReference(Expression expression) {
-	if (expression instanceof JavadocSingleTypeReference) {
-		JavadocSingleTypeReference singleRef = (JavadocSingleTypeReference) expression;
-		this.requestor.acceptTypeReference(singleRef.token, singleRef.sourceStart);
-	} else if (expression instanceof JavadocQualifiedTypeReference) {
-		JavadocQualifiedTypeReference qualifiedRef = (JavadocQualifiedTypeReference) expression;
-		this.requestor.acceptTypeReference(qualifiedRef.tokens, qualifiedRef.sourceStart, qualifiedRef.sourceEnd);
-	}
-}
 protected void classInstanceCreation(boolean alwaysQualified) {
 
 	boolean previousFlag = reportReferenceInfo;
@@ -251,6 +289,18 @@
 			alloc.sourceStart);
 	}
 }
+protected void consumeAnnotationTypeDeclarationHeaderName() {
+	int currentAstPtr = this.astPtr;
+	super.consumeAnnotationTypeDeclarationHeaderName();
+	if (this.astPtr > currentAstPtr) // if ast node was pushed on the ast stack
+		rememberCategories();
+}
+protected void consumeClassHeaderName1() {
+	int currentAstPtr = this.astPtr;
+	super.consumeClassHeaderName1();
+	if (this.astPtr > currentAstPtr) // if ast node was pushed on the ast stack
+		rememberCategories();
+}
 protected void consumeClassInstanceCreationExpressionWithTypeArguments() {
 	boolean previousFlag = reportReferenceInfo;
 	reportReferenceInfo = false; // not to see the type reference reported in super call to getTypeReference(...)
@@ -272,22 +322,27 @@
 	int selectorSourceEnd = (int) selectorSourcePositions;
 	int currentAstPtr = this.astPtr;
 	super.consumeConstructorHeaderName();
-	if (this.astPtr > currentAstPtr) // if ast node was pushed on the ast stack
+	if (this.astPtr > currentAstPtr) { // if ast node was pushed on the ast stack
 		this.sourceEnds.put(this.astStack[this.astPtr], selectorSourceEnd);
+		rememberCategories();
+	}
 }
 protected void consumeConstructorHeaderNameWithTypeParameters() {
 	long selectorSourcePositions = this.identifierPositionStack[this.identifierPtr];
 	int selectorSourceEnd = (int) selectorSourcePositions;
 	int currentAstPtr = this.astPtr;
 	super.consumeConstructorHeaderNameWithTypeParameters();
-	if (this.astPtr > currentAstPtr) // if ast node was pushed on the ast stack
+	if (this.astPtr > currentAstPtr) { // if ast node was pushed on the ast stack
 		this.sourceEnds.put(this.astStack[this.astPtr], selectorSourceEnd);
+		rememberCategories();
+	}
 }
 protected void consumeEnumConstantWithClassBody() {
 	super.consumeEnumConstantWithClassBody();
 	if ((currentToken == TokenNameCOMMA || currentToken == TokenNameSEMICOLON)
 			&& astStack[astPtr] instanceof FieldDeclaration) {
 		this.sourceEnds.put(this.astStack[this.astPtr], this.scanner.currentPosition - 1);
+		rememberCategories();
 	}
 }
 protected void consumeEnumConstantNoClassBody() {
@@ -295,8 +350,15 @@
 	if ((currentToken == TokenNameCOMMA || currentToken == TokenNameSEMICOLON)
 			&& this.astStack[this.astPtr] instanceof FieldDeclaration) {
 		this.sourceEnds.put(this.astStack[this.astPtr], this.scanner.currentPosition - 1);
+		rememberCategories();
 	}
 }
+protected void consumeEnumHeaderName() {
+	int currentAstPtr = this.astPtr;
+	super.consumeEnumHeaderName();
+	if (this.astPtr > currentAstPtr) // if ast node was pushed on the ast stack
+		rememberCategories();
+}
 protected void consumeExitVariableWithInitialization() {
 	// ExitVariableWithInitialization ::= $empty
 	// the scanner is located after the comma or the semi-colon.
@@ -305,6 +367,7 @@
 	if ((currentToken == TokenNameCOMMA || currentToken == TokenNameSEMICOLON)
 			&& this.astStack[this.astPtr] instanceof FieldDeclaration) {
 		this.sourceEnds.put(this.astStack[this.astPtr], this.scanner.currentPosition - 1);
+		rememberCategories();
 	}
 }
 protected void consumeExitVariableWithoutInitialization() {
@@ -314,6 +377,7 @@
 	if ((currentToken == TokenNameCOMMA || currentToken == TokenNameSEMICOLON)
 			&& astStack[astPtr] instanceof FieldDeclaration) {
 		this.sourceEnds.put(this.astStack[this.astPtr], this.scanner.currentPosition - 1);
+		rememberCategories();
 	}
 }
 /*
@@ -329,6 +393,21 @@
 		requestor.acceptFieldReference(fr.token, fr.sourceStart);
 	}
 }
+protected void consumeFormalParameter(boolean isVarArgs) {
+	super.consumeFormalParameter(isVarArgs);
+	
+	// Flush comments prior to this formal parameter so the declarationSourceStart of the following parameter
+	// is correctly set (see bug 80904)
+	// Note that this could be done in the Parser itself, but this would slow down all parsers, when they don't need 
+	// the declarationSourceStart to be set
+	flushCommentsDefinedPriorTo(this.scanner.currentPosition);
+}
+protected void consumeInterfaceHeaderName1() {
+	int currentAstPtr = this.astPtr;
+	super.consumeInterfaceHeaderName1();
+	if (this.astPtr > currentAstPtr) // if ast node was pushed on the ast stack
+		rememberCategories();
+}
 protected void consumeMemberValuePair() {
 	super.consumeMemberValuePair();
 	MemberValuePair memberValuepair = (MemberValuePair) this.astStack[this.astPtr];
@@ -348,9 +427,12 @@
 	int selectorSourceEnd = (int) selectorSourcePositions;
 	int currentAstPtr = this.astPtr;
 	super.consumeMethodHeaderName(isAnnotationMethod);
-	if (this.astPtr > currentAstPtr) // if ast node was pushed on the ast stack
+	if (this.astPtr > currentAstPtr) { // if ast node was pushed on the ast stack
 		this.sourceEnds.put(this.astStack[this.astPtr], selectorSourceEnd);
+		rememberCategories();
+	}
 }
+
 protected void consumeMethodHeaderNameWithTypeParameters(boolean isAnnotationMethod) {
 	long selectorSourcePositions = this.identifierPositionStack[this.identifierPtr];
 	int selectorSourceEnd = (int) selectorSourcePositions;
@@ -358,6 +440,7 @@
 	super.consumeMethodHeaderNameWithTypeParameters(isAnnotationMethod);
 	if (this.astPtr > currentAstPtr) // if ast node was pushed on the ast stack
 		this.sourceEnds.put(this.astStack[this.astPtr], selectorSourceEnd);
+		rememberCategories();
 }
 /*
  *
@@ -465,35 +548,92 @@
 }
 protected void consumeSingleStaticImportDeclarationName() {
 	// SingleTypeImportDeclarationName ::= 'import' 'static' Name
-	super.consumeSingleStaticImportDeclarationName();
-	ImportReference impt = (ImportReference)astStack[astPtr];
+	ImportReference impt;
+	int length;
+	char[][] tokens = new char[length = this.identifierLengthStack[this.identifierLengthPtr--]][];
+	this.identifierPtr -= length;
+	long[] positions = new long[length];
+	System.arraycopy(this.identifierStack, this.identifierPtr + 1, tokens, 0, length);
+	System.arraycopy(this.identifierPositionStack, this.identifierPtr + 1, positions, 0, length);
+	pushOnAstStack(impt = newImportReference(tokens, positions, false, ClassFileConstants.AccStatic));
+	
+	this.modifiers = ClassFileConstants.AccDefault;
+	this.modifiersSourceStart = -1; // <-- see comment into modifiersFlag(int)
+	
+	if (this.currentToken == TokenNameSEMICOLON){
+		impt.declarationSourceEnd = this.scanner.currentPosition - 1;
+	} else {
+		impt.declarationSourceEnd = impt.sourceEnd;
+	}
+	impt.declarationEnd = impt.declarationSourceEnd;
+	//this.endPosition is just before the ;
+	impt.declarationSourceStart = this.intStack[this.intPtr--];
+	
+	if(!this.statementRecoveryActivated &&
+			this.options.sourceLevel < ClassFileConstants.JDK1_5 &&
+			this.lastErrorEndPositionBeforeRecovery < this.scanner.currentPosition) {
+		impt.modifiers = ClassFileConstants.AccDefault; // convert the static import reference to a non-static importe reference
+		this.problemReporter().invalidUsageOfStaticImports(impt);
+	}
+	
+	// recovery
+	if (this.currentElement != null){
+		this.lastCheckPoint = impt.declarationSourceEnd+1;
+		this.currentElement = this.currentElement.add(impt, 0);
+		this.lastIgnoredToken = -1;
+		this.restartRecovery = true; // used to avoid branching back into the regular automaton		
+	}
 	if (reportReferenceInfo) {
 		// Name for static import is TypeName '.' Identifier
 		// => accept unknown ref on identifier
-		int length = impt.tokens.length-1;
-		int start = (int) (impt.sourcePositions[length] >>> 32);
-		char[] last = impt.tokens[length];
+		int tokensLength = impt.tokens.length-1;
+		int start = (int) (impt.sourcePositions[tokensLength] >>> 32);
+		char[] last = impt.tokens[tokensLength];
 		// accept all possible kind for last name, index users will have to select the right one...
 		// see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=86901
 		requestor.acceptFieldReference(last, start);
 		requestor.acceptMethodReference(last, 0,start);
 		requestor.acceptTypeReference(last, start);
 		// accept type name
-		if (length > 0) {
-			char[][] compoundName = new char[length][];
-			System.arraycopy(impt.tokens, 0, compoundName, 0, length);
-			int end = (int) impt.sourcePositions[length-1];
+		if (tokensLength > 0) {
+			char[][] compoundName = new char[tokensLength][];
+			System.arraycopy(impt.tokens, 0, compoundName, 0, tokensLength);
+			int end = (int) impt.sourcePositions[tokensLength-1];
 			requestor.acceptTypeReference(compoundName, impt.sourceStart, end);
 		}
 	}
 }
+
 protected void consumeSingleTypeImportDeclarationName() {
 	// SingleTypeImportDeclarationName ::= 'import' Name
 	/* push an ImportRef build from the last name 
 	stored in the identifier stack. */
 
-	super.consumeSingleTypeImportDeclarationName();
-	ImportReference impt = (ImportReference)astStack[astPtr];
+	ImportReference impt;
+	int length;
+	char[][] tokens = new char[length = this.identifierLengthStack[this.identifierLengthPtr--]][];
+	this.identifierPtr -= length;
+	long[] positions = new long[length];
+	System.arraycopy(this.identifierStack, this.identifierPtr + 1, tokens, 0, length);
+	System.arraycopy(this.identifierPositionStack, this.identifierPtr + 1, positions, 0, length);
+	pushOnAstStack(impt = newImportReference(tokens, positions, false, ClassFileConstants.AccDefault));
+	
+	if (this.currentToken == TokenNameSEMICOLON){
+		impt.declarationSourceEnd = this.scanner.currentPosition - 1;
+	} else {
+		impt.declarationSourceEnd = impt.sourceEnd;
+	}
+	impt.declarationEnd = impt.declarationSourceEnd;
+	//this.endPosition is just before the ;
+	impt.declarationSourceStart = this.intStack[this.intPtr--];
+	
+	// recovery
+	if (this.currentElement != null){
+		this.lastCheckPoint = impt.declarationSourceEnd+1;
+		this.currentElement = this.currentElement.add(impt, 0);
+		this.lastIgnoredToken = -1;
+		this.restartRecovery = true; // used to avoid branching back into the regular automaton		
+	}
 	if (reportReferenceInfo) {
 		requestor.acceptTypeReference(impt.tokens, impt.sourceStart, impt.sourceEnd);
 	}
@@ -503,8 +643,41 @@
 	/* push an ImportRef build from the last name 
 	stored in the identifier stack. */
 
-	super.consumeStaticImportOnDemandDeclarationName();
-	ImportReference impt = (ImportReference)astStack[astPtr];
+	ImportReference impt;
+	int length;
+	char[][] tokens = new char[length = this.identifierLengthStack[this.identifierLengthPtr--]][];
+	this.identifierPtr -= length;
+	long[] positions = new long[length];
+	System.arraycopy(this.identifierStack, this.identifierPtr + 1, tokens, 0, length);
+	System.arraycopy(this.identifierPositionStack, this.identifierPtr + 1, positions, 0, length);
+	pushOnAstStack(impt = new ImportReference(tokens, positions, true, ClassFileConstants.AccStatic));
+	
+	this.modifiers = ClassFileConstants.AccDefault;
+	this.modifiersSourceStart = -1; // <-- see comment into modifiersFlag(int)
+	
+	if (this.currentToken == TokenNameSEMICOLON){
+		impt.declarationSourceEnd = this.scanner.currentPosition - 1;
+	} else {
+		impt.declarationSourceEnd = impt.sourceEnd;
+	}
+	impt.declarationEnd = impt.declarationSourceEnd;
+	//this.endPosition is just before the ;
+	impt.declarationSourceStart = this.intStack[this.intPtr--];
+	
+	if(!this.statementRecoveryActivated &&
+			options.sourceLevel < ClassFileConstants.JDK1_5 &&
+			this.lastErrorEndPositionBeforeRecovery < this.scanner.currentPosition) {
+		impt.modifiers = ClassFileConstants.AccDefault; // convert the static import reference to a non-static importe reference
+		this.problemReporter().invalidUsageOfStaticImports(impt);
+	}
+	
+	// recovery
+	if (this.currentElement != null){
+		this.lastCheckPoint = impt.declarationSourceEnd+1;
+		this.currentElement = this.currentElement.add(impt, 0);
+		this.lastIgnoredToken = -1;
+		this.restartRecovery = true; // used to avoid branching back into the regular automaton		
+	}
 	if (reportReferenceInfo) {
 		requestor.acceptTypeReference(impt.tokens, impt.sourceStart, impt.sourceEnd);
 	}
@@ -514,8 +687,31 @@
 	/* push an ImportRef build from the last name 
 	stored in the identifier stack. */
 
-	super.consumeTypeImportOnDemandDeclarationName();
-	ImportReference impt = (ImportReference)astStack[astPtr];
+	ImportReference impt;
+	int length;
+	char[][] tokens = new char[length = this.identifierLengthStack[this.identifierLengthPtr--]][];
+	this.identifierPtr -= length;
+	long[] positions = new long[length];
+	System.arraycopy(this.identifierStack, this.identifierPtr + 1, tokens, 0, length);
+	System.arraycopy(this.identifierPositionStack, this.identifierPtr + 1, positions, 0, length);
+	pushOnAstStack(impt = new ImportReference(tokens, positions, true, ClassFileConstants.AccDefault));
+	
+	if (this.currentToken == TokenNameSEMICOLON){
+		impt.declarationSourceEnd = this.scanner.currentPosition - 1;
+	} else {
+		impt.declarationSourceEnd = impt.sourceEnd;
+	}
+	impt.declarationEnd = impt.declarationSourceEnd;
+	//this.endPosition is just before the ;
+	impt.declarationSourceStart = this.intStack[this.intPtr--];
+	
+	// recovery
+	if (this.currentElement != null){
+		this.lastCheckPoint = impt.declarationSourceEnd+1;
+		this.currentElement = this.currentElement.add(impt, 0);
+		this.lastIgnoredToken = -1;
+		this.restartRecovery = true; // used to avoid branching back into the regular automaton		
+	}
 	if (reportReferenceInfo) {
 		requestor.acceptUnknownReference(impt.tokens, impt.sourceStart, impt.sourceEnd);
 	}
@@ -525,21 +721,25 @@
 	int selectorSourceEnd = this.sourceEnds.removeKey(c);
 	if (selectorSourceEnd != -1)
 		this.sourceEnds.put(methodDeclaration, selectorSourceEnd);
+	char[][] categories =  (char[][]) this.nodesToCategories.remove(c);
+	if (categories != null)
+		this.nodesToCategories.put(methodDeclaration, categories);
+	
 	return methodDeclaration;
 }
 protected CompilationUnitDeclaration endParse(int act) {
 	if (sourceType != null) {
-		switch (sourceType.getKind()) {
-			case IGenericType.CLASS_DECL :
+		switch (TypeDeclaration.kind(sourceType.getModifiers())) {
+			case TypeDeclaration.CLASS_DECL :
 				consumeClassDeclaration();
 				break;
-			case IGenericType.INTERFACE_DECL :
+			case TypeDeclaration.INTERFACE_DECL :
 				consumeInterfaceDeclaration();
 				break;
-			case IGenericType.ENUM_DECL :
+			case TypeDeclaration.ENUM_DECL :
 				consumeEnumDeclaration();
 				break;
-			case IGenericType.ANNOTATION_TYPE_DECL :
+			case TypeDeclaration.ANNOTATION_TYPE_DECL :
 				consumeAnnotationTypeDeclaration();
 				break;
 		}
@@ -551,6 +751,42 @@
 		return null;
 	}		
 }
+private ISourceElementRequestor.TypeParameterInfo[] getTypeParameterInfos(TypeParameter[] typeParameters) {
+	if (typeParameters == null) return null;
+	int typeParametersLength = typeParameters.length;
+	ISourceElementRequestor.TypeParameterInfo[] result = new ISourceElementRequestor.TypeParameterInfo[typeParametersLength];
+	for (int i = 0; i < typeParametersLength; i++) {
+		TypeParameter typeParameter = typeParameters[i];
+		TypeReference firstBound = typeParameter.type;
+		TypeReference[] otherBounds = typeParameter.bounds;
+		char[][] typeParameterBounds = null;
+		if (firstBound != null) {
+			if (otherBounds != null) {
+				int otherBoundsLength = otherBounds.length;
+				char[][] boundNames = new char[otherBoundsLength+1][];
+				boundNames[0] = CharOperation.concatWith(firstBound.getParameterizedTypeName(), '.');
+				for (int j = 0; j < otherBoundsLength; j++) {
+					boundNames[j+1] = 
+						CharOperation.concatWith(otherBounds[j].getParameterizedTypeName(), '.'); 
+				}
+				typeParameterBounds = boundNames;
+			} else {
+				typeParameterBounds = new char[][] { CharOperation.concatWith(firstBound.getParameterizedTypeName(), '.')};
+			}
+		} else {
+			typeParameterBounds = CharOperation.NO_CHAR_CHAR;
+		}
+		ISourceElementRequestor.TypeParameterInfo typeParameterInfo = new ISourceElementRequestor.TypeParameterInfo();
+		typeParameterInfo.declarationStart = typeParameter.declarationSourceStart;
+		typeParameterInfo.declarationEnd = typeParameter.declarationSourceEnd;
+		typeParameterInfo.name = typeParameter.name;
+		typeParameterInfo.nameSourceStart = typeParameter.sourceStart;
+		typeParameterInfo.nameSourceEnd = typeParameter.sourceEnd;
+		typeParameterInfo.bounds = typeParameterBounds;
+		result[i] = typeParameterInfo;
+	}
+	return result;
+}
 public TypeReference getTypeReference(int dim) {
 	/* build a Reference on a variable that may be qualified or not
 	 * This variable is a type reference and dim will be its dimensions
@@ -645,7 +881,7 @@
 	if ((length = identifierLengthStack[identifierLengthPtr--]) == 1) {
 		// single variable reference
 		SingleNameReference ref = 
-			new SingleNameReference(
+			newSingleNameReference(
 				identifierStack[identifierPtr], 
 				identifierPositionStack[identifierPtr--]); 
 		if (reportReferenceInfo) {
@@ -660,7 +896,7 @@
 		long[] positions = new long[length];
 		System.arraycopy(identifierPositionStack, identifierPtr + 1, positions, 0, length);
 		QualifiedNameReference ref = 
-			new QualifiedNameReference(
+			newQualifiedNameReference(
 				tokens, 
 				positions,
 				(int) (identifierPositionStack[identifierPtr + 1] >> 32), // sourceStart
@@ -683,7 +919,7 @@
 	if ((length = identifierLengthStack[identifierLengthPtr--]) == 1) {
 		// single variable reference
 		SingleNameReference ref = 
-			new SingleNameReference(
+			newSingleNameReference(
 				identifierStack[identifierPtr], 
 				identifierPositionStack[identifierPtr--]); 
 		ref.bits &= ~ASTNode.RestrictiveFlagMASK;
@@ -706,7 +942,7 @@
 	long[] positions = new long[length];
 	System.arraycopy(identifierPositionStack, identifierPtr + 1, positions, 0, length);
 	QualifiedNameReference ref = 
-		new QualifiedNameReference(
+		newQualifiedNameReference(
 			tokens, 
 			positions,
 			(int) (identifierPositionStack[identifierPtr + 1] >> 32), 
@@ -719,6 +955,32 @@
 	}
 	return ref;
 }
+
+/*
+ * Checks whether one of the annotations is the @Deprecated annotation
+ * (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=89807)
+ */
+private boolean hasDeprecatedAnnotation(Annotation[] annotations) {
+	if (annotations != null) {
+		for (int i = 0, length = annotations.length; i < length; i++) {
+			Annotation annotation = annotations[i];
+			if (CharOperation.equals(annotation.type.getLastToken(), TypeConstants.JAVA_LANG_DEPRECATED[2])) {
+				return true;
+			}
+		}
+	}
+	return false;
+}
+
+protected ImportReference newImportReference(char[][] tokens, long[] positions, boolean onDemand, int mod) {
+	return new ImportReference(tokens, positions, onDemand, mod);
+}
+protected QualifiedNameReference newQualifiedNameReference(char[][] tokens, long[] positions, int sourceStart, int sourceEnd) {
+	return new QualifiedNameReference(tokens, positions, sourceStart, sourceEnd);
+}
+protected SingleNameReference newSingleNameReference(char[] source, long positions) {
+	return new SingleNameReference(source, positions);
+}
 /*
  * Update the bodyStart of the corresponding parse node
  */
@@ -737,9 +999,6 @@
 				scanner.initialPosition <= parsedUnit.sourceStart
 				&& scanner.eofPosition >= parsedUnit.sourceEnd;
 	
-	if (reportReferenceInfo) {
-		notifyAllUnknownReferences();
-	}
 	// collect the top level ast nodes
 	int length = 0;
 	ASTNode[] nodes = null;
@@ -805,44 +1064,6 @@
 	}
 }
 
-private void notifyAllUnknownReferences() {
-	for (int i = 0, max = this.unknownRefsCounter; i < max; i++) {
-		NameReference nameRef = this.unknownRefs[i];
-		if ((nameRef.bits & Binding.VARIABLE) != 0) {
-			if ((nameRef.bits & Binding.TYPE) == 0) { 
-				// variable but not type
-				if (nameRef instanceof SingleNameReference) { 
-					// local var or field
-					requestor.acceptUnknownReference(((SingleNameReference) nameRef).token, nameRef.sourceStart);
-				} else {
-					// QualifiedNameReference
-					// The last token is a field reference and the previous tokens are a type/variable references
-					char[][] tokens = ((QualifiedNameReference) nameRef).tokens;
-					int tokensLength = tokens.length;
-					requestor.acceptFieldReference(tokens[tokensLength - 1], nameRef.sourceEnd - tokens[tokensLength - 1].length + 1);
-					char[][] typeRef = new char[tokensLength - 1][];
-					System.arraycopy(tokens, 0, typeRef, 0, tokensLength - 1);
-					requestor.acceptUnknownReference(typeRef, nameRef.sourceStart, nameRef.sourceEnd - tokens[tokensLength - 1].length);
-				}
-			} else {
-				// variable or type
-				if (nameRef instanceof SingleNameReference) {
-					requestor.acceptUnknownReference(((SingleNameReference) nameRef).token, nameRef.sourceStart);
-				} else {
-					//QualifiedNameReference
-					requestor.acceptUnknownReference(((QualifiedNameReference) nameRef).tokens, nameRef.sourceStart, nameRef.sourceEnd);
-				}
-			}
-		} else if ((nameRef.bits & Binding.TYPE) != 0) {
-			if (nameRef instanceof SingleNameReference) {
-				requestor.acceptTypeReference(((SingleNameReference) nameRef).token, nameRef.sourceStart);
-			} else {
-				// it is a QualifiedNameReference
-				requestor.acceptTypeReference(((QualifiedNameReference) nameRef).tokens, nameRef.sourceStart, nameRef.sourceEnd);
-			}
-		}
-	}
-}
 /*
  * Update the bodyStart of the corresponding parse node
  */
@@ -913,12 +1134,15 @@
 		if (isInRange){
 			int currentModifiers = methodDeclaration.modifiers;
 			if (isVarArgs)
-				currentModifiers |= AccVarargs;
-			boolean deprecated = (currentModifiers & AccDeprecated) != 0; // remember deprecation so as to not lose it below
+				currentModifiers |= ClassFileConstants.AccVarargs;
+			
+			// remember deprecation so as to not lose it below
+			boolean deprecated = (currentModifiers & ClassFileConstants.AccDeprecated) != 0 || hasDeprecatedAnnotation(methodDeclaration.annotations);
+			
 			ISourceElementRequestor.MethodInfo methodInfo = new ISourceElementRequestor.MethodInfo();
 			methodInfo.isConstructor = true;
 			methodInfo.declarationStart = methodDeclaration.declarationSourceStart;
-			methodInfo.modifiers = deprecated ? (currentModifiers & AccJustFlag) | AccDeprecated : currentModifiers & AccJustFlag;
+			methodInfo.modifiers = deprecated ? (currentModifiers & ExtraCompilerModifiers.AccJustFlag) | ClassFileConstants.AccDeprecated : currentModifiers & ExtraCompilerModifiers.AccJustFlag;
 			methodInfo.name = methodDeclaration.selector;
 			methodInfo.nameSourceStart = methodDeclaration.sourceStart;
 			methodInfo.nameSourceEnd = selectorSourceEnd;
@@ -927,6 +1151,7 @@
 			methodInfo.exceptionTypes = thrownExceptionTypes;
 			methodInfo.typeParameters = getTypeParameterInfos(methodDeclaration.typeParameters());
 			methodInfo.annotationPositions = collectAnnotationPositions(methodDeclaration.annotations);
+			methodInfo.categories = (char[][]) this.nodesToCategories.get(methodDeclaration);
 			requestor.enterConstructor(methodInfo);
 		}
 		if (reportReferenceInfo) {
@@ -960,15 +1185,18 @@
 	if (isInRange) {
 		int currentModifiers = methodDeclaration.modifiers;
 		if (isVarArgs)
-			currentModifiers |= AccVarargs;
-		boolean deprecated = (currentModifiers & AccDeprecated) != 0; // remember deprecation so as to not lose it below
+			currentModifiers |= ClassFileConstants.AccVarargs;
+		
+		// remember deprecation so as to not lose it below
+		boolean deprecated = (currentModifiers & ClassFileConstants.AccDeprecated) != 0 || hasDeprecatedAnnotation(methodDeclaration.annotations);	
+			
 		TypeReference returnType = methodDeclaration instanceof MethodDeclaration
 			? ((MethodDeclaration) methodDeclaration).returnType
 			: null;
 		ISourceElementRequestor.MethodInfo methodInfo = new ISourceElementRequestor.MethodInfo();
 		methodInfo.isAnnotation = methodDeclaration instanceof AnnotationMethodDeclaration;
 		methodInfo.declarationStart = methodDeclaration.declarationSourceStart;
-		methodInfo.modifiers = deprecated ? (currentModifiers & AccJustFlag) | AccDeprecated : currentModifiers & AccJustFlag;
+		methodInfo.modifiers = deprecated ? (currentModifiers & ExtraCompilerModifiers.AccJustFlag) | ClassFileConstants.AccDeprecated : currentModifiers & ExtraCompilerModifiers.AccJustFlag;
 		methodInfo.returnType = returnType == null ? null : CharOperation.concatWith(returnType.getParameterizedTypeName(), '.');
 		methodInfo.name = methodDeclaration.selector;
 		methodInfo.nameSourceStart = methodDeclaration.sourceStart;
@@ -978,6 +1206,7 @@
 		methodInfo.exceptionTypes = thrownExceptionTypes;
 		methodInfo.typeParameters = getTypeParameterInfos(methodDeclaration.typeParameters());
 		methodInfo.annotationPositions = collectAnnotationPositions(methodDeclaration.annotations);
+		methodInfo.categories = (char[][]) this.nodesToCategories.get(methodDeclaration);
 		requestor.enterMethod(methodInfo);
 	}		
 		
@@ -995,42 +1224,6 @@
 		requestor.exitMethod(methodDeclaration.declarationSourceEnd, -1, -1);
 	}
 }
-private ISourceElementRequestor.TypeParameterInfo[] getTypeParameterInfos(TypeParameter[] typeParameters) {
-	if (typeParameters == null) return null;
-	int typeParametersLength = typeParameters.length;
-	ISourceElementRequestor.TypeParameterInfo[] result = new ISourceElementRequestor.TypeParameterInfo[typeParametersLength];
-	for (int i = 0; i < typeParametersLength; i++) {
-		TypeParameter typeParameter = typeParameters[i];
-		TypeReference firstBound = typeParameter.type;
-		TypeReference[] otherBounds = typeParameter.bounds;
-		char[][] typeParameterBounds = null;
-		if (firstBound != null) {
-			if (otherBounds != null) {
-				int otherBoundsLength = otherBounds.length;
-				char[][] boundNames = new char[otherBoundsLength+1][];
-				boundNames[0] = CharOperation.concatWith(firstBound.getParameterizedTypeName(), '.');
-				for (int j = 0; j < otherBoundsLength; j++) {
-					boundNames[j+1] = 
-						CharOperation.concatWith(otherBounds[j].getParameterizedTypeName(), '.'); 
-				}
-				typeParameterBounds = boundNames;
-			} else {
-				typeParameterBounds = new char[][] { CharOperation.concatWith(firstBound.getParameterizedTypeName(), '.')};
-			}
-		} else {
-			typeParameterBounds = CharOperation.NO_CHAR_CHAR;
-		}
-		ISourceElementRequestor.TypeParameterInfo typeParameterInfo = new ISourceElementRequestor.TypeParameterInfo();
-		typeParameterInfo.declarationStart = typeParameter.declarationSourceStart;
-		typeParameterInfo.declarationEnd = typeParameter.declarationSourceEnd;
-		typeParameterInfo.name = typeParameter.name;
-		typeParameterInfo.nameSourceStart = typeParameter.sourceStart;
-		typeParameterInfo.nameSourceEnd = typeParameter.sourceEnd;
-		typeParameterInfo.bounds = typeParameterBounds;
-		result[i] = typeParameterInfo;
-	}
-	return result;
-}
 
 /*
 * Update the bodyStart of the corresponding parse node
@@ -1061,12 +1254,15 @@
 			}
 			if (isInRange) {
 				int currentModifiers = fieldDeclaration.modifiers;
-				boolean deprecated = (currentModifiers & AccDeprecated) != 0; // remember deprecation so as to not lose it below
+				
+				// remember deprecation so as to not lose it below
+				boolean deprecated = (currentModifiers & ClassFileConstants.AccDeprecated) != 0 || hasDeprecatedAnnotation(fieldDeclaration.annotations);	
+			
 				char[] typeName = null;
 				if (fieldDeclaration.type == null) {
 					// enum constant
 					typeName = declaringType.name;
-					currentModifiers |= AccEnum;
+					currentModifiers |= ClassFileConstants.AccEnum;
 				} else {
 					// regular field
 					typeName = CharOperation.concatWith(fieldDeclaration.type.getParameterizedTypeName(), '.');
@@ -1074,11 +1270,12 @@
 				ISourceElementRequestor.FieldInfo fieldInfo = new ISourceElementRequestor.FieldInfo();
 				fieldInfo.declarationStart = fieldDeclaration.declarationSourceStart;
 				fieldInfo.name = fieldDeclaration.name;
-				fieldInfo.modifiers = deprecated ? (currentModifiers & AccJustFlag) | AccDeprecated : currentModifiers & AccJustFlag;
+				fieldInfo.modifiers = deprecated ? (currentModifiers & ExtraCompilerModifiers.AccJustFlag) | ClassFileConstants.AccDeprecated : currentModifiers & ExtraCompilerModifiers.AccJustFlag;
 				fieldInfo.type = typeName;
 				fieldInfo.nameSourceStart = fieldDeclaration.sourceStart;
 				fieldInfo.nameSourceEnd = fieldDeclaration.sourceEnd;
 				fieldInfo.annotationPositions = collectAnnotationPositions(fieldDeclaration.annotations);
+				fieldInfo.categories = (char[][]) this.nodesToCategories.get(fieldDeclaration);
 				requestor.enterField(fieldInfo);
 			}
 			this.visitIfNeeded(fieldDeclaration, declaringType);
@@ -1125,15 +1322,15 @@
 		requestor.acceptImport(
 			importReference.declarationSourceStart, 
 			importReference.declarationSourceEnd, 
-			CharOperation.concatWith(importReference.getImportName(), '.'), 
-			importReference.onDemand,
+			importReference.tokens, 
+			(importReference.bits & ASTNode.OnDemand) != 0,
 			importReference.modifiers); 
 	}
 }
 public void notifySourceElementRequestor(TypeDeclaration typeDeclaration, boolean notifyTypePresence, TypeDeclaration declaringType) {
 	
 	if (CharOperation.equals(TypeConstants.PACKAGE_INFO_NAME, typeDeclaration.name)) return;
-	
+
 	// range check
 	boolean isInRange = 
 		scanner.initialPosition <= typeDeclaration.declarationSourceStart
@@ -1157,7 +1354,7 @@
 			superInterfacesLength = superInterfaces.length;
 			interfaceNames = new char[superInterfacesLength][];
 		} else {
-			if ((typeDeclaration.bits & ASTNode.IsAnonymousTypeMASK) != 0) {
+			if ((typeDeclaration.bits & ASTNode.IsAnonymousType) != 0) {
 				// see PR 3442
 				QualifiedAllocationExpression alloc = typeDeclaration.allocation;
 				if (alloc != null && alloc.type != null) {
@@ -1173,24 +1370,26 @@
 					CharOperation.concatWith(superInterfaces[i].getParameterizedTypeName(), '.'); 
 			}
 		}
-		int kind = typeDeclaration.kind();
+		int kind = TypeDeclaration.kind(typeDeclaration.modifiers);
 		char[] implicitSuperclassName = TypeConstants.CharArray_JAVA_LANG_OBJECT;
 		if (isInRange) {
 			int currentModifiers = typeDeclaration.modifiers;
-			boolean deprecated = (currentModifiers & AccDeprecated) != 0; // remember deprecation so as to not lose it below
+			
+			// remember deprecation so as to not lose it below
+			boolean deprecated = (currentModifiers & ClassFileConstants.AccDeprecated) != 0 || hasDeprecatedAnnotation(typeDeclaration.annotations);	
+			
 			boolean isEnumInit = typeDeclaration.allocation != null && typeDeclaration.allocation.enumConstant != null;
 			char[] superclassName;
 			if (isEnumInit) {
-				currentModifiers |= AccEnum;
+				currentModifiers |= ClassFileConstants.AccEnum;
 				superclassName = declaringType.name;
 			} else {
 				TypeReference superclass = typeDeclaration.superclass;
 				superclassName = superclass != null ? CharOperation.concatWith(superclass.getParameterizedTypeName(), '.') : null;
 			}
 			ISourceElementRequestor.TypeInfo typeInfo = new ISourceElementRequestor.TypeInfo();
-			typeInfo.kind = kind;
 			typeInfo.declarationStart = typeDeclaration.declarationSourceStart;
-			typeInfo.modifiers = deprecated ? (currentModifiers & AccJustFlag) | AccDeprecated : currentModifiers & AccJustFlag;
+			typeInfo.modifiers = deprecated ? (currentModifiers & ExtraCompilerModifiers.AccJustFlag) | ClassFileConstants.AccDeprecated : currentModifiers & ExtraCompilerModifiers.AccJustFlag;
 			typeInfo.name = typeDeclaration.name;
 			typeInfo.nameSourceStart = typeDeclaration.sourceStart;
 			typeInfo.nameSourceEnd = sourceEnd(typeDeclaration);
@@ -1198,19 +1397,22 @@
 			typeInfo.superinterfaces = interfaceNames;
 			typeInfo.typeParameters = getTypeParameterInfos(typeDeclaration.typeParameters);
 			typeInfo.annotationPositions = collectAnnotationPositions(typeDeclaration.annotations);
+			typeInfo.categories = (char[][]) this.nodesToCategories.get(typeDeclaration);
+			typeInfo.secondary = typeDeclaration.isSecondary();
+			typeInfo.anonymousMember = typeDeclaration.allocation != null && typeDeclaration.allocation.enclosingInstance != null;
 			requestor.enterType(typeInfo);
 			switch (kind) {
-				case IGenericType.CLASS_DECL :
+				case TypeDeclaration.CLASS_DECL :
 					if (superclassName != null)
 						implicitSuperclassName = superclassName;
 					break;
-				case IGenericType.INTERFACE_DECL :
+				case TypeDeclaration.INTERFACE_DECL :
 					implicitSuperclassName = TypeConstants.CharArray_JAVA_LANG_OBJECT;
 					break;
-				case IGenericType.ENUM_DECL :
+				case TypeDeclaration.ENUM_DECL :
 					implicitSuperclassName = TypeConstants.CharArray_JAVA_LANG_ENUM;
 					break;
-				case IGenericType.ANNOTATION_TYPE_DECL :
+				case TypeDeclaration.ANNOTATION_TYPE_DECL :
 					implicitSuperclassName = TypeConstants.CharArray_JAVA_LANG_ANNOTATION_ANNOTATION;
 					break;
 			}
@@ -1274,16 +1476,6 @@
 		nestedTypeIndex--;
 	}
 }
-private int sourceEnd(TypeDeclaration typeDeclaration) {
-	if ((typeDeclaration.bits & ASTNode.IsAnonymousTypeMASK) != 0) {
-		QualifiedAllocationExpression allocation = typeDeclaration.allocation;
-		if (allocation.type == null) // case of enum constant body
-			return typeDeclaration.sourceEnd;
-		return allocation.type.sourceEnd;
-	} else {
-		return typeDeclaration.sourceEnd;
-	}
-}
 public void parseCompilationUnit(
 	ICompilationUnit unit, 
 	int start, 
@@ -1292,17 +1484,13 @@
 
 	this.reportReferenceInfo = fullParse;
 	boolean old = diet;
-	if (fullParse) {
-		unknownRefs = new NameReference[10];
-		unknownRefsCounter = 0;
-	}
 	
 	try {
 		diet = true;
 		CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0, this.options.maxProblemsPerUnit);
 		CompilationUnitDeclaration parsedUnit = parse(unit, compilationUnitResult, start, end);
 		if (scanner.recordLineSeparator) {
-			requestor.acceptLineSeparatorPositions(compilationUnitResult.lineSeparatorPositions);
+			requestor.acceptLineSeparatorPositions(compilationUnitResult.getLineSeparatorPositions());
 		}
 		if (this.localDeclarationVisitor != null || fullParse){
 			diet = false;
@@ -1314,6 +1502,7 @@
 		// ignore this exception
 	} finally {
 		diet = old;
+		reset();
 	}
 }
 public CompilationUnitDeclaration parseCompilationUnit(
@@ -1321,10 +1510,6 @@
 	boolean fullParse) {
 		
 	boolean old = diet;
-	if (fullParse) {
-		unknownRefs = new NameReference[10];
-		unknownRefsCounter = 0;
-	}
 
 	try {
 		diet = true;
@@ -1332,7 +1517,7 @@
 		CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0, this.options.maxProblemsPerUnit);
 		CompilationUnitDeclaration parsedUnit = parse(unit, compilationUnitResult);
 		if (scanner.recordLineSeparator) {
-			requestor.acceptLineSeparatorPositions(compilationUnitResult.lineSeparatorPositions);
+			requestor.acceptLineSeparatorPositions(compilationUnitResult.getLineSeparatorPositions());
 		}
 		int initialStart = this.scanner.initialPosition;
 		int initialEnd = this.scanner.eofPosition;
@@ -1347,6 +1532,7 @@
 		// ignore this exception
 	} finally {
 		diet = old;
+		reset();
 	}
 	return null;
 }
@@ -1357,10 +1543,6 @@
 	int end, 
 	boolean needReferenceInfo) {
 	boolean old = diet;
-	if (needReferenceInfo) {
-		unknownRefs = new NameReference[10];
-		unknownRefsCounter = 0;
-	}
 	
 	CompilationResult compilationUnitResult = 
 		new CompilationResult(sourceUnit, 0, 0, this.options.maxProblemsPerUnit); 
@@ -1402,9 +1584,10 @@
 		// ignore this exception
 	} finally {
 		if (scanner.recordLineSeparator) {
-			requestor.acceptLineSeparatorPositions(compilationUnitResult.lineSeparatorPositions);
+			requestor.acceptLineSeparatorPositions(compilationUnitResult.getLineSeparatorPositions());
 		}
 		diet = old;
+		reset();
 	}
 }
 
@@ -1440,6 +1623,7 @@
 		// ignore this exception
 	} finally {
 		diet = old;
+		reset();
 	}
 }
 /*
@@ -1448,7 +1632,7 @@
 private static void quickSort(ASTNode[] sortedCollection, int left, int right) {
 	int original_left = left;
 	int original_right = right;
-	ASTNode mid = sortedCollection[ (left + right) / 2];
+	ASTNode mid = sortedCollection[left +  (right - left) / 2];
 	do {
 		while (sortedCollection[left].sourceStart < mid.sourceStart) {
 			left++;
@@ -1471,22 +1655,36 @@
 		quickSort(sortedCollection, left, original_right);
 	}
 }
-public void addUnknownRef(NameReference nameRef) {
-	if (this.unknownRefs.length == this.unknownRefsCounter) {
-		// resize
-		System.arraycopy(
-			this.unknownRefs,
-			0,
-			(this.unknownRefs = new NameReference[this.unknownRefsCounter * 2]),
-			0,
-			this.unknownRefsCounter);
+private void rememberCategories() {
+	if (this.useSourceJavadocParser) {
+		SourceJavadocParser sourceJavadocParser = (SourceJavadocParser) this.javadocParser;
+		char[][] categories =  sourceJavadocParser.categories;
+		if (categories.length > 0) {
+			this.nodesToCategories.put(this.astStack[this.astPtr], categories);
+			sourceJavadocParser.categories = CharOperation.NO_CHAR_CHAR;
+		}
 	}
-	this.unknownRefs[this.unknownRefsCounter++] = nameRef;
 }
-
+private void reset() {
+	this.sourceEnds = new HashtableOfObjectToInt();
+	this.nodesToCategories = new HashMap();
+	typeNames = new char[4][];
+	superTypeNames = new char[4][];
+	nestedTypeIndex = 0;
+}
+private int sourceEnd(TypeDeclaration typeDeclaration) {
+	if ((typeDeclaration.bits & ASTNode.IsAnonymousType) != 0) {
+		QualifiedAllocationExpression allocation = typeDeclaration.allocation;
+		if (allocation.type == null) // case of enum constant body
+			return typeDeclaration.sourceEnd;
+		return allocation.type.sourceEnd;
+	} else {
+		return typeDeclaration.sourceEnd;
+	}
+}
 private void visitIfNeeded(AbstractMethodDeclaration method) {
 	if (this.localDeclarationVisitor != null 
-		&& (method.bits & ASTNode.HasLocalTypeMASK) != 0) {
+		&& (method.bits & ASTNode.HasLocalType) != 0) {
 			if (method instanceof ConstructorDeclaration) {
 				ConstructorDeclaration constructorDeclaration = (ConstructorDeclaration) method;
 				if (constructorDeclaration.constructorCall != null) {
@@ -1503,7 +1701,7 @@
 
 private void visitIfNeeded(FieldDeclaration field, TypeDeclaration declaringType) {
 	if (this.localDeclarationVisitor != null 
-		&& (field.bits & ASTNode.HasLocalTypeMASK) != 0) {
+		&& (field.bits & ASTNode.HasLocalType) != 0) {
 			if (field.initialization != null) {
 				try {
 					this.localDeclarationVisitor.pushDeclaringType(declaringType);
@@ -1517,7 +1715,7 @@
 
 private void visitIfNeeded(Initializer initializer) {
 	if (this.localDeclarationVisitor != null 
-		&& (initializer.bits & ASTNode.HasLocalTypeMASK) != 0) {
+		&& (initializer.bits & ASTNode.HasLocalType) != 0) {
 			if (initializer.block != null) {
 				initializer.block.traverse(this.localDeclarationVisitor, null);
 			}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/SourceElementRequestorAdapter.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/SourceElementRequestorAdapter.java
index b0ba625..7f31e8b 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/SourceElementRequestorAdapter.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/SourceElementRequestorAdapter.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,7 +10,7 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler;
 
-import org.eclipse.jdt.core.compiler.IProblem;
+import org.eclipse.jdt.core.compiler.CategorizedProblem;
 
 public class SourceElementRequestorAdapter implements ISourceElementRequestor {
 
@@ -32,12 +32,12 @@
 	}
 
 	/**
-	 * @see ISourceElementRequestor#acceptImport(int, int, char[], boolean, int)
+	 * @see ISourceElementRequestor#acceptImport(int, int, char[][], boolean, int)
 	 */
 	public void acceptImport(
 		int declarationStart,
 		int declarationEnd,
-		char[] name,
+		char[][] tokens,
 		boolean onDemand,
 		int modifiers) {
 		// default implementation: do nothing
@@ -71,9 +71,9 @@
 	}
 
 	/**
-	 * @see ISourceElementRequestor#acceptProblem(IProblem)
+	 * @see ISourceElementRequestor#acceptProblem(CategorizedProblem)
 	 */
-	public void acceptProblem(IProblem problem) {
+	public void acceptProblem(CategorizedProblem problem) {
 		// default implementation: do nothing
 	}
 
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/SourceJavadocParser.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/SourceJavadocParser.java
new file mode 100755
index 0000000..c9bd2d0
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/SourceJavadocParser.java
@@ -0,0 +1,142 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler;
+
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.parser.JavadocParser;
+import org.eclipse.jdt.internal.compiler.parser.Parser;
+import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
+import org.eclipse.jdt.internal.compiler.parser.TerminalTokens;
+
+public class SourceJavadocParser extends JavadocParser {
+
+	// Store categories identifiers parsed in javadoc
+	int categoriesPtr = -1;
+	char[][] categories = CharOperation.NO_CHAR_CHAR;
+
+public SourceJavadocParser(Parser sourceParser) {
+	super(sourceParser);
+	this.kind = SOURCE_PARSER | TEXT_VERIF;
+}
+
+public boolean checkDeprecation(int commentPtr) {
+	this.categoriesPtr = -1;
+	boolean result = super.checkDeprecation(commentPtr);
+	if (this.categoriesPtr > -1) {
+		System.arraycopy(this.categories, 0, this.categories = new char[this.categoriesPtr+1][], 0, this.categoriesPtr+1);
+	} else {
+		this.categories = CharOperation.NO_CHAR_CHAR;
+	}
+	return result;
+}
+
+/* (non-Javadoc)
+ * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#parseIdentifierTag()
+ */
+protected boolean parseIdentifierTag(boolean report) {
+	int end = this.lineEnd+1;
+	if (super.parseIdentifierTag(report) && this.index <= end) {
+		if (this.tagValue == TAG_CATEGORY_VALUE) {
+			// Store first category id
+			int length = this.categories.length;
+			if (++this.categoriesPtr >= length) {
+				System.arraycopy(this.categories, 0, this.categories = new char[length+5][], 0, length);
+				length += 5;
+			}
+			this.categories[this.categoriesPtr] = this.identifierStack[this.identifierPtr--];
+			// Store optional additional category identifiers
+			consumeToken();
+			while (this.index < end) {
+				if (readTokenSafely() == TerminalTokens.TokenNameIdentifier && (this.scanner.currentCharacter == ' ' || ScannerHelper.isWhitespace(this.scanner.currentCharacter))) {
+					if (this.index > (this.lineEnd+1)) break;
+					// valid additional identifier
+					if (++this.categoriesPtr >= length) {
+						System.arraycopy(this.categories, 0, this.categories = new char[length+5][], 0, length);
+						length += 5;
+					}
+					this.categories[this.categoriesPtr] = this.scanner.getCurrentIdentifierSource();
+					consumeToken();
+				} else {
+					// TODO (frederic) raise warning for invalid syntax when javadoc spec will be finalized...
+					break;
+				}
+			}
+			// Reset position to end of line
+			this.index = end;
+			this.scanner.currentPosition = end;
+			consumeToken();
+		}
+		return true;
+	}
+	return false;
+}
+
+/* (non-Javadoc)
+ * @see org.eclipse.jdt.internal.compiler.parser.JavadocParser#parseSimpleTag()
+ */
+protected void parseSimpleTag() {
+	
+	// Read first char
+	// readChar() code is inlined to balance additional method call in checkDeprectation(int)
+	char first = this.source[this.index++];
+	if (first == '\\' && this.source[this.index] == 'u') {
+		int c1, c2, c3, c4;
+		int pos = this.index;
+		this.index++;
+		while (this.source[this.index] == 'u')
+			this.index++;
+		if (!(((c1 = ScannerHelper.getNumericValue(this.source[this.index++])) > 15 || c1 < 0)
+				|| ((c2 = ScannerHelper.getNumericValue(this.source[this.index++])) > 15 || c2 < 0)
+				|| ((c3 = ScannerHelper.getNumericValue(this.source[this.index++])) > 15 || c3 < 0)
+				|| ((c4 = ScannerHelper.getNumericValue(this.source[this.index++])) > 15 || c4 < 0))) {
+			first = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
+		} else {
+			this.index = pos;
+		}
+	}
+
+	// switch on first tag char
+	switch (first) {
+		case 'd': // perhaps @deprecated tag?
+	        if ((readChar() == 'e') &&
+					(readChar() == 'p') && (readChar() == 'r') &&
+					(readChar() == 'e') && (readChar() == 'c') &&
+					(readChar() == 'a') && (readChar() == 't') &&
+					(readChar() == 'e') && (readChar() == 'd')) {
+				// ensure the tag is properly ended: either followed by a space, a tab, line end or asterisk.
+				char c = readChar();
+				if (ScannerHelper.isWhitespace(c) || c == '*') {
+					this.tagValue = TAG_DEPRECATED_VALUE;
+					this.deprecated = true;
+				}
+	        }
+			break;
+		case 'c': // perhaps @category tag?
+	        if ((readChar() == 'a') &&
+					(readChar() == 't') && (readChar() == 'e') &&
+					(readChar() == 'g') && (readChar() == 'o') &&
+					(readChar() == 'r') && (readChar() == 'y')) {
+				// ensure the tag is properly ended: either followed by a space, a tab, line end or asterisk.
+				char c = readChar();
+				if (ScannerHelper.isWhitespace(c) || c == '*') {
+					this.tagValue = TAG_CATEGORY_VALUE;
+					if (this.scanner.source == null) {
+						this.scanner.setSource(this.source);
+					}
+					this.scanner.resetTo(this.index, this.scanner.eofPosition);
+					parseIdentifierTag(false); // Do not report missing identifier
+				}
+	        }
+			break;
+	}
+}
+
+}
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
index 1c5015b..88bdeb2 100644
--- 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
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -26,7 +26,6 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 
-import org.eclipse.jdt.core.Flags;
 import org.eclipse.jdt.core.IImportDeclaration;
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.JavaModelException;
@@ -38,13 +37,24 @@
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
 import org.eclipse.jdt.internal.compiler.env.*;
 
-import org.eclipse.jdt.internal.compiler.lookup.CompilerModifiers;
+import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
 import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
 import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
 import org.eclipse.jdt.internal.core.*;
+import org.eclipse.jdt.internal.core.util.Util;
 
-public class SourceTypeConverter implements CompilerModifiers {
+public class SourceTypeConverter {
 	
+	/* 
+	 * Exception thrown while converting an anonymous type of a member type
+	 * in this case, we must parse the source as the enclosing instance cannot be recreated
+	 * from the model
+	 */
+	static class AnonymousMemberFound extends RuntimeException {
+		private static final long serialVersionUID = 1L;
+	}
+
 	public static final int FIELD = 0x01;
 	public static final int CONSTRUCTOR = 0x02;
 	public static final int METHOD = 0x04;
@@ -119,38 +129,52 @@
 		int end = topLevelTypeInfo.getNameSourceEnd();
 
 		/* convert package and imports */
-		char[] packageName = cuHandle.getParent().getElementName().toCharArray();
+		String[] packageName = ((PackageFragment) cuHandle.getParent()).names;
 		if (packageName.length > 0)
 			// if its null then it is defined in the default package
 			this.unit.currentPackage =
-				createImportReference(packageName, start, end, false, AccDefault);
+				createImportReference(packageName, start, end, false, ClassFileConstants.AccDefault);
 		IImportDeclaration[] importDeclarations = topLevelTypeInfo.getHandle().getCompilationUnit().getImports();
 		int importCount = importDeclarations.length;
 		this.unit.imports = new ImportReference[importCount];
 		for (int i = 0; i < importCount; i++) {
 			ImportDeclaration importDeclaration = (ImportDeclaration) importDeclarations[i];
 			ISourceImport sourceImport = (ISourceImport) importDeclaration.getElementInfo();
+			String nameWithoutStar = importDeclaration.getNameWithoutStar();
 			this.unit.imports[i] = createImportReference(
-				importDeclaration.getNameWithoutStar().toCharArray(), 
+				Util.splitOn('.', nameWithoutStar, 0, nameWithoutStar.length()), 
 				sourceImport.getDeclarationSourceStart(),
 				sourceImport.getDeclarationSourceEnd(),
 				importDeclaration.isOnDemand(),
 				sourceImport.getModifiers());
 		}
 		/* convert type(s) */
-		int typeCount = sourceTypes.length;
-		final TypeDeclaration[] types = new TypeDeclaration[typeCount];
-		/*
-		 * We used a temporary types collection to prevent this.unit.types from being null during a call to
-		 * convert(...) when the source is syntactically incorrect and the parser is flushing the unit's types.
-		 * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=97466
-		 */
-		for (int i = 0; i < typeCount; i++) {
-			SourceTypeElementInfo typeInfo = (SourceTypeElementInfo) sourceTypes[i];
-			types[i] = convert((SourceType) typeInfo.getHandle(), compilationResult);
+		try {
+			int typeCount = sourceTypes.length;
+			final TypeDeclaration[] types = new TypeDeclaration[typeCount];
+			/*
+			 * We used a temporary types collection to prevent this.unit.types from being null during a call to
+			 * convert(...) when the source is syntactically incorrect and the parser is flushing the unit's types.
+			 * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=97466
+			 */
+			for (int i = 0; i < typeCount; i++) {
+				SourceTypeElementInfo typeInfo = (SourceTypeElementInfo) sourceTypes[i];
+				types[i] = convert((SourceType) typeInfo.getHandle(), compilationResult);
+			}
+			this.unit.types = types;
+			return this.unit;
+		} catch (AnonymousMemberFound e) {
+			return new Parser(this.problemReporter, true).parse(this.cu, compilationResult);
 		}
-		this.unit.types = types;
-		return this.unit;
+	}
+	
+	private void addIdentifiers(String typeSignature, int start, int endExclusive, int identCount, ArrayList fragments) {
+		if (identCount == 1) {
+			char[] identifier;
+			typeSignature.getChars(start, endExclusive, identifier = new char[endExclusive-start], 0);
+			fragments.add(identifier);
+		} else
+			fragments.add(extractIdentifiers(typeSignature, start, endExclusive-1, identCount));
 	}
 	
 	/*
@@ -159,7 +183,7 @@
 	private Initializer convert(InitializerElementInfo initializerInfo, CompilationResult compilationResult) throws JavaModelException {
 
 		Block block = new Block(0);
-		Initializer initializer = new Initializer(block, IConstants.AccDefault);
+		Initializer initializer = new Initializer(block, ClassFileConstants.AccDefault);
 
 		int start = initializerInfo.getDeclarationSourceStart();
 		int end = initializerInfo.getDeclarationSourceEnd();
@@ -176,7 +200,7 @@
 			for (int i = 0; i < typesLength; i++) {
 				SourceType type = (SourceType) children[i];
 				TypeDeclaration localType = convert(type, compilationResult);
-				if ((localType.bits & ASTNode.IsAnonymousTypeMASK) != 0) {
+				if ((localType.bits & ASTNode.IsAnonymousType) != 0) {
 					QualifiedAllocationExpression expression = new QualifiedAllocationExpression(localType);
 					expression.type = localType.superclass;
 					localType.superclass = null;
@@ -210,9 +234,9 @@
 		field.declarationSourceStart = fieldInfo.getDeclarationSourceStart();
 		field.declarationSourceEnd = fieldInfo.getDeclarationSourceEnd();
 		int modifiers = fieldInfo.getModifiers();
-		boolean isEnumConstant = (modifiers & AccEnum) != 0;
+		boolean isEnumConstant = (modifiers & ClassFileConstants.AccEnum) != 0;
 		if (isEnumConstant) {
-			field.modifiers = modifiers & ~Flags.AccEnum; // clear AccEnum bit onto AST (binding will add it)
+			field.modifiers = modifiers & ~ClassFileConstants.AccEnum; // clear AccEnum bit onto AST (binding will add it)
 		} else {
 			field.modifiers = modifiers;
 			field.type = createTypeReference(fieldInfo.getTypeName(), start, end);
@@ -239,33 +263,40 @@
 		if ((this.flags & LOCAL_TYPE) != 0) {
 			IJavaElement[] children = fieldInfo.getChildren();
 			int childrenLength = children.length;
-			if (childrenLength > 0) {
+			if (childrenLength == 1) {
+				field.initialization = convert(children[0], isEnumConstant ? field : null, compilationResult);
+			} else if (childrenLength > 1) {
 				ArrayInitializer initializer = new ArrayInitializer();
 				field.initialization = initializer;
 				Expression[] expressions = new Expression[childrenLength];
 				initializer.expressions = expressions;
 				for (int i = 0; i < childrenLength; i++) {
-					IJavaElement localType = children[i];
-					TypeDeclaration anonymousLocalTypeDeclaration = convert((SourceType) localType, compilationResult);
-					QualifiedAllocationExpression expression = new QualifiedAllocationExpression(anonymousLocalTypeDeclaration);
-					expression.type = anonymousLocalTypeDeclaration.superclass;
-					anonymousLocalTypeDeclaration.superclass = null;
-					anonymousLocalTypeDeclaration.superInterfaces = null;
-					anonymousLocalTypeDeclaration.allocation = expression;
-					anonymousLocalTypeDeclaration.modifiers &= ~AccEnum; // remove tag in case this is the init of an enum constant
-					expressions[i] = expression;
+					expressions[i] = convert(children[i], isEnumConstant ? field : null, compilationResult);
 				}
 			}
 		}
 		return field;
 	}
 
+	private QualifiedAllocationExpression convert(IJavaElement localType, FieldDeclaration enumConstant, CompilationResult compilationResult) throws JavaModelException {
+		TypeDeclaration anonymousLocalTypeDeclaration = convert((SourceType) localType, compilationResult);
+		QualifiedAllocationExpression expression = new QualifiedAllocationExpression(anonymousLocalTypeDeclaration);
+		expression.type = anonymousLocalTypeDeclaration.superclass;
+		anonymousLocalTypeDeclaration.superclass = null;
+		anonymousLocalTypeDeclaration.superInterfaces = null;
+		anonymousLocalTypeDeclaration.allocation = expression;
+		if (enumConstant != null) {
+			anonymousLocalTypeDeclaration.modifiers &= ~ClassFileConstants.AccEnum;
+			expression.enumConstant = enumConstant;
+			expression.type = null;
+		}
+		return expression;
+	}
+
 	/*
 	 * Convert a method source element into a parsed method/constructor declaration 
 	 */
-	private AbstractMethodDeclaration convert(SourceMethod methodHandle, CompilationResult compilationResult) throws JavaModelException {
-
-		SourceMethodElementInfo methodInfo = (SourceMethodElementInfo) methodHandle.getElementInfo();
+	private AbstractMethodDeclaration convert(SourceMethod methodHandle, SourceMethodElementInfo methodInfo, CompilationResult compilationResult) throws JavaModelException {
 		AbstractMethodDeclaration method;
 
 		/* only source positions available */
@@ -292,7 +323,7 @@
 		int modifiers = methodInfo.getModifiers();
 		if (methodInfo.isConstructor()) {
 			ConstructorDeclaration decl = new ConstructorDeclaration(compilationResult);
-			decl.isDefaultConstructor = false;
+			decl.bits &= ~ASTNode.IsDefaultConstructor;
 			method = decl;
 			decl.typeParameters = typeParams;
 		} else {
@@ -301,16 +332,24 @@
 				AnnotationMethodDeclaration annotationMethodDeclaration = new AnnotationMethodDeclaration(compilationResult);
 
 				/* conversion of default value */
+				SourceAnnotationMethodInfo annotationMethodInfo = (SourceAnnotationMethodInfo) methodInfo;
+				boolean hasDefaultValue = annotationMethodInfo.defaultValueStart != -1 || annotationMethodInfo.defaultValueEnd != -1;
 				if ((this.flags & FIELD_INITIALIZATION) != 0) {
-					char[] defaultValueSource = ((SourceAnnotationMethodInfo) methodInfo).getDefaultValueSource(getSource());
-					if (defaultValueSource != null) {
-						Expression expression =  parseMemberValue(defaultValueSource);
-						if (expression != null) {
-							annotationMethodDeclaration.defaultValue = expression;
-							modifiers |= AccAnnotationDefault;
+					if (hasDefaultValue) {
+						char[] defaultValueSource = CharOperation.subarray(getSource(), annotationMethodInfo.defaultValueStart, annotationMethodInfo.defaultValueEnd+1);
+						if (defaultValueSource != null) {
+    						Expression expression =  parseMemberValue(defaultValueSource);
+    						if (expression != null) {
+    							annotationMethodDeclaration.defaultValue = expression;
+    						}
+						} else {
+							// could not retrieve the default value
+							hasDefaultValue = false;
 						}
 					}
 				}
+				if (hasDefaultValue)
+					modifiers |= ClassFileConstants.AccAnnotationDefault;
 				decl = annotationMethodDeclaration;
 			} else {
 				decl = new MethodDeclaration(compilationResult);
@@ -325,8 +364,8 @@
 			method = decl;
 		}
 		method.selector = methodHandle.getElementName().toCharArray();
-		boolean isVarargs = (modifiers & AccVarargs) != 0;
-		method.modifiers = modifiers & ~AccVarargs;
+		boolean isVarargs = (modifiers & ClassFileConstants.AccVarargs) != 0;
+		method.modifiers = modifiers & ~ClassFileConstants.AccVarargs;
 		method.sourceStart = start;
 		method.sourceEnd = end;
 		method.declarationSourceStart = methodInfo.getDeclarationSourceStart();
@@ -342,30 +381,33 @@
 		String[] argumentTypeSignatures = methodHandle.getParameterTypes();
 		char[][] argumentNames = methodInfo.getArgumentNames();
 		int argumentCount = argumentTypeSignatures == null ? 0 : argumentTypeSignatures.length;
-		long position = ((long) start << 32) + end;
-		method.arguments = new Argument[argumentCount];
-		for (int i = 0; i < argumentCount; i++) {
-			char[] typeName = Signature.toCharArray(argumentTypeSignatures[i].toCharArray());
-			TypeReference typeReference = createTypeReference(typeName, start, end);
-			if (isVarargs && i == argumentCount-1) {
-				typeReference.bits |= ASTNode.IsVarArgs;
+		if (argumentCount > 0) {
+			long position = ((long) start << 32) + end;
+			method.arguments = new Argument[argumentCount];
+			for (int i = 0; i < argumentCount; i++) {
+				TypeReference typeReference = createTypeReference(argumentTypeSignatures[i], start, end);
+				if (isVarargs && i == argumentCount-1) {
+					typeReference.bits |= ASTNode.IsVarArgs;
+				}
+				method.arguments[i] =
+					new Argument(
+						argumentNames[i],
+						position,
+						typeReference,
+						ClassFileConstants.AccDefault);
+				// do not care whether was final or not
 			}
-			method.arguments[i] =
-				new Argument(
-					argumentNames[i],
-					position,
-					typeReference,
-					AccDefault);
-			// do not care whether was final or not
 		}
 
 		/* convert thrown exceptions */
 		char[][] exceptionTypeNames = methodInfo.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);
+		if (exceptionCount > 0) {
+			method.thrownExceptions = new TypeReference[exceptionCount];
+			for (int i = 0; i < exceptionCount; i++) {
+				method.thrownExceptions[i] =
+					createTypeReference(exceptionTypeNames[i], start, end);
+			}
 		}
 		
 		/* convert local and anonymous types */
@@ -377,7 +419,7 @@
 				for (int i = 0; i < typesLength; i++) {
 					SourceType type = (SourceType) children[i];
 					TypeDeclaration localType = convert(type, compilationResult);
-					if ((localType.bits & ASTNode.IsAnonymousTypeMASK) != 0) {
+					if ((localType.bits & ASTNode.IsAnonymousType) != 0) {
 						QualifiedAllocationExpression expression = new QualifiedAllocationExpression(localType);
 						expression.type = localType.superclass;
 						localType.superclass = null;
@@ -400,21 +442,23 @@
 	 */
 	private TypeDeclaration convert(SourceType typeHandle, CompilationResult compilationResult) throws JavaModelException {
 		SourceTypeElementInfo typeInfo = (SourceTypeElementInfo) typeHandle.getElementInfo();
+		if (typeInfo.isAnonymousMember())
+			throw new AnonymousMemberFound();
 		/* create type declaration - can be member type */
 		TypeDeclaration type = new TypeDeclaration(compilationResult);
 		if (typeInfo.getEnclosingType() == null) {
 			if (typeHandle.isAnonymous()) {
-				type.name = TypeDeclaration.ANONYMOUS_EMPTY_NAME;
-				type.bits |= ASTNode.AnonymousAndLocalMask;
+				type.name = CharOperation.NO_CHAR;
+				type.bits |= (ASTNode.IsAnonymousType|ASTNode.IsLocalType);
 			} else {
 				if (typeHandle.isLocal()) {
-					type.bits |= ASTNode.IsLocalTypeMASK;
+					type.bits |= ASTNode.IsLocalType;
 				}
 			}
 		}  else {
-			type.bits |= ASTNode.IsMemberTypeMASK;
+			type.bits |= ASTNode.IsMemberType;
 		}
-		if ((type.bits & ASTNode.IsAnonymousTypeMASK) == 0) {
+		if ((type.bits & ASTNode.IsAnonymousType) == 0) {
 			type.name = typeInfo.getName();
 		}
 		type.name = typeInfo.getName();
@@ -504,8 +548,8 @@
 			/* by default, we assume that one is needed. */
 			int extraConstructor = 0;
 			int methodCount = 0;
-			int kind = type.kind();
-			boolean isAbstract = kind == IGenericType.INTERFACE_DECL || kind == IGenericType.ANNOTATION_TYPE_DECL;
+			int kind = TypeDeclaration.kind(type.modifiers);
+			boolean isAbstract = kind == TypeDeclaration.INTERFACE_DECL || kind == TypeDeclaration.ANNOTATION_TYPE_DECL;
 			if (!isAbstract) {
 				extraConstructor = needConstructor ? 1 : 0;
 				for (int i = 0; i < sourceMethodCount; i++) {
@@ -529,14 +573,15 @@
 			boolean hasAbstractMethods = false;
 			for (int i = 0; i < sourceMethodCount; i++) {
 				SourceMethod sourceMethod = sourceMethods[i];
-				boolean isConstructor = sourceMethod.isConstructor();
-				if ((sourceMethod.getFlags() & Flags.AccAbstract) != 0) {
+				SourceMethodElementInfo methodInfo = (SourceMethodElementInfo)sourceMethod.getElementInfo();
+				boolean isConstructor = methodInfo.isConstructor();
+				if ((methodInfo.getModifiers() & ClassFileConstants.AccAbstract) != 0) {
 					hasAbstractMethods = true;
 				}
 				if ((isConstructor && needConstructor) || (!isConstructor && needMethod)) {
-					AbstractMethodDeclaration method = convert(sourceMethod, compilationResult);
+					AbstractMethodDeclaration method = convert(sourceMethod, methodInfo, compilationResult);
 					if (isAbstract || method.isAbstract()) { // fix-up flag 
-						method.modifiers |= AccSemicolonBody;
+						method.modifiers |= ExtraCompilerModifiers.AccSemicolonBody;
 					}
 					type.methods[extraConstructor + index++] = method;
 				}
@@ -560,15 +605,17 @@
 			int start = (int) (position >>> 32);
 			int end = (int) position;
 			char[] annotationSource = CharOperation.subarray(cuSource, start, end+1);
-			Expression expression = parseMemberValue(annotationSource);
-			/*
-			 * expression can be null or not an annotation if the source has changed between
-			 * the moment where the annotation source positions have been retrieved and the moment were
-			 * this parsing occured.
-			 * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=90916
-			 */
-			if (expression instanceof Annotation) {
-				annotations[recordedAnnotations++] = (Annotation) expression;
+			if (annotationSource != null) {
+    			Expression expression = parseMemberValue(annotationSource);
+    			/*
+    			 * expression can be null or not an annotation if the source has changed between
+    			 * the moment where the annotation source positions have been retrieved and the moment were
+    			 * this parsing occured.
+    			 * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=90916
+    			 */
+    			if (expression instanceof Annotation) {
+    				annotations[recordedAnnotations++] = (Annotation) expression;
+    			}
 			}
 		}
 		if (length != recordedAnnotations) {
@@ -582,16 +629,18 @@
 	 * Build an import reference from an import name, e.g. java.lang.*
 	 */
 	private ImportReference createImportReference(
-		char[] importName,
+		String[] importName,
 		int start,
 		int end, 
 		boolean onDemand,
 		int modifiers) {
 	
-		char[][] qImportName = CharOperation.splitOn('.', importName);
-		long[] positions = new long[qImportName.length];
+		int length = importName.length;
+		long[] positions = new long[length];
 		long position = ((long) start << 32) + end;
-		for (int i = 0; i < qImportName.length; i++) {
+		char[][] qImportName = new char[length][];
+		for (int i = 0; i < length; i++) {
+			qImportName[i] = importName[i].toCharArray();
 			positions[i] = position; // dummy positions
 		}
 		return new ImportReference(
@@ -634,9 +683,242 @@
 
 		int length = typeName.length;
 		this.namePos = 0;
-		TypeReference type = decodeType(typeName, length, start, end);
-		return type;
+		return decodeType(typeName, length, start, end);
 	}
+	
+	/*
+	 * Build a type reference from a type signature, e.g. Ljava.lang.Object;
+	 */
+	private TypeReference createTypeReference(
+			String typeSignature,
+			int start,
+			int end) {
+		
+		int length = typeSignature.length();
+		this.namePos = 0;
+		return decodeType(typeSignature, length, start, end);
+	}
+	
+	private TypeReference decodeType(String typeSignature, int length, int start, int end) {
+		int identCount = 1;
+		int dim = 0;
+		int nameFragmentStart = this.namePos, nameFragmentEnd = -1;
+		boolean nameStarted = false;
+		ArrayList fragments = null;
+		typeLoop: while (this.namePos < length) {
+			char currentChar = typeSignature.charAt(this.namePos);
+			switch (currentChar) {
+				case Signature.C_BOOLEAN :
+					if (!nameStarted) {
+						this.namePos++;
+						if (dim == 0)
+							return new SingleTypeReference(TypeBinding.BOOLEAN.simpleName, ((long) start << 32) + end);
+						else
+							return new ArrayTypeReference(TypeBinding.BOOLEAN.simpleName, dim, ((long) start << 32) + end);
+					} 
+					break;
+				case Signature.C_BYTE :
+					if (!nameStarted) {
+						this.namePos++;
+						if (dim == 0)
+							return new SingleTypeReference(TypeBinding.BYTE.simpleName, ((long) start << 32) + end);
+						else
+							return new ArrayTypeReference(TypeBinding.BYTE.simpleName, dim, ((long) start << 32) + end);				
+					}
+					break;
+				case Signature.C_CHAR :
+					if (!nameStarted) {
+						this.namePos++;
+						if (dim == 0)
+							return new SingleTypeReference(TypeBinding.CHAR.simpleName, ((long) start << 32) + end);
+						else
+							return new ArrayTypeReference(TypeBinding.CHAR.simpleName, dim, ((long) start << 32) + end);
+					}
+					break;
+				case Signature.C_DOUBLE :
+					if (!nameStarted) {
+						this.namePos++;
+						if (dim == 0)
+							return new SingleTypeReference(TypeBinding.DOUBLE.simpleName, ((long) start << 32) + end);
+						else
+							return new ArrayTypeReference(TypeBinding.DOUBLE.simpleName, dim, ((long) start << 32) + end);				
+					}
+					break;
+				case Signature.C_FLOAT :
+					if (!nameStarted) {
+						this.namePos++;
+						if (dim == 0)
+							return new SingleTypeReference(TypeBinding.FLOAT.simpleName, ((long) start << 32) + end);
+						else
+							return new ArrayTypeReference(TypeBinding.FLOAT.simpleName, dim, ((long) start << 32) + end);				
+					}
+					break;
+				case Signature.C_INT :
+					if (!nameStarted) {
+						this.namePos++;
+						if (dim == 0)
+							return new SingleTypeReference(TypeBinding.INT.simpleName, ((long) start << 32) + end);
+						else
+							return new ArrayTypeReference(TypeBinding.INT.simpleName, dim, ((long) start << 32) + end);				
+					}
+					break;
+				case Signature.C_LONG :
+					if (!nameStarted) {
+						this.namePos++;
+						if (dim == 0)
+							return new SingleTypeReference(TypeBinding.LONG.simpleName, ((long) start << 32) + end);
+						else
+							return new ArrayTypeReference(TypeBinding.LONG.simpleName, dim, ((long) start << 32) + end);				
+					}
+					break;
+				case Signature.C_SHORT :
+					if (!nameStarted) {
+						this.namePos++;
+						if (dim == 0)
+							return new SingleTypeReference(TypeBinding.SHORT.simpleName, ((long) start << 32) + end);
+						else
+							return new ArrayTypeReference(TypeBinding.SHORT.simpleName, dim, ((long) start << 32) + end);				
+					}
+					break;
+				case Signature.C_VOID :
+					if (!nameStarted) {
+						this.namePos++;
+						new SingleTypeReference(TypeBinding.VOID.simpleName, ((long) start << 32) + end);
+					}
+					break;
+				case Signature.C_RESOLVED :
+				case Signature.C_UNRESOLVED :
+					if (!nameStarted) {
+						nameFragmentStart = this.namePos+1;
+						nameStarted = true;
+					}
+					break;
+				case Signature.C_STAR:
+					this.namePos++;
+					Wildcard result = new Wildcard(Wildcard.UNBOUND);
+					result.sourceStart = start;
+					result.sourceEnd = end;
+					return result;
+				case Signature.C_EXTENDS:
+					this.namePos++;
+					result = new Wildcard(Wildcard.EXTENDS);
+					result.bound = decodeType(typeSignature, length, start, end);
+					result.sourceStart = start;
+					result.sourceEnd = end;
+					return result;
+				case Signature.C_SUPER:
+					this.namePos++;
+					result = new Wildcard(Wildcard.SUPER);
+					result.bound = decodeType(typeSignature, length, start, end);
+					result.sourceStart = start;
+					result.sourceEnd = end;
+					return result;
+				case Signature.C_ARRAY :
+					dim++;
+					break;
+				case Signature.C_GENERIC_END :
+				case Signature.C_SEMICOLON :
+					nameFragmentEnd = this.namePos-1;
+					this.namePos++;
+					break typeLoop;
+				case Signature.C_DOT :
+				case Signature.C_DOLLAR:
+					if (!nameStarted) {
+						nameFragmentStart = this.namePos+1;
+						nameStarted = true;
+					} else if (this.namePos > nameFragmentStart) // handle name starting with a $ (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=91709)
+						identCount ++;
+					break;
+				case Signature.C_GENERIC_START :
+					nameFragmentEnd = this.namePos-1;
+					// convert 1.5 specific constructs only if compliance is 1.5 or above
+					if (!this.has1_5Compliance) 
+						break typeLoop;
+					if (fragments == null) fragments = new ArrayList(2);
+					addIdentifiers(typeSignature, nameFragmentStart, nameFragmentEnd + 1, identCount, fragments);
+					this.namePos++; // skip '<'
+					TypeReference[] arguments = decodeTypeArguments(typeSignature, length, start, end); // positionned on '>' at end
+					fragments.add(arguments);
+					identCount = 1;
+					nameStarted = false;
+					// next increment will skip '>'
+					break;
+			}
+			this.namePos++;
+		}
+		if (fragments == null) { // non parameterized 
+			/* rebuild identifiers and dimensions */
+			if (identCount == 1) { // simple type reference
+				if (dim == 0) {
+					char[] nameFragment = new char[nameFragmentEnd - nameFragmentStart + 1];
+					typeSignature.getChars(nameFragmentStart, nameFragmentEnd +1, nameFragment, 0);
+					return new SingleTypeReference(nameFragment, ((long) start << 32) + end);
+				} else {
+					char[] nameFragment = new char[nameFragmentEnd - nameFragmentStart + 1];
+					typeSignature.getChars(nameFragmentStart, nameFragmentEnd +1, nameFragment, 0);
+					return new ArrayTypeReference(nameFragment, 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 = extractIdentifiers(typeSignature, nameFragmentStart, nameFragmentEnd, identCount);
+				if (dim == 0) {
+					return new QualifiedTypeReference(identifiers, positions);
+				} else {
+					return new ArrayQualifiedTypeReference(identifiers, dim, positions);
+				}
+			}
+		} else { // parameterized
+			// rebuild type reference from available fragments: char[][], arguments, char[][], arguments...
+			// check trailing qualified name
+			if (nameStarted) {
+				addIdentifiers(typeSignature, nameFragmentStart, nameFragmentEnd + 1, identCount, fragments);
+			}
+			int fragmentLength = fragments.size();
+			if (fragmentLength == 2) {
+				Object firstFragment = fragments.get(0);
+				if (firstFragment instanceof char[]) {
+					// parameterized single type
+					return new ParameterizedSingleTypeReference((char[]) firstFragment, (TypeReference[]) fragments.get(1), dim, ((long) start << 32) + end);
+				}
+			}
+			// parameterized qualified type
+			identCount = 0;
+			for (int i = 0; i < fragmentLength; i ++) {
+				Object element = fragments.get(i);
+				if (element instanceof char[][]) {
+					identCount += ((char[][])element).length;
+				} else if (element instanceof char[])
+					identCount++;
+			}
+			char[][] tokens = new char[identCount][];
+			TypeReference[][] arguments = new TypeReference[identCount][];
+			int index = 0;
+			for (int i = 0; i < fragmentLength; i ++) {
+				Object element = fragments.get(i);
+				if (element instanceof char[][]) {
+					char[][] fragmentTokens = (char[][]) element;
+					int fragmentTokenLength = fragmentTokens.length;
+					System.arraycopy(fragmentTokens, 0, tokens, index, fragmentTokenLength);
+					index += fragmentTokenLength;
+				} else if (element instanceof char[]) {
+					tokens[index++] = (char[]) element;
+				} else {
+					arguments[index-1] = (TypeReference[]) element;
+				}
+			}
+			long[] positions = new long[identCount];
+			long pos = ((long) start << 32) + end;
+			for (int i = 0; i < identCount; i++) {
+				positions[i] = pos;
+			}
+			return new ParameterizedQualifiedTypeReference(tokens, arguments, dim, positions);
+		}
+	}
+	
 	private TypeReference decodeType(char[] typeName, int length, int start, int end) {
 		int identCount = 1;
 		int dim = 0;
@@ -814,6 +1096,38 @@
 		return typeArguments;
 	}
 	
+	private TypeReference[] decodeTypeArguments(String typeSignature, int length, int start, int end) {
+		ArrayList argumentList = new ArrayList(1);
+		int count = 0;
+		argumentsLoop: while (this.namePos < length) {
+			TypeReference argument = decodeType(typeSignature, length, start, end);
+			count++;
+			argumentList.add(argument);
+			if (this.namePos >= length) break argumentsLoop;
+			if (typeSignature.charAt(this.namePos) == '>') {
+				break argumentsLoop;
+			}
+		}
+		TypeReference[] typeArguments = new TypeReference[count];
+		argumentList.toArray(typeArguments);
+		return typeArguments;
+	}
+	
+	private char[][] extractIdentifiers(String typeSignature, int start, int endInclusive, int identCount) {
+		char[][] result = new char[identCount][];
+		int charIndex = start;
+		int i = 0;
+		while (charIndex < endInclusive) {
+			if (typeSignature.charAt(charIndex) == '.') {
+				typeSignature.getChars(start, charIndex, result[i++] = new char[charIndex - start], 0); 
+				start = ++charIndex;
+			} else
+				charIndex++;
+		}
+		typeSignature.getChars(start, charIndex + 1, result[i++] = new char[charIndex - start + 1], 0); 
+		return result;
+	}
+	
 	private char[] getSource() {
 		if (this.source == null)
 			this.source = this.cu.getContents();
@@ -821,6 +1135,7 @@
 	}
 	
 	private Expression parseMemberValue(char[] memberValue) {
+		// memberValue must not be null
 		if (this.parser == null) {
 			this.parser = new Parser(this.problemReporter, true);
 		}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ASTHolderCUInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ASTHolderCUInfo.java
index 6990e7a..ec91dc1 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ASTHolderCUInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ASTHolderCUInfo.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,9 +10,14 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
+import java.util.HashMap;
+
 import org.eclipse.jdt.core.dom.CompilationUnit;
 
 public class ASTHolderCUInfo extends CompilationUnitElementInfo {
 	int astLevel;
+	boolean resolveBindings;
+	int reconcileFlags;
+	HashMap problems = null;
 	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
deleted file mode 100644
index 627e3a4..0000000
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Assert.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core;
-
-/* This class is not intended to be instantiated. */
-public final class Assert {
-
-private Assert() {
-	// cannot be instantiated
-}
-/** Asserts that an argument is legal. If the given boolean is
- * not <code>true</code>, an <code>IllegalArgumentException</code>
- * is thrown.
- *
- * @param expression the outcode of the check
- * @return <code>true</code> if the check passes (does not return
- *    if the check fails)
- * @exception IllegalArgumentException if the legality test failed
- */
-public static boolean isLegal(boolean expression) {
-	return isLegal(expression, ""); //$NON-NLS-1$
-}
-/** Asserts that an argument is legal. If the given boolean is
- * not <code>true</code>, an <code>IllegalArgumentException</code>
- * is thrown.
- * The given message is included in that exception, to aid debugging.
- *
- * @param expression the outcode of the check
- * @param message the message to include in the exception
- * @return <code>true</code> if the check passes (does not return
- *    if the check fails)
- * @exception IllegalArgumentException if the legality test failed
- */
-public static boolean isLegal(boolean expression, String message) {
-	if (!expression)
-		throw new IllegalArgumentException(message);
-	return expression;
-}
-/** Asserts that the given object is not <code>null</code>. If this
- * is not the case, some kind of unchecked exception is thrown.
- * 
- * @param object the value to test
- * @exception IllegalArgumentException if the object is <code>null</code>
- */
-public static void isNotNull(Object object) {
-	isNotNull(object, ""); //$NON-NLS-1$
-}
-/** Asserts that the given object is not <code>null</code>. If this
- * is not the case, some kind of unchecked exception is thrown.
- * The given message is included in that exception, to aid debugging.
- *
- * @param object the value to test
- * @param message the message to include in the exception
- * @exception IllegalArgumentException if the object is <code>null</code>
- */
-public static void isNotNull(Object object, String message) {
-	if (object == null)
-		throw new AssertionFailedException("null argument; " + message); //$NON-NLS-1$
-}
-/** Asserts that the given boolean is <code>true</code>. If this
- * is not the case, some kind of unchecked exception is thrown.
- *
- * @param expression the outcode of the check
- * @return <code>true</code> if the check passes (does not return
- *    if the check fails)
- */
-public static boolean isTrue(boolean expression) {
-	return isTrue(expression, ""); //$NON-NLS-1$
-}
-/** Asserts that the given boolean is <code>true</code>. If this
- * is not the case, some kind of unchecked exception is thrown.
- * The given message is included in that exception, to aid debugging.
- *
- * @param expression the outcode of the check
- * @param message the message to include in the exception
- * @return <code>true</code> if the check passes (does not return
- *    if the check fails)
- */
-public static boolean isTrue(boolean expression, String message) {
-	if (!expression)
-		throw new AssertionFailedException("Assertion failed; " + message); //$NON-NLS-1$
-	return expression;
-}
-
-	public static class AssertionFailedException extends RuntimeException {
-		private static final long serialVersionUID = -3179320974982211564L; // backward compatible
-		public AssertionFailedException(String detail) {
-			super(detail);
-		}
-	}
-}
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 9d31c94..62845b2 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
@@ -29,7 +29,13 @@
  */
 public class BasicCompilationUnit implements ICompilationUnit {
 	protected char[] contents;
-	protected char[] fileName;
+	
+	// Note that if this compiler ICompilationUnit's content is known in advance, the fileName is not used to retrieve this content.
+	// Instead it is used to keep enough information to recreate the IJavaElement corresponding to this compiler ICompilationUnit.
+	// Thus the fileName can be a path to a .class file, or even a path in a .jar to a .class file.
+	// (e.g. /P/lib/mylib.jar|org/eclipse/test/X.class)
+	protected char[] fileName; 
+	
 	protected char[][] packageName;
 	protected char[] mainTypeName;
 	protected String encoding;
@@ -113,7 +119,7 @@
 			start = separator;
 	
 		int end = CharOperation.lastIndexOf('$', this.fileName);
-		if (end == -1) {
+		if (end == -1 || !Util.isClassFileName(this.fileName)) {
 			end = CharOperation.lastIndexOf('.', this.fileName);
 			if (end == -1)
 				end = this.fileName.length;
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 9d55df6..142c2d5 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 932a72f..7fa514b 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -39,13 +39,13 @@
 
 		if (!workingCopy.isPrimary()) {
 			// report added java delta for a non-primary working copy
-			JavaElementDelta delta = new JavaElementDelta(this.getJavaModel());
+			JavaElementDelta delta = new JavaElementDelta(getJavaModel());
 			delta.added(workingCopy);
 			addDelta(delta);
 		} else {
 			if (workingCopy.getResource().isAccessible()) {
 				// report a F_PRIMARY_WORKING_COPY change delta for a primary working copy
-				JavaElementDelta delta = new JavaElementDelta(this.getJavaModel());
+				JavaElementDelta delta = new JavaElementDelta(getJavaModel());
 				delta.changed(workingCopy, IJavaElementDelta.F_PRIMARY_WORKING_COPY);
 				addDelta(delta);
 			} else {
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 6e5066c..9934a55 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,8 +10,10 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
+import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.jdt.core.Flags;
 import org.eclipse.jdt.core.IField;
+import org.eclipse.jdt.core.IJavaModelStatusConstants;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.Signature;
 import org.eclipse.jdt.internal.compiler.env.IBinaryField;
@@ -105,4 +107,24 @@
 		}
 	}
 }
+public String getAttachedJavadoc(IProgressMonitor monitor) throws JavaModelException {
+	String contents = ((BinaryType) this.getDeclaringType()).getJavadocContents(monitor);
+	if (contents == null) return null;
+	int indexAnchor = contents.indexOf(
+			JavadocConstants.ANCHOR_PREFIX_START + this.getElementName() + JavadocConstants.ANCHOR_PREFIX_END);
+	if (indexAnchor == -1) throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.UNKNOWN_JAVADOC_FORMAT, this));
+	int indexOfEndLink = contents.indexOf(JavadocConstants.ANCHOR_SUFFIX, indexAnchor);
+	if (indexOfEndLink == -1) throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.UNKNOWN_JAVADOC_FORMAT, this));
+	int indexOfNextField = contents.indexOf(JavadocConstants.ANCHOR_PREFIX_START, indexOfEndLink);
+	int indexOfBottom = contents.indexOf(JavadocConstants.CONSTRUCTOR_DETAIL, indexOfEndLink);
+	if (indexOfBottom == -1) {
+		indexOfBottom = contents.indexOf(JavadocConstants.METHOD_DETAIL, indexOfEndLink);
+		if (indexOfBottom == -1) {
+			indexOfBottom = contents.indexOf(JavadocConstants.END_OF_CLASS_DATA, indexOfEndLink);
+		}
+	}
+	indexOfNextField= Math.min(indexOfNextField, indexOfBottom);
+	if (indexOfNextField == -1) throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.UNKNOWN_JAVADOC_FORMAT, this));
+	return contents.substring(indexOfEndLink + JavadocConstants.ANCHOR_SUFFIX_LENGTH, indexOfNextField);
+}
 }
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 79e894a..9ea6723 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -17,6 +17,7 @@
 import org.eclipse.jdt.core.IJavaModelStatusConstants;
 import org.eclipse.jdt.core.ISourceRange;
 import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.compiler.CharOperation;
 
 /**
  * Common functionality for Binary member handles.
@@ -38,16 +39,24 @@
  * @see JavaElement#generateInfos
  */
 protected void generateInfos(Object info, HashMap newElements, IProgressMonitor pm) throws JavaModelException {
-	Openable openableParent = (Openable)getOpenableParent();
-	if (openableParent == null) return;
-	
-	ClassFileInfo openableParentInfo = (ClassFileInfo) JavaModelManager.getJavaModelManager().getInfo(openableParent);
-	if (openableParentInfo == null) {
+	Openable openableParent = (Openable) getOpenableParent();
+	if (JavaModelManager.getJavaModelManager().getInfo(openableParent) == null) {
 		openableParent.generateInfos(openableParent.createElementInfo(), newElements, pm);
-		openableParentInfo = (ClassFileInfo)newElements.get(openableParent);
 	}
-	if (openableParentInfo == null) return;
-	openableParentInfo.getBinaryChildren(newElements); // forces the initialization
+}
+public String[] getCategories() throws JavaModelException {
+	SourceMapper mapper= getSourceMapper();
+	if (mapper != null) {
+		// ensure the class file's buffer is open so that categories are computed
+		((ClassFile)getClassFile()).getBuffer();
+		
+		if (mapper.categories != null) {
+			String[] categories = (String[]) mapper.categories.get(this);
+			if (categories != null)
+				return categories;
+		}
+	}
+	return CharOperation.NO_STRINGS;	
 }
 public String getKey() {
 	try {
@@ -72,7 +81,7 @@
 		
 		return mapper.getNameRange(this);
 	} else {
-		return SourceMapper.fgUnknownRange;
+		return SourceMapper.UNKNOWN_RANGE;
 	}
 }
 /*
@@ -86,7 +95,7 @@
 
 		return mapper.getSourceRange(this);
 	} else {
-		return SourceMapper.fgUnknownRange;
+		return SourceMapper.UNKNOWN_RANGE;
 	}
 }
 /*
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 1cedf39..09a7531 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,16 +10,14 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
+import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.jdt.core.*;
-import org.eclipse.jdt.core.Flags;
-import org.eclipse.jdt.core.IMethod;
-import org.eclipse.jdt.core.IType;
-import org.eclipse.jdt.core.JavaModelException;
-import org.eclipse.jdt.core.Signature;
 import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.internal.compiler.SourceElementRequestorAdapter;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
 import org.eclipse.jdt.internal.compiler.env.IBinaryMethod;
+import org.eclipse.jdt.internal.compiler.env.IBinaryType;
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
+import org.eclipse.jdt.internal.core.JavaModelManager.PerProjectInfo;
 import org.eclipse.jdt.internal.core.util.Util;
 
 /**
@@ -27,35 +25,6 @@
  */
 
 /* package */ class BinaryMethod extends BinaryMember implements IMethod {
-	
-	class DecodeParametersNames extends SourceElementRequestorAdapter {
-			String[] parametersNames;
-		
-			public void enterMethod(MethodInfo methodInfo) {
-					if (methodInfo.parameterNames != null) {
-						int length = methodInfo.parameterNames.length;
-						this.parametersNames = new String[length];
-						for (int i = 0; i < length; i++) {
-							this.parametersNames[i] = new String(methodInfo.parameterNames[i]);
-						}
-					}
-				}
-				
-			public void enterConstructor(MethodInfo methodInfo) {
-					if (methodInfo.parameterNames != null) {
-						int length = methodInfo.parameterNames.length;
-						this.parametersNames = new String[length];
-						for (int i = 0; i < length; i++) {
-							this.parametersNames[i] = new String(methodInfo.parameterNames[i]);
-						}
-					}
-				}
-				
-				public String[] getParametersNames() {
-					return this.parametersNames;
-				}
-	}
-
 	/**
 	 * The parameter type signatures of the method - stored locally
 	 * to perform equality test. <code>null</code> indicates no
@@ -67,17 +36,15 @@
 	 */
 	protected String[] parameterNames;
 
-	/**
-	 * An empty list of Strings
-	 */
-	protected static final String[] NO_TYPES= new String[] {};
 	protected String[] exceptionTypes;
 	protected String returnType;
+
 protected BinaryMethod(JavaElement parent, String name, String[] paramTypes) {
 	super(parent, name);
-	Assert.isTrue(name.indexOf('.') == -1);
+	// Assertion disabled since bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=179011
+	// Assert.isTrue(name.indexOf('.') == -1);
 	if (paramTypes == null) {
-		this.parameterTypes= NO_TYPES;
+		this.parameterTypes= CharOperation.NO_STRINGS;
 	} else {
 		this.parameterTypes= paramTypes;
 	}
@@ -100,7 +67,7 @@
 		if (this.exceptionTypes == null || this.exceptionTypes.length == 0) {
 			char[][] eTypeNames = info.getExceptionTypeNames();
 			if (eTypeNames == null || eTypeNames.length == 0) {
-				this.exceptionTypes = NO_TYPES;
+				this.exceptionTypes = CharOperation.NO_STRINGS;
 			} else {
 				eTypeNames = ClassFile.translatedNames(eTypeNames);
 				this.exceptionTypes = new String[eTypeNames.length];
@@ -168,42 +135,219 @@
  * Look for source attachment information to retrieve the actual parameter names as stated in source.
  */
 public String[] getParameterNames() throws JavaModelException {
-	if (this.parameterNames == null) {
+	if (this.parameterNames != null) 
+		return this.parameterNames;
 
-		// force source mapping if not already done
-		IType type = (IType) getParent();
-		SourceMapper mapper = getSourceMapper();
-		if (mapper != null) {
-			char[][] paramNames = mapper.getMethodParameterNames(this);
-			
-			// map source and try to find parameter names
-			if(paramNames == null) {
-				char[] source = mapper.findSource(type);
-				if (source != null){
-					mapper.mapSource(type, source);
-				}
-				paramNames = mapper.getMethodParameterNames(this);
+	// force source mapping if not already done
+	IType type = (IType) getParent();
+	SourceMapper mapper = getSourceMapper();
+	if (mapper != null) {
+		char[][] paramNames = mapper.getMethodParameterNames(this);
+		
+		// map source and try to find parameter names
+		if(paramNames == null) {
+			IBinaryType info = (IBinaryType) ((BinaryType) getDeclaringType()).getElementInfo();
+			char[] source = mapper.findSource(type, info);
+			if (source != null){
+				mapper.mapSource(type, source, info);
 			}
-			
-			// if parameter names exist, convert parameter names to String array
-			if(paramNames != null) {
-				this.parameterNames = new String[paramNames.length];
-				for (int i = 0; i < paramNames.length; i++) {
-					this.parameterNames[i] = new String(paramNames[i]);
-				}
-			}
+			paramNames = mapper.getMethodParameterNames(this);
 		}
-		// if still no parameter names, produce fake ones
-		if (this.parameterNames == null) {
-			IBinaryMethod info = (IBinaryMethod) getElementInfo();
-			int paramCount = Signature.getParameterCount(new String(info.getMethodDescriptor()));
-			this.parameterNames = new String[paramCount];
-			for (int i = 0; i < paramCount; i++) {
-				this.parameterNames[i] = "arg" + i; //$NON-NLS-1$
+		
+		// if parameter names exist, convert parameter names to String array
+		if(paramNames != null) {
+			this.parameterNames = new String[paramNames.length];
+			for (int i = 0; i < paramNames.length; i++) {
+				this.parameterNames[i] = new String(paramNames[i]);
 			}
+			return this.parameterNames;
 		}
 	}
-	return this.parameterNames;
+	
+	// try to see if we can retrieve the names from the attached javadoc
+	IBinaryMethod info = (IBinaryMethod) getElementInfo();
+	final int paramCount = Signature.getParameterCount(new String(info.getMethodDescriptor()));
+	if (paramCount != 0) {
+		// don't try to look for javadoc for synthetic methods
+		int modifiers = this.getFlags();
+		if ((modifiers & ClassFileConstants.AccSynthetic) != 0) {
+			return this.parameterNames = getRawParameterNames(paramCount);
+		}
+		String javadocContents = null;
+		IType declaringType = this.getDeclaringType();
+		PerProjectInfo projectInfo = JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(this.getJavaProject().getProject());
+		synchronized (projectInfo.javadocCache) {
+			javadocContents = (String) projectInfo.javadocCache.get(declaringType);
+			if (javadocContents == null) {
+				projectInfo.javadocCache.put(declaringType, BinaryType.EMPTY_JAVADOC);
+			}
+		}
+		if (javadocContents == null) {
+			long timeOut = 50; // default value
+			try {
+				String option = this.getJavaProject().getOption(JavaCore.TIMEOUT_FOR_PARAMETER_NAME_FROM_ATTACHED_JAVADOC, true);
+				if (option != null) {
+					timeOut = Long.parseLong(option);
+				}
+			} catch(NumberFormatException e) {
+				// ignore
+			}
+			if (timeOut == 0) {
+				// don't try to fetch the values
+				return this.parameterNames = getRawParameterNames(paramCount);
+			}
+			final class ParametersNameCollector {
+				String javadoc;
+				public void setJavadoc(String s) {
+					this.javadoc = s;
+				}
+				public String getJavadoc() {
+					return this.javadoc;
+				}
+			}
+			/*
+			 * The declaring type is not in the cache yet. The thread wil retrieve the javadoc contents
+			 */
+			final ParametersNameCollector nameCollector = new ParametersNameCollector();
+			Thread collect = new Thread() {
+				public void run() {
+					try {
+						// this call has a side-effect on the per project info cache
+						nameCollector.setJavadoc(BinaryMethod.this.getAttachedJavadoc(null));
+					} catch (JavaModelException e) {
+						// ignore
+					}
+					synchronized(nameCollector) {
+						nameCollector.notify();
+					}
+				}
+			};
+			collect.start();
+			synchronized(nameCollector) {
+				try {
+					nameCollector.wait(timeOut);
+				} catch (InterruptedException e) {
+					// ignore
+				}
+			}
+			javadocContents = nameCollector.getJavadoc();
+		} else if (javadocContents != BinaryType.EMPTY_JAVADOC){
+			// need to extract the part relative to the binary method since javadoc contains the javadoc for the declaring type
+			try {
+				javadocContents = extractJavadoc(declaringType, javadocContents);
+			} catch(JavaModelException e) {
+				// ignore
+			}
+		} else {
+			// let's see if we can retrieve them from the debug infos
+			char[][] argumentNames = info.getArgumentNames();
+			if (argumentNames != null && argumentNames.length == paramCount) {
+				String[] names = new String[paramCount];
+				for (int i = 0; i < paramCount; i++) {
+					names[i] = new String(argumentNames[i]);
+				}
+				return this.parameterNames = names;
+			}
+			return getRawParameterNames(paramCount);
+		}
+		if (javadocContents != null && javadocContents != BinaryType.EMPTY_JAVADOC) {
+			final int indexOfOpenParen = javadocContents.indexOf('(');
+			if (indexOfOpenParen != -1) {
+				final int indexOfClosingParen = javadocContents.indexOf(')', indexOfOpenParen);
+				if (indexOfClosingParen != -1) {
+					final char[] paramsSource =
+						CharOperation.replace(
+							javadocContents.substring(indexOfOpenParen + 1, indexOfClosingParen).toCharArray(),
+							"&nbsp;".toCharArray(), //$NON-NLS-1$
+							new char[] {' '});
+					final char[][] params = splitParameters(paramsSource, paramCount);
+					final int paramsLength = params.length;
+					this.parameterNames = new String[paramsLength];
+					for (int i = 0; i < paramsLength; i++) {
+						final char[] param = params[i];
+						int indexOfSpace = CharOperation.lastIndexOf(' ', param);
+						if (indexOfSpace != -1) {
+							this.parameterNames[i] = String.valueOf(param, indexOfSpace + 1, param.length - indexOfSpace -1);
+						} else {
+							this.parameterNames[i] = "arg" + i; //$NON-NLS-1$
+						}
+					}
+					return this.parameterNames;
+				}
+			}
+		}
+		// let's see if we can retrieve them from the debug infos
+		char[][] argumentNames = info.getArgumentNames();
+		if (argumentNames != null && argumentNames.length == paramCount) {
+			String[] names = new String[paramCount];
+			for (int i = 0; i < paramCount; i++) {
+				names[i] = new String(argumentNames[i]);
+			}
+			return this.parameterNames = names;
+		}
+	}
+	// if still no parameter names, produce fake ones
+	return this.parameterNames = getRawParameterNames(paramCount);
+}
+private char[][] splitParameters(char[] parametersSource, int paramCount) {
+	// we have generic types as one of the parameter types
+	char[][] params = new char[paramCount][];
+	int paramIndex = 0;
+	int index = 0;
+	int balance = 0;
+	int length = parametersSource.length;
+	int start = 0;
+	while(index < length) {
+		switch (parametersSource[index]) {
+			case '<':
+				balance++;
+				index++;
+				while(index < length && parametersSource[index] != '>') {
+					index++;
+				}
+				break;
+			case '>' :
+				balance--;
+				index++;
+				break;
+			case ',' :
+				if (balance == 0 && paramIndex < paramCount) {
+					params[paramIndex++] = CharOperation.subarray(parametersSource, start, index);
+					start = index + 1;
+				}
+				index++;
+				break;
+			case '&' :
+				if ((index + 4) < length) {
+					if (parametersSource[index + 1] == 'l'
+							&& parametersSource[index + 2] == 't'
+							&& parametersSource[index + 3] == ';') {
+						balance++;
+						index += 4;
+					} else if (parametersSource[index + 1] == 'g'
+							&& parametersSource[index + 2] == 't'
+							&& parametersSource[index + 3] == ';') {
+						balance--;
+						index += 4;
+					} else {
+						index++;
+					}
+				} else {
+					index++;
+				}
+				break;
+			default:
+				index++;
+		}
+	}
+	if (paramIndex < paramCount) {
+		params[paramIndex++] = CharOperation.subarray(parametersSource, start, index);
+	}
+	if (paramIndex != paramCount) {
+		// happens only for constructors with synthetic enclosing type in the signature
+		System.arraycopy(params, 0, (params = new char[paramIndex][]), 0, paramIndex);
+	}
+	return params;
 }
 /*
  * @see IMethod
@@ -243,6 +387,19 @@
 	return CharOperation.toStrings(typeParams);
 }
 
+public String[] getRawParameterNames() throws JavaModelException {
+	IBinaryMethod info = (IBinaryMethod) getElementInfo();
+	int paramCount = Signature.getParameterCount(new String(info.getMethodDescriptor()));
+	return getRawParameterNames(paramCount);
+}
+private String[] getRawParameterNames(int paramCount) {
+	String[] result = new String[paramCount];
+	for (int i = 0; i < paramCount; i++) {
+		result[i] = "arg" + i; //$NON-NLS-1$
+	}
+	return result;
+}
+
 /*
  * @see IMethod
  */
@@ -281,6 +438,10 @@
  * @see IMethod
  */
 public boolean isConstructor() throws JavaModelException {
+	if (!this.getElementName().equals(this.parent.getElementName())) {
+		// faster than reaching the info
+		return false;
+	}	
 	IBinaryMethod info = (IBinaryMethod) getElementInfo();
 	return info.isConstructor();
 }
@@ -387,4 +548,96 @@
 		buffer.append(this.occurrenceCount);
 	}
 }
+public String getAttachedJavadoc(IProgressMonitor monitor) throws JavaModelException {
+	IType declaringType = this.getDeclaringType();
+
+	String contents = ((BinaryType) declaringType).getJavadocContents(monitor);
+	return extractJavadoc(declaringType, contents);
+}
+private String extractJavadoc(IType declaringType, String contents) throws JavaModelException {
+	if (contents == null) return null;
+
+	String typeQualifiedName = null;
+	final boolean declaringTypeIsMember = declaringType.isMember();
+	if (declaringTypeIsMember) {
+		IType currentType = declaringType;
+		StringBuffer buffer = new StringBuffer();
+		while (currentType != null) {
+			buffer.insert(0, currentType.getElementName());
+			currentType = currentType.getDeclaringType();
+			if (currentType != null) {
+				buffer.insert(0, '.');
+			}
+		}
+		typeQualifiedName = new String(buffer.toString());
+	} else {
+		typeQualifiedName = declaringType.getElementName();
+	}
+	String methodName = this.getElementName();
+	if (this.isConstructor()) {
+		methodName = typeQualifiedName;
+	}
+	IBinaryMethod info = (IBinaryMethod) getElementInfo();
+	char[] genericSignature = info.getGenericSignature();
+	String anchor = null;
+	if (genericSignature != null) {
+		genericSignature = CharOperation.replaceOnCopy(genericSignature, '/', '.');
+		anchor = Util.toAnchor(genericSignature, methodName, Flags.isVarargs(this.getFlags()));
+		if (anchor == null) throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.UNKNOWN_JAVADOC_FORMAT, this));
+	} else {
+		anchor = Signature.toString(this.getSignature().replace('/', '.'), methodName, null, true, false, Flags.isVarargs(this.getFlags()));
+	}
+	if (declaringTypeIsMember) {
+		int depth = 0;
+		final String packageFragmentName = declaringType.getPackageFragment().getElementName();
+		// might need to remove a part of the signature corresponding to the synthetic argument
+		final IJavaProject javaProject = declaringType.getJavaProject();
+		char[][] typeNames = CharOperation.splitOn('.', typeQualifiedName.toCharArray());
+		if (!Flags.isStatic(declaringType.getFlags())) depth++;
+		StringBuffer typeName = new StringBuffer();
+		for (int i = 0, max = typeNames.length; i < max; i++) {
+			if (typeName.length() == 0) {
+				typeName.append(typeNames[i]);
+			} else {
+				typeName.append('.').append(typeNames[i]);
+			}
+			IType resolvedType = javaProject.findType(packageFragmentName, String.valueOf(typeName));
+			if (resolvedType != null && resolvedType.isMember() && !Flags.isStatic(resolvedType.getFlags())) depth++;
+		}
+		if (depth != 0) {
+			int indexOfOpeningParen = anchor.indexOf('(');
+			if (indexOfOpeningParen == -1) return null;
+			int index = indexOfOpeningParen;
+			indexOfOpeningParen++;
+			for (int i = 0; i < depth; i++) {
+				int indexOfComma = anchor.indexOf(',', index);
+				if (indexOfComma != -1) {
+					index = indexOfComma + 2;
+				}
+			}
+			anchor = anchor.substring(0, indexOfOpeningParen) + anchor.substring(index);
+		}
+	}
+	int indexAnchor = contents.indexOf(JavadocConstants.ANCHOR_PREFIX_START + anchor + JavadocConstants.ANCHOR_PREFIX_END);
+	if (indexAnchor == -1) {
+		return null; // method without javadoc
+	}
+	int indexOfEndLink = contents.indexOf(JavadocConstants.ANCHOR_SUFFIX, indexAnchor);
+	if (indexOfEndLink == -1) throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.UNKNOWN_JAVADOC_FORMAT, this));
+	int indexOfNextMethod = contents.indexOf(JavadocConstants.ANCHOR_PREFIX_START, indexOfEndLink);
+	// find bottom
+	int indexOfBottom = -1;
+	if (this.isConstructor()) {
+		indexOfBottom = contents.indexOf(JavadocConstants.METHOD_DETAIL, indexOfEndLink);
+		if (indexOfBottom == -1) {
+			indexOfBottom = contents.indexOf(JavadocConstants.END_OF_CLASS_DATA, indexOfEndLink);
+		}
+	} else {
+		indexOfBottom = contents.indexOf(JavadocConstants.END_OF_CLASS_DATA, indexOfEndLink);
+	}
+	if (indexOfBottom == -1) throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.UNKNOWN_JAVADOC_FORMAT, this));
+	indexOfNextMethod = Math.min(indexOfNextMethod, indexOfBottom);
+	if (indexOfNextMethod == -1) throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.UNKNOWN_JAVADOC_FORMAT, this));
+	return contents.substring(indexOfEndLink + JavadocConstants.ANCHOR_SUFFIX_LENGTH, indexOfNextMethod);
+}
 }
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 8a49849..3287cfc 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -11,18 +11,22 @@
 package org.eclipse.jdt.internal.core;
 
 import java.io.InputStream;
+import java.net.URL;
 import java.util.ArrayList;
 import java.util.HashMap;
 
+import org.eclipse.core.runtime.Assert;
 import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.OperationCanceledException;
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.search.SearchEngine;
 import org.eclipse.jdt.internal.codeassist.CompletionEngine;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
 import org.eclipse.jdt.internal.compiler.env.IBinaryType;
-import org.eclipse.jdt.internal.compiler.env.IGenericType;
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
+import org.eclipse.jdt.internal.core.JavaModelManager.PerProjectInfo;
 import org.eclipse.jdt.internal.core.hierarchy.TypeHierarchy;
 import org.eclipse.jdt.internal.core.util.MementoTokenizer;
 import org.eclipse.jdt.internal.core.util.Messages;
@@ -40,11 +44,10 @@
 	private static final IMethod[] NO_METHODS = new IMethod[0];
 	private static final IType[] NO_TYPES = new IType[0];
 	private static final IInitializer[] NO_INITIALIZERS = new IInitializer[0];
-	private static final String[] NO_STRINGS = new String[0];
+	public static final String EMPTY_JAVADOC = org.eclipse.jdt.internal.compiler.util.Util.EMPTY_STRING;
 	
 protected BinaryType(JavaElement parent, String name) {
 	super(parent, name);
-	Assert.isTrue(name.indexOf('.') == -1);
 }
 /*
  * Remove my cached children from the Java Model
@@ -158,30 +161,40 @@
  * @see IParent#getChildren()
  */
 public IJavaElement[] getChildren() throws JavaModelException {
-	// ensure present
-	// fix for 1FWWVYT
-	if (!exists()) {
-		throw newNotPresentException();
-	}
-	// get children
 	ClassFileInfo cfi = getClassFileInfo();
-	if (cfi.binaryChildren == null) {
-		JavaModelManager manager = JavaModelManager.getJavaModelManager();
-		boolean hadTemporaryCache = manager.hasTemporaryCache();
-		try {
-			Object info = manager.getInfo(this);
-			HashMap newElements = manager.getTemporaryCache();
-			cfi.readBinaryChildren(newElements, (IBinaryType)info);
-			if (!hadTemporaryCache) {
-				manager.putInfos(this, newElements);
-			}
-		} finally {
-			if (!hadTemporaryCache) {
-				manager.resetTemporaryCache();
+	return cfi.binaryChildren;
+}
+public IJavaElement[] getChildrenForCategory(String category) throws JavaModelException {
+	IJavaElement[] children = getChildren();
+	int length = children.length;
+	if (length == 0) return children;
+	SourceMapper mapper= getSourceMapper();
+	if (mapper != null) {
+		// ensure the class file's buffer is open so that categories are computed
+		((ClassFile)getClassFile()).getBuffer();
+		
+		HashMap categories = mapper.categories;
+		IJavaElement[] result = new IJavaElement[length];
+		int index = 0;
+		if (categories != null) {
+			for (int i = 0; i < length; i++) {
+				IJavaElement child = children[i];
+				String[] cats = (String[]) categories.get(child);
+				if (cats != null) {
+					for (int j = 0, length2 = cats.length; j < length2; j++) {
+						if (cats[j].equals(category)) {
+							result[index++] = child;
+							break;
+						}
+					}
+				}
 			}
 		}
+		if (index < length)
+			System.arraycopy(result, 0, result = new IJavaElement[index], 0, index);
+		return result;
 	}
-	return cfi.binaryChildren;
+	return NO_ELEMENTS;	
 }
 protected ClassFileInfo getClassFileInfo() throws JavaModelException {
 	ClassFile cf = (ClassFile)this.parent;
@@ -238,6 +251,12 @@
 		}
 	}
 }
+public Object getElementInfo(IProgressMonitor monitor) throws JavaModelException {
+	JavaModelManager manager = JavaModelManager.getJavaModelManager();
+	Object info = manager.getInfo(this);
+	if (info != null && info != JavaModelCache.NON_EXISTING_JAR_TYPE_INFO) return info;
+	return openWhenClosed(createElementInfo(), monitor);
+}
 /*
  * @see IJavaElement
  */
@@ -341,17 +360,13 @@
 			String[] parameters = new String[params.size()];
 			params.toArray(parameters);
 			JavaElement method = (JavaElement)getMethod(selector, parameters);
-			if (token != null) {
-				switch (token.charAt(0)) {
-					case JEM_TYPE:
-					case JEM_TYPE_PARAMETER:
-					case JEM_LOCALVARIABLE:
-						return method.getHandleFromMemento(token, memento, workingCopyOwner);
-					default:
-						return method;
-				}
-			} else {
-				return method;
+			switch (token.charAt(0)) {
+				case JEM_TYPE:
+				case JEM_TYPE_PARAMETER:
+				case JEM_LOCALVARIABLE:
+					return method.getHandleFromMemento(token, memento, workingCopyOwner);
+				default:
+					return method;
 			}
 		case JEM_TYPE:
 			String typeName;
@@ -472,6 +487,24 @@
 	}
 }
 
+public String getSourceFileName(IBinaryType info) {
+	if (info == null) {
+		try {
+			info = (IBinaryType) getElementInfo();
+		} catch (JavaModelException e) {
+			// default to using the outer most declaring type name
+			IType type = this;
+			IType enclosingType = getDeclaringType();
+			while (enclosingType != null) {
+				type = enclosingType;
+				enclosingType = type.getDeclaringType();
+			}
+			return type.getElementName() + Util.defaultJavaExtension();
+		}
+	}
+	return sourceFileName(info);
+}
+
 /*
  * @see IType#getSuperclassName()
  */
@@ -491,7 +524,7 @@
 	char[][] names= info.getInterfaceNames();
 	int length;
 	if (names == null || (length = names.length) == 0) {
-		return NO_STRINGS;
+		return CharOperation.NO_STRINGS;
 	}
 	names= ClassFile.translatedNames(names);
 	String[] strings= new String[length];
@@ -543,7 +576,7 @@
 		char[][] names= info.getInterfaceNames();
 		int length;
 		if (names == null || (length = names.length) == 0) {
-			return NO_STRINGS;
+			return CharOperation.NO_STRINGS;
 		}
 		names= ClassFile.translatedNames(names);
 		String[] strings= new String[length];
@@ -635,7 +668,7 @@
  */
 public boolean isClass() throws JavaModelException {
 	IBinaryType info = (IBinaryType) getElementInfo();
-	return info.getKind() == IGenericType.CLASS_DECL;
+	return TypeDeclaration.kind(info.getModifiers()) == TypeDeclaration.CLASS_DECL;
 
 }
 
@@ -645,7 +678,7 @@
  */
 public boolean isEnum() throws JavaModelException {
 	IBinaryType info = (IBinaryType) getElementInfo();
-	return info.getKind() == IGenericType.ENUM_DECL;
+	return TypeDeclaration.kind(info.getModifiers()) == TypeDeclaration.ENUM_DECL;
 }
 
 /*
@@ -653,9 +686,9 @@
  */
 public boolean isInterface() throws JavaModelException {
 	IBinaryType info = (IBinaryType) getElementInfo();
-	switch (info.getKind()) {
-		case IGenericType.INTERFACE_DECL:
-		case IGenericType.ANNOTATION_TYPE_DECL: // annotation is interface too
+	switch (TypeDeclaration.kind(info.getModifiers())) {
+		case TypeDeclaration.INTERFACE_DECL:
+		case TypeDeclaration.ANNOTATION_TYPE_DECL: // annotation is interface too
 			return true;
 	}
 	return false;
@@ -666,7 +699,7 @@
  */
 public boolean isAnnotation() throws JavaModelException {
 	IBinaryType info = (IBinaryType) getElementInfo();
-	return info.getKind() == IGenericType.ANNOTATION_TYPE_DECL;
+	return TypeDeclaration.kind(info.getModifiers()) == TypeDeclaration.ANNOTATION_TYPE_DECL;
 }
 
 /*
@@ -898,7 +931,8 @@
 			return getElementName() + Util.defaultJavaExtension();
 		}
 	} else {
-		return  new String(sourceFileName);
+		int index = CharOperation.lastIndexOf('/', sourceFileName);
+		return new String(sourceFileName, index + 1, sourceFileName.length - index - 1);
 	}
 }
 /*
@@ -934,4 +968,99 @@
 	else
 		buffer.append("<anonymous>"); //$NON-NLS-1$
 }
+public String getAttachedJavadoc(IProgressMonitor monitor) throws JavaModelException {
+	final String contents = getJavadocContents(monitor);
+	if (contents == null) return null;
+	final int indexOfStartOfClassData = contents.indexOf(JavadocConstants.START_OF_CLASS_DATA);
+	if (indexOfStartOfClassData == -1) throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.UNKNOWN_JAVADOC_FORMAT, this));
+	int indexOfNextSummary = contents.indexOf(JavadocConstants.NESTED_CLASS_SUMMARY);
+	if (this.isEnum() && indexOfNextSummary == -1) {
+		// try to find enum constant summary start
+		indexOfNextSummary = contents.indexOf(JavadocConstants.ENUM_CONSTANT_SUMMARY);
+	}
+	if (this.isAnnotation() && indexOfNextSummary == -1) {
+		// try to find required enum constant summary start
+		indexOfNextSummary = contents.indexOf(JavadocConstants.ANNOTATION_TYPE_REQUIRED_MEMBER_SUMMARY);
+		if (indexOfNextSummary == -1) {
+			// try to find optional enum constant summary start
+			indexOfNextSummary = contents.indexOf(JavadocConstants.ANNOTATION_TYPE_OPTIONAL_MEMBER_SUMMARY);
+		}
+	}
+	if (indexOfNextSummary == -1) {
+		// try to find field summary start
+		indexOfNextSummary = contents.indexOf(JavadocConstants.FIELD_SUMMARY);
+	}
+	if (indexOfNextSummary == -1) {
+		// try to find constructor summary start
+		indexOfNextSummary = contents.indexOf(JavadocConstants.CONSTRUCTOR_SUMMARY);
+	}
+	if (indexOfNextSummary == -1) {
+		// try to find method summary start
+		indexOfNextSummary = contents.indexOf(JavadocConstants.METHOD_SUMMARY);
+	}
+	if (indexOfNextSummary == -1) {
+		// we take the end of class data
+		indexOfNextSummary = contents.indexOf(JavadocConstants.END_OF_CLASS_DATA);
+	}
+	if (indexOfNextSummary == -1) {
+		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.UNKNOWN_JAVADOC_FORMAT, this));
+	}
+	/*
+	 * Check out to cut off the hierarchy see 119844
+	 * We remove what the contents between the start of class data and the first <P>
+	 */
+	int start = indexOfStartOfClassData + JavadocConstants.START_OF_CLASS_DATA_LENGTH;
+	int indexOfFirstParagraph = contents.indexOf("<P>", start); //$NON-NLS-1$
+	if (indexOfFirstParagraph == -1) {
+		indexOfFirstParagraph = contents.indexOf("<p>", start); //$NON-NLS-1$
+	}
+	if (indexOfFirstParagraph != -1 && indexOfFirstParagraph < indexOfNextSummary) {
+		start = indexOfFirstParagraph;
+	}	
+	return contents.substring(start, indexOfNextSummary);
+}
+public String getJavadocContents(IProgressMonitor monitor) throws JavaModelException {
+	PerProjectInfo projectInfo = JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(this.getJavaProject().getProject());
+	String cachedJavadoc = null;
+	synchronized (projectInfo.javadocCache) {
+		cachedJavadoc = (String) projectInfo.javadocCache.get(this);
+	}
+	if (cachedJavadoc != null && cachedJavadoc != EMPTY_JAVADOC) {
+		return cachedJavadoc;
+	}
+	URL baseLocation= getJavadocBaseLocation();
+	if (baseLocation == null) {
+		return null;
+	}
+	StringBuffer pathBuffer = new StringBuffer(baseLocation.toExternalForm());
+
+	if (!(pathBuffer.charAt(pathBuffer.length() - 1) == '/')) {
+		pathBuffer.append('/');
+	}
+	IPackageFragment pack= this.getPackageFragment();
+	String typeQualifiedName = null;
+	if (this.isMember()) {
+		IType currentType = this;
+		StringBuffer typeName = new StringBuffer();
+		while (currentType != null) {
+			typeName.insert(0, currentType.getElementName());
+			currentType = currentType.getDeclaringType();
+			if (currentType != null) {
+				typeName.insert(0, '.');
+			}
+		}
+		typeQualifiedName = new String(typeName.toString());
+	} else {
+		typeQualifiedName = this.getElementName();
+	}
+	
+	pathBuffer.append(pack.getElementName().replace('.', '/')).append('/').append(typeQualifiedName).append(JavadocConstants.HTML_EXTENSION);
+	
+	if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
+	final String contents = getURLContents(String.valueOf(pathBuffer));
+	synchronized (projectInfo.javadocCache) {
+		projectInfo.javadocCache.put(this, contents);
+	}
+	return contents;
+}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryTypeConverter.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryTypeConverter.java
index 5182406..0e33b88 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryTypeConverter.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryTypeConverter.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -33,7 +33,8 @@
 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.lookup.CompilerModifiers;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
 import org.eclipse.jdt.internal.core.util.Util;
 
 /**
@@ -49,7 +50,7 @@
 		char[][] packageName = Util.toCharArrays(pkg.names);
 		
 		if (packageName.length > 0) { 
-			compilationUnit.currentPackage = new ImportReference(packageName, new long[]{0}, false, CompilerModifiers.AccDefault);
+			compilationUnit.currentPackage = new ImportReference(packageName, new long[]{0}, false, ClassFileConstants.AccDefault);
 		}
 	
 		/* convert type */
@@ -88,7 +89,7 @@
 
 		if (method.isConstructor()) {
 			ConstructorDeclaration decl = new ConstructorDeclaration(compilationResult);
-			decl.isDefaultConstructor = false;
+			decl.bits &= ~ASTNode.IsDefaultConstructor;
 			methodDeclaration = decl;
 		} else {
 			MethodDeclaration decl = type.isAnnotation() ? new AnnotationMethodDeclaration(compilationResult) : new MethodDeclaration(compilationResult);
@@ -116,7 +117,7 @@
 				argumentNames[i].toCharArray(),
 				0,
 				typeReference,
-				CompilerModifiers.AccDefault);
+				ClassFileConstants.AccDefault);
 			// do not care whether was final or not
 		}
 
@@ -138,7 +139,7 @@
 		TypeDeclaration typeDeclaration = new TypeDeclaration(compilationResult);
 
 		if (type.getDeclaringType() != null) {
-			typeDeclaration.bits |= ASTNode.IsMemberTypeMASK;
+			typeDeclaration.bits |= ASTNode.IsMemberType;
 		}
 		typeDeclaration.name = type.getElementName().toCharArray();
 		typeDeclaration.modifiers = type.getFlags();
@@ -202,7 +203,7 @@
 			AbstractMethodDeclaration method =convert(methods[i], type, compilationResult);
 			boolean isAbstract;
 			if ((isAbstract = method.isAbstract()) || isInterface) { // fix-up flag 
-				method.modifiers |= CompilerModifiers.AccSemicolonBody;
+				method.modifiers |= ExtraCompilerModifiers.AccSemicolonBody;
 			}
 			if (isAbstract) {
 				hasAbstractMethods = true;
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 c24fbd0..de332fa 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -7,6 +7,7 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ *     Tim Hanson (thanson@bea.com) - patch for https://bugs.eclipse.org/bugs/show_bug.cgi?id=126673
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
@@ -19,7 +20,8 @@
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.ISafeRunnable;
-import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.core.runtime.content.IContentDescription;
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.internal.core.util.Util;
 
@@ -105,7 +107,9 @@
 		this.flags |= F_IS_CLOSED;
 	}
 	notifyChanged(event); // notify outside of synchronized block
-	this.changeListeners = null;
+	synchronized(this) { // ensure that no other thread is adding/removing a listener at the same time (https://bugs.eclipse.org/bugs/show_bug.cgi?id=126673)
+		this.changeListeners = null;
+	}
 }
 /**
  * @see IBuffer
@@ -253,7 +257,7 @@
 	if (listeners != null) {
 		for (int i = 0, size = listeners.size(); i < size; ++i) {
 			final IBufferChangedListener listener = (IBufferChangedListener) listeners.get(i);
-			Platform.run(new ISafeRunnable() {
+			SafeRunner.run(new ISafeRunnable() {
 				public void handleException(Throwable exception) {
 					Util.log(exception, "Exception occurred in listener of buffer change notification"); //$NON-NLS-1$
 				}
@@ -334,6 +338,10 @@
 		
 	// use a platform operation to update the resource contents
 	try {
+		String stringContents = this.getContents();
+		if (stringContents == null) return;
+
+		// Get encoding
 		String encoding = null;
 		try {
 			encoding = this.file.getCharset();
@@ -341,13 +349,27 @@
 		catch (CoreException ce) {
 			// use no encoding
 		}
-		String stringContents = this.getContents();
-		if (stringContents == null) return;
+		
+		// Create bytes array
 		byte[] bytes = encoding == null 
 			? stringContents.getBytes() 
 			: stringContents.getBytes(encoding);
-		ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
 
+		// Special case for UTF-8 BOM files
+		// see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=110576
+		if (encoding != null && encoding.equals(org.eclipse.jdt.internal.compiler.util.Util.UTF_8)) {
+			IContentDescription description = this.file.getContentDescription();
+			if (description != null && description.getProperty(IContentDescription.BYTE_ORDER_MARK) != null) {
+				int bomLength= IContentDescription.BOM_UTF_8.length;
+				byte[] bytesWithBOM= new byte[bytes.length + bomLength];
+				System.arraycopy(IContentDescription.BOM_UTF_8, 0, bytesWithBOM, 0, bomLength);
+				System.arraycopy(bytes, 0, bytesWithBOM, bomLength, bytes.length);
+				bytes= bytesWithBOM;
+			}
+		}
+		
+		// Set file contents
+		ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
 		if (this.file.exists()) {
 			this.file.setContents(
 				stream, 
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 c5252ab..3e35339 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,6 +10,8 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
+import java.util.ArrayList;
+
 import org.eclipse.jdt.core.IBuffer;
 import org.eclipse.jdt.internal.core.util.LRUCache;
 
@@ -17,6 +19,8 @@
  * An LRU cache of <code>IBuffers</code>.
  */
 public class BufferCache extends OverflowingLRUCache {
+	
+	private ThreadLocal buffersToClose = new ThreadLocal();
 /**
  * Constructs a new buffer cache of the given size.
  */
@@ -44,10 +48,25 @@
 	if (!((Openable)buffer.getOwner()).canBufferBeRemovedFromCache(buffer)) {
 		return false;
 	} else {
-		buffer.close();
+		ArrayList buffers = (ArrayList) this.buffersToClose.get();
+		if (buffers == null) {
+			buffers = new ArrayList();
+			this.buffersToClose.set(buffers);
+		}
+		buffers.add(buffer);
 		return true;
 	}
 }
+
+void closeBuffers() {
+	ArrayList buffers = (ArrayList) this.buffersToClose.get();
+	if (buffers == null)
+		return;
+	this.buffersToClose.set(null);
+	for (int i = 0, length = buffers.size(); i < length; i++) {
+		((IBuffer) buffers.get(i)).close();
+	}
+}
 	/**
 	 * Returns a new instance of the reciever.
 	 */
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 ca2f16c..036677f 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 5ade7f2..3bbe868 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -32,7 +32,7 @@
 	 * LRU cache of buffers. The key and value for an entry
 	 * in the table is the identical buffer.
 	 */
-	protected OverflowingLRUCache openBuffers = new BufferCache(60);
+	private BufferCache openBuffers = new BufferCache(60);
 	
 	/**
 	 * @deprecated
@@ -42,7 +42,7 @@
 	     * @deprecated
 	     */
 		public IBuffer createBuffer(IOpenable owner) {
-			return BufferManager.this.createBuffer(owner);
+			return BufferManager.createBuffer(owner);
 		}
 	};
 
@@ -54,12 +54,16 @@
 		String owner = ((Openable)buffer.getOwner()).toStringWithAncestors();
 		System.out.println("Adding buffer for " + owner); //$NON-NLS-1$
 	}
-	this.openBuffers.put(buffer.getOwner(), buffer);
+	synchronized (this.openBuffers) {
+		this.openBuffers.put(buffer.getOwner(), buffer);	
+	}
+	// close buffers that were removed from the cache if space was needed
+	this.openBuffers.closeBuffers();
 	if (VERBOSE) {
 		System.out.println("-> Buffer cache filling ratio = " + NumberFormat.getInstance().format(this.openBuffers.fillingRatio()) + "%"); //$NON-NLS-1$//$NON-NLS-2$
 	}
 }
-public IBuffer createBuffer(IOpenable owner) {
+public static IBuffer createBuffer(IOpenable owner) {
 	IJavaElement element = (IJavaElement)owner;
 	IResource resource = element.getResource();
 	return 
@@ -68,13 +72,24 @@
 			owner, 
 			element.isReadOnly());
 }
+public static IBuffer createNullBuffer(IOpenable owner) {
+	IJavaElement element = (IJavaElement)owner;
+	IResource resource = element.getResource();
+	return 
+		new NullBuffer(
+			resource instanceof IFile ? (IFile)resource : null, 
+			owner, 
+			element.isReadOnly());
+}
 /**
  * Returns the open buffer associated with the given owner,
  * or <code>null</code> if the owner does not have an open
  * buffer associated with it.
  */
 public IBuffer getBuffer(IOpenable owner) {
-	return (IBuffer)this.openBuffers.get(owner);
+	synchronized (this.openBuffers) {
+		return (IBuffer)this.openBuffers.get(owner);
+	}
 }
 /**
  * Returns the default buffer manager.
@@ -101,10 +116,14 @@
  * @return Enumeration of IBuffer
  */
 public Enumeration getOpenBuffers() {
+	Enumeration result;
 	synchronized (this.openBuffers) {
 		this.openBuffers.shrink();
-		return this.openBuffers.elements();
+		result = this.openBuffers.elements();
 	}
+	// close buffers that were removed from the cache if space was needed
+	this.openBuffers.closeBuffers();
+	return result;
 }
 
 /**
@@ -115,7 +134,11 @@
 		String owner = ((Openable)buffer.getOwner()).toStringWithAncestors();
 		System.out.println("Removing buffer for " + owner); //$NON-NLS-1$
 	}
-	this.openBuffers.remove(buffer.getOwner());
+	synchronized (this.openBuffers) {
+		this.openBuffers.remove(buffer.getOwner());
+	}
+	// close buffers that were removed from the cache (should be only one)
+	this.openBuffers.closeBuffers();	
 	if (VERBOSE) {
 		System.out.println("-> Buffer cache filling ratio = " + NumberFormat.getInstance().format(this.openBuffers.fillingRatio()) + "%"); //$NON-NLS-1$//$NON-NLS-2$
 	}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CancelableNameEnvironment.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CancelableNameEnvironment.java
index f62da56..ef0ea71 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CancelableNameEnvironment.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CancelableNameEnvironment.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -50,8 +50,8 @@
 		return super.findType(compoundTypeName);
 	}
 
-	public void findTypes(char[] prefix, boolean findMembers, ISearchRequestor storage) {
+	public void findTypes(char[] prefix, boolean findMembers, boolean camelCaseMatch, int searchFor, ISearchRequestor storage) {
 		checkCanceled();
-		super.findTypes(prefix, findMembers, storage);
+		super.findTypes(prefix, findMembers, camelCaseMatch, searchFor, storage);
 	}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CancelableProblemFactory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CancelableProblemFactory.java
index 8108478..8359de0 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CancelableProblemFactory.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CancelableProblemFactory.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -12,7 +12,7 @@
 
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.OperationCanceledException;
-import org.eclipse.jdt.core.compiler.IProblem;
+import org.eclipse.jdt.core.compiler.CategorizedProblem;
 import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
 import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
 
@@ -25,9 +25,9 @@
 		this.monitor = monitor;
 	}
 
-	public IProblem createProblem(char[] originatingFileName, int problemId, String[] problemArguments, String[] messageArguments, int severity, int startPosition, int endPosition, int lineNumber) {
+	public CategorizedProblem createProblem(char[] originatingFileName, int problemId, String[] problemArguments, String[] messageArguments, int severity, int startPosition, int endPosition, int lineNumber, int columnNumber) {
 		if (this.monitor != null && this.monitor.isCanceled()) 
 			throw new AbortCompilation(true/*silent*/, new OperationCanceledException());
-		return super.createProblem(originatingFileName, problemId, problemArguments, messageArguments, severity, startPosition, endPosition, lineNumber);
+		return super.createProblem(originatingFileName, problemId, problemArguments, messageArguments, severity, startPosition, endPosition, lineNumber, columnNumber);
 	}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ChangeClasspathOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ChangeClasspathOperation.java
new file mode 100755
index 0000000..bef87e4
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ChangeClasspathOperation.java
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core;
+
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.JavaModelException;
+
+/*
+ * Abstract class for operations that change the classpath
+ */
+public abstract class ChangeClasspathOperation extends JavaModelOperation {
+
+	protected boolean canChangeResources;
+
+	public ChangeClasspathOperation(IJavaElement[] elements, boolean canChangeResources) {
+		super(elements);
+		this.canChangeResources = canChangeResources;
+	}
+
+	protected boolean canModifyRoots() {
+		// changing the classpath can modify roots
+		return true;
+	}
+	
+	/*
+	 * The resolved classpath of the given project may have changed:
+	 * - generate a delta
+	 * - trigger indexing
+	 * - update project references
+	 * - create resolved classpath markers
+	 */
+	protected void classpathChanged(JavaProject project) throws JavaModelException {
+		DeltaProcessingState state = JavaModelManager.getJavaModelManager().deltaState;
+		DeltaProcessor deltaProcessor = state.getDeltaProcessor();
+		ClasspathChange change = (ClasspathChange) deltaProcessor.classpathChanges.get(project.getProject());
+		if (this.canChangeResources) {
+			// workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=177922
+			if (isTopLevelOperation() && !ResourcesPlugin.getWorkspace().isTreeLocked()) {
+				new ClasspathValidation(project).validate();
+			}
+				
+			// delta, indexing and classpath markers are going to be created by the delta processor 
+			// while handling the .classpath file change
+
+			// however ensure project references are updated
+			// since some clients rely on the project references when run inside an IWorkspaceRunnable
+			new ProjectReferenceChange(project, change.oldResolvedClasspath).updateProjectReferencesIfNecessary();
+		} else {
+			JavaElementDelta delta = new JavaElementDelta(getJavaModel());
+			int result = change.generateDelta(delta);
+			if ((result & ClasspathChange.HAS_DELTA) != 0) {
+				// create delta
+				addDelta(delta);
+				
+				// ensure indexes are updated
+				change.requestIndexing();
+				
+				// ensure classpath is validated on next build
+				state.addClasspathValidation(project);
+			}
+			if ((result & ClasspathChange.HAS_PROJECT_CHANGE) != 0) {
+				// ensure project references are updated on next build
+				state.addProjectReferenceChange(project, change.oldResolvedClasspath);
+			}
+		}
+	}
+
+	protected ISchedulingRule getSchedulingRule() {
+		return null; // no lock taken while changing classpath
+	}
+	
+	public boolean isReadOnly() {
+		return !this.canChangeResources;
+	}
+
+}
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 4ece9fb..976e7ee 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -11,32 +11,20 @@
 package org.eclipse.jdt.internal.core;
 
 import java.io.IOException;
+import java.util.HashMap;
 import java.util.Map;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
 import org.eclipse.core.resources.IContainer;
 import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IMarker;
 import org.eclipse.core.resources.IResource;
-import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Path;
 import org.eclipse.jdt.core.*;
-import org.eclipse.jdt.core.IBuffer;
-import org.eclipse.jdt.core.IClassFile;
-import org.eclipse.jdt.core.ICompilationUnit;
-import org.eclipse.jdt.core.IJavaElement;
-import org.eclipse.jdt.core.IJavaModelMarker;
-import org.eclipse.jdt.core.IJavaModelStatusConstants;
-import org.eclipse.jdt.core.IPackageFragmentRoot;
-import org.eclipse.jdt.core.IParent;
-import org.eclipse.jdt.core.ISourceRange;
-import org.eclipse.jdt.core.IType;
-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;
@@ -54,16 +42,32 @@
 
 	protected String name;
 	protected BinaryType binaryType = null;
-	private boolean checkAutomaticSourceMapping;
+	
 /*
  * Creates a handle to a class file.
  */
-protected ClassFile(PackageFragment parent, String name) {
+protected ClassFile(PackageFragment parent, String nameWithoutExtension) {
 	super(parent);
-	// don't hold on the .class file extension to save memory
-	// also make sure to copy the string (so that it doesn't hold on the underlying char[] that might be much bigger than necessary)
-	this.name = new String(name.substring(0, name.length() - 6)); // don't hold on the .class file extension to save memory
-	this.checkAutomaticSourceMapping = false;
+	this.name = nameWithoutExtension;
+}
+
+/*
+ * @see IClassFile#becomeWorkingCopy(IProblemRequestor, WorkingCopyOwner, IProgressMonitor)
+ */
+public ICompilationUnit becomeWorkingCopy(IProblemRequestor problemRequestor, WorkingCopyOwner owner, IProgressMonitor monitor) throws JavaModelException {
+	JavaModelManager manager = JavaModelManager.getJavaModelManager();
+	CompilationUnit workingCopy = new ClassFileWorkingCopy(this, owner == null ? DefaultWorkingCopyOwner.PRIMARY : owner);
+	JavaModelManager.PerWorkingCopyInfo perWorkingCopyInfo = manager.getPerWorkingCopyInfo(workingCopy, 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(workingCopy, problemRequestor);
+		operation.runOperation(monitor);
+		
+		return workingCopy;
+	}
+	return perWorkingCopyInfo.workingCopy;
 }
 
 /**
@@ -89,9 +93,13 @@
 	}
 
 	// Make the type
-	IType type = new BinaryType(this, simpleName(typeInfo.getName()));
-	info.addChild(type);
+	IType type = getType();
+	info.setChildren(new IJavaElement[] {type});
 	newElements.put(type, typeInfo);
+	
+	// Read children
+	((ClassFileInfo) info).readBinaryChildren(this, (HashMap) newElements, typeInfo);
+	
 	return true;
 }
 /**
@@ -161,15 +169,50 @@
  * Returns a new element info for this element.
  */
 protected Object createElementInfo() {
-	return new ClassFileInfo(this);
+	return new ClassFileInfo();
 }
 public boolean equals(Object o) {
 	if (!(o instanceof ClassFile)) return false;
-	return super.equals(o);
+	ClassFile other = (ClassFile) o;
+	return this.name.equals(other.name) && this.parent.equals(other.parent);
 }
 public boolean exists() {
 	return super.exists() && validateClassFile().isOK();
 }
+public boolean existsUsingJarTypeCache() {
+	if (getPackageFragmentRoot().isArchive()) {
+		JavaModelManager manager = JavaModelManager.getJavaModelManager();
+		IType type = getType();
+		Object info = manager.getInfo(type);
+		if (info == JavaModelCache.NON_EXISTING_JAR_TYPE_INFO)
+			return false;
+		else if (info != null)
+			return true;
+		// info is null
+		JavaElementInfo parentInfo = (JavaElementInfo) manager.getInfo(getParent());
+		if (parentInfo != null) {
+			// if parent is open, this class file must be in its children
+			IJavaElement[] children = parentInfo.getChildren();
+			for (int i = 0, length = children.length; i < length; i++) {
+				if (this.name.equals(((ClassFile) children[i]).name))
+					return true;
+			}
+			return false;
+		}
+		try {
+			info = getJarBinaryTypeInfo((PackageFragment) getParent());
+		} catch (CoreException e) {
+			// leave info null
+		} catch (IOException e) {
+			// leave info null
+		} catch (ClassFormatException e) {
+			// leave info null
+		}
+		manager.putJarTypeInfo(type, info == null ? JavaModelCache.NON_EXISTING_JAR_TYPE_INFO : info);
+		return info != null;
+	} else
+		return exists();
+}
 
 /**
  * Finds the deepest <code>IJavaElement</code> in the hierarchy of
@@ -198,6 +241,19 @@
 	return elt;
 }
 /**
+ * @see ITypeRoot#findPrimaryType()
+ */
+public IType findPrimaryType() {
+	IType primaryType= getType();
+	if (primaryType.exists()) {
+		return primaryType;
+	}
+	return null;
+}
+public String getAttachedJavadoc(IProgressMonitor monitor) throws JavaModelException {
+	return this.getType().getAttachedJavadoc(monitor);
+}
+/**
  * Returns the <code>ClassFileReader</code>specific for this IClassFile, based
  * on its underlying resource, or <code>null</code> if unable to create
  * the diet class file.
@@ -210,25 +266,10 @@
  * or when this class file is not present in the JAR
  */
 public IBinaryType getBinaryTypeInfo(IFile file) throws JavaModelException {
-	JavaElement le = (JavaElement) getParent();
-	if (le instanceof JarPackageFragment) {
+	JavaElement pkg = (JavaElement) getParent();
+	if (pkg instanceof JarPackageFragment) {
 		try {
-			JarPackageFragmentRoot root = (JarPackageFragmentRoot) le.getParent();
-			IBinaryType info = null;
-			ZipFile zip = null;
-			try {
-				zip = root.getJar();
-				PackageFragment pkg = (PackageFragment) le;
-				String entryName = Util.concatWith(pkg.names, getElementName(), '/');
-				ZipEntry ze = zip.getEntry(entryName);
-				if (ze != null) {
-					byte contents[] = org.eclipse.jdt.internal.compiler.util.Util.getZipEntryByteContent(ze, zip);
-					String fileName = root.getHandleIdentifier() + IDependent.JAR_FILE_ENTRY_SEPARATOR + entryName;
-					info = new ClassFileReader(contents, fileName.toCharArray(), true/*fully initialize so as to not keep a reference to the byte array*/);
-				}
-			} finally {
-				JavaModelManager.getJavaModelManager().closeZipFile(zip);
-			}
+			IBinaryType info = getJarBinaryTypeInfo((PackageFragment) pkg);
 			if (info == null) {
 				throw newNotPresentException();
 			}
@@ -258,12 +299,66 @@
 		}
 	}
 }
+
+public byte[] getBytes() throws JavaModelException {
+	JavaElement pkg = (JavaElement) getParent();
+	if (pkg instanceof JarPackageFragment) {
+		JarPackageFragmentRoot root = (JarPackageFragmentRoot) pkg.getParent();
+		ZipFile zip = null;
+		try {
+			zip = root.getJar();
+			String entryName = Util.concatWith(((PackageFragment) pkg).names, getElementName(), '/');
+			ZipEntry ze = zip.getEntry(entryName);
+			if (ze != null) {
+				return org.eclipse.jdt.internal.compiler.util.Util.getZipEntryByteContent(ze, zip);
+			}
+			throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
+		} catch (IOException ioe) {
+			throw new JavaModelException(ioe, IJavaModelStatusConstants.IO_EXCEPTION);
+		} catch (CoreException e) {
+			if (e instanceof JavaModelException) {
+				throw (JavaModelException)e;
+			} else {
+				throw new JavaModelException(e);
+			}
+		} finally {
+			JavaModelManager.getJavaModelManager().closeZipFile(zip);
+		}
+	} else {
+		IFile file = (IFile) getResource();
+		return Util.getResourceContentsAsByteArray(file);
+	}
+}
+private IBinaryType getJarBinaryTypeInfo(PackageFragment pkg) throws CoreException, IOException, ClassFormatException {
+	JarPackageFragmentRoot root = (JarPackageFragmentRoot) pkg.getParent();
+	ZipFile zip = null;
+	try {
+		zip = root.getJar();
+		String entryName = Util.concatWith(pkg.names, getElementName(), '/');
+		ZipEntry ze = zip.getEntry(entryName);
+		if (ze != null) {
+			byte contents[] = org.eclipse.jdt.internal.compiler.util.Util.getZipEntryByteContent(ze, zip);
+			String fileName = root.getHandleIdentifier() + IDependent.JAR_FILE_ENTRY_SEPARATOR + entryName;
+			return new ClassFileReader(contents, fileName.toCharArray(), true/*fully initialize so as to not keep a reference to the byte array*/);
+		}
+	} finally {
+		JavaModelManager.getJavaModelManager().closeZipFile(zip);
+	}
+	return null;
+}
 public IBuffer getBuffer() throws JavaModelException {
-	if (validateClassFile().isOK()) {
+	IStatus status = validateClassFile();
+	if (status.isOK()) {
 		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);
+		Object info = ((ClassFile) getClassFile()).getBinaryTypeInfo((IFile) getResource());
+		IBuffer buffer = openBuffer(null, info);
+		if (buffer != null && !(buffer instanceof NullBuffer))
+			return buffer;
+		if (status.getCode() == IJavaModelStatusConstants.ELEMENT_NOT_ON_CLASSPATH)
+			return null; // don't throw a JavaModelException to be able to open .class file outside the classpath (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=138507)
+		throw new JavaModelException((IJavaModelStatus) status);
 	}
 }
 /**
@@ -273,6 +368,12 @@
 	return this;
 }
 /**
+ * @see IMember#getTypeRoot()
+ */
+public ITypeRoot getTypeRoot() {
+	return this;
+}
+/**
  * A class file has a corresponding resource unless it is contained
  * in a jar.
  *
@@ -313,14 +414,8 @@
 	if (mapper == null) {
 		return null;
 	} else {		
-		String prefix = null;
 		int index = this.name.indexOf('$');
-		if (index > -1) {
-			prefix = this.name.substring(0, index);
-		} else {
-			prefix = this.name;
-		}
-		
+		int prefixLength = index < 0 ? this.name.length() : index;
 		
 		IType type = null;
 		int start = -1;
@@ -329,22 +424,16 @@
 		for (int i = 0; i < children.length; i++) {
 			String childName = children[i].getElementName();
 			
-			String childPrefix = null;
 			int childIndex = childName.indexOf('$');
-			if (childIndex > -1) {
-				childPrefix = childName.substring(0, childIndex);
-			} else {
-				childPrefix = childName.substring(0, childName.indexOf('.'));
-			}
-			
-			if(prefix.equals(childPrefix)) {
+			int childPrefixLength = childIndex < 0 ? childName.indexOf('.') : childIndex;
+			if (prefixLength == childPrefixLength && this.name.regionMatches(0, childName, 0, prefixLength)) {
 				IClassFile classFile = (IClassFile) children[i];
 				
 				// ensure this class file's buffer is open so that source ranges are computed
 				classFile.getBuffer();
 				
 				SourceRange range = mapper.getSourceRange(classFile.getType());
-				if (range == SourceMapper.fgUnknownRange) continue; 
+				if (range == SourceMapper.UNKNOWN_RANGE) continue; 
 				int newStart = range.offset;
 				int newEnd = newStart + range.length - 1;
 				if(newStart > start && newEnd < end
@@ -465,24 +554,15 @@
  * @see IClassFile
  */
 public ICompilationUnit getWorkingCopy(WorkingCopyOwner owner, IProgressMonitor monitor) throws JavaModelException {
-	// get the source if possible
-	char[] contents = null;
-	SourceMapper mapper = this.getSourceMapper();
-	if (mapper != null) {
-		contents = mapper.findSource(getType());
+	CompilationUnit workingCopy = new ClassFileWorkingCopy(this, owner == null ? DefaultWorkingCopyOwner.PRIMARY : owner);
+	JavaModelManager manager = JavaModelManager.getJavaModelManager();
+	JavaModelManager.PerWorkingCopyInfo perWorkingCopyInfo = 
+		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
 	}
-	if (contents == null) {
-		return null;
-	}
-
-	ClassFileWorkingCopy workingCopy = new ClassFileWorkingCopy();
-	IBuffer buffer = owner == null ? this.getBuffer() : owner.createBuffer(workingCopy);
-	workingCopy.buffer = buffer;
-	
-	// set the buffer source
-	if (buffer != null && buffer.getCharacters() == null){
-		buffer.setContents(contents);
-	}
+	BecomeWorkingCopyOperation op = new BecomeWorkingCopyOperation(workingCopy, null);
+	op.runOperation(monitor);
 	return workingCopy;
 }
 /**
@@ -498,6 +578,9 @@
 protected boolean hasBuffer() {
 	return true;
 }
+public int hashCode() {
+	return Util.combineHashCodes(this.name.hashCode(), this.parent.hashCode());
+}
 /**
  * @see IClassFile
  */
@@ -524,7 +607,8 @@
 	} catch (JavaModelException e) {
 		return e.getJavaModelStatus();
 	}
-	return JavaConventions.validateClassFileName(getElementName());
+	IJavaProject project = getJavaProject();
+	return JavaConventions.validateClassFileName(getElementName(), project.getOption(JavaCore.COMPILER_SOURCE, true), project.getOption(JavaCore.COMPILER_COMPLIANCE, true));
 }
 /**
  * Opens and returns buffer on the source code associated with this class file.
@@ -537,116 +621,42 @@
 protected IBuffer openBuffer(IProgressMonitor pm, Object info) throws JavaModelException {
 	SourceMapper mapper = getSourceMapper();
 	if (mapper != null) {
-		return mapSource(mapper);
-	} else if (!this.checkAutomaticSourceMapping) {
-		/*
-		 * We try to see if we can automatically attach a source
-		 * source files located inside the same folder than its .class file
-		 * See bug 36510.
-		 */
-		PackageFragmentRoot root = getPackageFragmentRoot();
-		if (root.isArchive()) {
-			// root is a jar file or a zip file
-			String elementName = getElementName();
-			String sourceFileWithoutExtension = elementName.substring(0, elementName.lastIndexOf('.'));
-			JarPackageFragmentRoot jarPackageFragmentRoot = (JarPackageFragmentRoot) root;
-			ZipFile jar = null;
-			try {
-				jar = jarPackageFragmentRoot.getJar();
-				String[] pkgName = ((PackageFragment) getParent()).names;
-				char[][] javaLikeExtensions = Util.getJavaLikeExtensions();
-				for (int i = 0, length = javaLikeExtensions.length; i < length; i++) {
-					StringBuffer entryName = new StringBuffer();
-					for (int j = 0, pkgNameLength = pkgName.length; j < pkgNameLength; j++) {
-						entryName.append(pkgName[j]);
-						entryName.append('/');
-					}
-					entryName.append(sourceFileWithoutExtension);
-					entryName.append(javaLikeExtensions[i]);
-					ZipEntry zipEntry = jar.getEntry(entryName.toString());
-					if (zipEntry != null) {
-						// found a source file
-						this.checkAutomaticSourceMapping = true;
-						root.attachSource(root.getPath(), null, null);
-						SourceMapper sourceMapper = getSourceMapper();
-						if (sourceMapper != null) {
-							return mapSource(sourceMapper);
-						}
-					}
-				}
-			} catch (CoreException e) {
-				if (e instanceof JavaModelException) throw (JavaModelException)e;
-				throw new JavaModelException(e);
-			} finally {
-				JavaModelManager.getJavaModelManager().closeZipFile(jar);
-			}
-		} else {
-			// Attempts to find the corresponding java file
-			String qualifiedName = getType().getFullyQualifiedName();
-			NameLookup lookup = ((JavaProject) getJavaProject()).newNameLookup(DefaultWorkingCopyOwner.PRIMARY);
-			ICompilationUnit cu = lookup.findCompilationUnit(qualifiedName);
-			if (cu != null) {
-				return cu.getBuffer();
-			} else	{
-				// root is a class folder
-				
-				IContainer pkgFolder = (IContainer) getParent().getResource();
-				IResource[] files = null;
-				try {
-					files = pkgFolder.members();
-				} catch (CoreException e) {
-					throw new JavaModelException(e);
-				}
-				IResource sourceFile = null;
-				String classFileName = getElementName();
-				String simpleName = classFileName.substring(0, classFileName.lastIndexOf('.'));
-				for (int i = 0, length = files.length; i < length; i++) {
-					IResource resource = files[i];
-					if (resource.getType() == IResource.FILE 
-							&& Util.equalsIgnoreJavaLikeExtension(resource.getName(), simpleName)) {
-						sourceFile = resource;
-						break;
-					}
-				}
-				if (sourceFile != null) {
-							
-					// found a source file
-					 // we don't need to check again. The source will be attached.
-					this.checkAutomaticSourceMapping = true;
-					root.attachSource(root.getPath(), null, null);
-					SourceMapper sourceMapper = getSourceMapper();
-					if (sourceMapper != null) {
-						return mapSource(sourceMapper);
-					}
-				}
-			}
-		}
+		return mapSource(mapper, info instanceof IBinaryType ? (IBinaryType) info : null);
 	}
 	return null;
 }
-private IBuffer mapSource(SourceMapper mapper) {
-	char[] contents = mapper.findSource(getType());
+private IBuffer mapSource(SourceMapper mapper, IBinaryType info) {
+	char[] contents = mapper.findSource(getType(), info);
 	if (contents != null) {
 		// create buffer
-		IBuffer buffer = getBufferManager().createBuffer(this);
+		IBuffer buffer = BufferManager.createBuffer(this);
 		if (buffer == null) return null;
 		BufferManager bufManager = getBufferManager();
 		bufManager.addBuffer(buffer);
-		
+
 		// set the buffer source
 		if (buffer.getCharacters() == null){
 			buffer.setContents(contents);
 		}
-		
+
 		// listen to buffer changes
-		buffer.addBufferChangedListener(this);	
-				
+		buffer.addBufferChangedListener(this);
+
 		// do the source mapping
-		mapper.mapSource(getType(), contents);
-		
+		mapper.mapSource(getType(), contents, info);
+
+		return buffer;
+	} else {
+		// create buffer
+		IBuffer buffer = BufferManager.createNullBuffer(this);
+		if (buffer == null) return null;
+		BufferManager bufManager = getBufferManager();
+		bufManager.addBuffer(buffer);
+
+		// listen to buffer changes
+		buffer.addBufferChangedListener(this);
 		return buffer;
 	}
-	return null;
 }
 /* package */ static String simpleName(char[] className) {
 	if (className == null)
@@ -745,20 +755,7 @@
 				requestor.acceptClass(packageName, className, completionName, modifiers, completionStart, completionEnd);
 			}
 			public void acceptError(IProblem error) {
-				if (true) return; // was disabled in 1.0
-
-				try {
-					IMarker marker = ResourcesPlugin.getWorkspace().getRoot().createMarker(IJavaModelMarker.TRANSIENT_PROBLEM);
-					marker.setAttribute(IJavaModelMarker.ID, error.getID());
-					marker.setAttribute(IMarker.CHAR_START, error.getSourceStart());
-					marker.setAttribute(IMarker.CHAR_END, error.getSourceEnd() + 1);
-					marker.setAttribute(IMarker.LINE_NUMBER, error.getSourceLineNumber());
-					marker.setAttribute(IMarker.MESSAGE, error.getMessage());
-					marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
-					requestor.acceptError(marker);
-				} catch(CoreException e){
-					// marker could not be created: ignore
-				}
+				// was disabled in 1.0
 			}
 			public void acceptField(char[] declaringTypePackageName, char[] declaringTypeName, char[] fieldName, char[] typePackageName, char[] typeName, char[] completionName, int modifiers, int completionStart, int completionEnd, int relevance) {
 				requestor.acceptField(declaringTypePackageName, declaringTypeName, fieldName, typePackageName, typeName, completionName, modifiers, completionStart, completionEnd);
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 65a2d89..0a9f255 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -13,7 +13,6 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 
-import org.eclipse.core.resources.IFile;
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.IClassFile;
 import org.eclipse.jdt.core.IField;
@@ -38,26 +37,13 @@
 	 * The children of the <code>BinaryType</code> corresponding to our
 	 * <code>ClassFile</code>. These are kept here because we don't have
 	 * access to the <code>BinaryType</code> info (<code>ClassFileReader</code>).
-	 * <p>
-	 * The children are lazily initialized, on the first call to
-	 * <code>getBinaryChildren()</code>, which in turn is called by
-	 * <code>BinaryType.getChildren()</code>. 
 	 */
 	protected JavaElement[] binaryChildren = null;
 	/*
 	 * The type parameters in this class file.
 	 */
 	protected ITypeParameter[] typeParameters;
-	/**
-	 * Back-pointer to the IClassFile to allow lazy initialization.
-	 */
-	protected ClassFile classFile = null;
-/**
- * Creates a new <code>ClassFileInfo</code> for <code>classFile</code>.
- */
-ClassFileInfo(ClassFile classFile) {
-	this.classFile = classFile;
-}
+	
 /**
  * Creates the handles and infos for the fields of the given binary type.
  * Adds new handles to the given vector.
@@ -87,10 +73,11 @@
 	// Can also return an entry for the enclosing type of an inner type.
 	IBinaryNestedType[] innerTypes = typeInfo.getMemberTypes();
 	if (innerTypes != null) {
+		IPackageFragment pkg = (IPackageFragment) type.getAncestor(IJavaElement.PACKAGE_FRAGMENT);
 		for (int i = 0, typeCount = innerTypes.length; i < typeCount; i++) {
 			IBinaryNestedType binaryType = innerTypes[i];
-			IClassFile parentClassFile= ((IPackageFragment)this.classFile.getParent()).getClassFile(new String(ClassFile.unqualifiedName(binaryType.getName())) + SUFFIX_STRING_class);
-			IType innerType = new BinaryType((JavaElement)parentClassFile, ClassFile.simpleName(binaryType.getName()));
+			IClassFile parentClassFile= pkg.getClassFile(new String(ClassFile.unqualifiedName(binaryType.getName())) + SUFFIX_STRING_class);
+			IType innerType = new BinaryType((JavaElement) parentClassFile, ClassFile.simpleName(binaryType.getName()));
 			childrenHandles.add(innerType);
 		}
 	}
@@ -177,16 +164,6 @@
 	}
 }
 /**
- * Returns the list of children (<code>BinaryMember</code>s) of the
- * <code>BinaryType</code> of our <code>ClassFile</code>.
- */
-IJavaElement[] getBinaryChildren(HashMap newElements) {
-	if (this.binaryChildren == null) {
-		readBinaryChildren(newElements, null/*type info not known here*/);
-	}
-	return this.binaryChildren;
-}
-/**
  * Returns true iff the <code>readBinaryChildren</code> has already
  * been called.
  */
@@ -198,21 +175,9 @@
  * <code>ClassFile</code> and adds them to the
  * <code>JavaModelManager</code>'s cache.
  */
-protected void readBinaryChildren(HashMap newElements, IBinaryType typeInfo) {
+protected void readBinaryChildren(ClassFile classFile, HashMap newElements, IBinaryType typeInfo) {
 	ArrayList childrenHandles = new ArrayList();
-	BinaryType type = null;
-	try {
-		type = (BinaryType) this.classFile.getType();
-		if (typeInfo == null) {
-			typeInfo = (IBinaryType) newElements.get(type);
-			if (typeInfo == null) {
-				// create a classfile reader 
-			    typeInfo = this.classFile.getBinaryTypeInfo((IFile)this.classFile.getResource());
-			}
-		}
-	} catch (JavaModelException npe) {
-		return;
-	}
+	BinaryType type = (BinaryType) classFile.getType();
 	ArrayList typeParameterHandles = new ArrayList();
 	if (typeInfo != null) { //may not be a valid class file
 		generateTypeParameterInfos(type, typeInfo.getGenericSignature(), newElements, typeParameterHandles);
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 fbbc2ba..e867eb4 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,653 +10,105 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
-import org.eclipse.core.resources.IMarker;
 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;
-import org.eclipse.jdt.core.IImportContainer;
-import org.eclipse.jdt.core.IImportDeclaration;
+import org.eclipse.jdt.core.IClassFile;
 import org.eclipse.jdt.core.IJavaElement;
-import org.eclipse.jdt.core.IJavaModel;
 import org.eclipse.jdt.core.IJavaModelStatusConstants;
-import org.eclipse.jdt.core.IJavaProject;
-import org.eclipse.jdt.core.IOpenable;
-import org.eclipse.jdt.core.IPackageDeclaration;
-import org.eclipse.jdt.core.IProblemRequestor;
-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;
+import org.eclipse.jdt.core.ToolFactory;
+import org.eclipse.jdt.core.WorkingCopyOwner;
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.core.util.ClassFileBytesDisassembler;
+import org.eclipse.jdt.core.util.IClassFileReader;
+import org.eclipse.jdt.internal.core.util.Disassembler;
+import org.eclipse.jdt.internal.core.util.Util;
 
 /**
  * A working copy on an <code>IClassFile</code>.
- * Only the <code>getBuffer()</code> and <code>getOriginalElement()</code> operations are valid.
- * All other operations return either <code>null</code> or throw a <code>JavaModelException</code>.
  */
-public class ClassFileWorkingCopy implements ICompilationUnit {
+public class ClassFileWorkingCopy extends CompilationUnit {
 	
-	public IBuffer buffer;
+	public IClassFile classFile;
 	
-	/*
-	 * @see ICompilationUnit#becomeWorkingCopy(IProblemRequestor, IProgressMonitor)
-	 */
-	public void becomeWorkingCopy(IProblemRequestor problemRequestor, IProgressMonitor monitor) throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-	
-	/*
-	 * @see ICompilationUnit#createImport(String, IJavaElement, IProgressMonitor)
-	 */
-	public IImportDeclaration createImport(
-		String name,
-		IJavaElement sibling,
-		IProgressMonitor monitor)
-		throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-
-	/*
-	 * @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(
-		String name,
-		IProgressMonitor monitor)
-		throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-
-	/*
-	 * @see ICompilationUnit#createType(String, IJavaElement, boolean, IProgressMonitor)
-	 */
-	public IType createType(
-		String contents,
-		IJavaElement sibling,
-		boolean force,
-		IProgressMonitor monitor)
-		throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-
-	/*
-	 * @see ICompilationUnit#discardWorkingCopy
-	 */
-	public void discardWorkingCopy() throws JavaModelException {
-		// not a real working copy: ignore
-	}
-	
-	/*
-	 * @see ICompilationUnit#getAllTypes()
-	 */
-	public IType[] getAllTypes() throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-
-	/*
-	 * @see ICompilationUnit#getElementAt(int)
-	 */
-	public IJavaElement getElementAt(int position) throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-
-	/*
-	 * @see ICompilationUnit#getImport(String)
-	 */
-	public IImportDeclaration getImport(String name) {
-		return null;
-	}
-
-	/*
-	 * @see ICompilationUnit#getImportContainer()
-	 */
-	public IImportContainer getImportContainer() {
-		return null;
-	}
-
-	/*
-	 * @see ICompilationUnit#getImports()
-	 */
-	public IImportDeclaration[] getImports() throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-
-	/*
-	 * @see IJavaElement#getOpenable()
-	 */
-	public IOpenable getOpenable() {
-		return null;
-	}
-
-	/*
-	 * @see ICompilationUnit#getOwner()
-	 */
-	public WorkingCopyOwner getOwner() {
-		return null;
-	}
-
-	/*
-	 * @see ICompilationUnit#getPackageDeclaration(String)
-	 */
-	public IPackageDeclaration getPackageDeclaration(String name) {
-		return null;
-	}
-
-	/*
-	 * @see ICompilationUnit#getPackageDeclarations()
-	 */
-	public IPackageDeclaration[] getPackageDeclarations()
-		throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-
-	/*
-	 * @see ICompilationUnit#getType(String)
-	 */
-	public IType getType(String name) {
-		return null;
-	}
-
-	/*
-	 * @see ICompilationUnit#getTypes()
-	 */
-	public IType[] getTypes() throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-
-	/*
-	 * @see IJavaElement#exists()
-	 */
-	public boolean exists() {
-		return false;
-	}
-/*
- * @see IWorkingCopy
- */
-public IJavaElement[] findElements(IJavaElement element) {
-	return null;
-}
-/*
- * @see IWorkingCopy
- */
-public IType findPrimaryType() {
-	return null;
+public ClassFileWorkingCopy(IClassFile classFile, WorkingCopyOwner owner) {
+	super((PackageFragment) classFile.getParent(), ((BinaryType) ((ClassFile) classFile).getType()).getSourceFileName(null/*no info available*/), owner);
+	this.classFile = classFile;
 }
 
-	/*
-	 * @see IJavaElement#getCorrespondingResource()
-	 */
-	public IResource getCorrespondingResource() throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
+public void commitWorkingCopy(boolean force, IProgressMonitor monitor) throws JavaModelException {
+	throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, this));
+}
 
-	/*
-	 * @see IJavaElement#getElementName()
-	 */
-	public String getElementName() {
-		return null;
-	}
+public IBuffer getBuffer() throws JavaModelException {
+	if (isWorkingCopy())
+		return super.getBuffer();
+	else
+		return this.classFile.getBuffer();
+}
 
-	/*
-	 * @see IJavaElement#getElementType()
-	 */
-	public int getElementType() {
-		return 0;
+public char[] getContents() {
+	try {
+		IBuffer buffer = getBuffer();
+		if (buffer == null) return CharOperation.NO_CHAR;
+		char[] characters = buffer.getCharacters();
+		if (characters == null) return CharOperation.NO_CHAR;
+		return characters;
+	} catch (JavaModelException e) {
+		return CharOperation.NO_CHAR;
 	}
+}
 
-	/*
-	 * @see IJavaElement#getHandleIdentifier()
-	 */
-	public String getHandleIdentifier() {
-		return null;
-	}
+public IPath getPath() {
+	return this.classFile.getPath();
+}
 
-	/*
-	 * @see IJavaElement#getJavaModel()
-	 */
-	public IJavaModel getJavaModel() {
-		return null;
-	}
+public IJavaElement getPrimaryElement(boolean checkOwner) {
+	if (checkOwner && isPrimary()) return this;
+	return new ClassFileWorkingCopy(this.classFile, DefaultWorkingCopyOwner.PRIMARY);
+}
 
-	/*
-	 * @see IJavaElement#getJavaProject()
-	 */
-	public IJavaProject getJavaProject() {
-		return null;
-	}
+public IResource getResource() {
+	return this.classFile.getResource();
+}
 
-	/*
-	 * @see IJavaElement#getParent()
-	 */
-	public IJavaElement getParent() {
-		return null;
-	}
+/**
+ * @see Openable#openBuffer(IProgressMonitor, Object)
+ */
+protected IBuffer openBuffer(IProgressMonitor pm, Object info) throws JavaModelException {
 
-	/*
-	 * @see IJavaElement
-	 */
-	public IPath getPath() {
-		return null;
-	}
-
-	/*
-	 * @see ICompilationUnit#getPrimary()
-	 */
-	public ICompilationUnit getPrimary() {
-		return this;
-	}
+	// create buffer
+	IBuffer buffer = this.owner.createBuffer(this);
+	if (buffer == null) return null;
 	
-	/*
-	 * @see ICompilationUnit#getPrimaryElement()
-	 */
-	public IJavaElement getPrimaryElement() {
-		return getPrimary();
+	// set the buffer source
+	if (buffer.getCharacters() == null) {
+		IBuffer classFileBuffer = this.classFile.getBuffer();
+		if (classFileBuffer != null) {
+			buffer.setContents(classFileBuffer.getCharacters());
+		} else {
+			// Disassemble
+			IClassFileReader reader = ToolFactory.createDefaultClassFileReader(this.classFile, IClassFileReader.ALL);
+			Disassembler disassembler = new Disassembler();
+			String contents = disassembler.disassemble(reader, Util.getLineSeparator("", getJavaProject()), ClassFileBytesDisassembler.WORKING_COPY); //$NON-NLS-1$
+			buffer.setContents(contents);
+		}
 	}
+
+	// add buffer to buffer cache
+	BufferManager bufManager = getBufferManager();
+	bufManager.addBuffer(buffer);
+			
+	// listen to buffer changes
+	buffer.addBufferChangedListener(this);
 	
-	/*
-	 * @see IJavaElement
-	 */
-	public IResource getResource() {
-		return null;
-	}
+	return buffer;
+}
 
-	/*
-	 * @see IJavaElement
-	 */
-	public ISchedulingRule getSchedulingRule() {
-		return null;
-	}
-	
-	/*
-	 * @see IJavaElement#getUnderlyingResource()
-	 */
-	public IResource getUnderlyingResource() throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-
-	/*
-	 * @see IJavaElement#isReadOnly()
-	 */
-	public boolean isReadOnly() {
-		return true;
-	}
-
-	/*
-	 * @see IJavaElement#isStructureKnown()
-	 */
-	public boolean isStructureKnown() {
-		return false;
-	}
-
-	/*
-	 * @see ISourceReference#getSource()
-	 */
-	public String getSource() throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-
-	/*
-	 * @see ISourceReference#getSourceRange()
-	 */
-	public ISourceRange getSourceRange() throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-
-	/*
-	 * @see IParent#getChildren()
-	 */
-	public IJavaElement[] getChildren() throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-
-	/*
-	 * @see IParent#hasChildren()
-	 */
-	public boolean hasChildren() throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-
-	/*
-	 * @see IOpenable#close()
-	 */
-	public void close() throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-
-	/*
-	 * @see IOpenable#getBuffer()
-	 */
-	public IBuffer getBuffer() {
-		return this.buffer;
-	}
-
-	/*
-	 * @see ICompilationUnit#hasResourceChanged()
-	 */
-	public boolean hasResourceChanged() {
-		return false;
-	}
-	
-	/*
-	 * @see IOpenable#hasUnsavedChanges()
-	 */
-	public boolean hasUnsavedChanges() {
-		return false;
-	}
-
-	/*
-	 * @see IOpenable#isConsistent()
-	 */
-	public boolean isConsistent() {
-		return false;
-	}
-
-	/*
-	 * @see IOpenable#isOpen()
-	 */
-	public boolean isOpen() {
-		return false;
-	}
-
-	/*
-	 * @see IOpenable#makeConsistent(IProgressMonitor)
-	 */
-	public void makeConsistent(IProgressMonitor progress)
-		throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-
-	/*
-	 * @see IOpenable#open(IProgressMonitor)
-	 */
-	public void open(IProgressMonitor progress) throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-
-	/*
-	 * @see IOpenable#save(IProgressMonitor, boolean)
-	 */
-	public void save(IProgressMonitor progress, boolean force)
-		throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-
-	/**
-	 * @see IWorkingCopy#commit(boolean, IProgressMonitor)
-	 * @deprecated
-	 */
-	public void commit(boolean force, IProgressMonitor monitor) throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-	
-	/*
-	 * @see IWorkingCopy#commitWorkingCopy(boolean, IProgressMonitor)
-	 */
-	public void commitWorkingCopy(boolean force, IProgressMonitor monitor)
-		throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-
-	/**
-	 * @see IWorkingCopy#destroy()
-	 * @deprecated
-	 */
-	public void destroy() {
-		// not a real working copy: ignore
-	}
-
-	/**
-	 * @see IWorkingCopy#findSharedWorkingCopy(IBufferFactory)
-	 * @deprecated
-	 */
-	public IJavaElement findSharedWorkingCopy(IBufferFactory bufferFactory) {
-		return null;
-	}
-	
-	/**
-	 * @see ICompilationUnit#findWorkingCopy(WorkingCopyOwner)
-	 */
-	public ICompilationUnit findWorkingCopy(WorkingCopyOwner owner) {
-		return null;
-	}
-
-	/**
-	 * @see IWorkingCopy#getOriginal(IJavaElement)
-	 * @deprecated
-	 */
-	public IJavaElement getOriginal(IJavaElement workingCopyElement) {
-		return null;
-	}
-
-	/**
-	 * @see IWorkingCopy#getOriginalElement()
-	 * @deprecated
-	 */
-	public IJavaElement getOriginalElement() {
-		return getPrimaryElement();
-	}
-
-	/**
-	 * @see IWorkingCopy#getSharedWorkingCopy(IProgressMonitor, IBufferFactory, IProblemRequestor)
-	 * @deprecated
-	 */
-	public IJavaElement getSharedWorkingCopy(
-		IProgressMonitor monitor,
-		IBufferFactory factory,
-		IProblemRequestor problemRequestor)
-		throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-
-	/**
-	 * @see IWorkingCopy#getWorkingCopy()
-	 * @deprecated
-	 */
-	public IJavaElement getWorkingCopy() throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-	
-	/**
-	 * @see ICompilationUnit#getWorkingCopy(IProgressMonitor)
-	 */
-	public ICompilationUnit getWorkingCopy(IProgressMonitor monitor) throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-
-	/**
-	 * @see IWorkingCopy#getWorkingCopy(IProgressMonitor, IBufferFactory, IProblemRequestor)
-	 * @deprecated
-	 */
-	public IJavaElement getWorkingCopy(IProgressMonitor monitor, IBufferFactory factory, IProblemRequestor problemRequestor) throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-
-	/* (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));
-	}
-
-	/**
-	 * @see IWorkingCopy#isBasedOn(IResource)
-	 * @deprecated
-	 */
-	public boolean isBasedOn(IResource resource) {
-		return false;
-	}
-
-	/*
-	 * @see IWorkingCopy#isWorkingCopy()
-	 */
-	public boolean isWorkingCopy() {
-		return true;
-	}
-
-	/**
-	 * @see org.eclipse.jdt.core.IWorkingCopy#reconcile()
-	 * @deprecated
-	 */
-	public IMarker[] reconcile() throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-
-	/**
-	 * @see ICompilationUnit#reconcile(int, boolean, WorkingCopyOwner, IProgressMonitor)
-	 * @since 3.0
-	 */
-	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 {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-
-	/**
-	 * @see org.eclipse.jdt.core.ISourceManipulation#copy(IJavaElement, IJavaElement, String, boolean, IProgressMonitor)
-	 */
-	public void copy(
-		IJavaElement container,
-		IJavaElement sibling,
-		String rename,
-		boolean replace,
-		IProgressMonitor monitor)
-		throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-
-	/**
-	 * @see org.eclipse.jdt.core.ISourceManipulation#delete(boolean, IProgressMonitor)
-	 */
-	public void delete(boolean force, IProgressMonitor monitor)
-		throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-
-	/**
-	 * @see org.eclipse.jdt.core.ISourceManipulation#move(IJavaElement, IJavaElement, String, boolean, IProgressMonitor)
-	 */
-	public void move(
-		IJavaElement container,
-		IJavaElement sibling,
-		String rename,
-		boolean replace,
-		IProgressMonitor monitor)
-		throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-
-	/**
-	 * @see org.eclipse.jdt.core.ISourceManipulation#rename(String, boolean, IProgressMonitor)
-	 */
-	public void rename(String name, boolean replace, IProgressMonitor monitor)
-		throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-
-	/**
-	 * @see org.eclipse.jdt.core.ICodeAssist#codeComplete(int, ICompletionRequestor)
-	 * @deprecated
-	 */
-	public void codeComplete(int offset, ICompletionRequestor requestor)
-		throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-
-	/**
-	 * @see org.eclipse.jdt.core.ICodeAssist#codeComplete(int, ICompletionRequestor, WorkingCopyOwner)
-	 * @deprecated
-	 */
-	public void codeComplete(int offset, ICompletionRequestor requestor, WorkingCopyOwner owner)
-		throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-
-	/**
-	 * @see org.eclipse.jdt.core.ICodeAssist#codeSelect(int, int)
-	 */
-	public IJavaElement[] codeSelect(int offset, int length)
-		throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-
-	/**
-	 * @see org.eclipse.jdt.core.ICodeAssist#codeSelect(int, int, WorkingCopyOwner)
-	 */
-	public IJavaElement[] codeSelect(int offset, int length, WorkingCopyOwner owner)
-		throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-
-	/**
-	 * @see org.eclipse.jdt.core.ICodeAssist#codeComplete(int, ICodeCompletionRequestor)
-	 * @deprecated
-	 */
-	public void codeComplete(int offset, org.eclipse.jdt.core.ICodeCompletionRequestor requestor)
-		throws JavaModelException {
-		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 {
-		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, org.eclipse.jdt.core.WorkingCopyOwner)
-	 */
-	public void codeComplete(int offset, CompletionRequestor requestor, WorkingCopyOwner wcowner) throws JavaModelException {
-		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
-	}
-
-	/**
-	 * @see org.eclipse.core.runtime.IAdaptable#getAdapter(Class)
-	 */
-	public Object getAdapter(Class adapter) {
-		return null;
-	}
-
-	/**
-	 * @see IJavaElement#getAncestor(int)
-	 */
-	public IJavaElement getAncestor(int ancestorType) {
-		return null;
-	}
+protected void toStringName(StringBuffer buffer) {
+	buffer.append(this.classFile.getElementName());
+}
 
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathAccessRule.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathAccessRule.java
index 9beb6d1..8dee3a6 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathAccessRule.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathAccessRule.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -27,13 +27,14 @@
 	}
 	
 	private static int toProblemId(int kind) {
-		switch (kind) {
+		boolean ignoreIfBetter = (kind & IAccessRule.IGNORE_IF_BETTER) != 0;
+		switch (kind & ~IAccessRule.IGNORE_IF_BETTER) {
 			case K_NON_ACCESSIBLE:
-				return IProblem.ForbiddenReference;
+				return ignoreIfBetter ? IProblem.ForbiddenReference | AccessRule.IgnoreIfBetter : IProblem.ForbiddenReference;
 			case K_DISCOURAGED:
-				return IProblem.DiscouragedReference;
+				return ignoreIfBetter ? IProblem.DiscouragedReference | AccessRule.IgnoreIfBetter : IProblem.DiscouragedReference;
 			default:
-				return -1;
+				return ignoreIfBetter ? AccessRule.IgnoreIfBetter : 0;
 		}
 	}
 
@@ -42,7 +43,7 @@
 	}
 
 	public int getKind() {
-		switch (this.problemId) {
+		switch (getProblemId()) {
 			case IProblem.ForbiddenReference:
 				return K_NON_ACCESSIBLE;
 			case IProblem.DiscouragedReference:
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathChange.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathChange.java
new file mode 100755
index 0000000..92f8f6e
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathChange.java
@@ -0,0 +1,501 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.IJavaElementDelta;
+import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.internal.compiler.util.ObjectVector;
+import org.eclipse.jdt.internal.core.JavaModelManager.PerProjectInfo;
+import org.eclipse.jdt.internal.core.search.indexing.IndexManager;
+import org.eclipse.jdt.internal.core.util.Util;
+
+public class ClasspathChange {
+	public static int NO_DELTA = 0x00;
+	public static int HAS_DELTA = 0x01;
+	public static int HAS_PROJECT_CHANGE = 0x10;
+	
+	JavaProject project;
+	IClasspathEntry[] oldRawClasspath;
+	IPath oldOutputLocation;
+	IClasspathEntry[] oldResolvedClasspath;
+	
+	public ClasspathChange(JavaProject project, IClasspathEntry[] oldRawClasspath, IPath oldOutputLocation, IClasspathEntry[] oldResolvedClasspath) {
+		this.project = project;
+		this.oldRawClasspath = oldRawClasspath;
+		this.oldOutputLocation = oldOutputLocation;
+		this.oldResolvedClasspath = oldResolvedClasspath;
+	}
+	
+	private void addClasspathDeltas(JavaElementDelta delta, IPackageFragmentRoot[] roots, int flag) {
+		for (int i = 0; i < roots.length; i++) {
+			IPackageFragmentRoot root = roots[i];
+			delta.changed(root, flag);
+			if ((flag & IJavaElementDelta.F_REMOVED_FROM_CLASSPATH) != 0 
+					|| (flag & IJavaElementDelta.F_SOURCEATTACHED) != 0
+					|| (flag & IJavaElementDelta.F_SOURCEDETACHED) != 0){
+				try {
+					root.close();
+				} catch (JavaModelException e) {
+					// ignore
+				}
+			}
+		}
+	}
+
+	/*
+	 * Returns the index of the item in the list if the given list contains the specified entry. If the list does
+	 * not contain the entry, -1 is returned.
+	 */
+	private int classpathContains(IClasspathEntry[] list, 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()
+				&& other.getEntryKind() == entry.getEntryKind()
+				&& other.isExported() == entry.isExported()
+				&& other.getPath().equals(entry.getPath())) {
+					// check custom outputs
+					IPath entryOutput = entry.getOutputLocation();
+					IPath otherOutput = other.getOutputLocation();
+					if (entryOutput == null) {
+						if (otherOutput != null)
+							continue;
+					} else {
+						if (!entryOutput.equals(otherOutput))
+							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 == null || otherExcludes.length != excludeLength)
+							continue;
+						for (int j = 0; j < excludeLength; j++) {
+							// compare toStrings instead of IPaths 
+							// since IPath.equals is specified to ignore trailing separators
+							if (!exclusionPatterns[j].toString().equals(otherExcludes[j].toString()))
+								continue nextEntry;
+						}
+					}
+					return i;
+			}
+		}
+		return -1;
+	}
+
+	/*
+	 * Recursively adds all subfolders of <code>folder</code> to the given collection.
+	 */
+	private void collectAllSubfolders(IFolder folder, ArrayList collection) throws JavaModelException {
+		try {
+			IResource[] members= folder.members();
+			for (int i = 0, max = members.length; i < max; i++) {
+				IResource r= members[i];
+				if (r.getType() == IResource.FOLDER) {
+					collection.add(r);
+					collectAllSubfolders((IFolder)r, collection);
+				}
+			}	
+		} catch (CoreException e) {
+			throw new JavaModelException(e);
+		}
+	}
+
+	/*
+	 * Returns a collection of package fragments that have been added/removed
+	 * as the result of changing the output location to/from the given
+	 * location. The collection is empty if no package fragments are
+	 * affected.
+	 */
+	private ArrayList determineAffectedPackageFragments(IPath location) throws JavaModelException {
+		ArrayList fragments = new ArrayList();
+	
+		// see if this will cause any package fragments to be affected
+		IWorkspace workspace = ResourcesPlugin.getWorkspace();
+		IResource resource = null;
+		if (location != null) {
+			resource = workspace.getRoot().findMember(location);
+		}
+		if (resource != null && resource.getType() == IResource.FOLDER) {
+			IFolder folder = (IFolder) resource;
+			// only changes if it actually existed
+			IClasspathEntry[] classpath = this.project.getExpandedClasspath();
+			for (int i = 0; i < classpath.length; i++) {
+				IClasspathEntry entry = classpath[i];
+				IPath path = classpath[i].getPath();
+				if (entry.getEntryKind() != IClasspathEntry.CPE_PROJECT && path.isPrefixOf(location) && !path.equals(location)) {
+					IPackageFragmentRoot[] roots = this.project.computePackageFragmentRoots(classpath[i]);
+					PackageFragmentRoot root = (PackageFragmentRoot) roots[0];
+					// now the output location becomes a package fragment - along with any subfolders
+					ArrayList folders = new ArrayList();
+					folders.add(folder);
+					collectAllSubfolders(folder, folders);
+					Iterator elements = folders.iterator();
+					int segments = path.segmentCount();
+					while (elements.hasNext()) {
+						IFolder f = (IFolder) elements.next();
+						IPath relativePath = f.getFullPath().removeFirstSegments(segments);
+						String[] pkgName = relativePath.segments();
+						IPackageFragment pkg = root.getPackageFragment(pkgName);
+						if (!Util.isExcluded(pkg))
+							fragments.add(pkg);
+					}
+				}
+			}
+		}
+		return fragments;
+	}
+	
+	public boolean equals(Object obj) {
+		if (!(obj instanceof ClasspathChange))
+			return false;
+		return this.project.equals(((ClasspathChange) obj).project);
+	}
+
+	/*
+	 * Generates a classpath change delta for this classpath change.
+	 * Returns whether a delta was generated, and whether project reference have changed.
+	 */
+	public int generateDelta(JavaElementDelta delta) {
+		JavaModelManager manager = JavaModelManager.getJavaModelManager();
+		DeltaProcessingState state = manager.deltaState;
+		if (state.findJavaProject(this.project.getElementName()) == null)
+			// project doesn't exist yet (we're in an IWorkspaceRunnable)
+			// no need to create a delta here and no need to index (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=133334)
+			// the delta processor will create an ADDED project delta, and index the project
+			return NO_DELTA;
+
+		DeltaProcessor deltaProcessor = state.getDeltaProcessor();
+		IClasspathEntry[] newResolvedClasspath = null;
+		IPath newOutputLocation = null;
+		int result = NO_DELTA;
+		try {
+			PerProjectInfo perProjectInfo = this.project.getPerProjectInfo();
+			
+			// get new info
+			this.project.resolveClasspath(perProjectInfo);
+			IClasspathEntry[] newRawClasspath;
+			
+			// use synchronized block to ensure consistency
+			synchronized (perProjectInfo) {
+				newRawClasspath = perProjectInfo.rawClasspath;
+				newResolvedClasspath = perProjectInfo.resolvedClasspath;
+				newOutputLocation = perProjectInfo.outputLocation;				
+			}
+			
+			// check if raw classpath has changed
+			if (this.oldRawClasspath != null && !JavaProject.areClasspathsEqual(this.oldRawClasspath, newRawClasspath, this.oldOutputLocation, newOutputLocation)) {
+				delta.changed(this.project, IJavaElementDelta.F_CLASSPATH_CHANGED);
+				result |= HAS_DELTA;
+			}
+					
+			// if no changes to resolved classpath, nothing more to do
+			if (this.oldResolvedClasspath != null && JavaProject.areClasspathsEqual(this.oldResolvedClasspath, newResolvedClasspath, this.oldOutputLocation, newOutputLocation))
+				return NO_DELTA;
+			
+			// close cached info
+			this.project.close();
+		} catch (JavaModelException e) {	
+			if (DeltaProcessor.VERBOSE) {
+				e.printStackTrace();
+			}
+			// project no longer exist
+			return NO_DELTA;
+		}
+		
+		if (this.oldResolvedClasspath == null)
+			return NO_DELTA;
+		
+		Map removedRoots = null;
+		IPackageFragmentRoot[] roots = null;
+		Map allOldRoots ;
+		if ((allOldRoots = deltaProcessor.oldRoots) != null) {
+	 		roots = (IPackageFragmentRoot[]) allOldRoots.get(this.project);
+		}
+		if (roots != null) {
+			removedRoots = new HashMap();
+			for (int i = 0; i < roots.length; i++) {
+				IPackageFragmentRoot root = roots[i];
+				removedRoots.put(root.getPath(), root);
+			}
+		}
+
+		int newLength = newResolvedClasspath.length;
+		int oldLength = this.oldResolvedClasspath.length;		
+		for (int i = 0; i < oldLength; i++) {
+			int index = classpathContains(newResolvedClasspath, this.oldResolvedClasspath[i]);
+			if (index == -1) {
+				// remote project changes
+				if (this.oldResolvedClasspath[i].getEntryKind() == IClasspathEntry.CPE_PROJECT) {
+					result |= HAS_PROJECT_CHANGE;
+					continue; 
+				}
+
+				IPackageFragmentRoot[] pkgFragmentRoots = null;
+				if (removedRoots != null) {
+					IPackageFragmentRoot oldRoot = (IPackageFragmentRoot)  removedRoots.get(this.oldResolvedClasspath[i].getPath());
+					if (oldRoot != null) { // use old root if any (could be none if entry wasn't bound)
+						pkgFragmentRoots = new IPackageFragmentRoot[] { oldRoot };
+					}
+				}
+				if (pkgFragmentRoots == null) {
+					try {
+						ObjectVector accumulatedRoots = new ObjectVector();
+						HashSet rootIDs = new HashSet(5);
+						rootIDs.add(this.project.rootID());
+						this.project.computePackageFragmentRoots(
+							this.oldResolvedClasspath[i], 
+							accumulatedRoots, 
+							rootIDs,
+							null, // inside original project
+							false, // don't check existency
+							false, // don't retrieve exported roots
+							null); /*no reverse map*/
+						pkgFragmentRoots = new IPackageFragmentRoot[accumulatedRoots.size()];
+						accumulatedRoots.copyInto(pkgFragmentRoots);
+					} catch (JavaModelException e) {
+						pkgFragmentRoots =  new IPackageFragmentRoot[] {};
+					}
+				}
+				addClasspathDeltas(delta, pkgFragmentRoots, IJavaElementDelta.F_REMOVED_FROM_CLASSPATH);
+				result |= HAS_DELTA;
+			} else {
+				// remote project changes
+				if (this.oldResolvedClasspath[i].getEntryKind() == IClasspathEntry.CPE_PROJECT) {
+					result |= HAS_PROJECT_CHANGE;
+					continue; 
+				}				
+				if (index != i) { //reordering of the classpath
+					addClasspathDeltas(delta, this.project.computePackageFragmentRoots(this.oldResolvedClasspath[i]),	IJavaElementDelta.F_REORDER);
+					result |= HAS_DELTA;
+				}
+				
+				// check source attachment
+				IPath newSourcePath = newResolvedClasspath[index].getSourceAttachmentPath();
+				int sourceAttachmentFlags = getSourceAttachmentDeltaFlag(this.oldResolvedClasspath[i].getSourceAttachmentPath(), newSourcePath);
+				IPath oldRootPath = this.oldResolvedClasspath[i].getSourceAttachmentRootPath();
+				IPath newRootPath = newResolvedClasspath[index].getSourceAttachmentRootPath();
+				int sourceAttachmentRootFlags = getSourceAttachmentDeltaFlag(oldRootPath, newRootPath);
+				int flags = sourceAttachmentFlags | sourceAttachmentRootFlags;
+				if (flags != 0) {
+					addClasspathDeltas(delta, this.project.computePackageFragmentRoots(this.oldResolvedClasspath[i]), flags);
+					result |= HAS_DELTA;
+				} else {
+					if (oldRootPath == null && newRootPath == null) {
+						// if source path is specified and no root path, it needs to be recomputed dynamically
+						// force detach source on jar package fragment roots (source will be lazily computed when needed)
+						IPackageFragmentRoot[] computedRoots = this.project.computePackageFragmentRoots(this.oldResolvedClasspath[i]);
+						for (int j = 0; j < computedRoots.length; j++) {
+							IPackageFragmentRoot root = computedRoots[j];
+							// force detach source on jar package fragment roots (source will be lazily computed when needed)
+							try {
+								root.close();
+							} catch (JavaModelException e) {
+								// ignore
+							}
+						}
+					}
+				}
+			}
+		}
+
+		for (int i = 0; i < newLength; i++) {
+			int index = classpathContains(this.oldResolvedClasspath, newResolvedClasspath[i]);
+			if (index == -1) {
+				// remote project changes
+				if (newResolvedClasspath[i].getEntryKind() == IClasspathEntry.CPE_PROJECT) {
+					result |= HAS_PROJECT_CHANGE;
+					continue; 
+				}
+				addClasspathDeltas(delta, this.project.computePackageFragmentRoots(newResolvedClasspath[i]), IJavaElementDelta.F_ADDED_TO_CLASSPATH);
+				result |= HAS_DELTA;
+			} // classpath reordering has already been generated in previous loop
+		}
+
+		// see if a change in output location will cause any package fragments to be added/removed
+		if ((newOutputLocation == null && this.oldOutputLocation != null) 
+				|| (newOutputLocation != null && !newOutputLocation.equals(this.oldOutputLocation))) {
+			try {
+				ArrayList added= determineAffectedPackageFragments(this.oldOutputLocation);
+				Iterator iter = added.iterator();
+				while (iter.hasNext()){
+					IPackageFragment frag= (IPackageFragment)iter.next();
+					((IPackageFragmentRoot)frag.getParent()).close();
+					delta.added(frag);
+					result |= HAS_DELTA;
+				}
+			
+				// see if this will cause any package fragments to be removed
+				ArrayList removed= determineAffectedPackageFragments(newOutputLocation);
+				iter = removed.iterator();
+				while (iter.hasNext()) {
+					IPackageFragment frag= (IPackageFragment)iter.next();
+					((IPackageFragmentRoot)frag.getParent()).close(); 
+					delta.removed(frag);
+					result |= HAS_DELTA;
+				}
+			} catch (JavaModelException e) {
+				if (DeltaProcessor.VERBOSE)
+					e.printStackTrace();
+			}
+		}
+
+		return result;
+	}
+	
+	/*
+	 * Returns the source attachment flag for the delta between the 2 give source paths.
+	 * Returns either F_SOURCEATTACHED, F_SOURCEDETACHED, F_SOURCEATTACHED | F_SOURCEDETACHED
+	 * or 0 if there is no difference.
+	 */
+	private int getSourceAttachmentDeltaFlag(IPath oldPath, IPath newPath) {
+		if (oldPath == null) {
+			if (newPath != null) {
+				return IJavaElementDelta.F_SOURCEATTACHED;
+			} else {
+				return 0;
+			}
+		} else if (newPath == null) {
+			return IJavaElementDelta.F_SOURCEDETACHED;
+		} else if (!oldPath.equals(newPath)) {
+			return IJavaElementDelta.F_SOURCEATTACHED | IJavaElementDelta.F_SOURCEDETACHED;
+		} else {
+			return 0;
+		}
+	}
+	
+	public int hashCode() {
+		return this.project.hashCode();
+	}
+
+	/*
+	 * Request the indexing of entries that have been added, and remove the index for removed entries.
+	 */
+	public void requestIndexing() {
+		IClasspathEntry[] newResolvedClasspath = null;
+		try {
+			newResolvedClasspath = this.project.getResolvedClasspath();
+		} catch (JavaModelException e) {	
+			// project doesn't exist
+			return;
+		}
+		
+		JavaModelManager manager = JavaModelManager.getJavaModelManager();
+		IndexManager indexManager = manager.indexManager;
+		if (indexManager == null)
+			return;
+		DeltaProcessingState state = manager.deltaState;
+
+		int newLength = newResolvedClasspath.length;
+		int oldLength = this.oldResolvedClasspath.length;		
+		for (int i = 0; i < oldLength; i++) {
+			int index = classpathContains(newResolvedClasspath, this.oldResolvedClasspath[i]);
+			if (index == -1) {
+				// remote projects are not indexed in this project
+				if (this.oldResolvedClasspath[i].getEntryKind() == IClasspathEntry.CPE_PROJECT){
+					continue; 
+				}
+
+				// Remove the .java files from the index for a source folder
+				// For a lib folder or a .jar file, remove the corresponding index if not shared.
+				IClasspathEntry oldEntry = this.oldResolvedClasspath[i];
+				final IPath path = oldEntry.getPath();
+				int changeKind = this.oldResolvedClasspath[i].getEntryKind();
+				switch (changeKind) {
+					case IClasspathEntry.CPE_SOURCE:
+						char[][] inclusionPatterns = ((ClasspathEntry)oldEntry).fullInclusionPatternChars();
+						char[][] exclusionPatterns = ((ClasspathEntry)oldEntry).fullExclusionPatternChars();
+						indexManager.removeSourceFolderFromIndex(this.project, path, inclusionPatterns, exclusionPatterns);
+						break;
+					case IClasspathEntry.CPE_LIBRARY:
+						if (state.otherRoots.get(path) == null) { // if root was not shared
+							indexManager.discardJobs(path.toString());
+							indexManager.removeIndex(path);
+							// TODO (kent) we could just remove the in-memory index and have the indexing check for timestamps
+						}
+						break;
+				}
+			}
+		}
+
+		for (int i = 0; i < newLength; i++) {
+			int index = classpathContains(this.oldResolvedClasspath, newResolvedClasspath[i]);
+			if (index == -1) {
+				// remote projects are not indexed in this project
+				if (newResolvedClasspath[i].getEntryKind() == IClasspathEntry.CPE_PROJECT){
+					continue; 
+				}
+				
+				// Request indexing
+				int entryKind = newResolvedClasspath[i].getEntryKind();
+				switch (entryKind) {
+					case IClasspathEntry.CPE_LIBRARY:
+						boolean pathHasChanged = true;
+						IPath newPath = newResolvedClasspath[i].getPath();
+						for (int j = 0; j < oldLength; j++) {
+							IClasspathEntry oldEntry = this.oldResolvedClasspath[j];
+							if (oldEntry.getPath().equals(newPath)) {
+								pathHasChanged = false;
+								break;
+							}
+						}
+						if (pathHasChanged) {
+							indexManager.indexLibrary(newPath, this.project.getProject());
+						}
+						break;
+					case IClasspathEntry.CPE_SOURCE:
+						IClasspathEntry entry = newResolvedClasspath[i];
+						IPath path = entry.getPath();
+						char[][] inclusionPatterns = ((ClasspathEntry)entry).fullInclusionPatternChars();
+						char[][] exclusionPatterns = ((ClasspathEntry)entry).fullExclusionPatternChars();
+						indexManager.indexSourceFolder(this.project, path, inclusionPatterns, exclusionPatterns);
+						break;
+				}
+			}
+		}
+	}
+	
+	public String toString() {
+		return "ClasspathChange: " + this.project.getElementName(); //$NON-NLS-1$
+	}
+}
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 66183fc..4278ac2 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,7 +10,11 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
+import java.io.ByteArrayOutputStream;
 import java.io.File;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
@@ -19,8 +23,10 @@
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.resources.IWorkspaceRoot;
 import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.AssertionFailedException;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Path;
 import org.eclipse.jdt.core.IAccessRule;
 import org.eclipse.jdt.core.IClasspathAttribute;
@@ -39,9 +45,12 @@
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.core.util.Messages;
 import org.eclipse.jdt.internal.core.util.Util;
+import org.w3c.dom.DOMException;
 import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
+import org.w3c.dom.Text;
 
 /**
  * @see IClasspathEntry
@@ -69,9 +78,10 @@
 	public static final String TAG_ACCESSIBLE = "accessible"; //$NON-NLS-1$
 	public static final String TAG_NON_ACCESSIBLE = "nonaccessible"; //$NON-NLS-1$
 	public static final String TAG_DISCOURAGED = "discouraged"; //$NON-NLS-1$
-	
+	public static final String TAG_IGNORE_IF_BETTER = "ignoreifbetter"; //$NON-NLS-1$
+
 	/**
-	 * Describes the kind of classpath entry - one of 
+	 * Describes the kind of classpath entry - one of
 	 * CPE_PROJECT, CPE_LIBRARY, CPE_SOURCE, CPE_VARIABLE or CPE_CONTAINER
 	 */
 	public int entryKind;
@@ -85,15 +95,15 @@
 
 	/**
 	 * The meaning of the path of a classpath entry depends on its entry kind:<ul>
-	 *	<li>Source code in the current project (<code>CPE_SOURCE</code>) -  
+	 *	<li>Source code in the current project (<code>CPE_SOURCE</code>) -
 	 *      The path associated with this entry is the absolute path to the root folder. </li>
 	 *	<li>A binary library in the current project (<code>CPE_LIBRARY</code>) - the path
-	 *		associated with this entry is the absolute path to the JAR (or root folder), and 
-	 *		in case it refers to an external JAR, then there is no associated resource in 
+	 *		associated with this entry is the absolute path to the JAR (or root folder), and
+	 *		in case it refers to an external JAR, then there is no associated resource in
 	 *		the workbench.
 	 *	<li>A required project (<code>CPE_PROJECT</code>) - the path of the entry denotes the
 	 *		path to the corresponding project resource.</li>
-	 *  <li>A variable entry (<code>CPE_VARIABLE</code>) - the first segment of the path 
+	 *  <li>A variable entry (<code>CPE_VARIABLE</code>) - the first segment of the path
 	 *      is the name of a classpath variable. If this classpath variable
 	 *		is bound to the path <it>P</it>, the path of the corresponding classpath entry
 	 *		is computed by appending to <it>P</it> the segments of the returned
@@ -113,32 +123,38 @@
 	private IPath[] exclusionPatterns;
 	private char[][] fullExclusionPatternChars;
 	private final static char[][] UNINIT_PATTERNS = new char[][] { "Non-initialized yet".toCharArray() }; //$NON-NLS-1$
-	
+
 	private boolean combineAccessRules;
-	
+
 	private String rootID;
 	private AccessRuleSet accessRuleSet;
-	
+
+
+	static class UnknownXmlElements {
+		String[] attributes;
+		ArrayList children;
+	}
+
 	/*
 	 * Default inclusion pattern set
 	 */
 	public final static IPath[] INCLUDE_ALL = {};
-				
+
 	/*
 	 * Default exclusion pattern set
 	 */
 	public final static IPath[] EXCLUDE_NONE = {};
-	
+
 	/*
 	 * Default extra attributes
 	 */
 	public final static IClasspathAttribute[] NO_EXTRA_ATTRIBUTES = {};
-	
+
 	/*
 	 * Default access rules
 	 */
 	public final static IAccessRule[] NO_ACCESS_RULES = {};
-				
+
 	/**
 	 * Describes the path to the source archive associated with this
 	 * classpath entry, or <code>null</code> if this classpath entry has no
@@ -147,7 +163,7 @@
 	 * Only library and variable classpath entries may have source attachments.
 	 * For library classpath entries, the result path (if present) locates a source
 	 * archive. For variable classpath entries, the result path (if present) has
-	 * an analogous form and meaning as the variable path, namely the first segment 
+	 * an analogous form and meaning as the variable path, namely the first segment
 	 * is the name of a classpath variable.
 	 */
 	public IPath sourceAttachmentPath;
@@ -156,7 +172,7 @@
 	 * Describes the path within the source archive where package fragments
 	 * are located. An empty path indicates that packages are located at
 	 * the root of the source archive. Returns a non-<code>null</code> value
-	 * if and only if <code>getSourceAttachmentPath</code> returns 
+	 * if and only if <code>getSourceAttachmentPath</code> returns
 	 * a non-<code>null</code> value.
 	 */
 	public IPath sourceAttachmentRootPath;
@@ -165,7 +181,7 @@
 	 * Specific output location (for this source entry)
 	 */
 	public IPath specificOutputLocation;
-	
+
 	/**
 	 * A constant indicating an output location.
 	 */
@@ -175,7 +191,7 @@
 	 * The export flag
 	 */
 	public boolean isExported;
-	
+
 	/*
 	 * The extra attributes
 	 */
@@ -203,17 +219,20 @@
 		this.path = path;
 		this.inclusionPatterns = inclusionPatterns;
 		this.exclusionPatterns = exclusionPatterns;
-		
-		AccessRuleSet ruleSet = createAccessRuleSet(accessRules);
-		if (ruleSet != null) {
-			// compute message template
-			ruleSet.messageTemplate = getMessageTemplate();
+
+		int length;
+		if (accessRules != null && (length = accessRules.length) > 0) {
+			AccessRule[] rules = new AccessRule[length];
+			System.arraycopy(accessRules, 0, rules, 0, length);
+			this.accessRuleSet = new AccessRuleSet(rules, getMessageTemplates());
 		}
-		this.accessRuleSet = ruleSet;
-		
+//		else { -- implicit!
+//			this.accessRuleSet = null;
+//		}
+
 		this.combineAccessRules = combineAccessRules;
 		this.extraAttributes = extraAttributes;
-		
+
 	    if (inclusionPatterns != INCLUDE_ALL && inclusionPatterns.length > 0) {
 			this.fullInclusionPatternChars = UNINIT_PATTERNS;
 	    }
@@ -225,19 +244,11 @@
 		this.specificOutputLocation = specificOutputLocation;
 		this.isExported = isExported;
 	}
-	
-	private static AccessRuleSet createAccessRuleSet(IAccessRule[] accessRules) {
-		int length = accessRules == null ? 0 : accessRules.length;
-		if (length == 0) return null;
-		AccessRule[] rules = new AccessRule[length];
-		System.arraycopy(accessRules, 0, rules, 0, length);
-		return new AccessRuleSet(rules);
-	}
-	
+
 	public boolean combineAccessRules() {
 		return this.combineAccessRules;
 	}
-	
+
 	/**
 	 * Used to perform export/restriction propagation across referring projects/containers
 	 */
@@ -246,18 +257,18 @@
 		if (referringEntry.isExported() || referringEntry.getAccessRuleSet() != null ) {
 			boolean combine = this.entryKind == CPE_SOURCE || referringEntry.combineAccessRules();
 			return new ClasspathEntry(
-								getContentKind(), 
-								getEntryKind(), 
+								getContentKind(),
+								getEntryKind(),
 								getPath(),
-								this.inclusionPatterns, 
-								this.exclusionPatterns, 
-								getSourceAttachmentPath(), 
-								getSourceAttachmentRootPath(), 
-								getOutputLocation(), 
+								this.inclusionPatterns,
+								this.exclusionPatterns,
+								getSourceAttachmentPath(),
+								getSourceAttachmentRootPath(),
+								getOutputLocation(),
 								referringEntry.isExported() || this.isExported, // duplicate container entry for tagging it as exported
 								combine(referringEntry.getAccessRules(), getAccessRules(), combine),
 								this.combineAccessRules,
-								this.extraAttributes); 
+								this.extraAttributes);
 		}
 		// no need to clone
 		return this;
@@ -266,7 +277,7 @@
 	private IAccessRule[] combine(IAccessRule[] referringRules, IAccessRule[] rules, boolean combine) {
 		if (!combine) return rules;
 		if (rules == null || rules.length == 0) return referringRules;
-		
+
 		// concat access rules
 		int referringRulesLength = referringRules.length;
 		int accessRulesLength = rules.length;
@@ -274,14 +285,11 @@
 		IAccessRule[] result = new IAccessRule[rulesLength];
 		System.arraycopy(referringRules, 0, result, 0, referringRulesLength);
 		System.arraycopy(rules, 0, result, referringRulesLength, accessRulesLength);
-		
+
 		return result;
 	}
 
-	static IClasspathAttribute[] decodeExtraAttributes(Element element) {
-		Node extra = element.getElementsByTagName(TAG_ATTRIBUTES).item(0);
-		if (extra == null) return NO_EXTRA_ATTRIBUTES;
-		NodeList attributes = element.getElementsByTagName(TAG_ATTRIBUTE);
+	static IClasspathAttribute[] decodeExtraAttributes(NodeList attributes) {
 		if (attributes == null) return NO_EXTRA_ATTRIBUTES;
 		int length = attributes.getLength();
 		if (length == 0) return NO_EXTRA_ATTRIBUTES;
@@ -302,56 +310,110 @@
 			System.arraycopy(result, 0, result = new IClasspathAttribute[index], 0, index);
 		return result;
 	}
-	
-	static IAccessRule[] decodeAccessRules(Element element) {
-		Node accessRules = element.getElementsByTagName(TAG_ACCESS_RULES).item(0);
-		if (accessRules == null || accessRules.getNodeType() != Node.ELEMENT_NODE) return null;
-		NodeList list = ((Element) accessRules).getElementsByTagName(TAG_ACCESS_RULE);
+
+	static IAccessRule[] decodeAccessRules(NodeList list) {
+		if (list == null) return null;
 		int length = list.getLength();
 		if (length == 0) return null;
 		IAccessRule[] result = new IAccessRule[length];
 		int index = 0;
 		for (int i = 0; i < length; i++) {
 			Node accessRule = list.item(i);
-			if (accessRule == null || accessRule.getNodeType() != Node.ELEMENT_NODE) return null;
-			Element elementAccessRule = (Element) accessRule;
-			String pattern = elementAccessRule.getAttribute(TAG_PATTERN);
-			if (pattern == null) continue;
-			String tagKind =  elementAccessRule.getAttribute(TAG_KIND);
-			int kind;
-			if (TAG_ACCESSIBLE.equals(tagKind))
-				kind = IAccessRule.K_ACCESSIBLE;
-			else if (TAG_NON_ACCESSIBLE.equals(tagKind))
-				kind = IAccessRule.K_NON_ACCESSIBLE;
-			else if (TAG_DISCOURAGED.equals(tagKind))
-				kind = IAccessRule.K_DISCOURAGED;
-			else
-				continue;
-			result[index++] = new ClasspathAccessRule(new Path(pattern), kind);
+			if (accessRule.getNodeType() == Node.ELEMENT_NODE) {
+				Element elementAccessRule = (Element) accessRule;
+				String pattern = elementAccessRule.getAttribute(TAG_PATTERN);
+				if (pattern == null) continue;
+				String tagKind =  elementAccessRule.getAttribute(TAG_KIND);
+				int kind;
+				if (TAG_ACCESSIBLE.equals(tagKind))
+					kind = IAccessRule.K_ACCESSIBLE;
+				else if (TAG_NON_ACCESSIBLE.equals(tagKind))
+					kind = IAccessRule.K_NON_ACCESSIBLE;
+				else if (TAG_DISCOURAGED.equals(tagKind))
+					kind = IAccessRule.K_DISCOURAGED;
+				else
+					continue;
+				boolean ignoreIfBetter = "true".equals(elementAccessRule.getAttribute(TAG_IGNORE_IF_BETTER)); //$NON-NLS-1$
+				result[index++] = new ClasspathAccessRule(new Path(pattern), ignoreIfBetter ? kind | IAccessRule.IGNORE_IF_BETTER : kind);
+			}
 		}
 		if (index != length)
 			System.arraycopy(result, 0, result = new IAccessRule[index], 0, index);
 		return result;
 	}
-	
+
 	/**
 	 * Decode some element tag containing a sequence of patterns into IPath[]
 	 */
-	private static IPath[] decodePatterns(Element element, String tag) {
-		String sequence = element.getAttribute(tag);
-		if (!sequence.equals("")) { //$NON-NLS-1$ 
+	private static IPath[] decodePatterns(NamedNodeMap nodeMap, String tag) {
+		String sequence = removeAttribute(tag, nodeMap);
+		if (!sequence.equals("")) { //$NON-NLS-1$
 			char[][] patterns = CharOperation.splitOn('|', sequence.toCharArray());
 			int patternCount;
-			if ((patternCount  = patterns.length) > 0) {
+			if ((patternCount = patterns.length) > 0) {
 				IPath[] paths = new IPath[patternCount];
-				for (int j = 0; j < patterns.length; j++){
-					paths[j] = new Path(new String(patterns[j]));
+				int index = 0;
+				for (int j = 0; j < patternCount; j++) {
+					char[] pattern = patterns[j];
+					if (pattern.length == 0) continue; // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=105581
+					paths[index++] = new Path(new String(pattern));
 				}
+				if (index < patternCount)
+					System.arraycopy(paths, 0, paths = new IPath[index], 0, index);
 				return paths;
 			}
 		}
 		return null;
 	}
+
+	private static void decodeUnknownNode(Node node, StringBuffer buffer, IJavaProject project) {
+		ByteArrayOutputStream s = new ByteArrayOutputStream();
+		OutputStreamWriter writer;
+		try {
+			writer = new OutputStreamWriter(s, "UTF8"); //$NON-NLS-1$
+			XMLWriter xmlWriter = new XMLWriter(writer, project, false/*don't print XML version*/);
+			decodeUnknownNode(node, xmlWriter, true/*insert new line*/);
+			xmlWriter.flush();
+			xmlWriter.close();
+			buffer.append(s.toString("UTF8")); //$NON-NLS-1$
+		} catch (UnsupportedEncodingException e) {
+			// ignore (UTF8 is always supported)
+		}
+	}
+
+	private static void decodeUnknownNode(Node node, XMLWriter xmlWriter, boolean insertNewLine) {
+		switch (node.getNodeType()) {
+		case Node.ELEMENT_NODE:
+			NamedNodeMap attributes;
+			HashMap parameters = null;
+			if ((attributes = node.getAttributes()) != null) {
+				int length = attributes.getLength();
+				if (length > 0) {
+					parameters = new HashMap();
+					for (int i = 0; i < length; i++) {
+						Node attribute = attributes.item(i);
+						parameters.put(attribute.getNodeName(), attribute.getNodeValue());
+					}
+				}
+			}
+			NodeList children = node.getChildNodes();
+			int childrenLength = children.getLength();
+			String nodeName = node.getNodeName();
+			xmlWriter.printTag(nodeName, parameters, false/*don't insert tab*/, false/*don't insert new line*/, childrenLength == 0/*close tag if no children*/);
+			if (childrenLength > 0) {
+				for (int i = 0; i < childrenLength; i++) {
+					decodeUnknownNode(children.item(i), xmlWriter, false/*don't insert new line*/);
+				}
+				xmlWriter.endTag(nodeName, false/*don't insert tab*/, insertNewLine);
+			}
+			break;
+		case Node.TEXT_NODE:
+			String data = ((Text) node).getData();
+			xmlWriter.printString(data, false/*don't insert tab*/, false/*don't insert new line*/);
+			break;
+		}
+	}
+
 	/*
 	 * Returns a char based representation of the exclusions patterns full path.
 	 */
@@ -362,13 +424,13 @@
 			this.fullExclusionPatternChars = new char[length][];
 			IPath prefixPath = this.path.removeTrailingSeparator();
 			for (int i = 0; i < length; i++) {
-				this.fullExclusionPatternChars[i] = 
+				this.fullExclusionPatternChars[i] =
 					prefixPath.append(this.exclusionPatterns[i]).toString().toCharArray();
 			}
 		}
 		return this.fullExclusionPatternChars;
 	}
-	
+
 	/*
 	 * Returns a char based representation of the exclusions patterns full path.
 	 */
@@ -379,7 +441,7 @@
 			this.fullInclusionPatternChars = new char[length][];
 			IPath prefixPath = this.path.removeTrailingSeparator();
 			for (int i = 0; i < length; i++) {
-				this.fullInclusionPatternChars[i] = 
+				this.fullInclusionPatternChars[i] =
 					prefixPath.append(this.inclusionPatterns[i]).toString().toCharArray();
 			}
 		}
@@ -389,11 +451,11 @@
 	/**
 	 * Returns the XML encoding of the class path.
 	 */
-	public void elementEncode(XMLWriter writer, IPath projectPath, boolean indent, boolean newLine) {
+	public void elementEncode(XMLWriter writer, IPath projectPath, boolean indent, boolean newLine, Map unknownElements) {
 		HashMap parameters = new HashMap();
-		
+
 		parameters.put(TAG_KIND, ClasspathEntry.kindToString(this.entryKind));
-		
+
 		IPath xmlPath = this.path;
 		if (this.entryKind != IClasspathEntry.CPE_VARIABLE && this.entryKind != IClasspathEntry.CPE_CONTAINER) {
 			// translate to project relative from absolute (unless a device path)
@@ -409,10 +471,10 @@
 			}
 		}
 		parameters.put(TAG_PATH, String.valueOf(xmlPath));
-		
+
 		if (this.sourceAttachmentPath != null) {
 			xmlPath = this.sourceAttachmentPath;
-			// translate to project relative from absolute 
+			// translate to project relative from absolute
 			if (this.entryKind != IClasspathEntry.CPE_VARIABLE && projectPath != null && projectPath.isPrefixOf(xmlPath)) {
 				if (xmlPath.segment(0).equals(projectPath.segment(0))) {
 					xmlPath = xmlPath.removeFirstSegments(1);
@@ -431,8 +493,18 @@
 		encodePatterns(this.exclusionPatterns, TAG_EXCLUDING, parameters);
 		if (this.entryKind == CPE_PROJECT && !this.combineAccessRules)
 			parameters.put(TAG_COMBINE_ACCESS_RULES, "false"); //$NON-NLS-1$
-		
-		
+
+
+		// unknown attributes
+		UnknownXmlElements unknownXmlElements = unknownElements == null ? null : (UnknownXmlElements) unknownElements.get(this.path);
+		String[] unknownAttributes;
+		if (unknownXmlElements != null && (unknownAttributes = unknownXmlElements.attributes) != null)
+			for (int i = 0, length = unknownAttributes.length; i < length; i+=2) {
+				String tagName = unknownAttributes[i];
+				String tagValue = unknownAttributes[i+1];
+				parameters.put(tagName, tagValue);
+			}
+
 		if (this.specificOutputLocation != null) {
 			IPath outputLocation = this.specificOutputLocation.removeFirstSegments(1);
 			outputLocation = outputLocation.makeRelative();
@@ -441,18 +513,28 @@
 
 		boolean hasExtraAttributes = this.extraAttributes.length != 0;
 		boolean hasRestrictions = getAccessRuleSet() != null; // access rule set is null if no access rules
-		writer.printTag(TAG_CLASSPATHENTRY, parameters, indent, newLine, !hasExtraAttributes && !hasRestrictions /*close tag if no extra attributes and no restriction*/);
-		
+		ArrayList unknownChildren = unknownXmlElements != null ? unknownXmlElements.children : null;
+		boolean hasUnknownChildren = unknownChildren != null;
+		writer.printTag(
+			TAG_CLASSPATHENTRY,
+			parameters,
+			indent,
+			newLine,
+			!hasExtraAttributes && !hasRestrictions && !hasUnknownChildren/*close tag if no extra attributes, no restriction and no unknown children*/);
+
 		if (hasExtraAttributes)
 			encodeExtraAttributes(writer, indent, newLine);
-	
+
 		if (hasRestrictions)
 			encodeAccessRules(writer, indent, newLine);
 
-		if (hasExtraAttributes || hasRestrictions)
-			writer.endTag(TAG_CLASSPATHENTRY, indent);
+		if (hasUnknownChildren)
+			encodeUnknownChildren(writer, indent, newLine, unknownChildren);
+
+		if (hasExtraAttributes || hasRestrictions || hasUnknownChildren)
+			writer.endTag(TAG_CLASSPATHENTRY, indent, true/*insert new line*/);
 	}
-	
+
 	void encodeExtraAttributes(XMLWriter writer, boolean indent, boolean newLine) {
 		writer.startTag(TAG_ATTRIBUTES, indent);
 		for (int i = 0; i < this.extraAttributes.length; i++) {
@@ -462,9 +544,9 @@
 			parameters.put(TAG_ATTRIBUTE_VALUE, attribute.getValue());
 			writer.printTag(TAG_ATTRIBUTE, parameters, indent, newLine, true);
 		}
-		writer.endTag(TAG_ATTRIBUTES, indent);
+		writer.endTag(TAG_ATTRIBUTES, indent, true/*insert new line*/);
 	}
-	
+
 	void encodeAccessRules(XMLWriter writer, boolean indent, boolean newLine) {
 
 		writer.startTag(TAG_ACCESS_RULES, indent);
@@ -472,15 +554,15 @@
 		for (int i = 0, length = rules.length; i < length; i++) {
 			encodeAccessRule(rules[i], writer, indent, newLine);
 		}
-		writer.endTag(TAG_ACCESS_RULES, indent);
+		writer.endTag(TAG_ACCESS_RULES, indent, true/*insert new line*/);
 	}
-	
+
 	private void encodeAccessRule(AccessRule accessRule, XMLWriter writer, boolean indent, boolean newLine) {
 
 		HashMap parameters = new HashMap();
 		parameters.put(TAG_PATTERN, new String(accessRule.pattern));
-		
-		switch (accessRule.problemId) {
+
+		switch (accessRule.getProblemId()) {
 			case IProblem.ForbiddenReference:
 				parameters.put(TAG_KIND, TAG_NON_ACCESSIBLE);
 				break;
@@ -491,76 +573,126 @@
 				parameters.put(TAG_KIND, TAG_ACCESSIBLE);
 				break;
 		}
-		
+		if (accessRule.ignoreIfBetter())
+			parameters.put(TAG_IGNORE_IF_BETTER, "true"); //$NON-NLS-1$
+
 		writer.printTag(TAG_ACCESS_RULE, parameters, indent, newLine, true);
 
 	}
-	
-	public static IClasspathEntry elementDecode(Element element, IJavaProject project) {
-	
+
+	private void encodeUnknownChildren(XMLWriter writer, boolean indent, boolean newLine, ArrayList unknownChildren) {
+		for (int i = 0, length = unknownChildren.size(); i < length; i++) {
+			String child = (String) unknownChildren.get(i);
+			writer.printString(child, indent, false/*don't insert new line*/);
+		}
+	}
+
+	public static IClasspathEntry elementDecode(Element element, IJavaProject project, Map unknownElements) {
+
 		IPath projectPath = project.getProject().getFullPath();
-		String kindAttr = element.getAttribute(TAG_KIND);
-		String pathAttr = element.getAttribute(TAG_PATH);
+		NamedNodeMap attributes = element.getAttributes();
+		NodeList children = element.getChildNodes();
+		boolean[] foundChildren = new boolean[children.getLength()];
+		String kindAttr = removeAttribute(TAG_KIND, attributes);
+		String pathAttr = removeAttribute(TAG_PATH, attributes);
 
 		// ensure path is absolute
-		IPath path = new Path(pathAttr); 		
+		IPath path = new Path(pathAttr);
 		int kind = kindFromString(kindAttr);
 		if (kind != IClasspathEntry.CPE_VARIABLE && kind != IClasspathEntry.CPE_CONTAINER && !path.isAbsolute()) {
 			path = projectPath.append(path);
 		}
 		// source attachment info (optional)
-		IPath sourceAttachmentPath = 
-			element.hasAttribute(TAG_SOURCEPATH)	
-			? new Path(element.getAttribute(TAG_SOURCEPATH))
+		IPath sourceAttachmentPath =
+			element.hasAttribute(TAG_SOURCEPATH)
+			? new Path(removeAttribute(TAG_SOURCEPATH, attributes))
 			: null;
 		if (kind != IClasspathEntry.CPE_VARIABLE && sourceAttachmentPath != null && !sourceAttachmentPath.isAbsolute()) {
 			sourceAttachmentPath = projectPath.append(sourceAttachmentPath);
 		}
-		IPath sourceAttachmentRootPath = 
+		IPath sourceAttachmentRootPath =
 			element.hasAttribute(TAG_ROOTPATH)
-			? new Path(element.getAttribute(TAG_ROOTPATH))
+			? new Path(removeAttribute(TAG_ROOTPATH, attributes))
 			: null;
-		
+
 		// exported flag (optional)
-		boolean isExported = element.getAttribute(TAG_EXPORTED).equals("true"); //$NON-NLS-1$
+		boolean isExported = removeAttribute(TAG_EXPORTED, attributes).equals("true"); //$NON-NLS-1$
 
 		// inclusion patterns (optional)
-		IPath[] inclusionPatterns = decodePatterns(element, TAG_INCLUDING);
+		IPath[] inclusionPatterns = decodePatterns(attributes, TAG_INCLUDING);
 		if (inclusionPatterns == null) inclusionPatterns = INCLUDE_ALL;
-		
+
 		// exclusion patterns (optional)
-		IPath[] exclusionPatterns = decodePatterns(element, TAG_EXCLUDING);
+		IPath[] exclusionPatterns = decodePatterns(attributes, TAG_EXCLUDING);
 		if (exclusionPatterns == null) exclusionPatterns = EXCLUDE_NONE;
-		
+
 		// access rules (optional)
-		IAccessRule[] accessRules = decodeAccessRules(element);
-		
+		NodeList attributeList = getChildAttributes(TAG_ACCESS_RULES, children, foundChildren);
+		IAccessRule[] accessRules = decodeAccessRules(attributeList);
+
 		// backward compatibility
 		if (accessRules == null) {
 			accessRules = getAccessRules(inclusionPatterns, exclusionPatterns);
 		}
 
 		// combine access rules (optional)
-		boolean combineAccessRestrictions = !element.getAttribute(TAG_COMBINE_ACCESS_RULES).equals("false"); //$NON-NLS-1$
-		
+		boolean combineAccessRestrictions = !removeAttribute(TAG_COMBINE_ACCESS_RULES, attributes).equals("false"); //$NON-NLS-1$
+
 		// extra attributes (optional)
-		IClasspathAttribute[] extraAttributes = decodeExtraAttributes(element);
-		
+		attributeList = getChildAttributes(TAG_ATTRIBUTES, children, foundChildren);
+		IClasspathAttribute[] extraAttributes = decodeExtraAttributes(attributeList);
+
 		// custom output location
-		IPath outputLocation = element.hasAttribute(TAG_OUTPUT) ? projectPath.append(element.getAttribute(TAG_OUTPUT)) : null;
-		
+		IPath outputLocation = element.hasAttribute(TAG_OUTPUT) ? projectPath.append(removeAttribute(TAG_OUTPUT, attributes)) : null;
+
+		String[] unknownAttributes = null;
+		ArrayList unknownChildren = null;
+
+		if (unknownElements != null) {
+			// unknown attributes
+			int unknownAttributeLength = attributes.getLength();
+			if (unknownAttributeLength != 0) {
+				unknownAttributes = new String[unknownAttributeLength*2];
+				for (int i = 0; i < unknownAttributeLength; i++) {
+					Node attribute = attributes.item(i);
+					unknownAttributes[i*2] = attribute.getNodeName();
+					unknownAttributes[i*2 + 1] = attribute.getNodeValue();
+				}
+			}
+
+			// unknown children
+			for (int i = 0, length = foundChildren.length; i < length; i++) {
+				if (!foundChildren[i]) {
+					Node node = children.item(i);
+					if (node.getNodeType() != Node.ELEMENT_NODE) continue;
+					if (unknownChildren == null)
+						unknownChildren = new ArrayList();
+					StringBuffer buffer = new StringBuffer();
+					decodeUnknownNode(node, buffer, project);
+					unknownChildren.add(buffer.toString());
+				}
+			}
+		}
+
 		// recreate the CP entry
 		IClasspathEntry entry = null;
 		switch (kind) {
 
 			case IClasspathEntry.CPE_PROJECT :
-				entry = JavaCore.newProjectEntry(
-												path, 
-												accessRules,
-												combineAccessRestrictions,
-												extraAttributes,
-												isExported);
-				break;				
+				entry = new ClasspathEntry(
+				IPackageFragmentRoot.K_SOURCE,
+				IClasspathEntry.CPE_PROJECT,
+				path,
+				ClasspathEntry.INCLUDE_ALL, // inclusion patterns
+				ClasspathEntry.EXCLUDE_NONE, // exclusion patterns
+				null, // source attachment
+				null, // source attachment root
+				null, // specific output folder
+				isExported,
+				accessRules,
+				combineAccessRestrictions,
+				extraAttributes);
+				break;
 			case IClasspathEntry.CPE_LIBRARY :
 				entry = JavaCore.newLibraryEntry(
 												path,
@@ -574,19 +706,19 @@
 				// 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, inclusionPatterns, exclusionPatterns, outputLocation, extraAttributes);
-				} else { 
+					entry = JavaCore.newSourceEntry(path, inclusionPatterns, exclusionPatterns, outputLocation, extraAttributes);
+				} else {
 					if (path.segmentCount() == 1) {
 						// another project
 						entry = JavaCore.newProjectEntry(
-												path, 
+												path,
 												accessRules,
 												combineAccessRestrictions,
 												extraAttributes,
 												isExported);
 					} else {
 						// an invalid source folder
-						return JavaCore.newSourceEntry(path, inclusionPatterns, exclusionPatterns, outputLocation, extraAttributes);
+						entry = JavaCore.newSourceEntry(path, inclusionPatterns, exclusionPatterns, outputLocation, extraAttributes);
 					}
 				}
 				break;
@@ -594,7 +726,7 @@
 				entry = JavaCore.newVariableEntry(
 						path,
 						sourceAttachmentPath,
-						sourceAttachmentRootPath, 
+						sourceAttachmentRootPath,
 						accessRules,
 						extraAttributes,
 						isExported);
@@ -608,12 +740,12 @@
 				break;
 			case ClasspathEntry.K_OUTPUT :
 				if (!path.isAbsolute()) return null;
-				return new ClasspathEntry(
+				entry = new ClasspathEntry(
 						ClasspathEntry.K_OUTPUT,
 						IClasspathEntry.CPE_LIBRARY,
 						path,
-						INCLUDE_ALL, 
-						EXCLUDE_NONE, 
+						INCLUDE_ALL,
+						EXCLUDE_NONE,
 						null, // source attachment
 						null, // source attachment root
 						null, // custom output location
@@ -621,12 +753,50 @@
 						null, // no access rules
 						false, // no accessible files to combine
 						NO_EXTRA_ATTRIBUTES);
+				break;
 			default :
-				throw new Assert.AssertionFailedException(Messages.bind(Messages.classpath_unknownKind, kindAttr)); 
+				throw new AssertionFailedException(Messages.bind(Messages.classpath_unknownKind, kindAttr));
 		}
+
+		if (unknownAttributes != null || unknownChildren != null) {
+			UnknownXmlElements unknownXmlElements = new UnknownXmlElements();
+			unknownXmlElements.attributes = unknownAttributes;
+			unknownXmlElements.children = unknownChildren;
+			unknownElements.put(path, unknownXmlElements);
+		}
+
 		return entry;
 	}
 
+	public static NodeList getChildAttributes(String childName, NodeList children, boolean[] foundChildren) {
+		for (int i = 0, length = foundChildren.length; i < length; i++) {
+			Node node = children.item(i);
+			if (childName.equals(node.getNodeName())) {
+				foundChildren[i] = true;
+				return node.getChildNodes();
+			}
+		}
+		return null;
+	}
+
+
+	private static String removeAttribute(String nodeName, NamedNodeMap nodeMap) {
+		Node node = removeNode(nodeName, nodeMap);
+		if (node == null)
+			return ""; // //$NON-NLS-1$
+		return node.getNodeValue();
+	}
+
+	private static Node removeNode(String nodeName, NamedNodeMap nodeMap) {
+		try {
+			return nodeMap.removeNamedItem(nodeName);
+		} catch (DOMException e) {
+			if (e.code != DOMException.NOT_FOUND_ERR)
+				throw e;
+			return null;
+		}
+	}
+
 	/**
 	 * Encode some patterns into XML parameter tag
 	 */
@@ -713,7 +883,7 @@
 		if (firstAttributes != secondAttributes){
 		    if (firstAttributes == null) return false;
 			int length = firstAttributes.length;
-			if (secondAttributes == null || secondAttributes.length != length) 
+			if (secondAttributes == null || secondAttributes.length != length)
 				return false;
 			for (int i = 0; i < length; i++) {
 				if (!firstAttributes[i].equals(secondAttributes[i]))
@@ -722,15 +892,15 @@
 		}
 		return true;
 	}
-	
+
 	private static boolean equalPatterns(IPath[] firstPatterns, IPath[] secondPatterns) {
 		if (firstPatterns != secondPatterns){
 		    if (firstPatterns == null) return false;
 			int length = firstPatterns.length;
-			if (secondPatterns == null || secondPatterns.length != length) 
+			if (secondPatterns == null || secondPatterns.length != length)
 				return false;
 			for (int i = 0; i < length; i++) {
-				// compare toStrings instead of IPaths 
+				// compare toStrings instead of IPaths
 				// since IPath.equals is specified to ignore trailing separators
 				if (!firstPatterns[i].toString().equals(secondPatterns[i].toString()))
 					return false;
@@ -738,7 +908,7 @@
 		}
 		return true;
 	}
-	
+
 	/**
 	 * @see IClasspathEntry#getAccessRules()
 	 */
@@ -751,7 +921,7 @@
 		System.arraycopy(rules, 0, result, 0, length);
 		return result;
 	}
-	
+
 	public AccessRuleSet getAccessRuleSet() {
 		return this.accessRuleSet;
 	}
@@ -776,16 +946,27 @@
 	public IPath[] getExclusionPatterns() {
 		return this.exclusionPatterns;
 	}
-	
+
 	public IClasspathAttribute[] getExtraAttributes() {
 		return this.extraAttributes;
 	}
-	
-	private String getMessageTemplate() {
+
+	private String[] getMessageTemplates() {
+		JavaModelManager manager = JavaModelManager.getJavaModelManager();
+		String [] result = new String[AccessRuleSet.MESSAGE_TEMPLATES_LENGTH];
 		if (this.entryKind == CPE_PROJECT || this.entryKind == CPE_SOURCE) { // can be remote source entry when reconciling
-			return Messages.bind(
+			result[0] = manager.intern(Messages.bind(
 				org.eclipse.jdt.internal.core.util.Messages.restrictedAccess_project,
-				new String[] {"{0}", getPath().segment(0)});  //$NON-NLS-1$
+				new String[] {"{0}", getPath().segment(0)}));  //$NON-NLS-1$
+			result[1] = manager.intern(Messages.bind(
+					org.eclipse.jdt.internal.core.util.Messages.restrictedAccess_constructor_project,
+					new String[] {"{0}", getPath().segment(0)}));  //$NON-NLS-1$
+			result[2] = manager.intern(Messages.bind(
+					org.eclipse.jdt.internal.core.util.Messages.restrictedAccess_method_project,
+					new String[] {"{0}", "{1}", getPath().segment(0)}));  //$NON-NLS-1$ //$NON-NLS-2$
+			result[3] = manager.intern(Messages.bind(
+					org.eclipse.jdt.internal.core.util.Messages.restrictedAccess_field_project,
+					new String[] {"{0}", "{1}", getPath().segment(0)}));  //$NON-NLS-1$ //$NON-NLS-2$
 		} else {
 			IPath libPath = getPath();
 			Object target = JavaModel.getTarget(ResourcesPlugin.getWorkspace().getRoot(), libPath, false);
@@ -794,10 +975,20 @@
 				pathString = libPath.toOSString();
 			else
 				pathString = libPath.makeRelative().toString();
-			return Messages.bind(
+			result[0] = manager.intern(Messages.bind(
 				org.eclipse.jdt.internal.core.util.Messages.restrictedAccess_library,
-				new String[] {"{0}", pathString}); //$NON-NLS-1$ 
+				new String[] {"{0}", pathString})); //$NON-NLS-1$
+			result[1] = manager.intern(Messages.bind(
+					org.eclipse.jdt.internal.core.util.Messages.restrictedAccess_constructor_library,
+					new String[] {"{0}", pathString})); //$NON-NLS-1$
+			result[2] = manager.intern(Messages.bind(
+					org.eclipse.jdt.internal.core.util.Messages.restrictedAccess_method_library,
+					new String[] {"{0}", "{1}", pathString})); //$NON-NLS-1$ //$NON-NLS-2$
+			result[3] = manager.intern(Messages.bind(
+					org.eclipse.jdt.internal.core.util.Messages.restrictedAccess_field_library,
+					new String[] {"{0}", "{1}", pathString})); //$NON-NLS-1$ //$NON-NLS-2$
 		}
+		return result;
 	}
 
 	/**
@@ -820,7 +1011,7 @@
 	public IPath getPath() {
 		return this.path;
 	}
-	
+
 	/**
 	 * @see IClasspathEntry
 	 */
@@ -849,6 +1040,15 @@
 		return this.isExported;
 	}
 
+	public boolean isOptional() {
+		for (int i = 0, length = this.extraAttributes.length; i < length; i++) {
+			IClasspathAttribute attribute = this.extraAttributes[i];
+			if (IClasspathAttribute.OPTIONAL.equals(attribute.getName()) && "true".equals(attribute.getValue())) //$NON-NLS-1$
+				return true;
+		}
+		return false;
+	}
+
 	/**
 	 * Returns the kind of a <code>PackageFragmentRoot</code> from its <code>String</code> form.
 	 */
@@ -892,6 +1092,9 @@
 		}
 	}
 
+	/*
+	 * Backward compatibility: only accessible and non-accessible files are suported.
+	 */
 	public static IAccessRule[] getAccessRules(IPath[] accessibleFiles, IPath[] nonAccessibleFiles) {
 		int accessibleFilesLength = accessibleFiles == null ? 0 : accessibleFiles.length;
 		int nonAccessibleFilesLength = nonAccessibleFiles == null ? 0 : nonAccessibleFiles.length;
@@ -906,13 +1109,13 @@
 		}
 		return accessRules;
 	}
-	
+
 	/**
 	 * Returns a printable representation of this classpath entry.
 	 */
 	public String toString() {
 		StringBuffer buffer = new StringBuffer();
-		buffer.append(getPath().toString());
+		buffer.append(String.valueOf(getPath()));
 		buffer.append('[');
 		switch (getEntryKind()) {
 			case IClasspathEntry.CPE_LIBRARY :
@@ -1007,7 +1210,7 @@
 		}
 		return buffer.toString();
 	}
-	
+
 	/**
 	 * Answers an ID which is used to distinguish entries during package
 	 * fragment root computations
@@ -1038,16 +1241,16 @@
 		}
 		return this.rootID;
 	}
-	
+
 	/**
 	 * @see IClasspathEntry
 	 * @deprecated
 	 */
 	public IClasspathEntry getResolvedEntry() {
-	
+
 		return JavaCore.getResolvedClasspathEntry(this);
 	}
-	
+
 	/**
 	 * Validate a given classpath and output location for a project, using the following rules:
 	 * <ul>
@@ -1056,15 +1259,15 @@
 	 *   <li> Specific output locations (specified on source entries) can be null, if not they must be located inside the project,
 	 *   <li> A project entry cannot refer to itself directly (that is, a project cannot prerequisite itself).
      *   <li> Classpath entries or output locations cannot coincidate or be nested in each other, except for the following scenarii listed below:
-	 *      <ul><li> A source folder can coincidate with its own output location, in which case this output can then contain library archives. 
-	 *                     However, a specific output location cannot coincidate with any library or a distinct source folder than the one referring to it. </li> 
+	 *      <ul><li> A source folder can coincidate with its own output location, in which case this output can then contain library archives.
+	 *                     However, a specific output location cannot coincidate with any library or a distinct source folder than the one referring to it. </li>
 	 *              <li> A source/library folder can be nested in any source folder as long as the nested folder is excluded from the enclosing one. </li>
 	 * 			<li> An output location can be nested in a source folder, if the source folder coincidates with the project itself, or if the output
 	 * 					location is excluded from the source folder. </li>
 	 *      </ul>
 	 * </ul>
-	 * 
-	 *  Note that the classpath entries are not validated automatically. Only bound variables or containers are considered 
+	 *
+	 *  Note that the classpath entries are not validated automatically. Only bound variables or containers are considered
 	 *  in the checking process (this allows to perform a consistency check on a classpath which has references to
 	 *  yet non existing projects, folders, ...).
 	 *  <p>
@@ -1075,15 +1278,15 @@
 	 * @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 
+	 *		the given classpath and output location are compatible, otherwise a status
 	 *		object indicating what is wrong with the classpath or output location
 	 */
 	public static IJavaModelStatus validateClasspath(IJavaProject javaProject, IClasspathEntry[] rawClasspath, IPath projectOutputLocation) {
-	
+
 		IProject project = javaProject.getProject();
 		IPath projectPath= project.getFullPath();
 		String projectName = javaProject.getElementName();
-	
+
 		/* validate output location */
 		if (projectOutputLocation == null) {
 			return new JavaModelStatus(IJavaModelStatusConstants.NULL_PATH);
@@ -1095,39 +1298,39 @@
 		} else {
 			return new JavaModelStatus(IJavaModelStatusConstants.RELATIVE_PATH, projectOutputLocation);
 		}
-	
+
 		boolean hasSource = false;
 		boolean hasLibFolder = false;
-	
+
 
 		// tolerate null path, it will be reset to default
-		if (rawClasspath == null) 
+		if (rawClasspath == null)
 			return JavaModelStatus.VERIFIED_OK;
-		
+
 		// retrieve resolved classpath
-		IClasspathEntry[] classpath; 
+		IClasspathEntry[] classpath;
 		try {
-			classpath = ((JavaProject)javaProject).getResolvedClasspath(rawClasspath, null /*output*/, true/*ignore pb*/, false/*no marker*/, null /*no reverse map*/);
+			classpath = ((JavaProject)javaProject).resolveClasspath(rawClasspath);
 		} catch(JavaModelException e){
 			return e.getJavaModelStatus();
 		}
-		int length = classpath.length; 
+		int length = classpath.length;
 
 		int outputCount = 1;
 		IPath[] outputLocations	= new IPath[length+1];
 		boolean[] allowNestingInOutputLocations = new boolean[length+1];
 		outputLocations[0] = projectOutputLocation;
-		
+
 		// retrieve and check output locations
 		IPath potentialNestedOutput = null; // for error reporting purpose
 		int sourceEntryCount = 0;
 		boolean disableExclusionPatterns = JavaCore.DISABLED.equals(javaProject.getOption(JavaCore.CORE_ENABLE_CLASSPATH_EXCLUSION_PATTERNS, true));
 		boolean disableCustomOutputLocations = JavaCore.DISABLED.equals(javaProject.getOption(JavaCore.CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS, true));
-		
+
 		for (int i = 0 ; i < length; i++) {
 			IClasspathEntry resolvedEntry = classpath[i];
 			if (disableExclusionPatterns &&
-			        ((resolvedEntry.getInclusionPatterns() != null && resolvedEntry.getInclusionPatterns().length > 0) 
+			        ((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());
 			}
@@ -1135,7 +1338,7 @@
 				case IClasspathEntry.CPE_SOURCE :
 					sourceEntryCount++;
 
-					IPath customOutput; 
+					IPath customOutput;
 					if ((customOutput = resolvedEntry.getOutputLocation()) != null) {
 
 						if (disableCustomOutputLocations) {
@@ -1149,7 +1352,7 @@
 						} else {
 							return new JavaModelStatus(IJavaModelStatusConstants.RELATIVE_PATH, customOutput);
 						}
-						
+
 						// ensure custom output doesn't conflict with other outputs
 						// check exact match
 						if (Util.indexOfMatchingPath(customOutput, outputLocations, outputCount) != -1) {
@@ -1171,15 +1374,15 @@
 					// output before complaining
 					if (potentialNestedOutput == null) potentialNestedOutput = customOutput;
 				} else {
-					return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_cannotNestOutputInOutput, new String[] {customOutput.makeRelative().toString(), outputLocations[index].makeRelative().toString()})); 
+					return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_cannotNestOutputInOutput, new String[] {customOutput.makeRelative().toString(), outputLocations[index].makeRelative().toString()}));
 				}
 			}
-		}	
+		}
 		// allow custom output nesting in project's output if all source entries have a custom output
 		if (sourceEntryCount <= outputCount-1) {
 		    allowNestingInOutputLocations[0] = true;
 		} else if (potentialNestedOutput != null) {
-			return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_cannotNestOutputInOutput, new String[] {potentialNestedOutput.makeRelative().toString(), outputLocations[0].makeRelative().toString()})); 
+			return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_cannotNestOutputInOutput, new String[] {potentialNestedOutput.makeRelative().toString(), outputLocations[0].makeRelative().toString()}));
 		}
 
 		for (int i = 0 ; i < length; i++) {
@@ -1187,7 +1390,7 @@
 			IPath path = resolvedEntry.getPath();
 			int index;
 			switch(resolvedEntry.getEntryKind()){
-				
+
 				case IClasspathEntry.CPE_SOURCE :
 					hasSource = true;
 					if ((index = Util.indexOfMatchingPath(path, outputLocations, outputCount)) != -1){
@@ -1206,23 +1409,23 @@
 		if (!hasSource && !hasLibFolder) { // if no source and no lib folder, then allowed
 			for (int i = 0; i < outputCount; i++) allowNestingInOutputLocations[i] = true;
 		}
-		
+
 		HashSet pathes = new HashSet(length);
-		
+
 		// check all entries
 		for (int i = 0 ; i < length; i++) {
 			IClasspathEntry entry = classpath[i];
 			if (entry == null) continue;
 			IPath entryPath = entry.getPath();
 			int kind = entry.getEntryKind();
-			
+
 			// Build some common strings for status message
 			boolean isProjectRelative = projectName.equals(entryPath.segment(0));
 			String entryPathMsg = isProjectRelative ? entryPath.removeFirstSegments(1).toString() : entryPath.makeRelative().toString();
-	
+
 			// complain if duplicate path
 			if (!pathes.add(entryPath)){
-				return new JavaModelStatus(IJavaModelStatusConstants.NAME_COLLISION, Messages.bind(Messages.classpath_duplicateEntryPath, new String[] {entryPathMsg, projectName})); 
+				return new JavaModelStatus(IJavaModelStatusConstants.NAME_COLLISION, Messages.bind(Messages.classpath_duplicateEntryPath, new String[] {entryPathMsg, projectName}));
 			}
 			// no further check if entry coincidates with project or output location
 			if (entryPath.equals(projectPath)){
@@ -1233,39 +1436,43 @@
 				// tolerate nesting output in src if src==prj
 				continue;
 			}
-	
+
 			// allow nesting source entries in each other as long as the outer entry excludes the inner one
-			if (kind == IClasspathEntry.CPE_SOURCE 
+			if (kind == IClasspathEntry.CPE_SOURCE
 					|| (kind == IClasspathEntry.CPE_LIBRARY && !org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(entryPath.lastSegment()))){
 				for (int j = 0; j < classpath.length; j++){
 					IClasspathEntry otherEntry = classpath[j];
 					if (otherEntry == null) continue;
 					int otherKind = otherEntry.getEntryKind();
 					IPath otherPath = otherEntry.getPath();
-					if (entry != otherEntry 
-						&& (otherKind == IClasspathEntry.CPE_SOURCE 
-								|| (otherKind == IClasspathEntry.CPE_LIBRARY 
+					if (entry != otherEntry
+						&& (otherKind == IClasspathEntry.CPE_SOURCE
+								|| (otherKind == IClasspathEntry.CPE_LIBRARY
 										&& !org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(otherPath.lastSegment())))){
 						char[][] inclusionPatterns, exclusionPatterns;
-						if (otherPath.isPrefixOf(entryPath) 
+						if (otherPath.isPrefixOf(entryPath)
 								&& !otherPath.equals(entryPath)
 								&& !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, inclusionPatterns, exclusionPatterns, false)) {
-								return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_mustEndWithSlash, new String[] {exclusionPattern, entryPath.makeRelative().toString()})); 
+								return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_mustEndWithSlash, new String[] {exclusionPattern, entryPath.makeRelative().toString()}));
 							} else {
 								if (otherKind == IClasspathEntry.CPE_SOURCE) {
 									exclusionPattern += '/';
-									return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_cannotNestEntryInEntry, new String[] {entryPath.makeRelative().toString(), otherEntry.getPath().makeRelative().toString(), exclusionPattern})); 
+									if (!disableExclusionPatterns) {
+										return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_cannotNestEntryInEntry, new String[] {entryPath.makeRelative().toString(), otherEntry.getPath().makeRelative().toString(), exclusionPattern}));
+									} else {
+										return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_cannotNestEntryInEntryNoExclusion, new String[] {entryPath.makeRelative().toString(), otherEntry.getPath().makeRelative().toString(), exclusionPattern}));
+									}
 								} else {
-									return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_cannotNestEntryInLibrary, new String[] {entryPath.makeRelative().toString(), otherEntry.getPath().makeRelative().toString()})); 
+									return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_cannotNestEntryInLibrary, new String[] {entryPath.makeRelative().toString(), otherEntry.getPath().makeRelative().toString()}));
 								}
 							}
 						}
 					}
 				}
 			}
-			
+
 			// 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();
@@ -1274,7 +1481,7 @@
     			if (entryPath.equals(currentOutput)) continue;
 				if (entryPath.isPrefixOf(currentOutput)) {
 				    if (kind != IClasspathEntry.CPE_SOURCE || !Util.isExcluded(currentOutput, inclusionPatterns, exclusionPatterns, true)) {
-						return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_cannotNestOutputInEntry, new String[] {currentOutput.makeRelative().toString(), entryPath.makeRelative().toString()})); 
+						return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_cannotNestOutputInEntry, new String[] {currentOutput.makeRelative().toString(), entryPath.makeRelative().toString()}));
 				    }
 				}
 		    }
@@ -1284,9 +1491,9 @@
 		        if (allowNestingInOutputLocations[j]) continue;
 		        IPath currentOutput = outputLocations[j];
 				if (currentOutput.isPrefixOf(entryPath)) {
-					return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_cannotNestEntryInOutput, new String[] {entryPath.makeRelative().toString(), currentOutput.makeRelative().toString()})); 
+					return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_cannotNestEntryInOutput, new String[] {entryPath.makeRelative().toString(), currentOutput.makeRelative().toString()}));
 				}
-		    }			
+		    }
 		}
 		// ensure that no specific output is coincidating with another source folder (only allowed if matching current source folder)
 		// 36465 - for 2.0 backward compatibility, only check specific output locations (the default can still coincidate)
@@ -1302,7 +1509,7 @@
 			// Build some common strings for status message
 			boolean isProjectRelative = projectName.equals(entryPath.segment(0));
 			String entryPathMsg = isProjectRelative ? entryPath.removeFirstSegments(1).toString() : entryPath.makeRelative().toString();
-	
+
 			if (kind == IClasspathEntry.CPE_SOURCE) {
 				IPath output = entry.getOutputLocation();
 				if (output == null) continue; // 36465 - for 2.0 backward compatibility, only check specific output locations (the default can still coincidate)
@@ -1314,29 +1521,29 @@
 					// Build some common strings for status message
 					boolean opStartsWithProject = projectName.equals(otherEntry.getPath().segment(0));
 					String otherPathMsg = opStartsWithProject ? otherEntry.getPath().removeFirstSegments(1).toString() : otherEntry.getPath().makeRelative().toString();
-	
+
 					switch (otherEntry.getEntryKind()) {
 						case IClasspathEntry.CPE_SOURCE :
 							if (otherEntry.getPath().equals(output)) {
-								return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_cannotUseDistinctSourceFolderAsOutput, new String[] {entryPathMsg, otherPathMsg, projectName})); 
+								return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_cannotUseDistinctSourceFolderAsOutput, new String[] {entryPathMsg, otherPathMsg, projectName}));
 							}
 							break;
 						case IClasspathEntry.CPE_LIBRARY :
 							if (otherEntry.getPath().equals(output)) {
-								return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_cannotUseLibraryAsOutput, new String[] {entryPathMsg, otherPathMsg, projectName})); 
+								return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_cannotUseLibraryAsOutput, new String[] {entryPathMsg, otherPathMsg, projectName}));
 							}
 					}
 				}
-			}			
+			}
 		}
-		return JavaModelStatus.VERIFIED_OK;	
+		return JavaModelStatus.VERIFIED_OK;
 	}
-	
+
 	/**
-	 * Returns a Java model status describing the problem related to this classpath entry if any, 
+	 * Returns a Java model status describing the problem related to this classpath entry if any,
 	 * 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 project the given java project
 	 * @param entry the given classpath entry
 	 * @param checkSourceAttachment a flag to determine if source attachement should be checked
@@ -1344,20 +1551,20 @@
 	 * @return a java model status describing the problem related to this classpath entry if any, a status object with code <code>IStatus.OK</code> if the entry is fine
 	 */
 	public static IJavaModelStatus validateClasspathEntry(IJavaProject project, IClasspathEntry entry, boolean checkSourceAttachment, boolean recurseInContainers){
-		
-		IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();			
+
+		IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
 		IPath path = entry.getPath();
-	
+
 		// Build some common strings for status message
 		String projectName = project.getElementName();
 		boolean pathStartsWithProject = projectName.equals(path.segment(0));
 		String entryPathMsg = pathStartsWithProject ? path.removeFirstSegments(1).makeRelative().toString() : path.toString();
-	
+
 		switch(entry.getEntryKind()){
-	
+
 			// container entry check
 			case IClasspathEntry.CPE_CONTAINER :
-				if (path != null && path.segmentCount() >= 1){
+				if (path.segmentCount() >= 1){
 					try {
 						IClasspathContainer container = JavaModelManager.getJavaModelManager().getClasspathContainer(path, project);
 						// container retrieval is performing validation check on container entry kinds.
@@ -1372,7 +1579,7 @@
 								for (int i=0; i<length; i++) {
 									String attName = extraAttributes[i].getName();
 									if (!set.add(attName)) {
-										return new JavaModelStatus(IJavaModelStatusConstants.NAME_COLLISION, Messages.bind(Messages.classpath_duplicateEntryExtraAttribute, new String[] {attName, entryPathMsg, projectName})); 
+										return new JavaModelStatus(IJavaModelStatusConstants.NAME_COLLISION, Messages.bind(Messages.classpath_duplicateEntryExtraAttribute, new String[] {attName, entryPathMsg, projectName}));
 									}
 								}
 							}
@@ -1397,23 +1604,23 @@
 									if (!containerEntryStatus.isOK()){
 										return containerEntryStatus;
 									}
-								} 
+								}
 							}
 						}
 					} catch(JavaModelException e){
 						return new JavaModelStatus(e);
 					}
 				} else {
-					return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_illegalContainerPath, new String[] {entryPathMsg, projectName}));					 
+					return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_illegalContainerPath, new String[] {entryPathMsg, projectName}));
 				}
 				break;
-				
+
 			// variable entry check
 			case IClasspathEntry.CPE_VARIABLE :
-				if (path != null && path.segmentCount() >= 1){
+				if (path.segmentCount() >= 1){
 					try {
 						entry = JavaCore.getResolvedClasspathEntry(entry);
-					} catch (Assert.AssertionFailedException e) {
+					} catch (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());
@@ -1421,21 +1628,32 @@
 					if (entry == null){
 						return new JavaModelStatus(IJavaModelStatusConstants.CP_VARIABLE_PATH_UNBOUND, project, path);
 					}
-					return validateClasspathEntry(project, entry, checkSourceAttachment, recurseInContainers);
+
+					// get validation status
+					IJavaModelStatus status = validateClasspathEntry(project, entry, checkSourceAttachment, recurseInContainers);
+					if (!status.isOK()) return status;
+
+					// return deprecation status if any
+					String variableName = path.segment(0);
+					String deprecatedMessage = JavaCore.getClasspathVariableDeprecationMessage(variableName);
+					if (deprecatedMessage != null) {
+						return new JavaModelStatus(IStatus.WARNING, IJavaModelStatusConstants.DEPRECATED_VARIABLE, project, path, deprecatedMessage);
+					}
+					return status;
 				} else {
-					return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_illegalVariablePath, new String[] {entryPathMsg, projectName}));					 
+					return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_illegalVariablePath, new String[] {entryPathMsg, projectName}));
 				}
-	
+
 			// library entry check
 			case IClasspathEntry.CPE_LIBRARY :
-				if (path != null && path.isAbsolute() && !path.isEmpty()) {
+				if (path.isAbsolute() && !path.isEmpty()) {
 					IPath sourceAttachment = entry.getSourceAttachmentPath();
 					Object target = JavaModel.getTarget(workspaceRoot, path, true);
-					if (target != null && project.getOption(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL, true) != JavaCore.IGNORE) {
+					if (target != null && !JavaCore.IGNORE.equals(project.getOption(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL, true))) {
 						long projectTargetJDK = CompilerOptions.versionToJdkLevel(project.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, true));
 						long libraryJDK = Util.getJdkLevel(target);
 						if (libraryJDK != 0 && libraryJDK > projectTargetJDK) {
-							return new JavaModelStatus(IJavaModelStatusConstants.INCOMPATIBLE_JDK_LEVEL, project, path, CompilerOptions.versionFromJdkLevel(libraryJDK)); 
+							return new JavaModelStatus(IJavaModelStatusConstants.INCOMPATIBLE_JDK_LEVEL, project, path, CompilerOptions.versionFromJdkLevel(libraryJDK));
 						}
 					}
 					if (target instanceof IResource){
@@ -1443,76 +1661,76 @@
 						switch(resolvedResource.getType()){
 							case IResource.FILE :
 								if (org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(resolvedResource.getName())) {
-									if (checkSourceAttachment 
+									if (checkSourceAttachment
 										&& sourceAttachment != null
 										&& !sourceAttachment.isEmpty()
 										&& JavaModel.getTarget(workspaceRoot, sourceAttachment, true) == null){
-										return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundSourceAttachment, new String [] {sourceAttachment.toString(), path.toString(), projectName})); 
+										return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundSourceAttachment, new String [] {sourceAttachment.toString(), path.toString(), projectName}));
 									}
 								} else {
-									return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_illegalLibraryArchive, new String[] {entryPathMsg, projectName})); 
+									return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_illegalLibraryArchive, new String[] {entryPathMsg, projectName}));
 								}
 								break;
 							case IResource.FOLDER :	// internal binary folder
-								if (checkSourceAttachment 
-									&& sourceAttachment != null 
+								if (checkSourceAttachment
+									&& sourceAttachment != null
 									&& !sourceAttachment.isEmpty()
 									&& JavaModel.getTarget(workspaceRoot, sourceAttachment, true) == null){
-									return  new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundSourceAttachment, new String [] {sourceAttachment.toString(), path.toString(), projectName})); 
+									return  new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundSourceAttachment, new String [] {sourceAttachment.toString(), path.toString(), projectName}));
 								}
 						}
 					} else if (target instanceof File){
 						File file = JavaModel.getFile(target);
 					    if (file == null) {
-							return  new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_illegalExternalFolder, new String[] {path.toOSString(), projectName})); 
+							return  new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_illegalExternalFolder, new String[] {path.toOSString(), projectName}));
 					    } else if (!org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(file.getName())) {
-							return  new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_illegalLibraryArchive, (new String[] {path.toOSString(), projectName}))); 
-					    } else if (checkSourceAttachment 
-								&& sourceAttachment != null 
+							return  new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_illegalLibraryArchive, (new String[] {path.toOSString(), projectName})));
+					    } else if (checkSourceAttachment
+								&& sourceAttachment != null
 								&& !sourceAttachment.isEmpty()
 								&& JavaModel.getTarget(workspaceRoot, sourceAttachment, true) == null){
-								return  new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundSourceAttachment, new String [] {sourceAttachment.toString(), path.toOSString(), projectName})); 
+								return  new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundSourceAttachment, new String [] {sourceAttachment.toString(), path.toOSString(), projectName}));
 					    }
 					} else {
 						boolean isExternal = path.getDevice() != null || !workspaceRoot.getProject(path.segment(0)).exists();
 						if (isExternal) {
-							return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundLibrary, new String[] {path.toOSString(), projectName})); 
+							return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundLibrary, new String[] {path.toOSString(), projectName}));
 						} else {
-							return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundLibrary, new String[] {entryPathMsg, projectName})); 
+							return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundLibrary, new String[] {entryPathMsg, projectName}));
 						}
 					}
 				} else {
-					return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_illegalLibraryPath, new String[] {entryPathMsg, projectName})); 
+					return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_illegalLibraryPath, new String[] {entryPathMsg, projectName}));
 				}
 				break;
-	
+
 			// project entry check
 			case IClasspathEntry.CPE_PROJECT :
-				if (path != null && path.isAbsolute() && !path.isEmpty()) {
+				if (path.isAbsolute() && path.segmentCount() == 1) {
 					IProject prereqProjectRsc = workspaceRoot.getProject(path.segment(0));
 					IJavaProject prereqProject = JavaCore.create(prereqProjectRsc);
 					try {
 						if (!prereqProjectRsc.exists() || !prereqProjectRsc.hasNature(JavaCore.NATURE_ID)){
-							return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundProject, new String[] {path.segment(0), projectName})); 
+							return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundProject, new String[] {path.segment(0), projectName}));
 						}
 						if (!prereqProjectRsc.isOpen()){
-							return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_closedProject, new String[] {path.segment(0)})); 
+							return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_closedProject, new String[] {path.segment(0)}));
 						}
-						if (project.getOption(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL, true) != JavaCore.IGNORE) {
+						if (!JavaCore.IGNORE.equals(project.getOption(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL, true))) {
 							long projectTargetJDK = CompilerOptions.versionToJdkLevel(project.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, true));
 							long prereqProjectTargetJDK = CompilerOptions.versionToJdkLevel(prereqProject.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, true));
 							if (prereqProjectTargetJDK > projectTargetJDK) {
-								return new JavaModelStatus(IJavaModelStatusConstants.INCOMPATIBLE_JDK_LEVEL, project, path, CompilerOptions.versionFromJdkLevel(prereqProjectTargetJDK)); 
+								return new JavaModelStatus(IJavaModelStatusConstants.INCOMPATIBLE_JDK_LEVEL, project, path, CompilerOptions.versionFromJdkLevel(prereqProjectTargetJDK));
 							}
 						}
 					} catch (CoreException e){
-						return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundProject, new String[] {path.segment(0), projectName})); 
+						return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundProject, new String[] {path.segment(0), projectName}));
 					}
 				} else {
-					return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_illegalProjectPath, new String[] {path.segment(0), projectName})); 
+					return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_illegalProjectPath, new String[] {path.toString(), projectName}));
 				}
 				break;
-	
+
 			// project source folder
 			case IClasspathEntry.CPE_SOURCE :
 				if (((entry.getInclusionPatterns() != null && entry.getInclusionPatterns().length > 0)
@@ -1523,13 +1741,13 @@
 				if (entry.getOutputLocation() != null && JavaCore.DISABLED.equals(project.getOption(JavaCore.CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS, true))) {
 					return new JavaModelStatus(IJavaModelStatusConstants.DISABLED_CP_MULTIPLE_OUTPUT_LOCATIONS, project, path);
 				}
-				if (path != null && path.isAbsolute() && !path.isEmpty()) {
+				if (path.isAbsolute() && !path.isEmpty()) {
 					IPath projectPath= project.getProject().getFullPath();
 					if (!projectPath.isPrefixOf(path) || JavaModel.getTarget(workspaceRoot, path, true) == null){
-						return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundSourceFolder, new String[] {entryPathMsg, projectName})); 
+						return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundSourceFolder, new String[] {entryPathMsg, projectName}));
 					}
 				} else {
-					return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_illegalSourceFolderPath, new String[] {entryPathMsg, projectName})); 
+					return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_illegalSourceFolderPath, new String[] {entryPathMsg, projectName}));
 				}
 				break;
 		}
@@ -1542,11 +1760,11 @@
 			for (int i=0; i<length; i++) {
 				String attName = extraAttributes[i].getName();
 				if (!set.add(attName)) {
-					return new JavaModelStatus(IJavaModelStatusConstants.NAME_COLLISION, Messages.bind(Messages.classpath_duplicateEntryExtraAttribute, new String[] {attName, entryPathMsg, projectName})); 
+					return new JavaModelStatus(IJavaModelStatusConstants.NAME_COLLISION, Messages.bind(Messages.classpath_duplicateEntryExtraAttribute, new String[] {attName, entryPathMsg, projectName}));
 				}
 			}
 		}
 
-		return JavaModelStatus.VERIFIED_OK;		
+		return JavaModelStatus.VERIFIED_OK;
 	}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathValidation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathValidation.java
new file mode 100755
index 0000000..03ce9e5
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathValidation.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.IJavaModelStatus;
+import org.eclipse.jdt.core.IJavaModelStatusConstants;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.internal.core.builder.JavaBuilder;
+
+/*
+ * Validates the raw classpath format and the resolved classpath of this project,
+ * updating markers if necessary.
+ */
+public class ClasspathValidation {
+	
+	private JavaProject project;
+	
+	public ClasspathValidation(JavaProject project) {
+		this.project = project;
+	}
+	
+	public void validate() {
+		JavaModelManager.PerProjectInfo perProjectInfo;
+		try {
+			perProjectInfo = this.project.getPerProjectInfo();
+		} catch (JavaModelException e) {
+			// project doesn't exist
+			IProject resource = this.project.getProject();
+			if (resource.isAccessible()) {
+				this.project.flushClasspathProblemMarkers(true/*flush cycle markers*/, true/*flush classpath format markers*/);
+					
+				// remove problems and tasks created  by the builder
+				JavaBuilder.removeProblemsAndTasksFor(resource);
+			}
+			return;
+		}
+		
+		// use synchronized block to ensure consistency
+		IClasspathEntry[] rawClasspath;
+		IPath outputLocation;
+		IJavaModelStatus status;
+		synchronized (perProjectInfo) {
+			rawClasspath = perProjectInfo.rawClasspath;
+			outputLocation = perProjectInfo.outputLocation;
+			status = perProjectInfo.rawClasspathStatus; // status has been set during POST_CHANGE
+		}
+		
+		// update classpath format problems
+		this.project.flushClasspathProblemMarkers(false/*cycle*/, true/*format*/);
+		if (!status.isOK())
+			this.project.createClasspathProblemMarker(status);	
+		
+		// update resolved classpath problems
+		this.project.flushClasspathProblemMarkers(false/*cycle*/, false/*format*/);
+		
+		if (rawClasspath != JavaProject.INVALID_CLASSPATH && outputLocation != null) {
+		 	for (int i = 0; i < rawClasspath.length; i++) {
+				status = ClasspathEntry.validateClasspathEntry(this.project, rawClasspath[i], false/*src attach*/, true /*recurse in container*/);
+				if (!status.isOK()) {
+					if (status.getCode() == IJavaModelStatusConstants.INVALID_CLASSPATH && ((ClasspathEntry) rawClasspath[i]).isOptional())
+						continue; // ignore this entry
+					this.project.createClasspathProblemMarker(status);	
+				}
+			 }
+			status = ClasspathEntry.validateClasspath(this.project, rawClasspath, outputLocation);
+			if (!status.isOK()) 
+				this.project.createClasspathProblemMarker(status);
+		 }
+	}
+
+}
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 19b321b..84a7ea5 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -18,12 +18,13 @@
 import org.eclipse.core.resources.IWorkspace;
 import org.eclipse.core.runtime.CoreException;
 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;
 import org.eclipse.jdt.core.IJavaModelStatus;
 import org.eclipse.jdt.core.IJavaModelStatusConstants;
+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.Messages;
 import org.eclipse.jdt.internal.core.util.Util;
@@ -69,14 +70,22 @@
 		try {
 			beginTask(Messages.workingCopy_commit, 2); 
 			CompilationUnit workingCopy = getCompilationUnit();
-			IFile resource = (IFile)workingCopy.getResource();
+			
+			if (ExternalJavaProject.EXTERNAL_PROJECT_NAME.equals(workingCopy.getJavaProject().getElementName())) {
+				// case of a working copy without a resource
+				workingCopy.getBuffer().save(this.progressMonitor, this.force);
+				return;
+			}
+			
 			ICompilationUnit primary = workingCopy.getPrimary();
 			boolean isPrimary = workingCopy.isPrimary();
 
 			JavaElementDeltaBuilder deltaBuilder = null;
 			PackageFragmentRoot root = (PackageFragmentRoot)workingCopy.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
 			boolean isIncluded = !Util.isExcluded(workingCopy);
-			if (isPrimary || (root.validateOnClasspath().isOK() && isIncluded && resource.isAccessible() && Util.isValidCompilationUnitName(workingCopy.getElementName()))) {
+			IFile resource = (IFile)workingCopy.getResource();
+			IJavaProject project = root.getJavaProject();
+			if (isPrimary || (root.validateOnClasspath().isOK() && isIncluded && resource.isAccessible() && Util.isValidCompilationUnitName(workingCopy.getElementName(), project.getOption(JavaCore.COMPILER_SOURCE, true), project.getOption(JavaCore.COMPILER_COMPLIANCE, true)))) {
 				
 				// force opening so that the delta builder can get the old info
 				if (!isPrimary && !primary.isOpen()) {
@@ -178,6 +187,7 @@
 	}
 	protected ISchedulingRule getSchedulingRule() {
 		IResource resource = getElementToProcess().getResource();
+		if (resource == null) return null;
 		IWorkspace workspace = resource.getWorkspace();
 		if (resource.exists()) {
 			return workspace.getRuleFactory().modifyRule(resource);
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 1345700..636ce73 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -7,6 +7,8 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ *     Alex Smirnoff (alexsmr@sympatico.ca) - part of the changes to support Java-like extension 
+ *                                                            (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=71460)
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
@@ -16,9 +18,7 @@
 import org.eclipse.core.runtime.*;
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.compiler.*;
-import org.eclipse.jdt.core.compiler.IProblem;
 import org.eclipse.jdt.core.dom.AST;
-import org.eclipse.jdt.internal.compiler.ASTVisitor;
 import org.eclipse.jdt.internal.compiler.IProblemFactory;
 import org.eclipse.jdt.internal.compiler.SourceElementParser;
 import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
@@ -40,6 +40,8 @@
 	 */
 	/*package*/ static final int JLS2_INTERNAL = AST.JLS2;
 	
+	private static final IImportDeclaration[] NO_IMPORTS = new IImportDeclaration[0];
+	
 	protected String name;
 	public WorkingCopyOwner owner;
 
@@ -47,28 +49,11 @@
  * Constructs a handle to a compilation unit with the given name in the
  * specified package for the specified owner
  */
-protected CompilationUnit(PackageFragment parent, String name, WorkingCopyOwner owner) {
+public CompilationUnit(PackageFragment parent, String name, WorkingCopyOwner owner) {
 	super(parent);
 	this.name = name;
 	this.owner = owner;
 }
-/**
- * Accepts the given visitor onto the parsed tree of this compilation unit, after
- * having runned the name resolution.
- * The visitor's corresponding <code>visit</code> method is called with the
- * corresponding parse tree. If the visitor returns <code>true</code>, this method
- * visits this parse node's members.
- *
- * @param visitor the visitor
- * @exception JavaModelException if this method fails. Reasons include:
- * <ul>
- * <li> This element does not exist.</li>
- * <li> The visitor failed with this exception.</li>
- * </ul>
- */
-public void accept(ASTVisitor visitor) throws JavaModelException {
-	CompilationUnitVisitor.visit(this, visitor);
-}
 /*
  * @see ICompilationUnit#becomeWorkingCopy(IProblemRequestor, IProgressMonitor)
  */
@@ -83,6 +68,13 @@
 		operation.runOperation(monitor);
 	}
 }
+/*
+ * @see ICompilationUnit#becomeWorkingCopy(IProgressMonitor)
+ */
+public void becomeWorkingCopy(IProgressMonitor monitor) throws JavaModelException {
+	IProblemRequestor requestor = this.owner == null ? null : this.owner.getProblemRequestor(this);
+	becomeWorkingCopy(requestor, monitor);
+}
 protected boolean buildStructure(OpenableElementInfo info, final IProgressMonitor pm, Map newElements, IResource underlyingResource) throws JavaModelException {
 
 	// check if this compilation unit can be opened
@@ -103,20 +95,43 @@
 	if (buffer == null) {
 		buffer = openBuffer(pm, unitInfo); // open buffer independently from the info, since we are building the info
 	}
-	final char[] contents = buffer == null ? null : buffer.getCharacters();
+	final char[] contents;
+	if (buffer == null) {
+		contents = CharOperation.NO_CHAR ;
+	} else {
+		char[] characters = buffer.getCharacters();
+		contents = characters == null ? CharOperation.NO_CHAR : characters;
+	}
 
 	// generate structure and compute syntax problems if needed
 	CompilationUnitStructureRequestor requestor = new CompilationUnitStructureRequestor(this, unitInfo, newElements);
 	JavaModelManager.PerWorkingCopyInfo perWorkingCopyInfo = getPerWorkingCopyInfo();
 	IJavaProject project = getJavaProject();
-	boolean computeProblems = JavaProject.hasJavaNature(project.getProject()) && perWorkingCopyInfo != null && perWorkingCopyInfo.isActive();
+
+	boolean createAST;
+	boolean resolveBindings;
+	int reconcileFlags;
+	HashMap problems;
+	if (info instanceof ASTHolderCUInfo) {
+		ASTHolderCUInfo astHolder = (ASTHolderCUInfo) info;
+		createAST = astHolder.astLevel != NO_AST;
+		resolveBindings = astHolder.resolveBindings;
+		reconcileFlags = astHolder.reconcileFlags;
+		problems = astHolder.problems;
+	} else {
+		createAST = false;
+		resolveBindings = false;
+		reconcileFlags = 0;
+		problems = null;
+	}
+	
+	boolean computeProblems = perWorkingCopyInfo != null && perWorkingCopyInfo.isActive() && project != null && JavaProject.hasJavaNature(project.getProject());
 	IProblemFactory problemFactory = new DefaultProblemFactory();
-	Map options = project.getOptions(true);
+	Map options = project == null ? JavaCore.getOptions() : project.getOptions(true);
 	if (!computeProblems) {
 		// disable task tags checking to speed up parsing
 		options.put(JavaCore.COMPILER_TASK_TAGS, ""); //$NON-NLS-1$
 	}
-	boolean createAST = info instanceof ASTHolderCUInfo;
 	SourceElementParser parser = new SourceElementParser(
 		requestor, 
 		problemFactory, 
@@ -124,10 +139,14 @@
 		true/*report local declarations*/,
 		!createAST /*optimize string literals only if not creating a DOM AST*/);
 	parser.reportOnlyOneSyntaxError = !computeProblems;
-	if (!computeProblems && !createAST) // disable javadoc parsing if not computing problems and not creating ast
+	parser.setMethodsFullRecovery(true);
+	parser.setStatementsRecovery((reconcileFlags & ICompilationUnit.ENABLE_STATEMENTS_RECOVERY) != 0);
+	
+	if (!computeProblems && !resolveBindings && !createAST) // disable javadoc parsing if not computing problems, not resolving and not creating ast
 		parser.javadocParser.checkDocComment = false;
 	requestor.parser = parser;
-	CompilationUnitDeclaration unit = parser.parseCompilationUnit(new org.eclipse.jdt.internal.compiler.env.ICompilationUnit() {
+	CompilationUnitDeclaration unit = parser.parseCompilationUnit(
+		new org.eclipse.jdt.internal.compiler.env.ICompilationUnit() {
 			public char[] getContents() {
 				return contents;
 			}
@@ -140,26 +159,46 @@
 			public char[] getFileName() {
 				return CompilationUnit.this.getFileName();
 			}
-		}, true /*full parse to find local elements*/);
+		}, 
+		true /*full parse to find local elements*/);
 	
 	// update timestamp (might be IResource.NULL_STAMP if original does not exist)
 	if (underlyingResource == null) {
 		underlyingResource = getResource();
 	}
-	unitInfo.timestamp = ((IFile)underlyingResource).getModificationStamp();
+	// underlying resource is null in the case of a working copy on a class file in a jar
+	if (underlyingResource != null)
+		unitInfo.timestamp = ((IFile)underlyingResource).getModificationStamp();
 	
 	// compute other problems if needed
 	CompilationUnitDeclaration compilationUnitDeclaration = null;
 	try {
-		if (computeProblems){
-			perWorkingCopyInfo.beginReporting();
-			compilationUnitDeclaration = CompilationUnitProblemFinder.process(unit, this, contents, parser, this.owner, perWorkingCopyInfo, !createAST/*reset env if not creating AST*/, pm);
-			perWorkingCopyInfo.endReporting();
+		if (computeProblems) {
+			if (problems == null) {
+				// report problems to the problem requestor
+				problems = new HashMap();
+				compilationUnitDeclaration = CompilationUnitProblemFinder.process(unit, this, contents, parser, this.owner, problems, createAST, reconcileFlags, pm);
+				try {
+					perWorkingCopyInfo.beginReporting();
+					for (Iterator iteraror = problems.values().iterator(); iteraror.hasNext();) {
+						CategorizedProblem[] categorizedProblems = (CategorizedProblem[]) iteraror.next();
+						if (categorizedProblems == null) continue;
+						for (int i = 0, length = categorizedProblems.length; i < length; i++) {
+							perWorkingCopyInfo.acceptProblem(categorizedProblems[i]);
+						}
+					}
+				} finally {
+					perWorkingCopyInfo.endReporting();
+				}
+			} else {
+				// collect problems
+				compilationUnitDeclaration = CompilationUnitProblemFinder.process(unit, this, contents, parser, this.owner, problems, createAST, reconcileFlags, pm);
+			}
 		}
 		
 		if (createAST) {
 			int astLevel = ((ASTHolderCUInfo) info).astLevel;
-			org.eclipse.jdt.core.dom.CompilationUnit cu = AST.convertCompilationUnit(astLevel, unit, contents, options, computeProblems, this, pm);
+			org.eclipse.jdt.core.dom.CompilationUnit cu = AST.convertCompilationUnit(astLevel, unit, contents, options, computeProblems, this, reconcileFlags, pm);
 			((ASTHolderCUInfo) info).ast = cu;
 		}
 	} finally {
@@ -235,20 +274,7 @@
 				requestor.acceptClass(packageName, className, completionName, modifiers, completionStart, completionEnd);
 			}
 			public void acceptError(IProblem error) {
-				if (true) return; // was disabled in 1.0
-
-				try {
-					IMarker marker = ResourcesPlugin.getWorkspace().getRoot().createMarker(IJavaModelMarker.TRANSIENT_PROBLEM);
-					marker.setAttribute(IJavaModelMarker.ID, error.getID());
-					marker.setAttribute(IMarker.CHAR_START, error.getSourceStart());
-					marker.setAttribute(IMarker.CHAR_END, error.getSourceEnd() + 1);
-					marker.setAttribute(IMarker.LINE_NUMBER, error.getSourceLineNumber());
-					marker.setAttribute(IMarker.MESSAGE, error.getMessage());
-					marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
-					requestor.acceptError(marker);
-				} catch(CoreException e){
-					// ignore
-				}
+				// was disabled in 1.0
 			}
 			public void acceptField(char[] declaringTypePackageName, char[] declaringTypeName, char[] fieldName, char[] typePackageName, char[] typeName, char[] completionName, int modifiers, int completionStart, int completionEnd, int relevance) {
 				requestor.acceptField(declaringTypePackageName, declaringTypeName, fieldName, typePackageName, typeName, completionName, modifiers, completionStart, completionEnd);
@@ -360,8 +386,7 @@
  * @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);
+	CreateImportOperation op = new CreateImportOperation(importName, this, flags);
 	if (sibling != null) {
 		op.createBefore(sibling);
 	}
@@ -506,8 +531,8 @@
  * @see ICompilationUnit#findPrimaryType()
  */
 public IType findPrimaryType() {
-	String typeName = Signature.getQualifier(this.getElementName());
-	IType primaryType= this.getType(typeName);
+	String typeName = Util.getNameWithoutJavaLikeExtension(getElementName());
+	IType primaryType= getType(typeName);
 	if (primaryType.exists()) {
 		return primaryType;
 	}
@@ -577,12 +602,20 @@
  * @see org.eclipse.jdt.internal.compiler.env.ICompilationUnit#getContents()
  */
 public char[] getContents() {
-	try {
-		IBuffer buffer = this.getBuffer();
-		return buffer == null ? CharOperation.NO_CHAR : buffer.getCharacters();
-	} catch (JavaModelException e) {
-		return CharOperation.NO_CHAR;
+	IBuffer buffer = getBufferManager().getBuffer(this);
+	if (buffer == null) {
+		// no need to force opening of CU to get the content
+		// also this cannot be a working copy, as its buffer is never closed while the working copy is alive
+		try {
+			return Util.getResourceContentsAsCharArray((IFile) getResource());
+		} catch (JavaModelException e) {
+			return CharOperation.NO_CHAR;
+		}
 	}
+	char[] contents = buffer.getCharacters();
+	if (contents == null) // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=129814
+		return CharOperation.NO_CHAR;
+	return contents;
 }
 /**
  * A compilation unit has a corresponding resource unless it is contained
@@ -591,8 +624,8 @@
  * @see IJavaElement#getCorrespondingResource()
  */
 public IResource getCorrespondingResource() throws JavaModelException {
-	IPackageFragmentRoot root= (IPackageFragmentRoot)getParent().getParent();
-	if (root.isArchive()) {
+	PackageFragmentRoot root = getPackageFragmentRoot();
+	if (root == null || root.isArchive()) {
 		return null;
 	} else {
 		return getUnderlyingResource();
@@ -673,17 +706,31 @@
  */
 public IImportDeclaration[] getImports() throws JavaModelException {
 	IImportContainer container= getImportContainer();
-	if (container.exists()) {
-		IJavaElement[] elements= container.getChildren();
-		IImportDeclaration[] imprts= new IImportDeclaration[elements.length];
-		System.arraycopy(elements, 0, imprts, 0, elements.length);
-		return imprts;
-	} else if (!exists()) {
-			throw newNotPresentException();
-	} else {
-		return new IImportDeclaration[0];
+	JavaModelManager manager = JavaModelManager.getJavaModelManager();
+	Object info = manager.getInfo(container);
+	if (info == null) {
+		if (manager.getInfo(this) != null)
+			// CU was opened, but no import container, then no imports
+			return NO_IMPORTS;
+		else {
+			open(null); // force opening of CU
+			info = manager.getInfo(container);
+			if (info == null) 
+				// after opening, if no import container, then no imports
+				return NO_IMPORTS;
+		}	
 	}
-
+	IJavaElement[] elements = ((JavaElementInfo) info).children;
+	int length = elements.length;
+	IImportDeclaration[] imports = new IImportDeclaration[length];
+	System.arraycopy(elements, 0, imports, 0, length);
+	return imports;
+}
+/**
+ * @see IMember#getTypeRoot()
+ */
+public ITypeRoot getTypeRoot() {
+	return this;
 }
 /**
  * @see org.eclipse.jdt.internal.compiler.env.ICompilationUnit#getMainTypeName()
@@ -741,6 +788,7 @@
  */
 public char[][] getPackageName() {
 	PackageFragment packageFragment = (PackageFragment) getParent();
+	if (packageFragment == null) return CharOperation.NO_CHAR_CHAR;
 	return Util.toCharArrays(packageFragment.names);
 }
 
@@ -748,11 +796,12 @@
  * @see IJavaElement#getPath()
  */
 public IPath getPath() {
-	PackageFragmentRoot root = this.getPackageFragmentRoot();
+	PackageFragmentRoot root = getPackageFragmentRoot();
+	if (root == null) return new Path(getElementName()); // working copy not in workspace
 	if (root.isArchive()) {
 		return root.getPath();
 	} else {
-		return this.getParent().getPath().append(this.getElementName());
+		return getParent().getPath().append(getElementName());
 	}
 }
 /*
@@ -779,11 +828,12 @@
  * @see IJavaElement#getResource()
  */
 public IResource getResource() {
-	PackageFragmentRoot root = this.getPackageFragmentRoot();
+	PackageFragmentRoot root = getPackageFragmentRoot();
+	if (root == null) return null; // working copy not in workspace
 	if (root.isArchive()) {
 		return root.getResource();
 	} else {
-		return ((IContainer)this.getParent().getResource()).getFile(new Path(this.getElementName()));
+		return ((IContainer) getParent().getResource()).getFile(new Path(getElementName()));
 	}
 }
 /**
@@ -847,6 +897,12 @@
 	return getWorkingCopy(new WorkingCopyOwner() {/*non shared working copy*/}, null/*no problem requestor*/, monitor);
 }
 /**
+ * @see ITypeRoot#getWorkingCopy(WorkingCopyOwner, IProgressMonitor)
+ */
+public ICompilationUnit getWorkingCopy(WorkingCopyOwner workingCopyOwner, IProgressMonitor monitor) throws JavaModelException {
+	return getWorkingCopy(workingCopyOwner, null, monitor);
+}
+/**
  * @see IWorkingCopy#getWorkingCopy(IProgressMonitor, IBufferFactory, IProblemRequestor)
  * @deprecated
  */
@@ -855,6 +911,7 @@
 }
 /**
  * @see ICompilationUnit#getWorkingCopy(WorkingCopyOwner, IProblemRequestor, IProgressMonitor)
+ * @deprecated
  */
 public ICompilationUnit getWorkingCopy(WorkingCopyOwner workingCopyOwner, IProblemRequestor problemRequestor, IProgressMonitor monitor) throws JavaModelException {
 	if (!isPrimary()) return this;
@@ -887,7 +944,9 @@
 	// timestamp
 	Object info = JavaModelManager.getJavaModelManager().getInfo(this);
 	if (info == null) return false;
-	return ((CompilationUnitElementInfo)info).timestamp != getResource().getModificationStamp();
+	IResource resource = getResource();
+	if (resource == null) return false;
+	return ((CompilationUnitElementInfo)info).timestamp != resource.getModificationStamp();
 }
 /**
  * @see IWorkingCopy#isBasedOn(IResource)
@@ -902,7 +961,7 @@
  * @see IOpenable#isConsistent()
  */
 public boolean isConsistent() {
-	return JavaModelManager.getJavaModelManager().getElementsOutOfSynchWithBuffers().get(this) == null;
+	return !JavaModelManager.getJavaModelManager().getElementsOutOfSynchWithBuffers().contains(this);
 }
 public boolean isPrimary() {
 	return this.owner == DefaultWorkingCopyOwner.PRIMARY;
@@ -915,6 +974,7 @@
 }
 protected IStatus validateCompilationUnit(IResource resource) {
 	IPackageFragmentRoot root = getPackageFragmentRoot();
+	// root never null as validation is not done for working copies
 	try {
 		if (root.getKind() != IPackageFragmentRoot.K_SOURCE) 
 			return new JavaModelStatus(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, root);
@@ -929,7 +989,8 @@
 		if (!resource.isAccessible())
 			return new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this);
 	}
-	return JavaConventions.validateCompilationUnitName(getElementName());
+	IJavaProject project = getJavaProject();
+	return JavaConventions.validateCompilationUnitName(getElementName(),project.getOption(JavaCore.COMPILER_SOURCE, true), project.getOption(JavaCore.COMPILER_COMPLIANCE, true));
 }
 /*
  * @see ICompilationUnit#isWorkingCopy()
@@ -943,16 +1004,19 @@
  * @see IOpenable#makeConsistent(IProgressMonitor)
  */
 public void makeConsistent(IProgressMonitor monitor) throws JavaModelException {
-	makeConsistent(false/*don't create AST*/, 0, monitor);
+	makeConsistent(NO_AST, false/*don't resolve bindings*/, 0 /* don't perform statements recovery */, null/*don't collect problems but report them*/, monitor);
 }
-public org.eclipse.jdt.core.dom.CompilationUnit makeConsistent(boolean createAST, int astLevel, IProgressMonitor monitor) throws JavaModelException {
+public org.eclipse.jdt.core.dom.CompilationUnit makeConsistent(int astLevel, boolean resolveBindings, int reconcileFlags, HashMap problems, IProgressMonitor monitor) throws JavaModelException {
 	if (isConsistent()) return null;
 		
 	// create a new info and make it the current info
 	// (this will remove the info and its children just before storing the new infos)
-	if (createAST) {
+	if (astLevel != NO_AST || problems != null) {
 		ASTHolderCUInfo info = new ASTHolderCUInfo();
 		info.astLevel = astLevel;
+		info.resolveBindings = resolveBindings;
+		info.reconcileFlags = reconcileFlags;
+		info.problems = problems;
 		openWhenClosed(info, monitor);
 		org.eclipse.jdt.core.dom.CompilationUnit result = info.ast;
 		info.ast = null;
@@ -985,43 +1049,52 @@
 protected IBuffer openBuffer(IProgressMonitor pm, Object info) throws JavaModelException {
 
 	// create buffer
+	BufferManager bufManager = getBufferManager();
 	boolean isWorkingCopy = isWorkingCopy();
 	IBuffer buffer = 
 		isWorkingCopy 
 			? this.owner.createBuffer(this) 
-			: BufferManager.getDefaultBufferManager().createBuffer(this);
+			: BufferManager.createBuffer(this);
 	if (buffer == null) return null;
 	
-	// set the buffer source
-	if (buffer.getCharacters() == null) {
-		if (isWorkingCopy) {
-			ICompilationUnit original;
-			if (!isPrimary() 
-					&& (original = new CompilationUnit((PackageFragment)getParent(), getElementName(), DefaultWorkingCopyOwner.PRIMARY)).isOpen()) {
-				buffer.setContents(original.getSource());
-			} else {
-				IFile file = (IFile)getResource();
-				if (file == null || !file.exists()) {
-					// initialize buffer with empty contents
-					buffer.setContents(CharOperation.NO_CHAR);
+	// synchronize to ensure that 2 threads are not putting 2 different buffers at the same time
+	// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=146331
+	synchronized(bufManager) {
+		IBuffer existingBuffer = bufManager.getBuffer(this);
+		if (existingBuffer != null)
+			return existingBuffer;
+		
+		// set the buffer source
+		if (buffer.getCharacters() == null) {
+			if (isWorkingCopy) {
+				ICompilationUnit original;
+				if (!isPrimary() 
+						&& (original = new CompilationUnit((PackageFragment)getParent(), getElementName(), DefaultWorkingCopyOwner.PRIMARY)).isOpen()) {
+					buffer.setContents(original.getSource());
 				} else {
-					buffer.setContents(Util.getResourceContentsAsCharArray(file));
+					IFile file = (IFile)getResource();
+					if (file == null || !file.exists()) {
+						// initialize buffer with empty contents
+						buffer.setContents(CharOperation.NO_CHAR);
+					} else {
+						buffer.setContents(Util.getResourceContentsAsCharArray(file));
+					}
 				}
+			} else {
+				IFile file = (IFile)this.getResource();
+				if (file == null || !file.exists()) throw newNotPresentException();
+				buffer.setContents(Util.getResourceContentsAsCharArray(file));
 			}
-		} else {
-			IFile file = (IFile)this.getResource();
-			if (file == null || !file.exists()) throw newNotPresentException();
-			buffer.setContents(Util.getResourceContentsAsCharArray(file));
 		}
-	}
-
-	// add buffer to buffer cache
-	BufferManager bufManager = getBufferManager();
-	bufManager.addBuffer(buffer);
-			
-	// listen to buffer changes
-	buffer.addBufferChangedListener(this);
 	
+		// add buffer to buffer cache
+		// note this may cause existing buffers to be removed from the buffer cache, but only primary compilation unit's buffer
+		// can be closed, thus no call to a client's IBuffer#close() can be done in this synchronized block.
+		bufManager.addBuffer(buffer);
+				
+		// listen to buffer changes
+		buffer.addBufferChangedListener(this);
+	}	
 	return buffer;
 }
 protected void openParent(Object childInfo, HashMap newElements, IProgressMonitor pm) throws JavaModelException {
@@ -1035,14 +1108,14 @@
  * @deprecated
  */
 public IMarker[] reconcile() throws JavaModelException {
-	reconcile(NO_AST, false/*don't force problem detection*/, null/*use primary owner*/, null/*no progress monitor*/);
+	reconcile(NO_AST, false/*don't force problem detection*/, false, null/*use primary owner*/, null/*no progress monitor*/);
 	return null;
 }
 /**
  * @see ICompilationUnit#reconcile(int, boolean, WorkingCopyOwner, IProgressMonitor)
  */
 public void reconcile(boolean forceProblemDetection, IProgressMonitor monitor) throws JavaModelException {
-	reconcile(NO_AST, forceProblemDetection, null/*use primary owner*/, monitor);
+	reconcile(NO_AST, forceProblemDetection? ICompilationUnit.FORCE_PROBLEM_DETECTION : 0, null/*use primary owner*/, monitor);
 }
 
 /**
@@ -1050,35 +1123,53 @@
  * @since 3.0
  */
 public org.eclipse.jdt.core.dom.CompilationUnit reconcile(
-	int astLevel,
-	boolean forceProblemDetection,
-	WorkingCopyOwner workingCopyOwner,
-	IProgressMonitor monitor)
-	throws JavaModelException {
+		int astLevel,
+		boolean forceProblemDetection,
+		WorkingCopyOwner workingCopyOwner,
+		IProgressMonitor monitor) throws JavaModelException {
+	return reconcile(astLevel, forceProblemDetection? ICompilationUnit.FORCE_PROBLEM_DETECTION : 0, workingCopyOwner, monitor);
+}
+
+/**
+ * @see ICompilationUnit#reconcile(int, boolean, WorkingCopyOwner, IProgressMonitor)
+ * @since 3.0
+ */
+public org.eclipse.jdt.core.dom.CompilationUnit reconcile(
+		int astLevel,
+		boolean forceProblemDetection,
+		boolean enableStatementsRecovery,
+		WorkingCopyOwner workingCopyOwner,
+		IProgressMonitor monitor) throws JavaModelException {
+	int flags = 0;
+	if (forceProblemDetection) flags |= ICompilationUnit.FORCE_PROBLEM_DETECTION;
+	if (enableStatementsRecovery) flags |= ICompilationUnit.ENABLE_STATEMENTS_RECOVERY;
+	return reconcile(astLevel, flags, workingCopyOwner, monitor);
+}
+
+public org.eclipse.jdt.core.dom.CompilationUnit reconcile(
+		int astLevel,
+		int reconcileFlags,
+		WorkingCopyOwner workingCopyOwner,
+		IProgressMonitor monitor)
+		throws JavaModelException {
 	
 	if (!isWorkingCopy()) return null; // Reconciling is not supported on non working copies
 	if (workingCopyOwner == null) workingCopyOwner = DefaultWorkingCopyOwner.PRIMARY;
 	
 	
-	boolean createAST = false;
-	switch(astLevel) {
-		case JLS2_INTERNAL :
-		case AST.JLS3 :
-			// client asking for level 2 or level 3 ASTs; these are supported
-			createAST = true;
-			break;
-		default:
-			// client asking for no AST (0) or unknown ast level
-			// either way, request denied
-			createAST = false;
-	}
 	PerformanceStats stats = null;
 	if(ReconcileWorkingCopyOperation.PERF) {
 		stats = PerformanceStats.getStats(JavaModelManager.RECONCILE_PERF, this);
 		stats.startRun(new String(this.getFileName()));
 	}
-	ReconcileWorkingCopyOperation op = new ReconcileWorkingCopyOperation(this, createAST, astLevel, forceProblemDetection, workingCopyOwner);
-	op.runOperation(monitor);
+	ReconcileWorkingCopyOperation op = new ReconcileWorkingCopyOperation(this, astLevel, reconcileFlags, workingCopyOwner);
+	JavaModelManager manager = JavaModelManager.getJavaModelManager();
+	try {
+		manager.cacheZipFiles(); // cache zip files for performance (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=134172)
+		op.runOperation(monitor);
+	} finally {
+		manager.flushZipFiles();
+	}
 	if(ReconcileWorkingCopyOperation.PERF) {
 		stats.endRun();
 	}
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 3712b68..802118a 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 ad0b386..e640de7 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,23 +10,20 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
+import java.util.HashMap;
 import java.util.Map;
 
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.OperationCanceledException;
-import org.eclipse.jdt.core.ICompilationUnit;
 import org.eclipse.jdt.core.*;
-import org.eclipse.jdt.core.compiler.IProblem;
+import org.eclipse.jdt.core.compiler.CategorizedProblem;
 import org.eclipse.jdt.internal.compiler.*;
-import org.eclipse.jdt.internal.compiler.CompilationResult;
 import org.eclipse.jdt.internal.compiler.Compiler;
-import org.eclipse.jdt.internal.compiler.ICompilerRequestor;
-import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
-import org.eclipse.jdt.internal.compiler.IProblemFactory;
 import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
 import org.eclipse.jdt.internal.compiler.env.AccessRestriction;
 import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
 import org.eclipse.jdt.internal.compiler.env.ISourceType;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
 import org.eclipse.jdt.internal.compiler.parser.Parser;
 import org.eclipse.jdt.internal.compiler.parser.SourceTypeConverter;
@@ -59,7 +56,7 @@
 	 *      in UI when compiling interactively.
 	 *      @see org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies
 	 * 
-	 *	@param settings The settings to use for the resolution.
+	 *	@param compilerOptions The compiler options to use for the resolution.
 	 *      
 	 *  @param requestor org.eclipse.jdt.internal.compiler.api.ICompilerRequestor
 	 *      Component which will receive and persist all compilation results and is intended
@@ -77,11 +74,16 @@
 	protected CompilationUnitProblemFinder(
 		INameEnvironment environment,
 		IErrorHandlingPolicy policy,
-		Map settings,
+		CompilerOptions compilerOptions,
 		ICompilerRequestor requestor,
 		IProblemFactory problemFactory) {
 
-		super(environment, policy, settings, requestor, problemFactory, true);
+		super(environment,
+			policy,
+			compilerOptions,
+			requestor,
+			problemFactory
+		);
 	}
 
 	/**
@@ -111,6 +113,15 @@
 		}
 	}
 
+	protected static CompilerOptions getCompilerOptions(Map settings, boolean creatingAST, boolean statementsRecovery) {
+		CompilerOptions compilerOptions = new CompilerOptions(settings);
+		compilerOptions.performMethodsFullRecovery = statementsRecovery;
+		compilerOptions.performStatementsRecovery = statementsRecovery;
+		compilerOptions.parseLiteralExpressionsAsConstants = !creatingAST; /*parse literal expressions as constants only if not creating a DOM AST*/
+		compilerOptions.storeAnnotations = creatingAST; /*store annotations in the bindings if creating a DOM AST*/
+		return compilerOptions;
+	}
+	
 	/*
 	 *  Low-level API performing the actual compilation
 	 */
@@ -135,8 +146,9 @@
 		char[] contents,
 		Parser parser,
 		WorkingCopyOwner workingCopyOwner,
-		IProblemRequestor problemRequestor,
-		boolean resetEnvironment,
+		HashMap problems,
+		boolean creatingAST,
+		int reconcileFlags,
 		IProgressMonitor monitor)
 		throws JavaModelException {
 
@@ -150,7 +162,7 @@
 			problemFinder = new CompilationUnitProblemFinder(
 				environment,
 				getHandlingPolicy(),
-				project.getOptions(true),
+				getCompilerOptions(project.getOptions(true), creatingAST, ((reconcileFlags & ICompilationUnit.ENABLE_STATEMENTS_RECOVERY) != 0)),
 				getRequestor(),
 				problemFactory);
 			if (parser != null) {
@@ -179,7 +191,21 @@
 					true, // analyze code
 					true); // generate code
 			}
-			reportProblems(unit, problemRequestor, monitor);
+			CompilationResult unitResult = unit.compilationResult;
+			CategorizedProblem[] unitProblems = unitResult.getProblems();
+			int length = unitProblems == null ? 0 : unitProblems.length;
+			if (length > 0) {
+				CategorizedProblem[] categorizedProblems = new CategorizedProblem[length];
+				System.arraycopy(unitProblems, 0, categorizedProblems, 0, length);
+				problems.put(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, categorizedProblems);
+			}
+			unitProblems = unitResult.getTasks();
+			length = unitProblems == null ? 0 : unitProblems.length;
+			if (length > 0) {
+				CategorizedProblem[] categorizedProblems = new CategorizedProblem[length];
+				System.arraycopy(unitProblems, 0, categorizedProblems, 0, length);
+				problems.put(IJavaModelMarker.TASK_MARKER, categorizedProblems);
+			}
 			if (NameLookup.VERBOSE) {
 				System.out.println(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInSourcePackage: " + environment.nameLookup.timeSpentInSeekTypesInSourcePackage + "ms");  //$NON-NLS-1$ //$NON-NLS-2$
 				System.out.println(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInBinaryPackage: " + environment.nameLookup.timeSpentInSeekTypesInBinaryPackage + "ms");  //$NON-NLS-1$ //$NON-NLS-2$
@@ -189,7 +215,15 @@
 			throw e;
 		} catch(RuntimeException e) { 
 			// avoid breaking other tools due to internal compiler failure (40334)
-			Util.log(e, "Exception occurred during problem detection: "); //$NON-NLS-1$ 
+			String lineDelimiter = unitElement.findRecommendedLineSeparator();
+			StringBuffer message = new StringBuffer("Exception occurred during problem detection:");  //$NON-NLS-1$ 
+			message.append(lineDelimiter);
+			message.append("----------------------------------- SOURCE BEGIN -------------------------------------"); //$NON-NLS-1$
+			message.append(lineDelimiter);
+			message.append(contents);
+			message.append(lineDelimiter);
+			message.append("----------------------------------- SOURCE END -------------------------------------"); //$NON-NLS-1$
+			Util.log(e, message.toString());
 			throw new JavaModelException(e, IJavaModelStatusConstants.COMPILER_FAILURE);
 		} finally {
 			if (environment != null)
@@ -197,8 +231,8 @@
 			if (problemFactory != null)
 				problemFactory.monitor = null; // don't hold a reference to this external object
 			// NB: unit.cleanUp() is done by caller
-			if (problemFinder != null && resetEnvironment)
-				problemFinder.lookupEnvironment.reset();			
+			if (problemFinder != null && !creatingAST)
+				problemFinder.lookupEnvironment.reset();		
 		}
 	}
 
@@ -206,25 +240,13 @@
 		ICompilationUnit unitElement, 
 		char[] contents,
 		WorkingCopyOwner workingCopyOwner,
-		IProblemRequestor problemRequestor,
-		boolean resetEnvironment,
+		HashMap problems,
+		boolean creatingAST,
+		int reconcileFlags,
 		IProgressMonitor monitor)
 		throws JavaModelException {
 			
-		return process(null/*no CompilationUnitDeclaration*/, unitElement, contents, null/*use default Parser*/, workingCopyOwner, problemRequestor, resetEnvironment, monitor);
-	}
-
-	
-	private static void reportProblems(CompilationUnitDeclaration unit, IProblemRequestor problemRequestor, IProgressMonitor monitor) {
-		CompilationResult unitResult = unit.compilationResult;
-		IProblem[] problems = unitResult.getAllProblems();
-		for (int i = 0, problemLength = problems == null ? 0 : problems.length; i < problemLength; i++) {
-			if (JavaModelManager.VERBOSE){
-				System.out.println("PROBLEM FOUND while reconciling : "+problems[i].getMessage());//$NON-NLS-1$
-			}
-			if (monitor != null && monitor.isCanceled()) break;
-			problemRequestor.acceptProblem(problems[i]);				
-		}
+		return process(null/*no CompilationUnitDeclaration*/, unitElement, contents, null/*use default Parser*/, workingCopyOwner, problems, creatingAST, reconcileFlags, monitor);
 	}
 
 	/* (non-Javadoc)
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 a455ef8..1241703 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,13 +10,14 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.Map;
 import java.util.Stack;
 
+import org.eclipse.core.runtime.Assert;
 import org.eclipse.jdt.core.*;
-import org.eclipse.jdt.core.ICompilationUnit;
-import org.eclipse.jdt.core.IJavaElement;
-import org.eclipse.jdt.core.Signature;
+import org.eclipse.jdt.core.compiler.CategorizedProblem;
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.compiler.IProblem;
 import org.eclipse.jdt.internal.compiler.ISourceElementRequestor;
@@ -59,6 +60,12 @@
 	 * will be the type the method is contained in.
 	 */
 	protected Stack infoStack;
+	
+	/*
+	 * Map from JavaElementInfo to of ArrayList of IJavaElement representing the children 
+	 * of the given info.
+	 */
+	protected HashMap children;
 
 	/**
 	 * Stack of parent handles, corresponding to the info stack. We
@@ -86,7 +93,6 @@
 	/**
 	 * Empty collections used for efficient initialization
 	 */
-	protected static String[] NO_STRINGS = new String[0];
 	protected static byte[] NO_BYTES= new byte[]{};
 
 	protected HashtableOfObject fieldRefCache;
@@ -102,8 +108,7 @@
 /**
  * @see ISourceElementRequestor
  */
-public void acceptImport(int declarationStart, int declarationEnd, char[] name, boolean onDemand, int modifiers) {
-	JavaElementInfo parentInfo = (JavaElementInfo) this.infoStack.peek();
+public void acceptImport(int declarationStart, int declarationEnd, char[][] tokens, boolean onDemand, int modifiers) {
 	JavaElement parentHandle= (JavaElement) this.handleStack.peek();
 	if (!(parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT)) {
 		Assert.isTrue(false); // Should not happen
@@ -113,12 +118,13 @@
 	//create the import container and its info
 	ImportContainer importContainer= (ImportContainer)parentCU.getImportContainer();
 	if (this.importContainerInfo == null) {
-		this.importContainerInfo= new JavaElementInfo();
-		parentInfo.addChild(importContainer);
+		this.importContainerInfo = new JavaElementInfo();
+		JavaElementInfo parentInfo = (JavaElementInfo) this.infoStack.peek();
+		addToChildren(parentInfo, importContainer);
 		this.newElements.put(importContainer, this.importContainerInfo);
 	}
 	
-	String elementName = JavaModelManager.getJavaModelManager().intern(new String(name));
+	String elementName = JavaModelManager.getJavaModelManager().intern(new String(CharOperation.concatWith(tokens, '.')));
 	ImportDeclaration handle = new ImportDeclaration(importContainer, elementName, onDemand);
 	resolveDuplicates(handle);
 	
@@ -127,7 +133,7 @@
 	info.setSourceRangeEnd(declarationEnd);
 	info.setFlags(modifiers);
 
-	this.importContainerInfo.addChild(handle);
+	addToChildren(this.importContainerInfo, handle);
 	this.newElements.put(handle, info);
 }
 /*
@@ -161,25 +167,31 @@
 		info.setSourceRangeStart(declarationStart);
 		info.setSourceRangeEnd(declarationEnd);
 
-		parentInfo.addChild(handle);
+		addToChildren(parentInfo, handle);
 		this.newElements.put(handle, info);
 
 }
-public void acceptProblem(IProblem problem) {
+public void acceptProblem(CategorizedProblem problem) {
 	if ((problem.getID() & IProblem.Syntax) != 0){
 		this.hasSyntaxErrors = true;
 	}
 }
+private void addToChildren(JavaElementInfo parentInfo, JavaElement handle) {
+	ArrayList childrenList = (ArrayList) this.children.get(parentInfo);
+	if (childrenList == null)
+		this.children.put(parentInfo, childrenList = new ArrayList());
+	childrenList.add(handle);
+}
 /**
  * Convert these type names to signatures.
  * @see Signature
  */
 /* default */ static String[] convertTypeNamesToSigs(char[][] typeNames) {
 	if (typeNames == null)
-		return NO_STRINGS;
+		return CharOperation.NO_STRINGS;
 	int n = typeNames.length;
 	if (n == 0)
-		return NO_STRINGS;
+		return CharOperation.NO_STRINGS;
 	JavaModelManager manager = JavaModelManager.getJavaModelManager();
 	String[] typeSigs = new String[n];
 	for (int i = 0; i < n; ++i) {
@@ -192,6 +204,7 @@
  */
 public void enterCompilationUnit() {
 	this.infoStack = new Stack();
+	this.children = new HashMap();
 	this.handleStack= new Stack();
 	this.infoStack.push(this.unitInfo);
 	this.handleStack.push(this.unit);
@@ -229,7 +242,8 @@
 	
 	this.unitInfo.addAnnotationPositions(handle, fieldInfo.annotationPositions);
 
-	parentInfo.addChild(handle);
+	addToChildren(parentInfo, handle);
+	parentInfo.addCategories(handle, fieldInfo.categories);
 	this.newElements.put(handle, info);
 
 	this.infoStack.push(info);
@@ -257,7 +271,7 @@
 		info.setSourceRangeStart(declarationSourceStart);
 		info.setFlags(modifiers);
 
-		parentInfo.addChild(handle);
+		addToChildren(parentInfo, handle);
 		this.newElements.put(handle, info);
 
 		this.infoStack.push(info);
@@ -317,7 +331,8 @@
 	for (int i = 0, length = exceptionTypes.length; i < length; i++)
 		exceptionTypes[i] = manager.intern(exceptionTypes[i]);
 	this.unitInfo.addAnnotationPositions(handle, methodInfo.annotationPositions);
-	parentInfo.addChild(handle);
+	addToChildren(parentInfo, handle);
+	parentInfo.addCategories(handle, methodInfo.categories);
 	this.newElements.put(handle, info);
 	this.infoStack.push(info);
 	this.handleStack.push(handle);
@@ -338,10 +353,17 @@
 	JavaElementInfo parentInfo = (JavaElementInfo) this.infoStack.peek();
 	JavaElement parentHandle= (JavaElement) this.handleStack.peek();
 	String nameString= new String(typeInfo.name);
-	SourceType handle = handle = new SourceType(parentHandle, nameString); //NB: occurenceCount is computed in resolveDuplicates
+	SourceType handle = new SourceType(parentHandle, nameString); //NB: occurenceCount is computed in resolveDuplicates
 	resolveDuplicates(handle);
 	
-	SourceTypeElementInfo info = new SourceTypeElementInfo();
+	SourceTypeElementInfo info = 
+		typeInfo.anonymousMember ? 
+			new SourceTypeElementInfo() {
+				public boolean isAnonymousMember() {
+					return true;
+				}
+			} : 
+		new SourceTypeElementInfo();
 	info.setHandle(handle);
 	info.setSourceRangeStart(typeInfo.declarationStart);
 	info.setFlags(typeInfo.modifiers);
@@ -354,7 +376,10 @@
 	for (int i = 0, length = superinterfaces == null ? 0 : superinterfaces.length; i < length; i++)
 		superinterfaces[i] = manager.intern(superinterfaces[i]);
 	info.setSuperInterfaceNames(superinterfaces);
-	parentInfo.addChild(handle);
+	info.addCategories(handle, typeInfo.categories);
+	if (parentHandle.getElementType() == IJavaElement.TYPE)
+		((SourceTypeElementInfo) parentInfo).addCategories(handle, typeInfo.categories);
+	addToChildren(parentInfo, handle);
 	this.unitInfo.addAnnotationPositions(handle, typeInfo.annotationPositions);
 	this.newElements.put(handle, info);
 	this.infoStack.push(info);
@@ -372,7 +397,7 @@
 	JavaElementInfo parentInfo = (JavaElementInfo) this.infoStack.peek();
 	JavaElement parentHandle = (JavaElement) this.handleStack.peek();
 	String nameString = new String(typeParameterInfo.name);
-	TypeParameter handle = handle = new TypeParameter(parentHandle, nameString); //NB: occurenceCount is computed in resolveDuplicates
+	TypeParameter handle = new TypeParameter(parentHandle, nameString); //NB: occurenceCount is computed in resolveDuplicates
 	resolveDuplicates(handle);
 	
 	TypeParameterElementInfo info = new TypeParameterElementInfo();
@@ -404,6 +429,14 @@
  * @see ISourceElementRequestor
  */
 public void exitCompilationUnit(int declarationEnd) {
+	// set import container children
+	if (this.importContainerInfo != null) {
+		setChildren(this.importContainerInfo);
+	}
+	
+	// set children
+	setChildren(this.unitInfo);
+	
 	this.unitInfo.setSourceLength(declarationEnd + 1);
 
 	// determine if there were any parsing errors
@@ -421,6 +454,7 @@
 public void exitField(int initializationStart, int declarationEnd, int declarationSourceEnd) {
 	SourceFieldElementInfo info = (SourceFieldElementInfo) this.infoStack.pop();
 	info.setSourceRangeEnd(declarationSourceEnd);
+	setChildren(info);
 	
 	// remember initializer source if field is a constant
 	if (initializationStart != -1) {
@@ -451,6 +485,7 @@
 protected void exitMember(int declarationEnd) {
 	SourceRefElementInfo info = (SourceRefElementInfo) this.infoStack.pop();
 	info.setSourceRangeEnd(declarationEnd);
+	setChildren(info);
 	this.handleStack.pop();
 }
 /**
@@ -459,6 +494,7 @@
 public void exitMethod(int declarationEnd, int defaultValueStart, int defaultValueEnd) {
 	SourceMethodElementInfo info = (SourceMethodElementInfo) this.infoStack.pop();
 	info.setSourceRangeEnd(declarationEnd);
+	setChildren(info);
 	
 	// remember default value of annotation method
 	if (info.isAnnotationMethod()) {
@@ -484,4 +520,13 @@
 		handle.occurrenceCount++;
 	}
 }
+private void setChildren(JavaElementInfo info) {
+	ArrayList childrenList = (ArrayList) this.children.get(info);
+	if (childrenList != null) {
+		int length = childrenList.size();
+		IJavaElement[] elements = new IJavaElement[length];
+		childrenList.toArray(elements);
+		info.children = elements;
+	}
+}
 }
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
deleted file mode 100644
index f61263f..0000000
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitVisitor.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core;
-
-import java.util.Locale;
-import java.util.Map;
-
-import org.eclipse.jdt.core.ICompilationUnit;
-import org.eclipse.jdt.core.IJavaElement;
-import org.eclipse.jdt.core.JavaModelException;
-import org.eclipse.jdt.core.compiler.IProblem;
-import org.eclipse.jdt.internal.compiler.CompilationResult;
-import org.eclipse.jdt.internal.compiler.Compiler;
-import org.eclipse.jdt.internal.compiler.ASTVisitor;
-import org.eclipse.jdt.internal.compiler.ICompilerRequestor;
-import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
-import org.eclipse.jdt.internal.compiler.IProblemFactory;
-import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
-import org.eclipse.jdt.internal.compiler.env.AccessRestriction;
-import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
-import org.eclipse.jdt.internal.compiler.env.ISourceType;
-import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
-import org.eclipse.jdt.internal.compiler.parser.SourceTypeConverter;
-import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
-import org.eclipse.jdt.internal.core.util.Util;
-
-public class CompilationUnitVisitor extends Compiler {
-	
-	/**
-	 * Answer a new CompilationUnitVisitor using the given name environment and compiler options.
-	 * The environment and options will be in effect for the lifetime of the compiler.
-	 * When the compiler is run, compilation results are sent to the given requestor.
-	 *
-	 *  @param environment org.eclipse.jdt.internal.compiler.api.env.INameEnvironment
-	 *      Environment used by the compiler in order to resolve type and package
-	 *      names. The name environment implements the actual connection of the compiler
-	 *      to the outside world (e.g. in batch mode the name environment is performing
-	 *      pure file accesses, reuse previous build state or connection to repositories).
-	 *      Note: the name environment is responsible for implementing the actual classpath
-	 *            rules.
-	 *
-	 *  @param policy org.eclipse.jdt.internal.compiler.api.problem.IErrorHandlingPolicy
-	 *      Configurable part for problem handling, allowing the compiler client to
-	 *      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.DefaultErrorHandlingPolicies
-	 *      
-	 *  @param requestor org.eclipse.jdt.internal.compiler.api.ICompilerRequestor
-	 *      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.CompilationResult
-	 *
-	 *  @param problemFactory org.eclipse.jdt.internal.compiler.api.problem.IProblemFactory
-	 *      Factory used inside the compiler to create problem descriptors. It allows the
-	 *      compiler client to supply its own representation of compilation problems in
-	 *      order to avoid object conversions. Note that the factory is not supposed
-	 *      to accumulate the created problems, the compiler will gather them all and hand
-	 *      them back as part of the compilation unit result.
-	 */
-	public CompilationUnitVisitor(
-		INameEnvironment environment,
-		IErrorHandlingPolicy policy,
-		Map settings,
-		ICompilerRequestor requestor,
-		IProblemFactory problemFactory) {
-
-		super(environment, policy, settings, requestor, problemFactory);
-	}
-
-	/**
-	 * Add additional source types
-	 */
-	public void accept(ISourceType[] sourceTypes, PackageBinding packageBinding, AccessRestriction accessRestriction) {
-		CompilationResult result =
-			new CompilationResult(sourceTypes[0].getFileName(), 1, 1, this.options.maxProblemsPerUnit);
-		// need to hold onto this
-		CompilationUnitDeclaration unit =
-			SourceTypeConverter.buildCompilationUnit(
-				sourceTypes,//sourceTypes[0] is always toplevel here
-				SourceTypeConverter.FIELD_AND_METHOD // need field and methods
-				| SourceTypeConverter.MEMBER_TYPE, // need member types
-				// no need for field initialization
-				this.lookupEnvironment.problemReporter,
-				result);
-
-		if (unit != null) {
-			this.lookupEnvironment.buildTypeBindings(unit, accessRestriction);
-			this.lookupEnvironment.completeTypeBindings(unit, true);
-		}
-	}
-
-	/*
-	 *  Low-level API performing the actual compilation
-	 */
-	protected static IErrorHandlingPolicy getHandlingPolicy() {
-
-		// passes the initial set of files to the batch oracle (to avoid finding more than once the same units when case insensitive match)	
-		return new IErrorHandlingPolicy() {
-			public boolean stopOnFirstError() {
-				return false;
-			}
-			public boolean proceedOnErrors() {
-				return false; // stop if there are some errors 
-			}
-		};
-	}
-
-	/*
-	 * Answer the component to which will be handed back compilation results from the compiler
-	 */
-	protected static ICompilerRequestor getRequestor() {
-		return new ICompilerRequestor() {
-			public void acceptResult(CompilationResult compilationResult) {
-				// nothing to do
-			}
-		};
-	}
-
-	public static void visit(
-		ICompilationUnit unitElement,
-		ASTVisitor visitor)
-		throws JavaModelException {
-
-		JavaProject project = (JavaProject) unitElement.getJavaProject();
-		CompilationUnitVisitor compilationUnitVisitor =
-			new CompilationUnitVisitor(
-				project.newSearchableNameEnvironment(unitElement.getOwner()),
-				getHandlingPolicy(),
-				project.getOptions(true),
-				getRequestor(),
-				getProblemFactory(visitor));
-
-		CompilationUnitDeclaration unit = null;
-		try {
-
-			PackageFragment packageFragment = (PackageFragment)unitElement.getAncestor(IJavaElement.PACKAGE_FRAGMENT);
-			char[][] expectedPackageName = null;
-			if (packageFragment != null){
-				expectedPackageName = Util.toCharArrays(packageFragment.names);
-			}
-			unit =
-				compilationUnitVisitor.resolve(
-					new BasicCompilationUnit(
-						unitElement.getSource().toCharArray(),
-						expectedPackageName,
-						unitElement.getElementName(),
-						unitElement),
-					true, // method verification
-					false, // no flow analysis
-					false); // no code generation
-			if (unit != null) {
-				unit.traverse(visitor, unit.scope);
-			}
-		} finally {
-			if (unit != null) {
-				unit.cleanUp();
-			}
-		}
-	}
-
-	protected static IProblemFactory getProblemFactory(final ASTVisitor visitor) {
-
-		return new DefaultProblemFactory(Locale.getDefault()) {
-			public IProblem createProblem(
-				char[] originatingFileName,
-				int problemId,
-				String[] problemArguments,
-				String[] messageArguments,
-				int severity,
-				int startPosition,
-				int endPosition,
-				int lineNumber) {
-
-				IProblem problem =
-					super.createProblem(
-						originatingFileName,
-						problemId,
-						problemArguments,
-						messageArguments,
-						severity,
-						startPosition,
-						endPosition,
-						lineNumber);
-				visitor.acceptProblem(problem);
-				return problem;
-			}
-		};
-	}
-}
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 c93e061..d1524eb 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -15,6 +15,7 @@
 
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IImportDeclaration;
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.IJavaModelStatus;
 import org.eclipse.jdt.core.IJavaModelStatusConstants;
@@ -95,12 +96,13 @@
 			case IJavaElement.PACKAGE_DECLARATION :
 				return new CreatePackageDeclarationOperation(element.getElementName(), (ICompilationUnit) dest);
 			case IJavaElement.IMPORT_DECLARATION :
-				return new CreateImportOperation(element.getElementName(), (ICompilationUnit) dest);
+				IImportDeclaration importDeclaration = (IImportDeclaration) element;
+				return new CreateImportOperation(element.getElementName(), (ICompilationUnit) dest, importDeclaration.getFlags());
 			case IJavaElement.TYPE :
 				if (isRenamingMainType(element, dest)) {
 					IPath path = element.getPath();
 					String extension = path.getFileExtension();
-					return new RenameResourceElementsOperation(new IJavaElement[] {dest}, new IJavaElement[] {dest.getParent()}, new String[]{getNewNameFor(element) + '.' + extension}, this.force); //$NON-NLS-1$
+					return new RenameResourceElementsOperation(new IJavaElement[] {dest}, new IJavaElement[] {dest.getParent()}, new String[]{getNewNameFor(element) + '.' + extension}, this.force);
 				} else {
 					String source = getSourceFor(element);
 					String lineSeparator = org.eclipse.jdt.internal.core.util.Util.getLineSeparator(source, element.getJavaProject());
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 d0698df..cfec9ba 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -11,15 +11,10 @@
 package org.eclipse.jdt.internal.core;
 
 import org.eclipse.core.resources.*;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.IResource;
-import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.AssertionFailedException;
 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.IJavaModelStatus;
-import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.internal.core.util.Messages;
 
 public class CopyPackageFragmentRootOperation extends JavaModelOperation {
@@ -129,7 +124,7 @@
 				throw new JavaModelException(e);
 			}
 		}
-		this.setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); 
+		setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); 
 	}
 	protected void addEntryToClasspath(IClasspathEntry rootEntry, IWorkspaceRoot workspaceRoot) throws JavaModelException {
 		
@@ -193,7 +188,7 @@
 			case IClasspathEntry.CPE_LIBRARY:
 				try {
 					return JavaCore.newLibraryEntry(this.destination, entry.getSourceAttachmentPath(), entry.getSourceAttachmentRootPath(), entry.getAccessRules(), entry.getExtraAttributes(), entry.isExported());
-				} catch (Assert.AssertionFailedException e) {
+				} catch (AssertionFailedException e) {
 					IJavaModelStatus status = new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, e.getMessage());
 					throw new JavaModelException(status);
 				}
@@ -204,7 +199,7 @@
 			case IClasspathEntry.CPE_VARIABLE:
 				try {
 					return JavaCore.newVariableEntry(entry.getPath(), entry.getSourceAttachmentPath(), entry.getSourceAttachmentRootPath(), entry.getAccessRules(), entry.getExtraAttributes(), entry.isExported());
-				} catch (Assert.AssertionFailedException e) {
+				} catch (AssertionFailedException e) {
 					IJavaModelStatus status = new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, e.getMessage());
 					throw new JavaModelException(status);
 				}
@@ -249,7 +244,7 @@
 						}
 					}
 					if (this.sibling != null && !foundSibling) {
-						return new JavaModelStatus(IJavaModelStatusConstants.INVALID_SIBLING, this.sibling == null ? "null" : this.sibling.toString()); //$NON-NLS-1$
+						return new JavaModelStatus(IJavaModelStatusConstants.INVALID_SIBLING, this.sibling.toString());
 					}
 					if (foundExistingEntry && (this.updateModelFlags & IPackageFragmentRoot.REPLACE) == 0) {
 						return new JavaModelStatus(
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 cc3c386..6eca474 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -247,27 +247,31 @@
 		org.eclipse.jdt.internal.core.CompilationUnit destCU = new org.eclipse.jdt.internal.core.CompilationUnit(dest, destName, DefaultWorkingCopyOwner.PRIMARY);
 		if (!destFile.equals(sourceResource)) {
 			try {
-				if (destFile.exists()) {
-					if (this.force) {
-						// we can remove it
-						deleteResource(destFile, IResource.KEEP_HISTORY);
-						destCU.close(); // ensure the in-memory buffer for the dest CU is closed
-					} else {
-						// abort
-						throw new JavaModelException(new JavaModelStatus(
-							IJavaModelStatusConstants.NAME_COLLISION, 
-							Messages.bind(Messages.status_nameCollision, destFile.getFullPath().toString()))); 
+				if (!destCU.isWorkingCopy()) {
+					if (destFile.exists()) {
+						if (this.force) {
+							// we can remove it
+							deleteResource(destFile, IResource.KEEP_HISTORY);
+							destCU.close(); // ensure the in-memory buffer for the dest CU is closed
+						} else {
+							// abort
+							throw new JavaModelException(new JavaModelStatus(
+								IJavaModelStatusConstants.NAME_COLLISION, 
+								Messages.bind(Messages.status_nameCollision, destFile.getFullPath().toString()))); 
+						}
 					}
-				}
-				int flags = this.force ? IResource.FORCE : IResource.NONE;
-				if (this.isMove()) {
-					flags |= IResource.KEEP_HISTORY;
-					sourceResource.move(destFile.getFullPath(), flags, getSubProgressMonitor(1));
+					int flags = this.force ? IResource.FORCE : IResource.NONE;
+					if (this.isMove()) {
+						flags |= IResource.KEEP_HISTORY;
+						sourceResource.move(destFile.getFullPath(), flags, getSubProgressMonitor(1));
+					} else {
+						if (rewrite != null) flags |= IResource.KEEP_HISTORY;
+						sourceResource.copy(destFile.getFullPath(), flags, getSubProgressMonitor(1));
+					}
+					setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); 
 				} else {
-					if (rewrite != null) flags |= IResource.KEEP_HISTORY;
-					sourceResource.copy(destFile.getFullPath(), flags, getSubProgressMonitor(1));
+					destCU.getBuffer().setContents(source.getBuffer().getContents());
 				}
-				this.setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); 
 			} catch (JavaModelException e) {
 				throw e;
 			} catch (CoreException e) {
@@ -304,13 +308,8 @@
 			// update new resource content
 			// in case we do a saveas on the same resource we have to simply update the contents
 			// see http://dev.eclipse.org/bugs/show_bug.cgi?id=9351
-			try {
-				if (rewrite != null){
-					saveContent(dest, destName, rewrite, sourceEncoding, destFile);
-				}
-			} catch (CoreException e) {
-				if (e instanceof JavaModelException) throw (JavaModelException) e;
-				throw new JavaModelException(e);
+			if (rewrite != null){
+				saveContent(dest, destName, rewrite, sourceEncoding, destFile);
 			}
 		}
 	}
@@ -405,7 +404,7 @@
 				if (sourceIsReadOnly) {
 					Util.setReadOnly(srcFolder, true);
 				}
-				this.setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); 
+				setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); 
 			} else {
 				// process the leaf resources
 				if (resources.length > 0) {
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 f05a7d7..f84a048 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -15,9 +15,6 @@
 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;
@@ -29,9 +26,10 @@
 import org.eclipse.jdt.core.IJavaElementDelta;
 import org.eclipse.jdt.core.IJavaModelStatus;
 import org.eclipse.jdt.core.IJavaModelStatusConstants;
+import org.eclipse.jdt.core.IJavaProject;
 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.Messages;
 import org.eclipse.jdt.internal.core.util.Util;
@@ -163,7 +161,8 @@
 	if (getParentElement() == null) {
 		return new JavaModelStatus(IJavaModelStatusConstants.NO_ELEMENTS_TO_PROCESS);
 	}
-	if (JavaConventions.validateCompilationUnitName(fName).getSeverity() == IStatus.ERROR) {
+	IJavaProject project = getParentElement().getJavaProject();
+	if (JavaConventions.validateCompilationUnitName(fName, project.getOption(JavaCore.COMPILER_SOURCE, true), project.getOption(JavaCore.COMPILER_COMPLIANCE, true)).getSeverity() == IStatus.ERROR) {
 		return new JavaModelStatus(IJavaModelStatusConstants.INVALID_NAME, fName);
 	}
 	if (fSource == null) {
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 c996a59..acd4b72 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,6 +10,8 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
+import java.util.Map;
+
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.resources.IWorkspace;
 import org.eclipse.core.runtime.jobs.ISchedulingRule;
@@ -91,8 +93,8 @@
 		super(null, new IJavaElement[]{parentElement});
 		initializeDefaultPosition();
 	}
-	protected void apply(ASTRewrite rewriter, IDocument document) throws JavaModelException {
-		TextEdit edits = rewriter.rewriteAST(document, null);
+	protected void apply(ASTRewrite rewriter, IDocument document, Map options) throws JavaModelException {
+		TextEdit edits = rewriter.rewriteAST(document, options);
  		try {
 	 		edits.apply(document);
  		} catch (BadLocationException e) {
@@ -140,7 +142,7 @@
 				unit.save(null, false);
 				boolean isWorkingCopy = unit.isWorkingCopy();
 				if (!isWorkingCopy)
-					this.setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE);
+					setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE);
 				worked(1);
 				resultElements = generateResultHandles();
 				if (!isWorkingCopy // if unit is working copy, then save will have already fired the delta
@@ -182,7 +184,7 @@
 			if (parent == null)
 				parent = this.cuAST;
 			insertASTNode(rewriter, parent, child);
-			apply(rewriter, document);
+			apply(rewriter, document, cu.getJavaProject().getOptions(true));
 		}
 		worked(1);
 	}
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 b47da45..5eaecce 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,6 +10,8 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
+import java.util.Iterator;
+
 import org.eclipse.jdt.core.ICompilationUnit;
 import org.eclipse.jdt.core.IField;
 import org.eclipse.jdt.core.IJavaElement;
@@ -64,6 +66,22 @@
 public String getMainTaskName(){
 	return Messages.operation_createFieldProgress; 
 }
+private VariableDeclarationFragment getFragment(ASTNode node) {
+	Iterator fragments =  ((FieldDeclaration) node).fragments().iterator();
+	if (this.anchorElement != null) {
+		VariableDeclarationFragment fragment = null;
+		String fragmentName = this.anchorElement.getElementName();
+		while (fragments.hasNext()) {
+			fragment = (VariableDeclarationFragment) fragments.next();
+			if (fragment.getName().getIdentifier().equals(fragmentName)) {
+				return fragment;
+			}
+		}
+		return fragment;
+	} else {
+		return (VariableDeclarationFragment) fragments.next();
+	}
+}
 /**
  * By default the new field is positioned after the last existing field
  * declaration, or as the first member in the type if there are no
@@ -109,11 +127,11 @@
 	return JavaModelStatus.VERIFIED_OK;
 }
 private String getASTNodeName() {
-	VariableDeclarationFragment fragment = (VariableDeclarationFragment) ((FieldDeclaration) this.createdNode).fragments().iterator().next();
-	return fragment.getName().getIdentifier();
+	if (this.alteredName != null) return this.alteredName;
+	return getFragment(this.createdNode).getName().getIdentifier();
 }
 protected SimpleName rename(ASTNode node, SimpleName newName) {
-	VariableDeclarationFragment fragment = (VariableDeclarationFragment) ((FieldDeclaration) node).fragments().iterator().next();
+	VariableDeclarationFragment fragment = getFragment(node);
 	SimpleName oldName = fragment.getName();
 	fragment.setName(newName);
 	return oldName;
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 44cc371..362fb57 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -13,13 +13,16 @@
 import java.util.Iterator;
 
 import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jdt.core.Flags;
 import org.eclipse.jdt.core.ICompilationUnit;
 import org.eclipse.jdt.core.IImportDeclaration;
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.IJavaModelStatus;
 import org.eclipse.jdt.core.IJavaModelStatusConstants;
+import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.JavaConventions;
+import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.dom.AST;
@@ -52,16 +55,23 @@
  */
 public class CreateImportOperation extends CreateElementInCUOperation {
 
-	/**
+	/*
 	 * The name of the import to be created.
 	 */
 	protected String importName;
+	
+	/*
+	 * The flags of the import to be created (either Flags#AccDefault or Flags#AccStatic)
+	 */
+	protected int flags;
+
 /**
  * When executed, this operation will add an import to the given compilation unit.
  */
-public CreateImportOperation(String importName, ICompilationUnit parentElement) {
+public CreateImportOperation(String importName, ICompilationUnit parentElement, int flags) {
 	super(parentElement);
 	this.importName = importName;
+	this.flags = flags;
 }
 protected StructuralPropertyDescriptor getChildPropertyDescriptor(ASTNode parent) {
 	return CompilationUnit.IMPORTS_PROPERTY;
@@ -69,10 +79,16 @@
 protected ASTNode generateElementAST(ASTRewrite rewriter, IDocument document, ICompilationUnit cu) throws JavaModelException {
 	// ensure no duplicate
 	Iterator imports = this.cuAST.imports().iterator();
+	boolean onDemand = this.importName.endsWith(".*"); //$NON-NLS-1$
+	String importActualName = this.importName;
+	if (onDemand) {
+		importActualName = this.importName.substring(0, this.importName.length() - 2);
+	}
 	while (imports.hasNext()) {
 		ImportDeclaration importDeclaration = (ImportDeclaration) imports.next();
-		if (this.importName.equals(importDeclaration.getName().getFullyQualifiedName())) {
-			//no new import was generated
+		if (importActualName.equals(importDeclaration.getName().getFullyQualifiedName())
+				&& (onDemand == importDeclaration.isOnDemand())
+				&& (Flags.isStatic(this.flags) == importDeclaration.isStatic())) {
 			this.creationOccurred = false;
 			return null;
 		}
@@ -80,9 +96,9 @@
 	
 	AST ast = this.cuAST.getAST();
 	ImportDeclaration importDeclaration = ast.newImportDeclaration();
+	importDeclaration.setStatic(Flags.isStatic(this.flags));
 	// split import name into individual fragments, checking for on demand imports
-	boolean onDemand = this.importName.endsWith("*"); //$NON-NLS-1$
-	char[][] charFragments = CharOperation.splitOn('.', this.importName.toCharArray(), 0, onDemand ? this.importName.length()-2 : this.importName.length());
+	char[][] charFragments = CharOperation.splitOn('.', importActualName.toCharArray(), 0, importActualName.length());
 	int length = charFragments.length;
 	String[] strFragments = new String[length];
 	for (int i = 0; i < length; i++) {
@@ -151,7 +167,8 @@
 	if (!status.isOK()) {
 		return status;
 	}
-	if (JavaConventions.validateImportDeclaration(this.importName).getSeverity() == IStatus.ERROR) {
+	IJavaProject project = getParentElement().getJavaProject();
+	if (JavaConventions.validateImportDeclaration(this.importName, project.getOption(JavaCore.COMPILER_SOURCE, true), project.getOption(JavaCore.COMPILER_COMPLIANCE, true)).getSeverity() == IStatus.ERROR) {
 		return new JavaModelStatus(IJavaModelStatusConstants.INVALID_NAME, this.importName);
 	}
 	return JavaModelStatus.VERIFIED_OK;
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 9265806..af4fd26 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -16,8 +16,10 @@
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.IJavaModelStatus;
 import org.eclipse.jdt.core.IJavaModelStatusConstants;
+import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.JavaConventions;
+import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.dom.AST;
 import org.eclipse.jdt.core.dom.ASTNode;
@@ -120,7 +122,8 @@
 	if (!status.isOK()) {
 		return status;
 	}
-	if (JavaConventions.validatePackageName(this.name).getSeverity() == IStatus.ERROR) {
+	IJavaProject project = getParentElement().getJavaProject();
+	if (JavaConventions.validatePackageName(this.name, project.getOption(JavaCore.COMPILER_SOURCE, true), project.getOption(JavaCore.COMPILER_COMPLIANCE, true)).getSeverity() == IStatus.ERROR) {
 		return new JavaModelStatus(IJavaModelStatusConstants.INVALID_NAME, this.name);
 	}
 	return JavaModelStatus.VERIFIED_OK;
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 fa757f5..d186a90 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -19,9 +19,11 @@
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.IJavaModelStatus;
 import org.eclipse.jdt.core.IJavaModelStatusConstants;
+import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.IPackageFragment;
 import org.eclipse.jdt.core.IPackageFragmentRoot;
 import org.eclipse.jdt.core.JavaConventions;
+import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.core.util.Messages;
@@ -67,43 +69,46 @@
  * @exception JavaModelException if the operation is unable to complete
  */
 protected void executeOperation() throws JavaModelException {
-	JavaElementDelta delta = null;
-	PackageFragmentRoot root = (PackageFragmentRoot) getParentElement();
-	beginTask(Messages.operation_createPackageFragmentProgress, this.pkgName.length); 
-	IContainer parentFolder = (IContainer) root.getResource();
-	String[] sideEffectPackageName = CharOperation.NO_STRINGS; 
-	ArrayList results = new ArrayList(this.pkgName.length);
-	char[][] inclusionPatterns = root.fullInclusionPatternChars();
-	char[][] exclusionPatterns = root.fullExclusionPatternChars();
-	int i;
-	for (i = 0; i < this.pkgName.length; i++) {
-		String subFolderName = this.pkgName[i];
-		sideEffectPackageName = Util.arrayConcat(sideEffectPackageName, subFolderName);
-		IResource subFolder = parentFolder.findMember(subFolderName);
-		if (subFolder == null) {
-			createFolder(parentFolder, subFolderName, force);
-			parentFolder = parentFolder.getFolder(new Path(subFolderName));
-			IPackageFragment addedFrag = root.getPackageFragment(sideEffectPackageName);
-			if (!Util.isExcluded(parentFolder, inclusionPatterns, exclusionPatterns)) {
-				if (delta == null) {
-					delta = newJavaElementDelta();
+	try {
+		JavaElementDelta delta = null;
+		PackageFragmentRoot root = (PackageFragmentRoot) getParentElement();
+		beginTask(Messages.operation_createPackageFragmentProgress, this.pkgName.length); 
+		IContainer parentFolder = (IContainer) root.getResource();
+		String[] sideEffectPackageName = CharOperation.NO_STRINGS; 
+		ArrayList results = new ArrayList(this.pkgName.length);
+		char[][] inclusionPatterns = root.fullInclusionPatternChars();
+		char[][] exclusionPatterns = root.fullExclusionPatternChars();
+		int i;
+		for (i = 0; i < this.pkgName.length; i++) {
+			String subFolderName = this.pkgName[i];
+			sideEffectPackageName = Util.arrayConcat(sideEffectPackageName, subFolderName);
+			IResource subFolder = parentFolder.findMember(subFolderName);
+			if (subFolder == null) {
+				createFolder(parentFolder, subFolderName, force);
+				parentFolder = parentFolder.getFolder(new Path(subFolderName));
+				IPackageFragment addedFrag = root.getPackageFragment(sideEffectPackageName);
+				if (!Util.isExcluded(parentFolder, inclusionPatterns, exclusionPatterns)) {
+					if (delta == null) {
+						delta = newJavaElementDelta();
+					}
+					delta.added(addedFrag);
 				}
-				delta.added(addedFrag);
+				results.add(addedFrag);
+			} else {
+				parentFolder = (IContainer) subFolder;
 			}
-			results.add(addedFrag);
-		} else {
-			parentFolder = (IContainer) subFolder;
+			worked(1);
 		}
-		worked(1);
-	}
-	if (results.size() > 0) {
-		this.resultElements = new IJavaElement[results.size()];
-		results.toArray(this.resultElements);
-		if (delta != null) {
-			addDelta(delta);
+		if (results.size() > 0) {
+			this.resultElements = new IJavaElement[results.size()];
+			results.toArray(this.resultElements);
+			if (delta != null) {
+				addDelta(delta);
+			}
 		}
+	} finally {
+		done();
 	}
-	done();
 }
 /**
  * Possible failures: <ul>
@@ -120,12 +125,14 @@
  * @see JavaConventions
  */
 public IJavaModelStatus verify() {
-	if (getParentElement() == null) {
+	IJavaElement parentElement = getParentElement();
+	if (parentElement == null) {
 		return new JavaModelStatus(IJavaModelStatusConstants.NO_ELEMENTS_TO_PROCESS);
 	}
 	
 	String packageName = this.pkgName == null ? null : Util.concatWith(this.pkgName, '.');
-	if (this.pkgName == null || (this.pkgName.length > 0 && JavaConventions.validatePackageName(packageName).getSeverity() == IStatus.ERROR)) {
+	IJavaProject project = parentElement.getJavaProject();
+	if (this.pkgName == null || (this.pkgName.length > 0 && JavaConventions.validatePackageName(packageName, project.getOption(JavaCore.COMPILER_SOURCE, true), project.getOption(JavaCore.COMPILER_COMPLIANCE, true)).getSeverity() == IStatus.ERROR)) {
 		return new JavaModelStatus(IJavaModelStatusConstants.INVALID_NAME, packageName);
 	}
 	IPackageFragmentRoot root = (IPackageFragmentRoot) getParentElement();
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 bdf6a41..d5dc7fd 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -30,7 +30,8 @@
 import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor;
 import org.eclipse.jdt.core.dom.TypeDeclaration;
 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
-import org.eclipse.jdt.internal.core.dom.rewrite.Indents;
+import org.eclipse.jdt.core.formatter.IndentManipulation;
+import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
 import org.eclipse.jface.text.IDocument;
 import org.eclipse.jface.text.TextUtilities;
 
@@ -104,7 +105,7 @@
 				newSource.append(this.alteredName);
 				newSource.append(createdNodeSource.substring(nameEnd));
 			} else {
-				// syntacticaly incorrect source
+				// syntactically incorrect source
 				int createdNodeStart = this.createdNode.getStartPosition();
 				int createdNodeEnd = createdNodeStart + this.createdNode.getLength();
 				newSource.append(createdNodeSource.substring(createdNodeStart, nameStart));
@@ -122,20 +123,20 @@
 private String removeIndentAndNewLines(String code, IDocument document, ICompilationUnit cu) {
 	IJavaProject project = cu.getJavaProject();
 	Map options = project.getOptions(true/*inherit JavaCore options*/);
-	int tabWidth = Indents.getTabWidth(options);
-	int indentWidth = Indents.getIndentWidth(options, tabWidth);
-	int indent = Indents.computeIndentUnits(code, tabWidth, indentWidth);
+	int tabWidth = IndentManipulation.getTabWidth(options);
+	int indentWidth = IndentManipulation.getIndentWidth(options);
+	int indent = IndentManipulation.measureIndentUnits(code, tabWidth, indentWidth);
 	int firstNonWhiteSpace = -1;
 	int length = code.length();
 	while (firstNonWhiteSpace < length-1)
-		if (!Character.isWhitespace(code.charAt(++firstNonWhiteSpace)))
+		if (!ScannerHelper.isWhitespace(code.charAt(++firstNonWhiteSpace)))
 			break;
 	int lastNonWhiteSpace = length;
 	while (lastNonWhiteSpace > 0)
-		if (!Character.isWhitespace(code.charAt(--lastNonWhiteSpace)))
+		if (!ScannerHelper.isWhitespace(code.charAt(--lastNonWhiteSpace)))
 			break;
 	String lineDelimiter = TextUtilities.getDefaultLineDelimiter(document);
-	return Indents.changeIndent(code.substring(firstNonWhiteSpace, lastNonWhiteSpace+1), indent, tabWidth, indentWidth, "", lineDelimiter); //$NON-NLS-1$
+	return IndentManipulation.changeIndent(code.substring(firstNonWhiteSpace, lastNonWhiteSpace+1), indent, tabWidth, indentWidth, "", lineDelimiter); //$NON-NLS-1$
 }
 /*
  * Renames the given node to the given name.
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 f9c8872..ff17445 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -28,9 +28,6 @@
 		// only one instance can be created
 	}
 
-	/**
-	 * @deprecated Marked deprecated as it is using deprecated code
-	 */
 	public IBuffer createBuffer(ICompilationUnit workingCopy) {
 		if (this.primaryBufferProvider != null) return this.primaryBufferProvider.createBuffer(workingCopy);
 		return super.createBuffer(workingCopy);
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 c4c99a7..2bcc349 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -16,6 +16,7 @@
 
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.Assert;
 import org.eclipse.core.runtime.jobs.ISchedulingRule;
 import org.eclipse.jdt.core.ICompilationUnit;
 import org.eclipse.jdt.core.IJavaElement;
@@ -164,7 +165,7 @@
 			cu.save(getSubProgressMonitor(1), force);
 			if (!cu.isWorkingCopy()) { // if unit is working copy, then save will have already fired the delta
 				addDelta(delta);
-				this.setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE);
+				setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE);
 			}
 		}
 	}
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 966bd67..c6be226 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,6 +10,9 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
+import java.util.HashMap;
+import java.util.Map;
+
 import org.eclipse.core.resources.*;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPath;
@@ -35,18 +38,23 @@
 		IPackageFragmentRoot root = (IPackageFragmentRoot)this.getElementToProcess();
 		IClasspathEntry rootEntry = root.getRawClasspathEntry();
 		
+		// remember olds roots
+		DeltaProcessor deltaProcessor = JavaModelManager.getJavaModelManager().getDeltaProcessor();
+		if (deltaProcessor.oldRoots == null)
+			deltaProcessor.oldRoots = new HashMap();
+		
+		// update classpath if needed
+		if ((updateModelFlags & IPackageFragmentRoot.ORIGINATING_PROJECT_CLASSPATH) != 0) {
+			updateProjectClasspath(rootEntry.getPath(), root.getJavaProject(), deltaProcessor.oldRoots);
+		}
+		if ((updateModelFlags & IPackageFragmentRoot.OTHER_REFERRING_PROJECTS_CLASSPATH) != 0) {
+			updateReferringProjectClasspaths(rootEntry.getPath(), root.getJavaProject(), deltaProcessor.oldRoots);
+		}
+		
 		// delete resource
 		if (!root.isExternal() && (this.updateModelFlags & IPackageFragmentRoot.NO_RESOURCE_MODIFICATION) == 0) {
 			deleteResource(root, rootEntry);
 		}
-
-		// update classpath if needed
-		if ((this.updateModelFlags & IPackageFragmentRoot.ORIGINATING_PROJECT_CLASSPATH) != 0) {
-			updateProjectClasspath(rootEntry.getPath(), root.getJavaProject());
-		}
-		if ((this.updateModelFlags & IPackageFragmentRoot.OTHER_REFERRING_PROJECTS_CLASSPATH) != 0) {
-			updateReferringProjectClasspaths(rootEntry.getPath(), root.getJavaProject());
-		}
 	}
 
 	protected void deleteResource(
@@ -87,28 +95,30 @@
 				throw new JavaModelException(e);
 			}
 		}
-		this.setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); 
+		setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); 
 	}
 
 
 	/*
 	 * Deletes the classpath entries equals to the given rootPath from all Java projects.
 	 */
-	protected void updateReferringProjectClasspaths(IPath rootPath, IJavaProject projectOfRoot) throws JavaModelException {
+	protected void updateReferringProjectClasspaths(IPath rootPath, IJavaProject projectOfRoot, Map oldRoots) throws JavaModelException {
 		IJavaModel model = this.getJavaModel();
 		IJavaProject[] projects = model.getJavaProjects();
 		for (int i = 0, length = projects.length; i < length; i++) {
 			IJavaProject project = projects[i];
 			if (project.equals(projectOfRoot)) continue;
-			updateProjectClasspath(rootPath, project);
+			updateProjectClasspath(rootPath, project, oldRoots);
 		}
 	}
 
 	/*
 	 * Deletes the classpath entries equals to the given rootPath from the given project.
 	 */
-	protected void updateProjectClasspath(IPath rootPath, IJavaProject project)
-		throws JavaModelException {
+	protected void updateProjectClasspath(IPath rootPath, IJavaProject project, Map oldRoots) throws JavaModelException {
+		// remember old roots
+		oldRoots.put(project, project.getPackageFragmentRoots());
+		
 		IClasspathEntry[] classpath = project.getRawClasspath();
 		IClasspathEntry[] newClasspath = null;
 		int cpLength = classpath.length;
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 b036daf..7d0c7ae 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 607b963..19f50c1 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -41,6 +41,7 @@
 	 * Collection of pre Java resource change listeners
 	 */
 	public IResourceChangeListener[] preResourceChangeListeners = new IResourceChangeListener[1];
+	public int[] preResourceChangeEventMasks = new int[1];
 	public int preResourceChangeListenerCount = 0;
 
 	/*
@@ -48,18 +49,18 @@
 	 */
 	private ThreadLocal deltaProcessors = new ThreadLocal();
 	
-	/* A table from IPath (from a classpath entry) to RootInfo */
+	/* A table from IPath (from a classpath entry) to DeltaProcessor.RootInfo */
 	public HashMap roots = new HashMap();
 	
-	/* A table from IPath (from a classpath entry) to ArrayList of RootInfo
+	/* A table from IPath (from a classpath entry) to ArrayList of DeltaProcessor.RootInfo
 	 * Used when an IPath corresponds to more than one root */
 	public HashMap otherRoots = new HashMap();
 	
-	/* A table from IPath (from a classpath entry) to RootInfo
+	/* A table from IPath (from a classpath entry) to DeltaProcessor.RootInfo
 	 * from the last time the delta processor was invoked. */
 	public HashMap oldRoots = new HashMap();
 	
-	/* A table from IPath (from a classpath entry) to ArrayList of RootInfo
+	/* A table from IPath (from a classpath entry) to ArrayList of DeltaProcessor.RootInfo
 	 * from the last time the delta processor was invoked.
 	 * Used when an IPath corresponds to more than one root */
 	public HashMap oldOtherRoots = new HashMap();
@@ -76,104 +77,34 @@
 	/* Threads that are currently running initializeRoots() */
 	private Set initializingThreads = Collections.synchronizedSet(new HashSet());	
 	
+	/* A table from file system absoulte path (String) to timestamp (Long) */
 	public Hashtable externalTimeStamps;
 	
-	public HashMap projectUpdates = new HashMap();
+	/* A table from JavaProject to ClasspathValidation */
+	private HashMap classpathValidations = new HashMap();
+	
+	/* A table from JavaProject to ProjectReferenceChange */
+	private HashMap projectReferenceChanges= 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;
+	private HashSet javaProjectNamesCache;
 	
 	/*
 	 * 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).
 	 */
-	public void addElementChangedListener(IElementChangedListener listener, int eventMask) {
+	public synchronized void addElementChangedListener(IElementChangedListener listener, int eventMask) {
 		for (int i = 0; i < this.elementChangedListenerCount; i++){
-			if (this.elementChangedListeners[i].equals(listener)){
+			if (this.elementChangedListeners[i] == listener){
 				
 				// only clone the masks, since we could be in the middle of notifications and one listener decide to change
 				// any event mask of another listeners (yet not notified).
 				int cloneLength = this.elementChangedListenerMasks.length;
 				System.arraycopy(this.elementChangedListenerMasks, 0, this.elementChangedListenerMasks = new int[cloneLength], 0, cloneLength);
-				this.elementChangedListenerMasks[i] = eventMask; // could be different
+				this.elementChangedListenerMasks[i] |= eventMask; // could be different
 				return;
 			}
 		}
@@ -188,18 +119,21 @@
 		this.elementChangedListenerCount++;
 	}
 
-	public void addPreResourceChangedListener(IResourceChangeListener listener) {
+	public synchronized void addPreResourceChangedListener(IResourceChangeListener listener, int eventMask) {
 		for (int i = 0; i < this.preResourceChangeListenerCount; i++){
-			if (this.preResourceChangeListeners[i].equals(listener)) {
+			if (this.preResourceChangeListeners[i] == listener) {
+				this.preResourceChangeEventMasks[i] |= eventMask;
 				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){
+		if ((length = this.preResourceChangeListeners.length) == this.preResourceChangeListenerCount) {
 			System.arraycopy(this.preResourceChangeListeners, 0, this.preResourceChangeListeners = new IResourceChangeListener[length*2], 0, length);
+			System.arraycopy(this.preResourceChangeEventMasks, 0, this.preResourceChangeEventMasks = new int[length*2], 0, length);
 		}
 		this.preResourceChangeListeners[this.preResourceChangeListenerCount] = listener;
+		this.preResourceChangeEventMasks[this.preResourceChangeListenerCount] = eventMask;
 		this.preResourceChangeListenerCount++;
 	}
 
@@ -211,18 +145,21 @@
 		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;
+	public synchronized ClasspathValidation addClasspathValidation(JavaProject project) {
+		ClasspathValidation validation = (ClasspathValidation) this.classpathValidations.get(project);
+		if (validation == null) {
+			validation = new ClasspathValidation(project);
+			this.classpathValidations.put(project, validation);
 	    }
-	    this.recordProjectUpdate(info);
+		return validation;
+	}
+	
+	public synchronized void addProjectReferenceChange(JavaProject project, IClasspathEntry[] oldResolvedClasspath) {
+		ProjectReferenceChange change = (ProjectReferenceChange) this.projectReferenceChanges.get(project);
+		if (change == null) {
+			change = new ProjectReferenceChange(project, oldResolvedClasspath);
+			this.projectReferenceChanges.put(project, change);
+	    }
 	}
 	
 	public void initializeRoots() {
@@ -262,7 +199,7 @@
 					JavaProject project = (JavaProject) projects[i];
 					IClasspathEntry[] classpath;
 					try {
-						classpath = project.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
+						classpath = project.getResolvedClasspath();
 					} catch (JavaModelException e) {
 						// continue with next project
 						continue;
@@ -298,12 +235,11 @@
 						
 						// source attachment path
 						if (entry.getEntryKind() != IClasspathEntry.CPE_LIBRARY) continue;
-						QualifiedName qName = new QualifiedName(JavaCore.PLUGIN_ID, "sourceattachment: " + path.toOSString()); //$NON-NLS-1$;
 						String propertyString = null;
 						try {
-							propertyString = ResourcesPlugin.getWorkspace().getRoot().getPersistentProperty(qName);
-						} catch (CoreException e) {
-							continue;
+							propertyString = Util.getSourceAttachmentProperty(path);
+						} catch (JavaModelException e) {
+							e.printStackTrace();
 						}
 						IPath sourceAttachmentPath;
 						if (propertyString != null) {
@@ -336,31 +272,29 @@
 		}
 	}
 
-	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();
+	public synchronized ClasspathValidation[] removeClasspathValidations() {
+	    int length = this.classpathValidations.size();
 	    if (length == 0) return null;
-	    ProjectUpdateInfo[]  updates = new ProjectUpdateInfo[length];
-	    this.projectUpdates.values().toArray(updates);
-	    this.projectUpdates.clear();
+	    ClasspathValidation[]  validations = new ClasspathValidation[length];
+	    this.classpathValidations.values().toArray(validations);
+	    this.classpathValidations.clear();
+	    return validations;
+	}
+	
+	public synchronized ProjectReferenceChange[] removeProjectReferenceChanges() {
+	    int length = this.projectReferenceChanges.size();
+	    if (length == 0) return null;
+	    ProjectReferenceChange[]  updates = new ProjectReferenceChange[length];
+	    this.projectReferenceChanges.values().toArray(updates);
+	    this.projectReferenceChanges.clear();
 	    return updates;
 	}
 	
-	public void removeElementChangedListener(IElementChangedListener listener) {
+	public synchronized void removeElementChangedListener(IElementChangedListener listener) {
 		
 		for (int i = 0; i < this.elementChangedListenerCount; i++){
 			
-			if (this.elementChangedListeners[i].equals(listener)){
+			if (this.elementChangedListeners[i] == listener){
 				
 				// need to clone defensively since we might be in the middle of listener notifications (#fire)
 				int length = this.elementChangedListeners.length;
@@ -386,26 +320,30 @@
 		}
 	}
 
-	public void removePreResourceChangedListener(IResourceChangeListener listener) {
+	public synchronized void removePreResourceChangedListener(IResourceChangeListener listener) {
 		
 		for (int i = 0; i < this.preResourceChangeListenerCount; i++){
 			
-			if (this.preResourceChangeListeners[i].equals(listener)){
+			if (this.preResourceChangeListeners[i] == 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];
+				int[] newEventMasks = new int[length];
 				System.arraycopy(this.preResourceChangeListeners, 0, newListeners, 0, i);
+				System.arraycopy(this.preResourceChangeEventMasks, 0, newEventMasks, 0, i);
 				
 				// copy trailing listeners
 				int trailingLength = this.preResourceChangeListenerCount - i - 1;
-				if (trailingLength > 0){
+				if (trailingLength > 0) {
 					System.arraycopy(this.preResourceChangeListeners, i+1, newListeners, i, trailingLength);
+					System.arraycopy(this.preResourceChangeEventMasks, i+1, newEventMasks, 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.preResourceChangeEventMasks = newEventMasks;
 				this.preResourceChangeListenerCount--;
 				return;
 			}
@@ -413,12 +351,11 @@
 	}
 
 	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() {
+		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];
+			if ((this.preResourceChangeEventMasks[i] & event.getType()) != 0)
+				SafeRunner.run(new ISafeRunnable() {
 					public void handleException(Throwable exception) {
 						Util.log(exception, "Exception occurred in listener of pre Java resource change notification"); //$NON-NLS-1$
 					}
@@ -426,13 +363,12 @@
 						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 (isPostChange) {
+			if (event.getType() == IResourceChangeEvent.POST_CHANGE) {
 				this.deltaProcessors.set(null);
 			}
 		}
@@ -469,6 +405,39 @@
 		return this.externalTimeStamps;
 	}
 	
+	public IJavaProject findJavaProject(String name) {
+		if (getOldJavaProjecNames().contains(name))
+			return JavaModelManager.getJavaModelManager().getJavaModel().getJavaProject(name);
+		return null;
+	}
+	
+	/*
+	 * Workaround for bug 15168 circular errors not reported 
+	 * Returns the list of java projects before resource delta processing
+	 * has started.
+	 */
+	public synchronized HashSet getOldJavaProjecNames() {
+		if (this.javaProjectNamesCache == null) {
+			HashSet result = new HashSet();
+			IJavaProject[] projects;
+			try {
+				projects = JavaModelManager.getJavaModelManager().getJavaModel().getJavaProjects();
+			} catch (JavaModelException e) {
+				return this.javaProjectNamesCache;
+			}
+			for (int i = 0, length = projects.length; i < length; i++) {
+				IJavaProject project = projects[i];
+				result.add(project.getElementName());
+			}
+			return this.javaProjectNamesCache = result;
+		}
+		return this.javaProjectNamesCache;
+	}
+	
+	public synchronized void resetOldJavaProjectNames() {
+		this.javaProjectNamesCache = null;
+	}
+	
 	private File getTimeStampsFile() {
 		return JavaCore.getPlugin().getStateLocation().append("externalLibsTimeStamps").toFile(); //$NON-NLS-1$
 	}
@@ -480,11 +449,12 @@
 		try {
 			out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(timestamps)));
 			out.writeInt(this.externalTimeStamps.size());
-			Iterator keys = this.externalTimeStamps.keySet().iterator();
-			while (keys.hasNext()) {
-				IPath key = (IPath) keys.next();
+			Iterator entries = this.externalTimeStamps.entrySet().iterator();
+			while (entries.hasNext()) {
+				Map.Entry entry = (Map.Entry) entries.next();
+				IPath key = (IPath) entry.getKey();
 				out.writeUTF(key.toPortableString());
-				Long timestamp = (Long) this.externalTimeStamps.get(key);
+				Long timestamp = (Long) entry.getValue();
 				out.writeLong(timestamp.longValue());
 			}
 		} catch (IOException e) {
@@ -514,15 +484,19 @@
 			updatedRoots = this.roots;
 			otherUpdatedRoots = this.otherRoots;
 		}
-		Iterator iterator = updatedRoots.keySet().iterator();
+		int containerSegmentCount = containerPath.segmentCount();
+		boolean containerIsProject = containerSegmentCount == 1;
+		Iterator iterator = updatedRoots.entrySet().iterator();
 		while (iterator.hasNext()) {
-			IPath path = (IPath)iterator.next();
+			Map.Entry entry = (Map.Entry) iterator.next();
+			IPath path = (IPath) entry.getKey();
 			if (containerPath.isPrefixOf(path) && !containerPath.equals(path)) {
-				IResourceDelta rootDelta = containerDelta.findMember(path.removeFirstSegments(1));
+				IResourceDelta rootDelta = containerDelta.findMember(path.removeFirstSegments(containerSegmentCount));
 				if (rootDelta == null) continue;
-				DeltaProcessor.RootInfo rootInfo = (DeltaProcessor.RootInfo)updatedRoots.get(path);
+				DeltaProcessor.RootInfo rootInfo = (DeltaProcessor.RootInfo) entry.getValue();
 	
-				if (!rootInfo.project.getPath().isPrefixOf(path)) { // only consider roots that are not included in the container
+				if (!containerIsProject 
+						|| !rootInfo.project.getPath().isPrefixOf(path)) { // only consider folder roots that are not included in the container
 					deltaProcessor.updateCurrentDeltaAndIndex(rootDelta, IJavaElement.PACKAGE_FRAGMENT_ROOT, rootInfo);
 				}
 				
@@ -531,7 +505,8 @@
 					Iterator otherProjects = rootList.iterator();
 					while (otherProjects.hasNext()) {
 						rootInfo = (DeltaProcessor.RootInfo)otherProjects.next();
-						if (!rootInfo.project.getPath().isPrefixOf(path)) { // only consider roots that are not included in the container
+						if (!containerIsProject 
+								|| !rootInfo.project.getPath().isPrefixOf(path)) { // only consider folder roots that are not included in the container
 							deltaProcessor.updateCurrentDeltaAndIndex(rootDelta, IJavaElement.PACKAGE_FRAGMENT_ROOT, rootInfo);
 						}
 					}
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 3b0356c..9965ee6 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -20,13 +20,13 @@
 import org.eclipse.core.resources.IResourceChangeEvent;
 import org.eclipse.core.resources.IResourceDelta;
 import org.eclipse.core.resources.IResourceDeltaVisitor;
-import org.eclipse.core.resources.IWorkspace;
 import org.eclipse.core.resources.IWorkspaceRoot;
 import org.eclipse.core.resources.IWorkspaceRunnable;
 import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.*;
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.SourceElementParser;
 import org.eclipse.jdt.internal.core.builder.JavaBuilder;
 import org.eclipse.jdt.internal.core.hierarchy.TypeHierarchy;
 import org.eclipse.jdt.internal.core.search.AbstractSearchScope;
@@ -39,6 +39,20 @@
  * <code>IResourceDelta</code>s into <code>IJavaElementDelta</code>s.
  * It also does some processing on the <code>JavaElement</code>s involved
  * (e.g. closing them or updating classpaths).
+ * <p>
+ * High level summary of what the delta processor does:
+ * <ul>
+ * <li>reacts to resource deltas</li>
+ * <li>fires corresponding Java element deltas</li>
+ * <li>deltas also contain non-Java resources changes</li>
+ * <li>updates the model to reflect the Java element changes</li>
+ * <li>notifies type hierarchies of the changes</li>
+ * <li>triggers indexing of the changed elements</li>
+ * <li>refresh external archives (delta, model update, indexing)</li>
+ * <li>is thread safe (one delta processor instance per thread, see DeltaProcessingState#resourceChanged(...))</li>
+ * <li>handles .classpath changes (updates package fragment roots, update project references, validate classpath (.classpath format, 
+ * 		resolved classpath, cycles))</li>
+ * </ul>
  */
 public class DeltaProcessor {
 	
@@ -218,7 +232,7 @@
 	private final ModelUpdater modelUpdater = new ModelUpdater();
 
 	/* A set of IJavaProject whose caches need to be reset */
-	private HashSet projectCachesToReset = new HashSet();  
+	public HashSet projectCachesToReset = new HashSet();  
 
 	/*
 	 * A list of IJavaElement used as a scope for external archives refresh during POST_CHANGE.
@@ -229,7 +243,7 @@
 	/* A table from IJavaProject to an array of IPackageFragmentRoot.
 	 * This table contains the pkg fragment roots of the project that are being deleted.
 	 */
-	public Map removedRoots;
+	public Map oldRoots;
 	
 	/* A set of IJavaProject whose package fragment roots need to be refreshed */
 	private HashSet rootsToRefresh = new HashSet();
@@ -238,11 +252,37 @@
 	 * Type of event that should be processed no matter what the real event type is.
 	 */
 	public int overridenEventType = -1;
-		
+	
+	/*
+	 * Cache SourceElementParser for the project being visited
+	 */
+	private SourceElementParser sourceElementParserCache;
+	
+	/*
+	 * Map from IProject to ClasspathChange
+	 */
+	public HashMap classpathChanges = new HashMap();
+
 	public DeltaProcessor(DeltaProcessingState state, JavaModelManager manager) {
 		this.state = state;
 		this.manager = manager;
 	}
+	
+	public ClasspathChange addClasspathChange(IProject project, IClasspathEntry[] oldRawClasspath, IPath oldOutputLocation, IClasspathEntry[] oldResolvedClasspath) {
+		ClasspathChange change = (ClasspathChange) this.classpathChanges.get(project);
+		if (change == null) {
+			change = new ClasspathChange((JavaProject) this.manager.getJavaModel().getJavaProject(project), oldRawClasspath, oldOutputLocation, oldResolvedClasspath);
+			this.classpathChanges.put(project, change);
+		} else {
+			if (change.oldRawClasspath == null)
+				change.oldRawClasspath = oldRawClasspath;
+			if (change.oldOutputLocation == null)
+				change.oldOutputLocation = oldOutputLocation;
+			if (change.oldResolvedClasspath == null)
+				change.oldResolvedClasspath = oldResolvedClasspath;
+		}
+		return change;
+	}
 
 	/*
 	 * Adds the dependents of the given project to the list of the projects
@@ -294,25 +334,28 @@
 	 * Also triggers index updates
 	 */
 	public void checkExternalArchiveChanges(IJavaElement[] elementsToRefresh, IProgressMonitor monitor) throws JavaModelException {
+		if (monitor != null && monitor.isCanceled()) 
+			throw new OperationCanceledException(); 
 		try {
+			if (monitor != null) monitor.beginTask("", 1); //$NON-NLS-1$
+
 			for (int i = 0, length = elementsToRefresh.length; i < length; i++) {
 				this.addForRefresh(elementsToRefresh[i]);
 			}
 			boolean hasDelta = this.createExternalArchiveDelta(monitor);
-			if (monitor != null && monitor.isCanceled()) return; 
 			if (hasDelta){
 				// force classpath marker refresh of affected projects
 				JavaModel.flushExternalFileCache();
+				
+				// flush jar type cache
+				JavaModelManager.getJavaModelManager().resetJarTypeCache();
+				
 				IJavaElementDelta[] projectDeltas = this.currentDelta.getAffectedChildren();
 				final int length = projectDeltas.length;
 				final IProject[] projectsToTouch = new IProject[length];
 				for (int i = 0; i < length; i++) {
 					IJavaElementDelta delta = projectDeltas[i];
 					JavaProject javaProject = (JavaProject)delta.getElement();
-					javaProject.getResolvedClasspath(
-						true/*ignoreUnresolvedEntry*/, 
-						true/*generateMarkerOnError*/, 
-						false/*don't returnResolutionInProgress*/);
 					projectsToTouch[i] = javaProject.getProject();
 				}
 				
@@ -355,19 +398,13 @@
 	 */
 	private void checkProjectsBeingAddedOrRemoved(IResourceDelta delta) {
 		IResource resource = delta.getResource();
-		boolean processChildren = false;
-
+		IResourceDelta[] children = null;
+	
 		switch (resource.getType()) {
 			case IResource.ROOT :
 				// workaround for bug 15168 circular errors not reported 
-				if (this.state.modelProjectsCache == null) {
-					try {
-						this.state.modelProjectsCache = this.manager.getJavaModel().getJavaProjects();
-					} catch (JavaModelException e) {
-						// java model doesn't exist: never happens
-					}
-				}
-				processChildren = true;
+				this.state.getOldJavaProjecNames(); // force list to be computed
+				children = delta.getAffectedChildren();
 				break;
 			case IResource.PROJECT :
 				// NB: No need to check project's nature as if the project is not a java project:
@@ -380,12 +417,16 @@
 						this.manager.batchContainerInitializations = true;
 					
 						// remember project and its dependents
-						this.addToRootsToRefreshWithDependents(javaProject);
+						addToRootsToRefreshWithDependents(javaProject);
 						
 						// workaround for bug 15168 circular errors not reported 
 						if (JavaProject.hasJavaNature(project)) {
-							this.addToParentInfo(javaProject);
+							addToParentInfo(javaProject);
+							readRawClasspath(javaProject);
+							// ensure project references are updated (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=121569)
+							checkProjectReferenceChange(project, javaProject);
 						}
+						
 						this.state.rootsAreStale = true; 
 						break;
 						
@@ -394,12 +435,15 @@
 								this.manager.batchContainerInitializations = true;
 		
 								// project opened or closed: remember  project and its dependents
-								this.addToRootsToRefreshWithDependents(javaProject);
+								addToRootsToRefreshWithDependents(javaProject);
 								
 								// workaround for bug 15168 circular errors not reported 
 								if (project.isOpen()) {
 									if (JavaProject.hasJavaNature(project)) {
-										this.addToParentInfo(javaProject);
+										addToParentInfo(javaProject);
+										readRawClasspath(javaProject);
+										// ensure project references are updated
+										checkProjectReferenceChange(project, javaProject);
 									}
 								} else {
 									try {
@@ -409,12 +453,13 @@
 									}
 									this.removeFromParentInfo(javaProject);
 									this.manager.removePerProjectInfo(javaProject);
+									this.manager.containerRemove(javaProject);
 								}
 								this.state.rootsAreStale = true;
 							} else if ((delta.getFlags() & IResourceDelta.DESCRIPTION) != 0) {
-								boolean wasJavaProject = this.manager.getJavaModel().findJavaProject(project) != null;
+								boolean wasJavaProject = this.state.findJavaProject(project.getName()) != null;
 								boolean isJavaProject = JavaProject.hasJavaNature(project);
-								if (wasJavaProject != isJavaProject) { 
+								if (wasJavaProject != isJavaProject) {
 									this.manager.batchContainerInitializations = true;
 									
 									// java nature added or removed: remember  project and its dependents
@@ -423,9 +468,14 @@
 									// workaround for bug 15168 circular errors not reported 
 									if (isJavaProject) {
 										this.addToParentInfo(javaProject);
+										readRawClasspath(javaProject);
+										// ensure project references are updated (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=172666)
+										checkProjectReferenceChange(project, javaProject);
 									} else {
 										// remove classpath cache so that initializeRoots() will not consider the project has a classpath
-										this.manager.removePerProjectInfo((JavaProject)JavaCore.create(project));
+										this.manager.removePerProjectInfo(javaProject);
+										// remove container cache for this project
+										this.manager.containerRemove(javaProject);
 										// close project
 										try {
 											javaProject.close();
@@ -439,7 +489,7 @@
 									// in case the project was removed then added then changed (see bug 19799)
 									if (isJavaProject) { // need nature check - 18698
 										this.addToParentInfo(javaProject);
-										processChildren = true;
+										children = delta.getAffectedChildren();
 									}
 								}
 							} else {
@@ -447,16 +497,19 @@
 								// in case the project was removed then added then changed
 								if (JavaProject.hasJavaNature(project)) { // need nature check - 18698
 									this.addToParentInfo(javaProject);
-									processChildren = true;
+									children = delta.getAffectedChildren();
 								}						
 							}		
 							break;
-
+	
 					case IResourceDelta.REMOVED : 
 						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.manager.removePerProjectInfo(javaProject);
+						// remove container cache for this project
+						this.manager.containerRemove(javaProject);
+						
 						this.state.rootsAreStale = true;
 						break;
 				}
@@ -470,19 +523,54 @@
 				/* classpath file change */
 				if (file.getName().equals(JavaProject.CLASSPATH_FILENAME)) {
 					this.manager.batchContainerInitializations = true;
-					reconcileClasspathFileUpdate(delta, (JavaProject)JavaCore.create(file.getProject()));
+					switch (delta.getKind()) {
+						case IResourceDelta.CHANGED :
+							int flags = delta.getFlags();
+							if ((flags & IResourceDelta.CONTENT) == 0  // only consider content change
+								&& (flags & IResourceDelta.ENCODING) == 0 // and encoding change
+								&& (flags & IResourceDelta.MOVED_FROM) == 0) {// and also move and overide scenario (see http://dev.eclipse.org/bugs/show_bug.cgi?id=21420)
+								break;
+							}
+						// fall through
+						case IResourceDelta.ADDED :
+							javaProject = (JavaProject)JavaCore.create(file.getProject());
+							
+							// force to (re)read the .classpath file
+							try {
+								javaProject.getPerProjectInfo().readAndCacheClasspath(javaProject);
+							} catch (JavaModelException e) {
+								// project doesn't exist
+								return;
+							}
+							break;
+					}
 					this.state.rootsAreStale = true;
 				}
 				break;
 				
 		}
-		if (processChildren) {
-			IResourceDelta[] children = delta.getAffectedChildren();
+		if (children != null) {
 			for (int i = 0; i < children.length; i++) {
 				checkProjectsBeingAddedOrRemoved(children[i]);
 			}
 		}
 	}
+
+	private void checkProjectReferenceChange(IProject project, JavaProject javaProject) {
+		ClasspathChange change = (ClasspathChange) this.classpathChanges.get(project);
+		this.state.addProjectReferenceChange(javaProject, change == null ? null : change.oldResolvedClasspath);
+	}
+
+	private void readRawClasspath(JavaProject javaProject) {
+		try {
+			// force to (re)read the .classpath file
+			javaProject.getPerProjectInfo().readAndCacheClasspath(javaProject);
+		} catch (JavaModelException e) {	
+			if (VERBOSE) {
+				e.printStackTrace();
+			}
+		}
+	}
 	private void checkSourceAttachmentChange(IResourceDelta delta, IResource res) {
 		IPath rootPath = (IPath)this.state.sourceAttachments.get(res.getFullPath());
 		if (rootPath != null) {
@@ -551,6 +639,9 @@
 			int flags = IJavaElementDelta.F_CONTENT;
 			if (element instanceof JarPackageFragmentRoot){
 				flags |= IJavaElementDelta.F_ARCHIVE_CONTENT_CHANGED;
+				// need also to reset project cache otherwise it will be out-of-date
+				// see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=162621
+				this.projectCachesToReset.add(element.getJavaProject());
 			}
 			if (isPrimary) {
 				flags |= IJavaElementDelta.F_PRIMARY_RESOURCE;
@@ -592,7 +683,7 @@
 					} else {
 						// java project may have been been closed or removed (look for
 						// element amongst old java project s list).
-						element =  (Openable) this.manager.getJavaModel().findJavaProject(proj);
+						element =  this.state.findJavaProject(proj.getName());
 					}
 				}
 				break;
@@ -701,14 +792,14 @@
 					archivePathsToRefresh.add(element.getPath());
 					break;
 				case IJavaElement.JAVA_PROJECT :
-					JavaProject project = (JavaProject) element;
-					if (!JavaProject.hasJavaNature(project.getProject())) {
+					JavaProject javaProject = (JavaProject) element;
+					if (!JavaProject.hasJavaNature(javaProject.getProject())) {
 						// project is not accessible or has lost its Java nature
 						break;
 					}
 					IClasspathEntry[] classpath;
 					try {
-						classpath = project.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
+						classpath = javaProject.getResolvedClasspath();
 						for (int j = 0, cpLength = classpath.length; j < cpLength; j++){
 							if (classpath[j].getEntryKind() == IClasspathEntry.CPE_LIBRARY){
 								archivePathsToRefresh.add(classpath[j].getPath());
@@ -719,21 +810,17 @@
 					}
 					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())) {
+					Iterator projectNames = this.state.getOldJavaProjecNames().iterator();
+					while (projectNames.hasNext()) {
+						String projectName = (String) projectNames.next();
+						IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
+						if (!JavaProject.hasJavaNature(project)) {
 							// project is not accessible or has lost its Java nature
 							continue;
 						}
+						javaProject = (JavaProject) JavaCore.create(project);
 						try {
-							classpath = project.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
+							classpath = javaProject.getResolvedClasspath();
 						} catch (JavaModelException e2) {
 							// project doesn't exist -> ignore
 							continue;
@@ -749,26 +836,22 @@
 		}
 		
 		// perform refresh
-		IJavaProject[] projects;
-		try {
-			projects = this.manager.getJavaModel().getOldJavaProjectsList();
-		} catch (JavaModelException e) {
-			// cannot retrieve old projects list -> give up
-			return false;
-		}
+		Iterator projectNames = this.state.getOldJavaProjecNames().iterator();
 		IWorkspaceRoot wksRoot = ResourcesPlugin.getWorkspace().getRoot();
-		for (int i = 0, length = projects.length; i < length; i++) {
+		while (projectNames.hasNext()) {
 			
 			if (monitor != null && monitor.isCanceled()) break; 
 			
-			JavaProject project = (JavaProject) projects[i];
-			if (!JavaProject.hasJavaNature(project.getProject())) {
+			String projectName = (String) projectNames.next();
+			IProject project = wksRoot.getProject(projectName);
+			if (!JavaProject.hasJavaNature(project)) {
 				// project is not accessible or has lost its Java nature
 				continue;
 			}
+			JavaProject javaProject = (JavaProject) JavaCore.create(project);
 			IClasspathEntry[] entries;
 			try {
-				entries = project.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
+				entries = javaProject.getResolvedClasspath();
 			} catch (JavaModelException e1) {
 				// project does not exist -> ignore
 				continue;
@@ -836,25 +919,27 @@
 					status = (String)externalArchivesStatus.get(entryPath); 
 					if (status != null){
 						if (status == EXTERNAL_JAR_ADDED){
-							PackageFragmentRoot root = (PackageFragmentRoot)project.getPackageFragmentRoot(entryPath.toString());
+							PackageFragmentRoot root = (PackageFragmentRoot) javaProject.getPackageFragmentRoot(entryPath.toString());
 							if (VERBOSE){
 								System.out.println("- External JAR ADDED, affecting root: "+root.getElementName()); //$NON-NLS-1$
 							} 
 							elementAdded(root, null, null);
+							this.state.addClasspathValidation(javaProject); // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=185733
 							hasDelta = true;
 						} else if (status == EXTERNAL_JAR_CHANGED) {
-							PackageFragmentRoot root = (PackageFragmentRoot)project.getPackageFragmentRoot(entryPath.toString());
+							PackageFragmentRoot root = (PackageFragmentRoot) javaProject.getPackageFragmentRoot(entryPath.toString());
 							if (VERBOSE){
 								System.out.println("- External JAR CHANGED, affecting root: "+root.getElementName()); //$NON-NLS-1$
 							}
 							contentChanged(root);
 							hasDelta = true;
 						} else if (status == EXTERNAL_JAR_REMOVED) {
-							PackageFragmentRoot root = (PackageFragmentRoot)project.getPackageFragmentRoot(entryPath.toString());
+							PackageFragmentRoot root = (PackageFragmentRoot) javaProject.getPackageFragmentRoot(entryPath.toString());
 							if (VERBOSE){
 								System.out.println("- External JAR REMOVED, affecting root: "+root.getElementName()); //$NON-NLS-1$
 							}
 							elementRemoved(root, null, null);
+							this.state.addClasspathValidation(javaProject); // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=185733
 							hasDelta = true;
 						}
 					}
@@ -882,17 +967,17 @@
 			JavaProject javaProject = (JavaProject)JavaCore.create(project);
 			
 			// remember roots of this project
-			if (this.removedRoots == null) {
-				this.removedRoots = new HashMap();
+			if (this.oldRoots == null) {
+				this.oldRoots = new HashMap();
 			}
 			if (javaProject.isOpen()) {
-				this.removedRoots.put(javaProject, javaProject.getPackageFragmentRoots());
+				this.oldRoots.put(javaProject, javaProject.getPackageFragmentRoots());
 			} else {
 				// compute roots without opening project
-				this.removedRoots.put(
+				this.oldRoots.put(
 					javaProject, 
 					javaProject.computePackageFragmentRoots(
-						javaProject.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/), 
+						javaProject.getResolvedClasspath(), 
 						false,
 						null /*no reverse map*/));
 			}
@@ -900,9 +985,8 @@
 			javaProject.close();
 
 			// workaround for bug 15168 circular errors not reported
-			if (this.state.modelProjectsCache == null) {
-				this.state.modelProjectsCache = this.manager.getJavaModel().getJavaProjects();
-			}
+			this.state.getOldJavaProjecNames(); // foce list to be computed
+			
 			this.removeFromParentInfo(javaProject);
 
 			// remove preferences from per project info
@@ -933,6 +1017,17 @@
 					Openable movedFromElement = (Openable)element.getJavaModel().getJavaProject(delta.getMovedFromPath().lastSegment());
 					currentDelta().movedTo(element, movedFromElement);
 				} else {
+					// Force the project to be closed as it might have been opened 
+					// before the resource modification came in and it might have a new child
+					// For example, in an IWorkspaceRunnable:
+					// 1. create a Java project P (where P=src)
+					// 2. open project P
+					// 3. add folder f in P's pkg fragment root
+					// When the resource delta comes in, only the addition of P is notified, 
+					// but the pkg fragment root of project P is already opened, thus its children are not recomputed
+					// and it appears to contain only the default package.
+					close(element);
+
 					currentDelta().added(element);
 				}
 				this.state.updateRoots(element.getPath(), delta, this);
@@ -1152,17 +1247,26 @@
 					return NON_JAVA_RESOURCE;
 				}
 				if (res.getType() == IResource.FOLDER) {
-					if (Util.isValidFolderNameForPackage(res.getName())) {
+					if (parentType == NON_JAVA_RESOURCE && !Util.isExcluded(res.getParent(), rootInfo.inclusionPatterns, rootInfo.exclusionPatterns)) {
+						// parent is a non-Java resource because it doesn't have a valid package name (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=130982)
+						return NON_JAVA_RESOURCE;
+					}
+					String sourceLevel = rootInfo.project == null ? null : rootInfo.project.getOption(JavaCore.COMPILER_SOURCE, true);
+					String complianceLevel = rootInfo.project == null ? null : rootInfo.project.getOption(JavaCore.COMPILER_COMPLIANCE, true);
+					if (Util.isValidFolderNameForPackage(res.getName(), sourceLevel, complianceLevel)) {
 						return IJavaElement.PACKAGE_FRAGMENT;
 					}
 					return NON_JAVA_RESOURCE;
 				}
 				String fileName = res.getName();
-				if (Util.isValidCompilationUnitName(fileName)) {
+				String sourceLevel = rootInfo.project == null ? null : rootInfo.project.getOption(JavaCore.COMPILER_SOURCE, true);
+				String complianceLevel = rootInfo.project == null ? null : rootInfo.project.getOption(JavaCore.COMPILER_COMPLIANCE, true);
+				if (Util.isValidCompilationUnitName(fileName, sourceLevel, complianceLevel)) {
 					return IJavaElement.COMPILATION_UNIT;
-				} else if (Util.isValidClassFileName(fileName)) {
+				} else if (Util.isValidClassFileName(fileName, sourceLevel, complianceLevel)) {
 					return IJavaElement.CLASS_FILE;
-				} else if (this.rootInfo(res.getFullPath(), kind) != null) {
+				} else if ((rootInfo = this.rootInfo(res.getFullPath(), kind)) != null 
+						&& rootInfo.project.getProject().getFullPath().isPrefixOf(res.getFullPath()) /*ensure root is a root of its project (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=185310) */) {
 					// case of proj=src=bin and resource is a jar file on the classpath
 					return IJavaElement.PACKAGE_FRAGMENT_ROOT;
 				} else {
@@ -1179,16 +1283,11 @@
 	public void flush() {
 		this.javaModelDeltas = new ArrayList();
 	}
-	/* Returns the list of Java projects in the workspace.
-	 * 
-	 */
-	IJavaProject[] getJavaProjects() {
-		try {
-			return this.manager.getJavaModel().getJavaProjects();
-		} catch (JavaModelException e) {
-			// java model doesn't exist
-			return new IJavaProject[0];
-		}
+
+	private SourceElementParser getSourceElementParser(Openable element) {
+		if (this.sourceElementParserCache == null)
+			this.sourceElementParserCache = this.manager.indexManager.getSourceElementParser(element.getJavaProject(), null/*requestor will be set by indexer*/);
+		return this.sourceElementParserCache;
 	}
 	/*
 	 * Finds the root info this path is included in.
@@ -1236,9 +1335,14 @@
 	
 		// Important: if any listener reacts to notification by updating the listeners list or mask, these lists will
 		// be duplicated, so it is necessary to remember original lists in a variable (since field values may change under us)
-		IElementChangedListener[] listeners = this.state.elementChangedListeners;
-		int[] listenerMask = this.state.elementChangedListenerMasks;
-		int listenerCount = this.state.elementChangedListenerCount;
+		IElementChangedListener[] listeners;
+		int[] listenerMask;
+		int listenerCount;
+		synchronized (this.state) {
+			listeners = this.state.elementChangedListeners;
+			listenerMask = this.state.elementChangedListenerMasks;
+			listenerCount = this.state.elementChangedListenerCount;
+		}
 
 		switch (eventType) {
 			case DEFAULT_CHANGE_EVENT:
@@ -1267,6 +1371,9 @@
 			// flush now so as to keep listener reactions to post their own deltas for subsequent iteration
 			this.flush();
 			
+			// mark the operation stack has not modifying resources since resource deltas are being fired
+			JavaModelOperation.setAttribute(JavaModelOperation.HAS_MODIFIED_RESOURCE_ATTR, null);
+			
 			notifyListeners(deltaToNotify, ElementChangedEvent.POST_CHANGE, listeners, listenerMask, listenerCount);
 		} 
 	}		
@@ -1341,8 +1448,11 @@
 	 * Returns whether the given resource is in one of the given output folders and if
 	 * it is filtered out from this output folder.
 	 */
-	private boolean isResFilteredFromOutput(OutputsInfo info, IResource res, int elementType) {
+	private boolean isResFilteredFromOutput(RootInfo rootInfo, OutputsInfo info, IResource res, int elementType) {
 		if (info != null) {
+			JavaProject javaProject = null;
+			String sourceLevel = null;
+			String complianceLevel = null;
 			IPath resPath = res.getFullPath();
 			for (int i = 0;  i < info.outputCount; i++) {
 				if (info.paths[i].isPrefixOf(resPath)) {
@@ -1353,10 +1463,20 @@
 						}
 						// 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;
+						if (elementType == IJavaElement.JAVA_PROJECT && res instanceof IFile) {
+							if (sourceLevel == null) {
+								// Get java project to use its source and compliance levels
+								javaProject = rootInfo == null ?
+									(JavaProject)this.createElement(res.getProject(), IJavaElement.JAVA_PROJECT, null) :
+									rootInfo.project;
+								if (javaProject != null) {
+									sourceLevel = javaProject.getOption(JavaCore.COMPILER_SOURCE, true);
+									complianceLevel = javaProject.getOption(JavaCore.COMPILER_COMPLIANCE, true);
+								}
+							}
+							if (Util.isValidClassFileName(res.getName(), sourceLevel, complianceLevel)) {
+								return true;
+							}
 						}
 					} else {
 						return true;
@@ -1419,7 +1539,7 @@
 					start = System.currentTimeMillis();
 				}
 				// wrap callbacks with Safe runnable for subsequent listeners to be called when some are causing grief
-				Platform.run(new ISafeRunnable() {
+				SafeRunner.run(new ISafeRunnable() {
 					public void handleException(Throwable exception) {
 						Util.log(exception, "Exception occurred in listener of Java element change notification"); //$NON-NLS-1$
 					}
@@ -1447,7 +1567,7 @@
 			if (!(listener instanceof TypeHierarchy)) continue;
 
 			// wrap callbacks with Safe runnable for subsequent listeners to be called when some are causing grief
-			Platform.run(new ISafeRunnable() {
+			SafeRunner.run(new ISafeRunnable() {
 				public void handleException(Throwable exception) {
 					Util.log(exception, "Exception occurred in listener of Java element change notification"); //$NON-NLS-1$
 				}
@@ -1530,7 +1650,7 @@
 				if (proj.getProject().getFullPath().equals(projectOutput)){ // case of proj==bin==src
 					return new OutputsInfo(new IPath[] {projectOutput}, new int[] {SOURCE}, 1);
 				} 
-				IClasspathEntry[] classpath = proj.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
+				IClasspathEntry[] classpath = proj.getResolvedClasspath();
 				IPath[] outputs = new IPath[classpath.length+1];
 				int[] traverseModes = new int[classpath.length+1];
 				int outputCount = 1;
@@ -1620,7 +1740,7 @@
 				RootInfo rootInfo = null;
 				int elementType;
 				IProject proj = (IProject)res;
-				boolean wasJavaProject = this.manager.getJavaModel().findJavaProject(proj) != null;
+				boolean wasJavaProject = this.state.findJavaProject(proj.getName()) != null;
 				boolean isJavaProject = JavaProject.hasJavaNature(proj);
 				if (!wasJavaProject && !isJavaProject) {
 					elementType = NON_JAVA_RESOURCE;
@@ -1658,52 +1778,15 @@
 		}
 	}
 	/*
-	 * Update the JavaModel according to a .classpath file change. The file can have changed as a result of a previous
-	 * call to JavaProject#setRawClasspath or as a result of some user update (through repository)
-	 */
-	private void reconcileClasspathFileUpdate(IResourceDelta delta, JavaProject project) {
-
-		switch (delta.getKind()) {
-			case IResourceDelta.REMOVED : // recreate one based on in-memory classpath
-//				try {
-//					JavaModelManager.PerProjectInfo info = project.getPerProjectInfo();
-//					if (info.rawClasspath != null) { // if there is an in-memory classpath
-//						project.saveClasspath(info.rawClasspath, info.outputLocation);
-//					}
-//				} catch (JavaModelException e) {
-//					if (project.getProject().isAccessible()) {
-//						Util.log(e, "Could not save classpath for "+ project.getPath()); //$NON-NLS-1$
-//					}
-//				}
-				break;
-			case IResourceDelta.CHANGED :
-				int flags = delta.getFlags();
-				if ((flags & IResourceDelta.CONTENT) == 0  // only consider content change
-					&& (flags & IResourceDelta.ENCODING) == 0 // and encoding change
-					&& (flags & IResourceDelta.MOVED_FROM) == 0) {// and also move and overide scenario (see http://dev.eclipse.org/bugs/show_bug.cgi?id=21420)
-					break;
-				}
-			// fall through
-			case IResourceDelta.ADDED :
-				try {
-					project.forceClasspathReload(null);
-				} catch (RuntimeException e) {
-					if (VERBOSE) {
-						e.printStackTrace();
-					}
-				} catch (JavaModelException e) {	
-					if (VERBOSE) {
-						e.printStackTrace();
-					}
-				}
-		}
-	}
-
-	/*
 	 * Traverse the set of projects which have changed namespace, and reset their 
 	 * caches and their dependents
 	 */
-	private void resetProjectCaches() {
+	public void resetProjectCaches() {
+		if (this.projectCachesToReset.size() == 0)
+			return;
+		
+		JavaModelManager.getJavaModelManager().resetJarTypeCache();
+		
 		Iterator iterator = this.projectCachesToReset.iterator();
 		HashMap projectDepencies = this.state.projectDependencies;
 		HashSet affectedDependents = new HashSet();
@@ -1762,76 +1845,130 @@
 	 * @see IResource 
 	 */
 	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(eventType){
-				case IResourceChangeEvent.PRE_DELETE :
-					try {
-						if(resource.getType() == IResource.PROJECT 
-							&& ((IProject) resource).hasNature(JavaCore.NATURE_ID)) {
-								
-							deleting((IProject)resource);
-						}
-					} catch(CoreException e){
-						// project doesn't exist or is not open: ignore
-					}
-					return;
-					
-				case IResourceChangeEvent.POST_CHANGE :
-					if (isAffectedBy(delta)) { // avoid populating for SYNC or MARKER deltas
-						try {
-							try {
-								stopDeltas();
-								checkProjectsBeingAddedOrRemoved(delta);
-								if (this.refreshedElements != null) {
-									createExternalArchiveDelta(null);
-								}
-								IJavaElementDelta translatedDelta = processResourceDelta(delta);
-								if (translatedDelta != null) { 
-									registerJavaModelDelta(translatedDelta);
-								}
-							} finally {
-								startDeltas();
-							}
-							notifyTypeHierarchies(this.state.elementChangedListeners, this.state.elementChangedListenerCount);
-							fire(null, ElementChangedEvent.POST_CHANGE);
-						} finally {
-							// workaround for bug 15168 circular errors not reported 
-							this.state.modelProjectsCache = null;
-							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;
-			}
+		int eventType = this.overridenEventType == -1 ? event.getType() : this.overridenEventType;
+		IResource resource = event.getResource();
+		IResourceDelta delta = event.getDelta();
+		
+		switch(eventType){
+			case IResourceChangeEvent.PRE_DELETE :
+				try {
+					if(resource.getType() == IResource.PROJECT 
+						&& ((IProject) resource).hasNature(JavaCore.NATURE_ID)) {
+							
+						deleting((IProject)resource);
+					}
+				} catch(CoreException e){
+					// project doesn't exist or is not open: ignore
+				}
+				return;
+				
+			case IResourceChangeEvent.POST_CHANGE :
+				if (isAffectedBy(delta)) { // avoid populating for SYNC or MARKER deltas
+					try {
+						try {
+							stopDeltas();
+							checkProjectsBeingAddedOrRemoved(delta);
+							
+							// generate classpath change deltas
+							if (this.classpathChanges.size() > 0) {
+								boolean hasDelta = this.currentDelta != null;
+								JavaElementDelta javaDelta = currentDelta();
+								Iterator changes = this.classpathChanges.values().iterator();
+								while (changes.hasNext()) {
+									ClasspathChange change = (ClasspathChange) changes.next();
+									int result = change.generateDelta(javaDelta);
+									if ((result & ClasspathChange.HAS_DELTA) != 0) {
+										hasDelta = true;
+										change.requestIndexing();
+										this.state.addClasspathValidation(change.project);
+									}
+									if ((result & ClasspathChange.HAS_PROJECT_CHANGE) != 0) {
+										this.state.addProjectReferenceChange(change.project, change.oldResolvedClasspath);
+									}
+								}
+								this.classpathChanges.clear();
+								if (!hasDelta)
+									this.currentDelta = null;
+							}
+							
+							// generate external archive change deltas
+							if (this.refreshedElements != null) {
+								createExternalArchiveDelta(null);
+							}
+							
+							// generate Java deltas from resource changes
+							IJavaElementDelta translatedDelta = processResourceDelta(delta);
+							if (translatedDelta != null) { 
+								registerJavaModelDelta(translatedDelta);
+							}
+						} finally {
+							this.sourceElementParserCache = null; // don't hold onto parser longer than necessary
+							startDeltas();
+						}
+						IElementChangedListener[] listeners;
+						int listenerCount;
+						synchronized (this.state) {
+							listeners = this.state.elementChangedListeners;
+							listenerCount = this.state.elementChangedListenerCount;
+						}
+						notifyTypeHierarchies(listeners, listenerCount);
+						fire(null, ElementChangedEvent.POST_CHANGE);
+					} finally {
+						// workaround for bug 15168 circular errors not reported 
+						this.state.resetOldJavaProjectNames();
+						this.oldRoots = null;
+					}
+				}
+				return;
+				
+			case IResourceChangeEvent.PRE_BUILD :
+				if(!isAffectedBy(delta))
+					return; // avoid populating for SYNC or MARKER deltas
+
+				// create classpath markers if necessary
+				boolean needCycleValidation = validateClasspaths(delta);
+				ClasspathValidation[] validations = this.state.removeClasspathValidations();
+				if (validations != null) {
+					for (int i = 0, length = validations.length; i < length; i++) {
+						ClasspathValidation validation = validations[i];
+						validation.validate();
+					}
+				}
+				
+				// update project references if necessary
+			    ProjectReferenceChange[] projectRefChanges = this.state.removeProjectReferenceChanges();
+				if (projectRefChanges != null) {
+				    for (int i = 0, length = projectRefChanges.length; i < length; i++) {
+				        try {
+					        projectRefChanges[i].updateProjectReferencesIfNecessary();
+				        } catch(JavaModelException e) {
+				            // project doesn't exist any longer, continue with next one
+				        }
+				    }
+				}
+				
+				if (needCycleValidation || projectRefChanges != null) {
+					// update all cycle markers since the project references changes may have affected cycles
+					try {
+						JavaProject.validateCycles(null);
+					} catch (JavaModelException e) {
+						// a project no longer exists
+					}
+				}
+				
+				JavaModel.flushExternalFileCache();
+				JavaBuilder.buildStarting();
+				
+				// does not fire any deltas
+				return;
+
+			case IResourceChangeEvent.POST_BUILD :
+				JavaBuilder.buildFinished();
+				return;
 		}
 	}
+
 	/*
 	 * Returns the root info for the given path. Look in the old roots table if kind is REMOVED.
 	 */
@@ -1875,6 +2012,9 @@
 		// process current delta
 		boolean processChildren = true;
 		if (res instanceof IProject) {
+			// reset source element parser cache
+			this.sourceElementParserCache = null;
+			
 			processChildren = 
 				this.updateCurrentDeltaAndIndex(
 					delta, 
@@ -1926,7 +2066,7 @@
 					);
 						
 				// is childRes in the output folder and is it filtered out ?
-				boolean isResFilteredFromOutput = this.isResFilteredFromOutput(outputsInfo, childRes, childType);
+				boolean isResFilteredFromOutput = this.isResFilteredFromOutput(rootInfo, outputsInfo, childRes, childType);
 
 				boolean isNestedRoot = rootInfo != null && childRootInfo != null;
 				if (!isResFilteredFromOutput 
@@ -1969,7 +2109,11 @@
 							orphanChildren[i] = child;
 						}
 					} else {
-						oneChildOnClasspath = true;
+						if (rootInfo == null && childRootInfo == null) {
+							// the non-java resource (or its parent folder) will be attached to the java project
+							if (orphanChildren == null) orphanChildren = new IResourceDelta[length];
+							orphanChildren[i] = child;
+						}
 					}
 				} else {
 					oneChildOnClasspath = true; // to avoid reporting child delta as non-java resource delta
@@ -2016,17 +2160,10 @@
 		} // else resource delta will be added by parent
 	}
 
-	/*
-	 * Check whether .classpath files are affected by the given delta.
-	 * Creates/removes problem markers if needed.
-	 * Remember the affected projects in the given set.
-	 */
-	private void updateClasspathMarkers(IResourceDelta delta, HashSet affectedProjects, Map preferredClasspaths, Map preferredOutputs) {
+	private void validateClasspaths(IResourceDelta delta, HashSet affectedProjects) {
 		IResource resource = delta.getResource();
 		boolean processChildren = false;
-
 		switch (resource.getType()) {
-	
 			case IResource.ROOT :
 				if (delta.getKind() == IResourceDelta.CHANGED) {
 					processChildren = true;
@@ -2044,35 +2181,19 @@
 					case IResourceDelta.CHANGED:
 						processChildren = isJavaProject;
 						if ((delta.getFlags() & IResourceDelta.OPEN) != 0) {
-							// project opened or closed: remember  project and its dependents
-							affectedProjects.add(project.getFullPath());
+							// project opened or closed
 							if (isJavaProject) {
 								JavaProject javaProject = (JavaProject)JavaCore.create(project);
-								javaProject.updateClasspathMarkers(preferredClasspaths, preferredOutputs); // in case .classpath got modified while closed
+								this.state.addClasspathValidation(javaProject); // in case .classpath got modified while closed
 							}
+							affectedProjects.add(project.getFullPath());
 						} else if ((delta.getFlags() & IResourceDelta.DESCRIPTION) != 0) {
-							boolean wasJavaProject = this.manager.getJavaModel().findJavaProject(project) != null;
-							if (wasJavaProject && !isJavaProject) {
-								// project no longer has Java nature, discard Java related obsolete markers
+							boolean wasJavaProject = this.state.findJavaProject(project.getName()) != null;
+							if (wasJavaProject  != isJavaProject) {
+								// project gained or lost Java nature
+								JavaProject javaProject = (JavaProject)JavaCore.create(project);
+								this.state.addClasspathValidation(javaProject); // add/remove classpath markers
 								affectedProjects.add(project.getFullPath());
-								// flush classpath markers
-								JavaProject javaProject = (JavaProject)JavaCore.create(project);
-								javaProject.
-									flushClasspathProblemMarkers(
-										true, // flush cycle markers
-										true  //flush classpath format markers
-									);
-									
-								// 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;
@@ -2082,86 +2203,71 @@
 				}
 				break;
 			case IResource.FILE :
-				/* check classpath file change */
+				/* check classpath or prefs files change */
 				IFile file = (IFile) resource;
-				if (file.getName().equals(JavaProject.CLASSPATH_FILENAME)) {
-					affectedProjects.add(file.getProject().getFullPath());
+				String fileName = file.getName();
+				if (fileName.equals(JavaProject.CLASSPATH_FILENAME)) {
 					JavaProject javaProject = (JavaProject)JavaCore.create(file.getProject());
-					javaProject.updateClasspathMarkers(preferredClasspaths, preferredOutputs);
-					break;
+					this.state.addClasspathValidation(javaProject);
+					affectedProjects.add(file.getProject().getFullPath());
 				}
-//				/* check custom preference file change */
-//				if (file.getName().equals(JavaProject.PREF_FILENAME)) {
-//					reconcilePreferenceFileUpdate(delta, file, project);
-//					break;
-//				}
 				break;
 		}
 		if (processChildren) {
 			IResourceDelta[] children = delta.getAffectedChildren();
 			for (int i = 0; i < children.length; i++) {
-				updateClasspathMarkers(children[i], affectedProjects, preferredClasspaths, preferredOutputs);
+				validateClasspaths(children[i], affectedProjects);
 			}
 		}
 	}
 
 	/*
-	 * Update the .classpath format, missing entries and cycle markers for the projects affected by the given delta.
+	 * Validate the classpaths of the projects affected by the given delta.
+	 * Create markers if necessary.
+	 * Returns whether cycle markers should be recomputed.
 	 */
-	private void updateClasspathMarkers(IResourceDelta delta) {
-		
-		Map preferredClasspaths = new HashMap(5);
-		Map preferredOutputs = new HashMap(5);
+	private boolean validateClasspaths(IResourceDelta delta) {
 		HashSet affectedProjects = new HashSet(5);
-		
-		// 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); 
+		validateClasspaths(delta, affectedProjects);
+		boolean needCycleValidation = false;
 	
-		// update .classpath format markers for affected projects (dependent projects 
+		// validate classpaths of affected projects (dependent projects 
 		// or projects that reference a library in one of the projects that have changed)
 		if (!affectedProjects.isEmpty()) {
-			try {
-				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;
+			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);
+				try {
+					IPath projectPath = project.getFullPath();
+					IClasspathEntry[] classpath = javaProject.getResolvedClasspath(); // 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())) {
+									this.state.addClasspathValidation(javaProject);
+									needCycleValidation = true;
 								}
-							}
-						} catch(JavaModelException e) {
-								// project no longer exists
+								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)) {
+									this.state.addClasspathValidation(javaProject);
+								}
+								break;
 						}
 					}
+				} catch(JavaModelException e) {
+						// project no longer exists
 				}
-
-				// update all cycle markers
-				JavaProject.updateAllCycleMarkers(preferredClasspaths);
-			} catch(JavaModelException e) {
-				// project no longer exists
 			}
 		}
+		return needCycleValidation;
 	}
 	
 	/*
@@ -2182,6 +2288,8 @@
 				}
 				updateIndex(element, delta);
 				elementAdded(element, delta, rootInfo);
+				if (elementType == IJavaElement.PACKAGE_FRAGMENT_ROOT)
+					this.state.addClasspathValidation(rootInfo.project);
 				return elementType == IJavaElement.PACKAGE_FRAGMENT;
 			case IResourceDelta.REMOVED :
 				deltaRes = delta.getResource();
@@ -2193,6 +2301,8 @@
 				}
 				updateIndex(element, delta);
 				elementRemoved(element, delta, rootInfo);
+				if (elementType == IJavaElement.PACKAGE_FRAGMENT_ROOT) 
+					this.state.addClasspathValidation(rootInfo.project);
 	
 				if (deltaRes.getType() == IResource.PROJECT){			
 					// reset the corresponding project built state, since cannot reuse if added back
@@ -2235,8 +2345,7 @@
 								this.manager.indexManager.indexAll(res);
 							}
 						} else {
-							JavaModel javaModel = this.manager.getJavaModel();
-							boolean wasJavaProject = javaModel.findJavaProject(res) != null;
+							boolean wasJavaProject = this.state.findJavaProject(res.getName()) != null;
 							if (wasJavaProject) {
 								close(element);
 								removeFromParentInfo(element);
@@ -2249,8 +2358,7 @@
 					}
 					if ((flags & IResourceDelta.DESCRIPTION) != 0) {
 						IProject res = (IProject)delta.getResource();
-						JavaModel javaModel = this.manager.getJavaModel();
-						boolean wasJavaProject = javaModel.findJavaProject(res) != null;
+						boolean wasJavaProject = this.state.findJavaProject(res.getName()) != null;
 						boolean isJavaProject = JavaProject.hasJavaNature(res);
 						if (wasJavaProject != isJavaProject) {
 							// project's nature has been added or removed
@@ -2400,10 +2508,14 @@
 						if ((flags & IResourceDelta.CONTENT) == 0 && (flags & IResourceDelta.ENCODING) == 0)
 							break;
 					case IResourceDelta.ADDED :
-						indexManager.addSource(file, file.getProject().getFullPath());
+						indexManager.addSource(file, file.getProject().getFullPath(), getSourceElementParser(element));
+						// Clean file from secondary types cache but do not update indexing secondary type cache as it will be updated through indexing itself
+						this.manager.secondaryTypesRemoving(file, false);
 						break;
 					case IResourceDelta.REMOVED :
 						indexManager.remove(Util.relativePath(file.getFullPath(), 1/*remove project segment*/), file.getProject().getFullPath());
+						// Clean file from secondary types cache and update indexing secondary type cache as indexing cannot remove secondary types from cache
+						this.manager.secondaryTypesRemoving(file, true);
 						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 fc424d6..0dc263f 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -12,6 +12,7 @@
 
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.IJavaElementDelta;
+import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.JavaModelException;
 
 /**
@@ -26,23 +27,29 @@
 	protected void executeOperation() throws JavaModelException {
 		CompilationUnit workingCopy = getWorkingCopy();
 		
-		int useCount = JavaModelManager.getJavaModelManager().discardPerWorkingCopyInfo(workingCopy);
+		JavaModelManager manager = JavaModelManager.getJavaModelManager();
+		int useCount = manager.discardPerWorkingCopyInfo(workingCopy);
 		if (useCount == 0) {
+			IJavaProject javaProject = workingCopy.getJavaProject();
+			if (ExternalJavaProject.EXTERNAL_PROJECT_NAME.equals(javaProject.getElementName())) {
+				manager.removePerProjectInfo((JavaProject) javaProject);
+				manager.containerRemove(javaProject);
+			}
 			if (!workingCopy.isPrimary()) {
 				// report removed java delta for a non-primary working copy
-				JavaElementDelta delta = new JavaElementDelta(this.getJavaModel());
+				JavaElementDelta delta = new JavaElementDelta(getJavaModel());
 				delta.removed(workingCopy);
 				addDelta(delta);
 				removeReconcileDelta(workingCopy);
 			} else {
 				if (workingCopy.getResource().isAccessible()) {
 					// report a F_PRIMARY_WORKING_COPY change delta for a primary working copy
-					JavaElementDelta delta = new JavaElementDelta(this.getJavaModel());
+					JavaElementDelta delta = new JavaElementDelta(getJavaModel());
 					delta.changed(workingCopy, IJavaElementDelta.F_PRIMARY_WORKING_COPY);
 					addDelta(delta);
 				} else {
 					// report a REMOVED delta
-					JavaElementDelta delta = new JavaElementDelta(this.getJavaModel());
+					JavaElementDelta delta = new JavaElementDelta(getJavaModel());
 					delta.removed(workingCopy, IJavaElementDelta.F_PRIMARY_WORKING_COPY);
 					addDelta(delta);
 				}
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 a9ce910..599602f 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -77,6 +77,13 @@
 }
 
 /*
+ * Returns a new instance of the receiver.
+ */
+protected LRUCache newInstance(int size, int overflow) {
+	return new ElementCache(size, overflow);
+}
+
+/*
  * If the given parent was the one that increased the space limit, reset
  * the space limit to the given default value.
  */
@@ -87,11 +94,4 @@
 	}
 }
 
-/**
- * Returns a new instance of the reciever.
- */
-protected LRUCache newInstance(int size, int overflow) {
-	return new ElementCache(size, overflow);
-}
-
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ExternalJavaProject.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ExternalJavaProject.java
new file mode 100755
index 0000000..03f42d0
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ExternalJavaProject.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.JavaModelException;
+
+public class ExternalJavaProject extends JavaProject {
+	
+	/*
+	 * Note this name can be surfaced in the UI (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=128258)
+	 */
+	public static final String EXTERNAL_PROJECT_NAME = " "; //$NON-NLS-1$
+
+	public ExternalJavaProject(IClasspathEntry[] rawClasspath) {
+		super(ResourcesPlugin.getWorkspace().getRoot().getProject(EXTERNAL_PROJECT_NAME), JavaModelManager.getJavaModelManager().getJavaModel());
+		try {
+			getPerProjectInfo().setClasspath(rawClasspath, defaultOutputLocation(), JavaModelStatus.VERIFIED_OK/*no .classpath format problem*/, null/*no resolved claspath*/, null/*no reverse map*/, null/*no resolve entry map*/, null/*no resolved status*/);
+		} catch (JavaModelException e) {
+			// getPerProjectInfo() never throws JavaModelException for an ExternalJavaProject
+		}
+	}
+	
+	public boolean equals(Object o) {
+		return this == o;
+	}
+
+	public boolean exists() {
+		// external project never exists
+		return false;
+	}
+	
+	public String getOption(String optionName, boolean inheritJavaCoreOptions) {
+		if (JavaCore.COMPILER_PB_FORBIDDEN_REFERENCE.equals(optionName)
+				|| JavaCore.COMPILER_PB_DISCOURAGED_REFERENCE.equals(optionName))
+			return JavaCore.IGNORE;
+		return super.getOption(optionName, inheritJavaCoreOptions);
+	}
+	
+	public boolean isOnClasspath(IJavaElement element) {
+		// since project is external, no element is on classpath (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=61013#c16)
+		return false;
+	}
+
+	public boolean isOnClasspath(IResource resource) {
+		// since project is external, no resource is on classpath (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=61013#c16)
+		return false;
+	}
+
+}
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 55b467c..f054045 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 5c42b88..bf37134 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -11,8 +11,8 @@
 package org.eclipse.jdt.internal.core;
 
 public interface INamingRequestor {
-	void acceptNameWithPrefixAndSuffix(char[] name, boolean isFirstPrefix, boolean isFirstSuffix);
-	void acceptNameWithPrefix(char[] name, boolean isFirstPrefix);
-	void acceptNameWithSuffix(char[] name, boolean isFirstSuffix);
-	void acceptNameWithoutPrefixAndSuffix(char[] name);
+	void acceptNameWithPrefixAndSuffix(char[] name, boolean isFirstPrefix, boolean isFirstSuffix, int reusedCharacters);
+	void acceptNameWithPrefix(char[] name, boolean isFirstPrefix, int reusedCharacters);
+	void acceptNameWithSuffix(char[] name, boolean isFirstSuffix, int reusedCharacters);
+	void acceptNameWithoutPrefixAndSuffix(char[] name, int reusedCharacters);
 }
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 c303e6a..f96b7fc 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 5b86608..e2e0003 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,9 +10,8 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
+import org.eclipse.core.runtime.Assert;
 import org.eclipse.jdt.core.*;
-import org.eclipse.jdt.core.IImportDeclaration;
-import org.eclipse.jdt.core.JavaModelException;
 
 /**
  * Handle for an import declaration. Info object is a ImportDeclarationElementInfo.
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 2554b08..11d1781 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 665aa22..9818348 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 3e28798..ea6e4a7 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -14,12 +14,12 @@
 
 import org.eclipse.jdt.core.Flags;
 import org.eclipse.jdt.core.IJavaProject;
-import org.eclipse.jdt.core.JavaConventions;
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.compiler.InvalidInputException;
 import org.eclipse.jdt.internal.codeassist.impl.AssistOptions;
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.compiler.parser.Scanner;
+import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
 import org.eclipse.jdt.internal.compiler.parser.TerminalTokens;
 
 public class InternalNamingConventions {
@@ -36,7 +36,7 @@
 				null/*taskPriorities*/,
 				true/*taskCaseSensitive*/);
 	}
-	public static void suggestArgumentNames(IJavaProject javaProject, char[] packageName, char[] qualifiedTypeName, int dim, char[][] excludedNames, INamingRequestor requestor) {
+	public static void suggestArgumentNames(IJavaProject javaProject, char[] packageName, char[] qualifiedTypeName, int dim, char[] internalPrefix, char[][] excludedNames, INamingRequestor requestor) {
 		Map options = javaProject.getOptions(true);
 		CompilerOptions compilerOptions = new CompilerOptions(options);
 		AssistOptions assistOptions = new AssistOptions(options);
@@ -45,13 +45,14 @@
 			packageName,
 			qualifiedTypeName,
 			dim,
+			internalPrefix,
 			assistOptions.argumentPrefixes,
 			assistOptions.argumentSuffixes,
 			excludedNames,
 			getNameScanner(compilerOptions),
 			requestor);
 	}
-	public static void suggestFieldNames(IJavaProject javaProject, char[] packageName, char[] qualifiedTypeName, int dim, int modifiers, char[][] excludedNames, INamingRequestor requestor) {
+	public static void suggestFieldNames(IJavaProject javaProject, char[] packageName, char[] qualifiedTypeName, int dim, int modifiers, char[] internalPrefix, char[][] excludedNames, INamingRequestor requestor) {
 		boolean isStatic = Flags.isStatic(modifiers);
 		
 		Map options = javaProject.getOptions(true);
@@ -62,13 +63,14 @@
 			packageName,
 			qualifiedTypeName,
 			dim,
+			internalPrefix,
 			isStatic ? assistOptions.staticFieldPrefixes : assistOptions.fieldPrefixes,
 			isStatic ? assistOptions.staticFieldSuffixes : assistOptions.fieldSuffixes,
 			excludedNames,
 			getNameScanner(compilerOptions),
 			requestor);
 	}
-	public static void suggestLocalVariableNames(IJavaProject javaProject, char[] packageName, char[] qualifiedTypeName, int dim, char[][] excludedNames, INamingRequestor requestor) {
+	public static void suggestLocalVariableNames(IJavaProject javaProject, char[] packageName, char[] qualifiedTypeName, int dim, char[] internalPrefix, char[][] excludedNames, INamingRequestor requestor) {
 		Map options = javaProject.getOptions(true);
 		CompilerOptions compilerOptions = new CompilerOptions(options);
 		AssistOptions assistOptions = new AssistOptions(options);
@@ -77,6 +79,7 @@
 			packageName,
 			qualifiedTypeName,
 			dim,
+			internalPrefix,
 			assistOptions.localPrefixes,
 			assistOptions.localSuffixes,
 			excludedNames,
@@ -88,6 +91,7 @@
 		char[] packageName,
 		char[] qualifiedTypeName,
 		int dim,
+		char[] internalPrefix,
 		char[][] prefixes,
 		char[][] suffixes,
 		char[][] excludedNames,
@@ -97,6 +101,12 @@
 		if(qualifiedTypeName == null || qualifiedTypeName.length == 0)
 			return;
 		
+		if(internalPrefix == null) {
+			internalPrefix = CharOperation.NO_CHAR;
+		} else {
+			internalPrefix = removePrefix(internalPrefix, prefixes);
+		}
+		
 		char[] typeName = CharOperation.lastSegment(qualifiedTypeName, '.');
 	
 		if(prefixes == null || prefixes.length == 0) {
@@ -128,7 +138,10 @@
 				case TerminalTokens.TokenNamelong :
 				case TerminalTokens.TokenNamefloat :
 				case TerminalTokens.TokenNamedouble :
-				case TerminalTokens.TokenNameboolean :	
+				case TerminalTokens.TokenNameboolean :
+					
+					if (internalPrefix != null && internalPrefix.length > 0) return;
+					
 					char[] name = computeBaseTypeNames(typeName[0], excludedNames);
 					if(name != null) {
 						tempNames =  new char[][]{name};
@@ -146,7 +159,7 @@
 	
 		boolean acceptDefaultName = true;
 		
-		for (int i = 0; i < tempNames.length; i++) {
+		next : for (int i = 0; i < tempNames.length; i++) {
 			char[] tempName = tempNames[i];
 			if(dim > 0) {
 				int length = tempName.length;
@@ -167,50 +180,72 @@
 				}
 			}
 		
-			for (int j = 0; j < prefixes.length; j++) {
-				if(prefixes[j].length > 0
-					&& Character.isLetterOrDigit(prefixes[j][prefixes[j].length - 1])) {
-					tempName[0] = Character.toUpperCase(tempName[0]);
-				} else {
-					tempName[0] = Character.toLowerCase(tempName[0]);
-				}
-				char[] prefixName = CharOperation.concat(prefixes[j], tempName);
-				for (int k = 0; k < suffixes.length; k++) {
-					char[] suffixName = CharOperation.concat(prefixName, suffixes[k]);
-					suffixName =
-						excludeNames(
-							suffixName,
-							prefixName,
-							suffixes[k],
-							excludedNames);
-					if(JavaConventions.validateFieldName(new String(suffixName)).isOK()) {
-						acceptName(suffixName, prefixes[j], suffixes[k],  j == 0, k == 0, requestor);
-						acceptDefaultName = false;
-					} else {
-						suffixName = CharOperation.concat(
-							prefixName,
-							String.valueOf(1).toCharArray(),
-							suffixes[k]
-						);
-						suffixName =
-							excludeNames(
-								suffixName,
-								prefixName,
-								suffixes[k],
-								excludedNames);
-						if(JavaConventions.validateFieldName(new String(suffixName)).isOK()) {
-							acceptName(suffixName, prefixes[j], suffixes[k], j == 0, k == 0, requestor);
-							acceptDefaultName = false;
+			char[] unprefixedName = tempName;
+			for (int j = 0; j <= internalPrefix.length; j++) {
+				if(j == internalPrefix.length || CharOperation.prefixEquals(CharOperation.subarray(internalPrefix, j, -1), unprefixedName, false)) {
+					tempName = CharOperation.concat(CharOperation.subarray(internalPrefix, 0, j), unprefixedName);
+					if(j != 0) tempName[j] = ScannerHelper.toUpperCase(tempName[j]);
+					for (int k = 0; k < prefixes.length; k++) {
+						if(prefixes[k].length > 0
+							&& ScannerHelper.isLetterOrDigit(prefixes[k][prefixes[k].length - 1])) {
+							tempName[0] = ScannerHelper.toUpperCase(tempName[0]);
+						} else {
+							tempName[0] = ScannerHelper.toLowerCase(tempName[0]);
+						}
+						char[] prefixName = CharOperation.concat(prefixes[k], tempName);
+						for (int l = 0; l < suffixes.length; l++) {
+							char[] suffixName = CharOperation.concat(prefixName, suffixes[l]);
+							suffixName =
+								excludeNames(
+									suffixName,
+									prefixName,
+									suffixes[l],
+									excludedNames);
+							try{
+								nameScanner.setSource(suffixName);
+								switch (nameScanner.getNextToken()) {
+									case TerminalTokens.TokenNameIdentifier :
+										int token = nameScanner.getNextToken();
+										if (token == TerminalTokens.TokenNameEOF && nameScanner.startPosition == suffixName.length) {
+											acceptName(suffixName, prefixes[k], suffixes[l],  k == 0, l == 0, internalPrefix.length - j, requestor);
+											acceptDefaultName = false;
+										}
+										break;
+									default:
+										suffixName = CharOperation.concat(
+											prefixName,
+											String.valueOf(1).toCharArray(),
+											suffixes[l]
+										);
+										suffixName =
+											excludeNames(
+												suffixName,
+												prefixName,
+												suffixes[l],
+												excludedNames);
+										nameScanner.setSource(suffixName);
+										switch (nameScanner.getNextToken()) {
+											case TerminalTokens.TokenNameIdentifier :
+												token = nameScanner.getNextToken();
+												if (token == TerminalTokens.TokenNameEOF && nameScanner.startPosition == suffixName.length) {
+													acceptName(suffixName, prefixes[k], suffixes[l], k == 0, l == 0, internalPrefix.length - j, requestor);
+													acceptDefaultName = false;
+												}
+										}
+								}
+							} catch(InvalidInputException e){
+								// ignore
+							}
 						}
 					}
+					continue next;
 				}
-			
 			}
 		}
 		// if no names were found
 		if(acceptDefaultName) {
 			char[] name = excludeNames(DEFAULT_NAME, DEFAULT_NAME, CharOperation.NO_CHAR, excludedNames);
-			requestor.acceptNameWithoutPrefixAndSuffix(name);
+			requestor.acceptNameWithoutPrefixAndSuffix(name, 0);
 		}
 	}
 	
@@ -220,15 +255,16 @@
 		char[] suffix,
 		boolean isFirstPrefix,
 		boolean isFirstSuffix,
+		int reusedCharacters,
 		INamingRequestor requestor) {
 		if(prefix.length > 0 && suffix.length > 0) {
-			requestor.acceptNameWithPrefixAndSuffix(name, isFirstPrefix, isFirstSuffix);
+			requestor.acceptNameWithPrefixAndSuffix(name, isFirstPrefix, isFirstSuffix, reusedCharacters);
 		} else if(prefix.length > 0){
-			requestor.acceptNameWithPrefix(name, isFirstPrefix);
+			requestor.acceptNameWithPrefix(name, isFirstPrefix, reusedCharacters);
 		} else if(suffix.length > 0){
-			requestor.acceptNameWithSuffix(name, isFirstSuffix);
+			requestor.acceptNameWithSuffix(name, isFirstSuffix, reusedCharacters);
 		} else {
-			requestor.acceptNameWithoutPrefixAndSuffix(name);
+			requestor.acceptNameWithoutPrefixAndSuffix(name, reusedCharacters);
 		}
 	}
 	
@@ -255,15 +291,15 @@
 		boolean previousIsUpperCase = false;
 		boolean previousIsLetter = true;
 		for(int i = sourceName.length - 1 ; i >= 0 ; i--){
-			boolean isUpperCase = Character.isUpperCase(sourceName[i]);
-			boolean isLetter = Character.isLetter(sourceName[i]);
+			boolean isUpperCase = ScannerHelper.isUpperCase(sourceName[i]);
+			boolean isLetter = ScannerHelper.isLetter(sourceName[i]);
 			if(isUpperCase && !previousIsUpperCase && previousIsLetter){
 				char[] name = CharOperation.subarray(sourceName,i,sourceName.length);
 				if(name.length > 1){
 					if(nameCount == names.length) {
 						System.arraycopy(names, 0, names = new char[nameCount * 2][], 0, nameCount);
 					}
-					name[0] = Character.toLowerCase(name[0]);
+					name[0] = ScannerHelper.toLowerCase(name[0]);
 					names[nameCount++] = name;
 				}
 			}
@@ -298,4 +334,90 @@
 		}
 		return suffixName;
 	}
+	
+	private static char[] removePrefix(char[] name, char[][] prefixes) {
+		// remove longer prefix
+		char[] withoutPrefixName = name;
+		if (prefixes != null) {
+			int bestLength = 0;
+			int nameLength = name.length;
+			for (int i= 0; i < prefixes.length; i++) {
+				char[] prefix = prefixes[i];
+				
+				int prefixLength = prefix.length;
+				if(prefixLength <= nameLength) {
+					if(CharOperation.prefixEquals(prefix, name, false)) {
+						if (prefixLength > bestLength) {
+							bestLength = prefixLength;
+						}
+					}
+				} else {
+					int currLen = 0;
+					for (; currLen < nameLength; currLen++) {
+						if(ScannerHelper.toLowerCase(prefix[currLen]) != ScannerHelper.toLowerCase(name[currLen])) {
+							if (currLen > bestLength) {
+								bestLength = currLen;
+							}
+							break;
+						}
+					}
+					if(currLen == nameLength && currLen > bestLength) {
+						bestLength = currLen;
+					}
+				}
+			}
+			if(bestLength > 0) {
+				if(bestLength == nameLength) {
+					withoutPrefixName = CharOperation.NO_CHAR;
+				} else {
+					withoutPrefixName = CharOperation.subarray(name, bestLength, nameLength);
+				}
+			}
+		}
+//		
+//		
+//		// remove longer prefix
+//		char[] withoutPrefixName = name;
+//		if (prefixes != null) {
+//			int bestLength = 0;
+//			for (int i= 0; i < prefixes.length; i++) {
+//				char[] prefix = prefixes[i];
+//				int max = prefix.length < name.length ? prefix.length : name.length;
+//				int currLen = 0;
+//				for (; currLen < max; currLen++) {
+//					if(Character.toLowerCase(prefix[currLen]) != Character.toLowerCase(name[currLen])) {
+//						if (currLen > bestLength) {
+//							bestLength = currLen;
+//						}
+//						break;
+//					}
+//				}
+//				if(currLen == max && currLen > bestLength) {
+//					bestLength = max;
+//				}
+//			}
+//			if(bestLength > 0) {
+//				if(bestLength == name.length) {
+//					withoutPrefixName = CharOperation.NO_CHAR;
+//				} else {
+//					withoutPrefixName = CharOperation.subarray(name, bestLength, name.length);
+//				}
+//			}
+//		}
+		
+		return withoutPrefixName;
+	}
+	
+	public static final boolean prefixEquals(char[] prefix, char[] name) {
+
+		int max = prefix.length;
+		if (name.length < max)
+			return false;
+		for (int i = max;
+			--i >= 0;
+			) // assumes the prefix is not larger than the name
+				if (prefix[i] != name[i])
+					return false;
+			return true;
+	}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarEntryDirectory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarEntryDirectory.java
new file mode 100755
index 0000000..317df0e
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarEntryDirectory.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jdt.core.IJarEntryResource;
+
+public class JarEntryDirectory extends JarEntryResource {
+	private IJarEntryResource[] children;
+	
+	public JarEntryDirectory(String simpleName) {
+		super(simpleName);
+	}
+	
+	public JarEntryResource clone(Object newParent) {
+		JarEntryDirectory dir = new JarEntryDirectory(this.simpleName);
+		dir.setParent(newParent);
+		int length = this.children.length;
+		if (length > 0) {
+			IJarEntryResource[] newChildren = new IJarEntryResource[length];
+			for (int i = 0; i < length; i++) {
+				JarEntryResource child = (JarEntryResource) this.children[i];
+				newChildren[i] = child.clone(dir);
+			}
+			dir.setChildren(newChildren);
+		}
+		return dir;
+	}
+	
+	public IJarEntryResource[] getChildren() {
+		return this.children;
+	}
+
+	public InputStream getContents() throws CoreException {
+		return new ByteArrayInputStream(new byte[0]);
+	}
+
+	public boolean isFile() {
+		return false;
+	}
+
+	public void setChildren(IJarEntryResource[] children) {
+		this.children = children;
+	}
+
+	public String toString() {
+		return "JarEntryDirectory["+getEntryName()+"]"; //$NON-NLS-1$ //$NON-NLS-2$ 
+	}
+}
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 b457b77..2848e33 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,6 +10,7 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.zip.ZipEntry;
@@ -17,65 +18,60 @@
 
 import org.eclipse.core.resources.IStorage;
 import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IPath;
-import org.eclipse.core.runtime.Path;
-import org.eclipse.core.runtime.PlatformObject;
+import org.eclipse.jdt.core.IJarEntryResource;
 import org.eclipse.jdt.core.IJavaModelStatusConstants;
 import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.internal.compiler.util.Util;
 
 /**
- * A jar entry that represents a non-java resource found in a JAR.
+ * A jar entry that represents a non-java file found in a JAR.
  *
  * @see IStorage
  */
-public class JarEntryFile extends PlatformObject implements IStorage {
-	private String entryName;
-	private String zipName;
-	private IPath path;
+public class JarEntryFile  extends JarEntryResource {
+	private static final IJarEntryResource[] NO_CHILDREN = new IJarEntryResource[0];
 	
-	public JarEntryFile(String entryName, String zipName){
-		this.entryName = entryName;
-		this.zipName = zipName;
-		this.path = new Path(this.entryName);
+	public JarEntryFile(String simpleName) {
+		super(simpleName);
 	}
-public InputStream getContents() throws CoreException {
-
-	try {
-		if (JavaModelManager.ZIP_ACCESS_VERBOSE) {
-			System.out.println("(" + Thread.currentThread() + ") [JarEntryFile.getContents()] Creating ZipFile on " + this.zipName); //$NON-NLS-1$	//$NON-NLS-2$
-		}
-		ZipFile zipFile = new ZipFile(this.zipName); 
-		ZipEntry zipEntry = zipFile.getEntry(this.entryName);
-		if (zipEntry == null){
-			throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, this.entryName));
-		}
-		return zipFile.getInputStream(zipEntry);
-	} catch (IOException e){
-		throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
+	
+	public JarEntryResource clone(Object newParent) {
+		JarEntryFile file = new JarEntryFile(simpleName);
+		file.setParent(newParent);
+		return file;
 	}
-}
-/**
- * @see IStorage#getFullPath
- */
-public IPath getFullPath() {
-	return this.path;
-}
-/**
- * @see IStorage#getName
- */
-public String getName() {
-	return this.path.lastSegment();
-}
-/**
- * @see IStorage#isReadOnly()
- */
-public boolean isReadOnly() {
-	return true;
-}
-/**
- * @see IStorage#isReadOnly()
- */
-public String toString() {
-	return "JarEntryFile["+this.zipName+"::"+this.entryName+"]"; //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-1$
-}
+	
+	public InputStream getContents() throws CoreException {
+		ZipFile zipFile = null;
+		try {
+			zipFile = getZipFile();
+			if (JavaModelManager.ZIP_ACCESS_VERBOSE) {
+				System.out.println("(" + Thread.currentThread() + ") [JarEntryFile.getContents()] Creating ZipFile on " +zipFile.getName()); //$NON-NLS-1$	//$NON-NLS-2$
+			}
+			String entryName = getEntryName();
+			ZipEntry zipEntry = zipFile.getEntry(entryName);
+			if (zipEntry == null){
+				throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, entryName));
+			}
+			byte[] contents = Util.getZipEntryByteContent(zipEntry, zipFile);
+			return new ByteArrayInputStream(contents);
+		} catch (IOException e){
+			throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
+		} finally {
+			// avoid leaking ZipFiles
+			JavaModelManager.getJavaModelManager().closeZipFile(zipFile);
+		}
+	}
+	
+	public IJarEntryResource[] getChildren() {
+		return NO_CHILDREN;
+	}
+	
+	public boolean isFile() {
+		return true;
+	}
+	
+	public String toString() {
+		return "JarEntryFile["+getEntryName()+"]"; //$NON-NLS-2$ //$NON-NLS-1$
+	}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarEntryResource.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarEntryResource.java
new file mode 100755
index 0000000..cc8c4de
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarEntryResource.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core;
+
+import java.util.zip.ZipFile;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.PlatformObject;
+import org.eclipse.jdt.core.IJarEntryResource;
+import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
+import org.eclipse.jdt.internal.core.util.Util;
+
+public abstract class JarEntryResource  extends PlatformObject implements IJarEntryResource {
+
+	protected Object parent;
+	protected String simpleName;
+
+	public JarEntryResource(String simpleName) {
+		this.simpleName = simpleName;
+	}
+	
+	public abstract JarEntryResource clone(Object newParent);
+
+	public boolean equals(Object obj) {
+		if (! (obj instanceof JarEntryResource))
+			return false;
+		JarEntryResource other = (JarEntryResource) obj;
+		return this.parent.equals(other.parent) && this.simpleName.equals(other.simpleName);
+	}
+	
+	protected String getEntryName() {
+		String parentEntryName;
+		if (this.parent instanceof IPackageFragment) {
+			String elementName = ((IPackageFragment) this.parent).getElementName();
+			parentEntryName = elementName.length() == 0 ? "" : elementName .replace('.', '/') + '/'; //$NON-NLS-1$
+		} else if (this.parent instanceof IPackageFragmentRoot) {
+			parentEntryName = ""; //$NON-NLS-1$
+		} else {
+			parentEntryName = ((JarEntryDirectory) this.parent).getEntryName() + '/';
+		}
+		return parentEntryName + this.simpleName;
+	}
+	
+	public IPath getFullPath() {
+		return new Path(getEntryName()).makeAbsolute();
+	}
+	
+	public String getName() {
+		return this.simpleName;
+	}
+	
+	public Object getParent() {
+		return this.parent;
+	}
+	
+	public IPackageFragmentRoot getPackageFragmentRoot() {
+		if (this.parent instanceof IPackageFragment) {
+			return (IPackageFragmentRoot) ((IPackageFragment) this.parent).getParent();
+		} else if (this.parent instanceof IPackageFragmentRoot) {
+			return (IPackageFragmentRoot) this.parent;
+		} else {
+			return ((JarEntryDirectory) this.parent).getPackageFragmentRoot();
+		}
+	}
+	
+	protected ZipFile getZipFile() throws CoreException {
+		if (this.parent instanceof IPackageFragment) {
+			JarPackageFragmentRoot root = (JarPackageFragmentRoot) ((IPackageFragment) this.parent).getParent();
+			return root.getJar();
+		} else if (this.parent instanceof JarPackageFragmentRoot) {
+			return ((JarPackageFragmentRoot) this.parent).getJar();
+		} else
+			return ((JarEntryDirectory) this.parent).getZipFile();
+	}
+	
+	public int hashCode() {
+		return Util.combineHashCodes(this.simpleName.hashCode(), this.parent.hashCode());
+	}
+	
+	public boolean isReadOnly() {
+		return true;
+	}
+
+	public void setParent(Object parent) {
+		this.parent = parent;
+	}
+}
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 3ef3b6a..66a3350 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -13,11 +13,15 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.Map;
 
 import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Path;
 import org.eclipse.jdt.core.IClassFile;
 import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IJarEntryResource;
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.IJavaModelStatusConstants;
 import org.eclipse.jdt.core.JavaModelException;
@@ -59,7 +63,7 @@
 /**
  * Compute all the non-java resources according to the entry name found in the jar file.
  */
-/* package */ void computeNonJavaResources(String[] resNames, JarPackageFragmentInfo info, String zipName) {
+/* package */ void computeNonJavaResources(String[] resNames, JarPackageFragment pkg, JarPackageFragmentInfo info, String zipName) {
 	if (resNames == null) {
 		info.setNonJavaResources(null);
 		return;
@@ -68,19 +72,62 @@
 	if (max == 0) {
 	    info.setNonJavaResources(JavaElementInfo.NO_NON_JAVA_RESOURCES);
 	} else {
-		Object[] res = new Object[max];
-		int index = 0;
+		HashMap jarEntries = new HashMap(); // map from IPath to IJarEntryResource
+		HashMap childrenMap = new HashMap(); // map from IPath to ArrayList<IJarEntryResource>
+		ArrayList topJarEntries = new ArrayList();
 		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 (!Util.isJavaLikeFileName(resName)) {
-				resName = Util.concatWith(this.names, resName, '/');
-				res[index++] = new JarEntryFile(resName, zipName);
+				IPath filePath = new Path(resName);
+				IPath childPath = filePath.removeFirstSegments(this.names.length);
+				JarEntryFile file = new JarEntryFile(filePath.lastSegment());
+				jarEntries.put(childPath, file);
+				if (childPath.segmentCount() == 1) {
+					file.setParent(pkg);
+					topJarEntries.add(file);
+				} else {
+					IPath parentPath = childPath.removeLastSegments(1);
+					while (parentPath.segmentCount() > 0) {
+						ArrayList parentChildren = (ArrayList) childrenMap.get(parentPath);
+						if (parentChildren == null) {
+							Object dir = new JarEntryDirectory(parentPath.lastSegment());
+							jarEntries.put(parentPath, dir);
+							childrenMap.put(parentPath, parentChildren = new ArrayList());
+							parentChildren.add(childPath);
+							if (parentPath.segmentCount() == 1) {
+								topJarEntries.add(dir);
+								break;
+							}
+							childPath = parentPath;
+							parentPath = childPath.removeLastSegments(1);
+						} else {
+							parentChildren.add(childPath);
+							break; // all parents are already registered
+						}
+					}
+				}
 			}
-		} 
-		if (index != max) {
-			System.arraycopy(res, 0, res = new Object[index], 0, index);
 		}
+		Iterator entries = childrenMap.entrySet().iterator();
+		while (entries.hasNext()) {
+			Map.Entry entry = (Map.Entry) entries.next();
+			IPath entryPath = (IPath) entry.getKey();
+			ArrayList entryValue =  (ArrayList) entry.getValue();
+			JarEntryDirectory jarEntryDirectory = (JarEntryDirectory) jarEntries.get(entryPath);
+			int size = entryValue.size();
+			IJarEntryResource[] children = new IJarEntryResource[size];
+			for (int i = 0; i < size; i++) {
+				JarEntryResource child = (JarEntryResource) jarEntries.get(entryValue.get(i));
+				child.setParent(jarEntryDirectory);
+				children[i] = child;
+			}
+			jarEntryDirectory.setChildren(children);
+			if (entryPath.segmentCount() == 1) {
+				jarEntryDirectory.setParent(pkg);
+			}
+		}
+		Object[] res = topJarEntries.toArray(new Object[topJarEntries.size()]);
 		info.setNonJavaResources(res);
 	}
 }
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 ed4f277..6a406d2 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 2aafe2a..a729b47 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -84,29 +84,9 @@
 	
 			for (Enumeration e= jar.entries(); e.hasMoreElements();) {
 				ZipEntry member= (ZipEntry) e.nextElement();
-				String entryName= member.getName();
-	
-				if (member.isDirectory()) {
-					
-					initPackageFragToTypes(packageFragToTypes, entryName, entryName.length()-1);
-				} else {
-					//store the class file / non-java rsc entry name to be cached in the appropriate package fragment
-					//zip entries only use '/'
-					int lastSeparator= entryName.lastIndexOf('/');
-					String fileName= entryName.substring(lastSeparator + 1);
-					String[] pkgName = initPackageFragToTypes(packageFragToTypes, entryName, lastSeparator);
-
-					// add classfile info amongst children
-					ArrayList[] children = (ArrayList[]) packageFragToTypes.get(pkgName);
-					if (org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(entryName)) {
-						if (children[JAVA] == EMPTY_LIST) children[JAVA] = new ArrayList();
-						children[JAVA].add(fileName);
-					} else {
-						if (children[NON_JAVA] == EMPTY_LIST) children[NON_JAVA] = new ArrayList();
-						children[NON_JAVA].add(fileName);
-					}
-				}
+				initPackageFragToTypes(packageFragToTypes, member.getName(), member.isDirectory());
 			}
+			
 			//loop through all of referenced packages, creating package fragments if necessary
 			// and cache the entry names in the infos created for those package fragments
 			for (int i = 0, length = packageFragToTypes.keyTable.length; i < length; i++) {
@@ -118,11 +98,11 @@
 				JarPackageFragmentInfo fragInfo= new JarPackageFragmentInfo();
 				int resLength= entries[NON_JAVA].size();
 				if (resLength == 0) {
-					packFrag.computeNonJavaResources(CharOperation.NO_STRINGS, fragInfo, jar.getName());
+					packFrag.computeNonJavaResources(CharOperation.NO_STRINGS, packFrag, fragInfo, jar.getName());
 				} else {
 					String[] resNames= new String[resLength];
 					entries[NON_JAVA].toArray(resNames);
-					packFrag.computeNonJavaResources(resNames, fragInfo, jar.getName());
+					packFrag.computeNonJavaResources(resNames, packFrag, fragInfo, jar.getName());
 				}
 				packFrag.computeChildren(fragInfo, entries[JAVA]);
 				newElements.put(packFrag, fragInfo);
@@ -191,7 +171,16 @@
 	 */
 	public Object[] getNonJavaResources() throws JavaModelException {
 		// We want to show non java resources of the default package at the root (see PR #1G58NB8)
-		return ((JarPackageFragment) getPackageFragment(CharOperation.NO_STRINGS)).storedNonJavaResources();
+		Object[] defaultPkgResources =  ((JarPackageFragment) getPackageFragment(CharOperation.NO_STRINGS)).storedNonJavaResources();
+		int length = defaultPkgResources.length;
+		if (length == 0)
+			return defaultPkgResources;
+		Object[] nonJavaResources = new Object[length];
+		for (int i = 0; i < length; i++) {
+			JarEntryResource nonJavaResource = (JarEntryResource) defaultPkgResources[i];
+			nonJavaResources[i] = nonJavaResource.clone(this);
+		}
+		return nonJavaResources;
 	}
 	public PackageFragment getPackageFragment(String[] pkgName) {
 		return new JarPackageFragment(this, pkgName);
@@ -233,7 +222,8 @@
 	public int hashCode() {
 		return this.jarPath.hashCode();
 	}
-	private String[] initPackageFragToTypes(HashtableOfArrayToObject packageFragToTypes, String entryName, int lastSeparator) {
+	private void initPackageFragToTypes(HashtableOfArrayToObject packageFragToTypes, String entryName, boolean isDirectory) {
+		int lastSeparator = isDirectory ? entryName.length()-1 : entryName.lastIndexOf('/');
 		String[] pkgName = Util.splitOn('/', entryName, 0, lastSeparator);
 		String[] existing = null;
 		int length = pkgName.length;
@@ -244,13 +234,36 @@
 			existingLength--;
 		}
 		JavaModelManager manager = JavaModelManager.getJavaModelManager();
+		IJavaProject project = getJavaProject();
 		for (int i = existingLength; i < length; i++) {
-			System.arraycopy(existing, 0, existing = new String[i+1], 0, i);
-			existing[i] = manager.intern(pkgName[i]);
-			packageFragToTypes.put(existing, new ArrayList[] { EMPTY_LIST, EMPTY_LIST });
+			if (Util.isValidFolderNameForPackage(pkgName[i], project.getOption(JavaCore.COMPILER_SOURCE, true), project.getOption(JavaCore.COMPILER_COMPLIANCE, true))) {
+				System.arraycopy(existing, 0, existing = new String[i+1], 0, i);
+				existing[i] = manager.intern(pkgName[i]);
+				packageFragToTypes.put(existing, new ArrayList[] { EMPTY_LIST, EMPTY_LIST });
+			} else {
+				// non-Java resource folder
+				if (!isDirectory) {
+					ArrayList[] children = (ArrayList[]) packageFragToTypes.get(existing);
+					if (children[1/*NON_JAVA*/] == EMPTY_LIST) children[1/*NON_JAVA*/] = new ArrayList();
+					children[1/*NON_JAVA*/].add(entryName);
+				}
+				return;
+			}
+		}
+		if (isDirectory)
+			return;
+		
+		// add classfile info amongst children
+		ArrayList[] children = (ArrayList[]) packageFragToTypes.get(pkgName);
+		if (org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(entryName)) {
+			if (children[0/*JAVA*/] == EMPTY_LIST) children[0/*JAVA*/] = new ArrayList();
+			String fileName = entryName.substring(lastSeparator + 1);
+			children[0/*JAVA*/].add(fileName);
+		} else {
+			if (children[1/*NON_JAVA*/] == EMPTY_LIST) children[1/*NON_JAVA*/] = new ArrayList();
+			children[1/*NON_JAVA*/].add(entryName);
 		}
 		
-		return existing;
 	}
 	/**
 	 * @see IPackageFragmentRoot
@@ -285,4 +298,11 @@
 		return super.resourceExists();
 	}
 }
+protected void toStringAncestors(StringBuffer buffer) {
+	if (isExternal())
+		// don't show project as it is irrelevant for external jar files.
+		// also see https://bugs.eclipse.org/bugs/show_bug.cgi?id=146615
+		return;
+	super.toStringAncestors(buffer);
+}
 }
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 e353be5..26804df 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java
index 32f0765..ba869ce 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -13,8 +13,6 @@
 import java.util.*;
 
 import org.eclipse.core.runtime.preferences.*;
-import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
-import org.eclipse.core.runtime.preferences.IEclipsePreferences;
 import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants;
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
@@ -30,7 +28,7 @@
 	 * @see org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer#initializeDefaultPreferences()
 	 */
 	public void initializeDefaultPreferences() {
-
+		// If modified, also modify the method JavaModelManager#getDefaultOptionsNoInitialization()
 		// Get options names set
 		HashSet optionNames = JavaModelManager.getJavaModelManager().optionNames;
 		
@@ -45,12 +43,13 @@
 		defaultOptionsMap.put(JavaCore.COMPILER_TASK_CASE_SENSITIVE, JavaCore.ENABLED);
 		defaultOptionsMap.put(JavaCore.COMPILER_DOC_COMMENT_SUPPORT, JavaCore.ENABLED);
 		defaultOptionsMap.put(JavaCore.COMPILER_PB_FORBIDDEN_REFERENCE, JavaCore.ERROR);
-	
+		
 		// Builder settings
 		defaultOptionsMap.put(JavaCore.CORE_JAVA_BUILD_RESOURCE_COPY_FILTER, ""); //$NON-NLS-1$
 		defaultOptionsMap.put(JavaCore.CORE_JAVA_BUILD_INVALID_CLASSPATH, JavaCore.ABORT); 
 		defaultOptionsMap.put(JavaCore.CORE_JAVA_BUILD_DUPLICATE_RESOURCE, JavaCore.WARNING); 
 		defaultOptionsMap.put(JavaCore.CORE_JAVA_BUILD_CLEAN_OUTPUT_FOLDER, JavaCore.CLEAN); 
+		defaultOptionsMap.put(JavaCore.CORE_JAVA_BUILD_RECREATE_MODIFIED_CLASS_FILES_IN_OUTPUT_FOLDER, JavaCore.IGNORE); 
 
 		// JavaCore settings
 		defaultOptionsMap.put(JavaCore.CORE_JAVA_BUILD_ORDER, JavaCore.IGNORE); 
@@ -73,8 +72,9 @@
 		}
 
 		// CodeAssist settings
-		defaultOptionsMap.put(JavaCore.CODEASSIST_VISIBILITY_CHECK, JavaCore.DISABLED); //$NON-NLS-1$
-		defaultOptionsMap.put(JavaCore.CODEASSIST_IMPLICIT_QUALIFICATION, JavaCore.DISABLED); //$NON-NLS-1$
+		defaultOptionsMap.put(JavaCore.CODEASSIST_VISIBILITY_CHECK, JavaCore.DISABLED);
+		defaultOptionsMap.put(JavaCore.CODEASSIST_DEPRECATION_CHECK, JavaCore.DISABLED);
+		defaultOptionsMap.put(JavaCore.CODEASSIST_IMPLICIT_QUALIFICATION, JavaCore.DISABLED);
 		defaultOptionsMap.put(JavaCore.CODEASSIST_FIELD_PREFIXES, ""); //$NON-NLS-1$
 		defaultOptionsMap.put(JavaCore.CODEASSIST_STATIC_FIELD_PREFIXES, ""); //$NON-NLS-1$
 		defaultOptionsMap.put(JavaCore.CODEASSIST_LOCAL_PREFIXES, ""); //$NON-NLS-1$
@@ -83,11 +83,16 @@
 		defaultOptionsMap.put(JavaCore.CODEASSIST_STATIC_FIELD_SUFFIXES, ""); //$NON-NLS-1$
 		defaultOptionsMap.put(JavaCore.CODEASSIST_LOCAL_SUFFIXES, ""); //$NON-NLS-1$
 		defaultOptionsMap.put(JavaCore.CODEASSIST_ARGUMENT_SUFFIXES, ""); //$NON-NLS-1$
-		defaultOptionsMap.put(JavaCore.CODEASSIST_FORBIDDEN_REFERENCE_CHECK, JavaCore.ENABLED); //$NON-NLS-1$
-		defaultOptionsMap.put(JavaCore.CODEASSIST_DISCOURAGED_REFERENCE_CHECK, JavaCore.DISABLED); //$NON-NLS-1$
+		defaultOptionsMap.put(JavaCore.CODEASSIST_FORBIDDEN_REFERENCE_CHECK, JavaCore.ENABLED);
+		defaultOptionsMap.put(JavaCore.CODEASSIST_DISCOURAGED_REFERENCE_CHECK, JavaCore.DISABLED);
+		defaultOptionsMap.put(JavaCore.CODEASSIST_CAMEL_CASE_MATCH, JavaCore.ENABLED);
+		defaultOptionsMap.put(JavaCore.CODEASSIST_SUGGEST_STATIC_IMPORTS, JavaCore.ENABLED);
 		
+		// Time out for parameter names
+		defaultOptionsMap.put(JavaCore.TIMEOUT_FOR_PARAMETER_NAME_FROM_ATTACHED_JAVADOC, "50"); //$NON-NLS-1$
+
 		// Store default values to default preferences
-	 	IEclipsePreferences defaultPreferences = new DefaultScope().getNode(JavaCore.PLUGIN_ID);
+	 	IEclipsePreferences defaultPreferences = ((IScopeContext) new DefaultScope()).getNode(JavaCore.PLUGIN_ID);
 		for (Iterator iter = defaultOptionsMap.entrySet().iterator(); iter.hasNext();) {
 			Map.Entry entry = (Map.Entry) iter.next();
 			String optionName = (String) entry.getKey();
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 06fad7f..1492540 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,6 +10,16 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
+import java.io.BufferedInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.JarURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
 import java.util.ArrayList;
 import java.util.HashMap;
 
@@ -29,7 +39,12 @@
  * @see IJavaElement
  */
 public abstract class JavaElement extends PlatformObject implements IJavaElement {
+//	private static final QualifiedName PROJECT_JAVADOC= new QualifiedName(JavaCore.PLUGIN_ID, "project_javadoc_location"); //$NON-NLS-1$
 
+	private static final byte[] CLOSING_DOUBLE_QUOTE = new byte[] { 34 };
+	private static final byte[] CHARSET = new byte[] {99, 104, 97, 114, 115, 101, 116, 61 };
+	private static final byte[] CONTENT_TYPE = new byte[] { 34, 67, 111, 110, 116, 101, 110, 116, 45, 84, 121, 112, 101, 34 };
+	private static final byte[] CONTENT = new byte[] { 99, 111, 110, 116, 101, 110, 116, 61, 34 };
 	public static final char JEM_ESCAPE = '\\';
 	public static final char JEM_JAVAPROJECT = '=';
 	public static final char JEM_PACKAGEFRAGMENTROOT = '/';
@@ -123,6 +138,7 @@
 				case JEM_PACKAGEDECLARATION:
 				case JEM_IMPORTDECLARATION:
 				case JEM_LOCALVARIABLE:
+				case JEM_TYPE_PARAMETER:
 					buffer.append(JEM_ESCAPE);
 			}
 			buffer.append(character);
@@ -154,6 +170,7 @@
 	 * Puts the newly created element info in the given map.
 	 */
 	protected abstract void generateInfos(Object info, HashMap newElements, IProgressMonitor pm) throws JavaModelException;
+	
 	/**
 	 * @see IJavaElement
 	 */
@@ -516,6 +533,9 @@
 	public JavaElement resolved(Binding binding) {
 		return this;
 	}
+	public JavaElement unresolved() {
+		return this;
+	}
 	protected String tabString(int tab) {
 		StringBuffer buffer = new StringBuffer();
 		for (int i = tab; i > 0; i--)
@@ -611,4 +631,181 @@
 	protected void toStringName(StringBuffer buffer) {
 		buffer.append(getElementName());
 	}
+	
+	protected URL getJavadocBaseLocation() throws JavaModelException {
+		IPackageFragmentRoot root= (IPackageFragmentRoot) this.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
+		if (root == null) {
+			return null;
+		}
+
+		if (root.getKind() == IPackageFragmentRoot.K_BINARY) {
+			IClasspathEntry entry= root.getRawClasspathEntry();
+			if (entry == null) {
+				return null;
+			}
+			if (entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
+				entry= getRealClasspathEntry(root.getJavaProject(), entry.getPath(), root.getPath());
+				if (entry == null) {
+					return null;
+				}
+			}
+			return getLibraryJavadocLocation(entry);
+		}
+		return null;
+	}
+	
+	private static IClasspathEntry getRealClasspathEntry(IJavaProject jproject, IPath containerPath, IPath libPath) throws JavaModelException {
+		IClasspathContainer container= JavaCore.getClasspathContainer(containerPath, jproject);
+		if (container != null) {
+			IClasspathEntry[] entries= container.getClasspathEntries();
+			for (int i= 0; i < entries.length; i++) {
+				IClasspathEntry curr = entries[i];
+				if (curr == null) {
+					if (JavaModelManager.CP_RESOLVE_VERBOSE) {
+						JavaModelManager.getJavaModelManager().verbose_missbehaving_container(jproject, containerPath, entries);
+					}
+					break;
+				}
+				IClasspathEntry resolved= JavaCore.getResolvedClasspathEntry(curr);
+				if (resolved != null && libPath.equals(resolved.getPath())) {
+					return curr; // return the real entry
+				}
+			}
+		}
+		return null; // not found
+	}
+	
+	protected static URL getLibraryJavadocLocation(IClasspathEntry entry) throws JavaModelException {
+		switch(entry.getEntryKind()) {
+			case IClasspathEntry.CPE_LIBRARY :
+			case IClasspathEntry.CPE_VARIABLE :
+				break;
+			default :
+				throw new IllegalArgumentException("Entry must be of kind CPE_LIBRARY or CPE_VARIABLE"); //$NON-NLS-1$
+		}
+		
+		IClasspathAttribute[] extraAttributes= entry.getExtraAttributes();
+		for (int i= 0; i < extraAttributes.length; i++) {
+			IClasspathAttribute attrib= extraAttributes[i];
+			if (IClasspathAttribute.JAVADOC_LOCATION_ATTRIBUTE_NAME.equals(attrib.getName())) {
+				String value = attrib.getValue();
+				try {
+					return new URL(value);
+				} catch (MalformedURLException e) {
+					throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.CANNOT_RETRIEVE_ATTACHED_JAVADOC, value));
+				}
+			}
+		}
+		return null;
+	}
+	
+	/*
+	 * @see IJavaElement#getAttachedJavadoc(IProgressMonitor)
+	 */
+	public String getAttachedJavadoc(IProgressMonitor monitor) throws JavaModelException {
+		return null;
+	}
+	
+	int getIndexOf(byte[] array, byte[] toBeFound, int start) {
+		if (array == null || toBeFound == null)
+			return -1;
+		final int toBeFoundLength = toBeFound.length;
+		final int arrayLength = array.length;
+		if (arrayLength < toBeFoundLength)
+			return -1;
+		loop: for (int i = start, max = arrayLength - toBeFoundLength + 1; i < max; i++) {
+			if (array[i] == toBeFound[0]) {
+				for (int j = 1; j < toBeFoundLength; j++) {
+					if (array[i + j] != toBeFound[j])
+						continue loop;
+				}
+				return i;
+			}
+		}
+		return -1;
+	}	
+	/*
+	 * We don't use getContentEncoding() on the URL connection, because it might leave open streams behind.
+	 * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=117890 
+	 */
+	protected String getURLContents(String docUrlValue) throws JavaModelException {
+		InputStream stream = null;
+		JarURLConnection connection2 = null;
+		try {
+			URL docUrl = new URL(docUrlValue);
+			URLConnection connection = docUrl.openConnection();
+			if (connection instanceof JarURLConnection) {
+				connection2 = (JarURLConnection) connection;
+				// https://bugs.eclipse.org/bugs/show_bug.cgi?id=156307
+				connection.setUseCaches(false);
+			}
+			stream = new BufferedInputStream(connection.getInputStream());
+			String encoding = connection.getContentEncoding();
+			byte[] contents = org.eclipse.jdt.internal.compiler.util.Util.getInputStreamAsByteArray(stream, connection.getContentLength());
+			if (encoding == null) {
+				int index = getIndexOf(contents, CONTENT_TYPE, 0);
+				if (index != -1) {
+					index = getIndexOf(contents, CONTENT, index);
+					if (index != -1) {
+						int offset = index + CONTENT.length;
+						int index2 = getIndexOf(contents, CLOSING_DOUBLE_QUOTE, offset);
+						if (index2 != -1) {
+							final int charsetIndex = getIndexOf(contents, CHARSET, offset);
+							if (charsetIndex != -1) {
+								int start = charsetIndex + CHARSET.length;
+								encoding = new String(contents, start, index2 - start, "UTF-8"); //$NON-NLS-1$
+							}
+						}
+					}
+				}
+			}
+			try {
+				if (encoding == null) {
+					encoding = this.getJavaProject().getProject().getDefaultCharset();
+				}
+			} catch (CoreException e) {
+				// ignore
+			}
+			if (contents != null) {
+				if (encoding != null) {
+					return new String(contents, encoding);
+				} else {
+					// platform encoding is used
+					return new String(contents);
+				}
+			}			
+ 		} catch (MalformedURLException e) {
+ 			throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.CANNOT_RETRIEVE_ATTACHED_JAVADOC, this));
+		} catch (FileNotFoundException e) {
+			// ignore. see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=120559
+		} catch(IOException e) {
+			StringWriter stringWriter = new StringWriter();
+			PrintWriter writer = new PrintWriter(stringWriter);
+			e.printStackTrace(writer);
+			writer.flush();
+			writer.close();
+			throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.CANNOT_RETRIEVE_ATTACHED_JAVADOC, this, String.valueOf(stringWriter.getBuffer())));
+		} finally {
+			if (stream != null) {
+				try {
+					stream.close();
+				} catch (IOException e) {
+					// ignore
+				}
+			}
+			if (connection2 != null) {
+				try {
+					connection2.getJarFile().close();
+				} catch(IOException e) {
+					// ignore
+				} catch(IllegalStateException e) {
+					/*
+					 * ignore. Can happen in case the stream.close() did close the jar file
+					 * see https://bugs.eclipse.org/bugs/show_bug.cgi?id=140750
+					 */
+				}
+ 			}
+		}
+		return null;
+	}
 }
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 401810c..070b303 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -15,6 +15,7 @@
 import org.eclipse.core.resources.IResourceDelta;
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.IJavaElementDelta;
+import org.eclipse.jdt.core.dom.CompilationUnit;
 
 /**
  * @see IJavaElementDelta
@@ -23,7 +24,16 @@
 	/**
 	 * @see #getAffectedChildren()
 	 */
-	protected IJavaElementDelta[] fAffectedChildren = fgEmptyDelta;
+	protected IJavaElementDelta[] affectedChildren = EMPTY_DELTA;
+	
+	/*
+	 * The AST created during the last reconcile operation.
+	 * Non-null only iff:
+	 * - in a POST_RECONCILE event
+	 * - an AST was requested during the last reconcile operation
+	 * - the changed element is an ICompilationUnit in working copy mode
+	 */
+	protected CompilationUnit ast = null;
 
 	/*
 	 * The element that this delta describes the change to.
@@ -42,15 +52,15 @@
 	/**
 	 * @see #getMovedFromElement()
 	 */
-	protected IJavaElement fMovedFromHandle = null;
+	protected IJavaElement movedFromHandle = null;
 	/**
 	 * @see #getMovedToElement()
 	 */
-	protected IJavaElement fMovedToHandle = null;
+	protected IJavaElement movedToHandle = null;
 	/**
 	 * Empty array of IJavaElementDelta
 	 */
-	protected static  IJavaElementDelta[] fgEmptyDelta= new IJavaElementDelta[] {};
+	protected static  IJavaElementDelta[] EMPTY_DELTA= new IJavaElementDelta[] {};
 /**
  * Creates the root delta. To create the nested delta
  * hierarchies use the following convenience methods. The root
@@ -91,23 +101,23 @@
 		this.fineGrained();
 	}
 	
-	if (fAffectedChildren.length == 0) {
-		fAffectedChildren = new IJavaElementDelta[] {child};
+	if (this.affectedChildren.length == 0) {
+		this.affectedChildren = new IJavaElementDelta[] {child};
 		return;
 	}
 	JavaElementDelta existingChild = null;
 	int existingChildIndex = -1;
-	if (fAffectedChildren != null) {
-		for (int i = 0; i < fAffectedChildren.length; i++) {
-			if (this.equalsAndSameParent(fAffectedChildren[i].getElement(), child.getElement())) { // handle case of two jars that can be equals but not in the same project
-				existingChild = (JavaElementDelta)fAffectedChildren[i];
+	if (this.affectedChildren != null) {
+		for (int i = 0; i < this.affectedChildren.length; i++) {
+			if (this.equalsAndSameParent(this.affectedChildren[i].getElement(), child.getElement())) { // handle case of two jars that can be equals but not in the same project
+				existingChild = (JavaElementDelta)this.affectedChildren[i];
 				existingChildIndex = i;
 				break;
 			}
 		}
 	}
 	if (existingChild == null) { //new affected child
-		fAffectedChildren= growAndAddToArray(fAffectedChildren, child);
+		this.affectedChildren= growAndAddToArray(this.affectedChildren, child);
 	} else {
 		switch (existingChild.getKind()) {
 			case ADDED:
@@ -116,7 +126,7 @@
 					case CHANGED: // child was added then changed -> it is added
 						return;
 					case REMOVED: // child was added then removed -> noop
-						fAffectedChildren = this.removeAndShrinkArray(fAffectedChildren, existingChildIndex);
+						this.affectedChildren = this.removeAndShrinkArray(this.affectedChildren, existingChildIndex);
 						return;
 				}
 				break;
@@ -124,7 +134,7 @@
 				switch (child.getKind()) {
 					case ADDED: // child was removed then added -> it is changed
 						child.kind = CHANGED;
-						fAffectedChildren[existingChildIndex] = child;
+						this.affectedChildren[existingChildIndex] = child;
 						return;
 					case CHANGED: // child was removed then changed -> it is removed
 					case REMOVED: // child was removed then removed -> it is removed
@@ -135,7 +145,7 @@
 				switch (child.getKind()) {
 					case ADDED: // child was changed then added -> it is added
 					case REMOVED: // child was changed then removed -> it is removed
-						fAffectedChildren[existingChildIndex] = child;
+						this.affectedChildren[existingChildIndex] = child;
 						return;
 					case CHANGED: // child was changed then changed -> it is changed
 						IJavaElementDelta[] children = child.getAffectedChildren();
@@ -164,13 +174,14 @@
 							existingChild.resourceDeltas = resDeltas;
 							existingChild.resourceDeltasCounter = child.resourceDeltasCounter;
 						}
+						
 						return;
 				}
 				break;
 			default: 
 				// unknown -> existing child becomes the child with the existing child's flags
 				int flags = existingChild.getFlags();
-				fAffectedChildren[existingChildIndex] = child;
+				this.affectedChildren[existingChildIndex] = child;
 				child.changeFlags |= flags;
 		}
 	}
@@ -230,6 +241,13 @@
 	insertDeltaTree(element, changedDelta);
 	return changedDelta;
 }
+/*
+ * Records the last changed AST  .
+ */
+public void changedAST(CompilationUnit changedAST) {
+	this.ast = changedAST;
+	changed(F_AST_AFFECTED);
+}
 /**
  * Mark this delta as a content changed delta.
  */
@@ -257,8 +275,8 @@
 			// the element being changed is the root element
 			this.kind= delta.kind;
 			this.changeFlags = delta.changeFlags;
-			fMovedToHandle = delta.fMovedToHandle;
-			fMovedFromHandle = delta.fMovedFromHandle;
+			this.movedToHandle = delta.movedToHandle;
+			this.movedFromHandle = delta.movedFromHandle;
 		}
 	} else {
 		for (int i = 0, size = ancestors.size(); i < size; i++) {
@@ -285,8 +303,8 @@
 	if (this.equalsAndSameParent(this.changedElement, e)) { // handle case of two jars that can be equals but not in the same project
 		return this;
 	} else {
-		for (int i = 0; i < fAffectedChildren.length; i++) {
-			JavaElementDelta delta = ((JavaElementDelta)fAffectedChildren[i]).find(e);
+		for (int i = 0; i < this.affectedChildren.length; i++) {
+			JavaElementDelta delta = ((JavaElementDelta)this.affectedChildren[i]).find(e);
 			if (delta != null) {
 				return delta;
 			}
@@ -310,7 +328,7 @@
  * @see IJavaElementDelta
  */
 public IJavaElementDelta[] getAffectedChildren() {
-	return fAffectedChildren;
+	return this.affectedChildren;
 }
 /**
  * Returns a collection of all the parents of this element up to (but
@@ -334,6 +352,9 @@
 	parents.trimToSize();
 	return parents;
 }
+public CompilationUnit getCompilationUnitAST() {
+	return this.ast;
+}
 /**
  * @see IJavaElementDelta
  */
@@ -344,14 +365,14 @@
  * @see IJavaElementDelta
  */
 protected IJavaElementDelta[] getChildrenOfType(int type) {
-	int length = fAffectedChildren.length;
+	int length = this.affectedChildren.length;
 	if (length == 0) {
 		return new IJavaElementDelta[] {};
 	}
 	ArrayList children= new ArrayList(length);
 	for (int i = 0; i < length; i++) {
-		if (fAffectedChildren[i].getKind() == type) {
-			children.add(fAffectedChildren[i]);
+		if (this.affectedChildren[i].getKind() == type) {
+			children.add(this.affectedChildren[i]);
 		}
 	}
 
@@ -367,11 +388,11 @@
 protected JavaElementDelta getDeltaFor(IJavaElement element) {
 	if (this.equalsAndSameParent(getElement(), element)) // handle case of two jars that can be equals but not in the same project
 		return this;
-	if (fAffectedChildren.length == 0)
+	if (this.affectedChildren.length == 0)
 		return null;
-	int childrenCount = fAffectedChildren.length;
+	int childrenCount = this.affectedChildren.length;
 	for (int i = 0; i < childrenCount; i++) {
-		JavaElementDelta delta = (JavaElementDelta)fAffectedChildren[i];
+		JavaElementDelta delta = (JavaElementDelta)this.affectedChildren[i];
 		if (this.equalsAndSameParent(delta.getElement(), element)) { // handle case of two jars that can be equals but not in the same project
 			return delta;
 		} else {
@@ -392,13 +413,13 @@
  * @see IJavaElementDelta
  */
 public IJavaElement getMovedFromElement() {
-	return fMovedFromHandle;
+	return this.movedFromHandle;
 }
 /**
  * @see IJavaElementDelta
  */
 public IJavaElement getMovedToElement() {
-	return fMovedToHandle;
+	return movedToHandle;
 }
 /**
  * @see IJavaElementDelta
@@ -447,7 +468,7 @@
 	JavaElementDelta removedDelta = new JavaElementDelta(movedFromElement);
 	removedDelta.kind = REMOVED;
 	removedDelta.changeFlags |= F_MOVED_TO;
-	removedDelta.fMovedToHandle = movedToElement;
+	removedDelta.movedToHandle = movedToElement;
 	insertDeltaTree(movedFromElement, removedDelta);
 }
 /**
@@ -460,7 +481,7 @@
 	JavaElementDelta addedDelta = new JavaElementDelta(movedToElement);
 	addedDelta.kind = ADDED;
 	addedDelta.changeFlags |= F_MOVED_FROM;
-	addedDelta.fMovedFromHandle = movedFromElement;
+	addedDelta.movedFromHandle = movedFromElement;
 	insertDeltaTree(movedToElement, addedDelta);
 }
 /**
@@ -476,16 +497,16 @@
  */
 protected void removeAffectedChild(JavaElementDelta child) {
 	int index = -1;
-	if (fAffectedChildren != null) {
-		for (int i = 0; i < fAffectedChildren.length; i++) {
-			if (this.equalsAndSameParent(fAffectedChildren[i].getElement(), child.getElement())) { // handle case of two jars that can be equals but not in the same project
+	if (this.affectedChildren != null) {
+		for (int i = 0; i < this.affectedChildren.length; i++) {
+			if (this.equalsAndSameParent(this.affectedChildren[i].getElement(), child.getElement())) { // handle case of two jars that can be equals but not in the same project
 				index = i;
 				break;
 			}
 		}
 	}
 	if (index >= 0) {
-		fAffectedChildren= removeAndShrinkArray(fAffectedChildren, index);
+		this.affectedChildren= removeAndShrinkArray(this.affectedChildren, index);
 	}
 }
 /**
@@ -517,7 +538,7 @@
 	if (actualDelta != null) {
 		actualDelta.removed();
 		actualDelta.changeFlags |= flags;
-		actualDelta.fAffectedChildren = fgEmptyDelta;
+		actualDelta.affectedChildren = EMPTY_DELTA;
 	}
 }
 /**
@@ -687,6 +708,18 @@
 		buffer.append("CLOSED"); //$NON-NLS-1$
 		prev = true;
 	}
+	if ((flags & IJavaElementDelta.F_AST_AFFECTED) != 0) {
+		if (prev)
+			buffer.append(" | "); //$NON-NLS-1$
+		buffer.append("AST AFFECTED"); //$NON-NLS-1$
+		prev = true;
+	}
+	if ((flags & IJavaElementDelta.F_CATEGORIES) != 0) {
+		if (prev)
+			buffer.append(" | "); //$NON-NLS-1$
+		buffer.append("CATEGORIES"); //$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 afe4ea1..5be0890 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -12,14 +12,17 @@
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.Set;
 
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.IJavaElementDelta;
 import org.eclipse.jdt.core.IParent;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.core.util.Util;
 
 /**
  * A java element delta biulder creates a java element delta on
@@ -61,7 +64,7 @@
 	/**
 	 * Change delta
 	 */
-	JavaElementDelta delta;
+	public JavaElementDelta delta = null;
 
 	/**
 	 * List of added elements
@@ -76,7 +79,7 @@
 	/**
 	 * Doubly linked list item
 	 */
-	class ListItem {
+	static class ListItem {
 		public IJavaElement previous;
 		public IJavaElement next;
 
@@ -132,6 +135,12 @@
  * unit and its new content.
  */
 public void buildDeltas() {
+	this.delta = new JavaElementDelta(this.javaElement);
+	// if building a delta on a compilation unit or below, 
+	// it's a fine grained delta
+	if (this.javaElement.getElementType() >= IJavaElement.COMPILATION_UNIT) {
+		this.delta.fineGrained();
+	}
 	this.recordNewPositions(this.javaElement, 0);
 	this.findAdditions(this.javaElement, 0);
 	this.findDeletions();
@@ -255,6 +264,32 @@
 				|| !equals(oldSourceTypeInfo.getTypeParameterBounds(), newSourceTypeInfo.getTypeParameterBounds())) {
 			this.delta.changed(newElement, IJavaElementDelta.F_CONTENT);
 		}
+		HashMap oldTypeCategories = oldSourceTypeInfo.categories;
+		HashMap newTypeCategories = newSourceTypeInfo.categories;
+		if (oldTypeCategories != null) {
+			// take the union of old and new categories elements (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=125675)
+			Set elements;
+			if (newTypeCategories != null) {
+				elements = new HashSet(oldTypeCategories.keySet());
+				elements.addAll(newTypeCategories.keySet());
+			} else
+				elements = oldTypeCategories.keySet();
+			Iterator iterator = elements.iterator();
+			while (iterator.hasNext()) {
+				IJavaElement element = (IJavaElement) iterator.next();
+				String[] oldCategories = (String[]) oldTypeCategories.get(element);
+				String[] newCategories = newTypeCategories == null ? null : (String[]) newTypeCategories.get(element);
+				if (!Util.equalArraysOrNull(oldCategories, newCategories)) {
+					this.delta.changed(element, IJavaElementDelta.F_CATEGORIES);
+				}
+			}
+		} else if (newTypeCategories != null) {
+			Iterator elements = newTypeCategories.keySet().iterator();
+			while (elements.hasNext()) {
+				IJavaElement element = (IJavaElement) elements.next();
+				this.delta.changed(element, IJavaElementDelta.F_CATEGORIES); // all categories for this element were removed
+			}
+		}
 	}
 }
 /**
@@ -282,15 +317,7 @@
 	this.oldPositions = new HashMap(20);
 	this.newPositions = new HashMap(20);
 	this.putOldPosition(this.javaElement, new ListItem(null, null));
-	this.putNewPosition(this.javaElement, new ListItem(null, null));
-	this.delta = new JavaElementDelta(javaElement);
-	
-	// if building a delta on a compilation unit or below, 
-	// it's a fine grained delta
-	if (javaElement.getElementType() >= IJavaElement.COMPILATION_UNIT) {
-		this.delta.fineGrained();
-	}
-	
+	this.putNewPosition(this.javaElement, new ListItem(null, null));	
 	this.added = new ArrayList(5);
 	this.removed = new ArrayList(5);
 }
@@ -405,7 +432,7 @@
 public String toString() {
 	StringBuffer buffer = new StringBuffer();
 	buffer.append("Built delta:\n"); //$NON-NLS-1$
-	buffer.append(this.delta.toString());
+	buffer.append(this.delta == null ? "<null>" : this.delta.toString()); //$NON-NLS-1$
 	return buffer.toString();
 }
 /**
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 f45a060..ea1e690 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -34,12 +34,16 @@
 		this.children = JavaElement.NO_ELEMENTS;
 	}
 	public void addChild(IJavaElement child) {
-		if (this.children == JavaElement.NO_ELEMENTS) {
-			setChildren(new IJavaElement[] {child});
+		int length = this.children.length;		
+		if (length == 0) {
+			this.children = new IJavaElement[] {child};
 		} else {
-			if (!includesChild(child)) {
-				setChildren(growAndAddToArray(this.children, child));
+			for (int i = 0; i < length; i++) {
+				if (children[i].equals(child))
+					return; // already included
 			}
+			System.arraycopy(this.children, 0, this.children = new IJavaElement[length+1], 0, length);
+			this.children[length] = child;
 		}
 	}
 	public Object clone() {
@@ -53,51 +57,21 @@
 	public IJavaElement[] getChildren() {
 		return this.children;
 	}
-	/**
-	 * Adds the new element to a new array that contains all of the elements of the old array.
-	 * Returns the new array.
-	 */
-	protected IJavaElement[] growAndAddToArray(IJavaElement[] array, IJavaElement addition) {
-		IJavaElement[] old = array;
-		array = new IJavaElement[old.length + 1];
-		System.arraycopy(old, 0, array, 0, old.length);
-		array[old.length] = addition;
-		return array;
-	}
-	/**
-	 * Returns <code>true</code> if this child is in my children collection
-	 */
-	protected boolean includesChild(IJavaElement child) {
-		
-		for (int i= 0; i < this.children.length; i++) {
-			if (this.children[i].equals(child)) {
-				return true;
-			}
-		}
-		return false;
-	}
-	/**
-	 * Returns an array with all the same elements as the specified array except for
-	 * the element to remove. Assumes that the deletion is contained in the array.
-	 */
-	protected IJavaElement[] removeAndShrinkArray(IJavaElement[] array, IJavaElement deletion) {
-		IJavaElement[] old = array;
-		array = new IJavaElement[old.length - 1];
-		int j = 0;
-		for (int i = 0; i < old.length; i++) {
-			if (!old[i].equals(deletion)) {
-				array[j] = old[i];
-			} else {
-				System.arraycopy(old, i + 1, array, j, old.length - (i + 1));
-				return array;
-			}
-			j++;
-		}
-		return array;
-	}
 	public void removeChild(IJavaElement child) {
-		if (includesChild(child)) {
-			setChildren(removeAndShrinkArray(this.children, child));
+		for (int i = 0, length = this.children.length; i < length; i++) {
+			IJavaElement element = this.children[i];
+			if (element.equals(child)) {
+				if (length == 1) {
+					this.children = JavaElement.NO_ELEMENTS;
+				} else {
+					IJavaElement[] newChildren = new IJavaElement[length-1];
+					System.arraycopy(this.children, 0, newChildren , 0, i);
+					if (i < length-1)
+						System.arraycopy(this.children, i+1, newChildren, i, length-1-i);
+					this.children = newChildren;
+				}
+				break;
+			}
 		}
 	}
 	public void setChildren(IJavaElement[] children) {
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 ddcd8d2..97751d5 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 cbebfbe..519bf7a 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -22,14 +22,11 @@
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.resources.IWorkspace;
 import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.Assert;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.Path;
 import org.eclipse.jdt.core.*;
-import org.eclipse.jdt.core.IJavaElement;
-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.Messages;
 
@@ -72,12 +69,18 @@
 
 	// determine my children
 	IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
-	for (int i = 0, max = projects.length; i < max; i++) {
+	int length = projects.length;
+	IJavaElement[] children = new IJavaElement[length];
+	int index = 0;
+	for (int i = 0; i < length; i++) {
 		IProject project = projects[i];
 		if (JavaProject.hasJavaNature(project)) {
-			info.addChild(getJavaProject(project));
+			children[index++] = getJavaProject(project);
 		}
 	}
+	if (index < length)
+		System.arraycopy(children, 0, children = new IJavaElement[index], 0, index);
+	info.setChildren(children);
 
 	newElements.put(this, info);
 	
@@ -139,24 +142,6 @@
 	return super.equals(o);
 }
 /**
- * Finds the given project in the list of the java model's children.
- * Returns null if not found.
- */
-public IJavaProject findJavaProject(IProject project) {
-	try {
-		IJavaProject[] projects = this.getOldJavaProjectsList();
-		for (int i = 0, length = projects.length; i < length; i++) {
-			IJavaProject javaProject = projects[i];
-			if (project.equals(javaProject.getProject())) {
-				return javaProject;
-			}
-		}
-	} catch (JavaModelException e) {
-		// java model doesn't exist: cannot find any project
-	}
-	return null;
-}
-/**
  * @see IJavaElement
  */
 public int getElementType() {
@@ -240,17 +225,6 @@
 		return ((JavaModelInfo) getElementInfo()).getNonJavaResources();
 }
 
-/**
- * Workaround for bug 15168 circular errors not reported 
- * Returns the list of java projects before resource delta processing
- * has started.
- */
-public IJavaProject[] getOldJavaProjectsList() throws JavaModelException {
-	JavaModelManager manager = JavaModelManager.getJavaModelManager();
-	return manager.deltaState.modelProjectsCache == null ? 
-			this.getJavaProjects() : 
-			manager.deltaState.modelProjectsCache; 
-}
 /*
  * @see IJavaElement
  */
@@ -358,6 +332,9 @@
 	if (!path.isAbsolute()) return null; 
 
 	// lookup - outside the container
+	return getTargetAsExternalFile(path, checkResourceExistence);	
+}
+private synchronized static Object getTargetAsExternalFile(IPath path, boolean checkResourceExistence) {
 	File externalFile = new File(path.toOSString());
 	if (!checkResourceExistence) {
 		return externalFile;
@@ -373,7 +350,7 @@
 			return externalFile;
 		}
 	}
-	return null;	
+	return null;
 }
 
 /**
@@ -387,7 +364,7 @@
  * Helper method - returns the file item (ie. which returns true to {@link java.io.File#isFile()},
  * or null if unbound
  */
-public static File getFile(Object target) {
+public static synchronized File getFile(Object target) {
 	if (existingExternalConfirmedFiles.contains(target))
 		return (File) target;
 	if (target instanceof File) {
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 4a96fd3..ee2d80b 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -9,22 +9,30 @@
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
-import java.text.NumberFormat;
 import java.util.HashMap;
 import java.util.Map;
 
 import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.internal.core.util.LRUCache;
 
 /**
  * The cache of java elements to their respective info.
  */
 public class JavaModelCache {
-	public static final int BASE_VALUE = 20;
+	public static boolean VERBOSE = false;
+
 	public static final int DEFAULT_PROJECT_SIZE = 5;  // average 25552 bytes per project.
-	public static final int DEFAULT_ROOT_SIZE = BASE_VALUE*10; // average 2590 bytes per root -> maximum size : 25900*BASE_VALUE bytes
-	public static final int DEFAULT_PKG_SIZE = BASE_VALUE*100; // average 1782 bytes per pkg -> maximum size : 178200*BASE_VALUE bytes
-	public static final int DEFAULT_OPENABLE_SIZE = BASE_VALUE*100; // average 6629 bytes per openable (includes children) -> maximum size : 662900*BASE_VALUE bytes
-	public static final int DEFAULT_CHILDREN_SIZE = BASE_VALUE*100*20; // average 20 children per openable
+	public static final int DEFAULT_ROOT_SIZE = 50; // average 2590 bytes per root -> maximum size : 25900*BASE_VALUE bytes
+	public static final int DEFAULT_PKG_SIZE = 500; // average 1782 bytes per pkg -> maximum size : 178200*BASE_VALUE bytes
+	public static final int DEFAULT_OPENABLE_SIZE = 500; // average 6629 bytes per openable (includes children) -> maximum size : 662900*BASE_VALUE bytes
+	public static final int DEFAULT_CHILDREN_SIZE = 500*20; // average 20 children per openable
+	
+	public static final Object NON_EXISTING_JAR_TYPE_INFO = new Object();
+
+	/*
+	 * The memory ratio that should be applied to the above constants.
+	 */
+	protected double memoryRatio = -1;
 	
 	/**
 	 * Active Java Model Info
@@ -56,12 +64,26 @@
 	 */
 	protected Map childrenCache;
 	
+	/*
+	 * Cache of open binary type (inside a jar) that have a non-open parent
+	 */
+	protected LRUCache jarTypeCache;
+	
 public JavaModelCache() {
+	// set the size of the caches in function of the maximum amount of memory available
+	double ratio = getMemoryRatio();
 	this.projectCache = new HashMap(DEFAULT_PROJECT_SIZE); // NB: Don't use a LRUCache for projects as they are constantly reopened (e.g. during delta processing)
-	this.rootCache = new ElementCache(DEFAULT_ROOT_SIZE);
-	this.pkgCache = new ElementCache(DEFAULT_PKG_SIZE);
-	this.openableCache = new ElementCache(DEFAULT_OPENABLE_SIZE);
-	this.childrenCache = new HashMap(DEFAULT_CHILDREN_SIZE);
+	if (VERBOSE) {
+		this.rootCache = new VerboseElementCache((int) (DEFAULT_ROOT_SIZE * ratio), "Root cache"); //$NON-NLS-1$
+		this.pkgCache = new VerboseElementCache((int) (DEFAULT_PKG_SIZE * ratio), "Package cache"); //$NON-NLS-1$
+		this.openableCache = new VerboseElementCache((int) (DEFAULT_OPENABLE_SIZE * ratio), "Openable cache"); //$NON-NLS-1$
+	} else {
+		this.rootCache = new ElementCache((int) (DEFAULT_ROOT_SIZE * ratio));
+		this.pkgCache = new ElementCache((int) (DEFAULT_PKG_SIZE * ratio));
+		this.openableCache = new ElementCache((int) (DEFAULT_OPENABLE_SIZE * ratio));
+	}
+	this.childrenCache = new HashMap((int) (DEFAULT_CHILDREN_SIZE * ratio));
+	resetJarTypeCache();
 }
 
 /**
@@ -80,11 +102,27 @@
 		case IJavaElement.COMPILATION_UNIT:
 		case IJavaElement.CLASS_FILE:
 			return this.openableCache.get(element);
+		case IJavaElement.TYPE:
+			Object result = this.jarTypeCache.get(element);
+			if (result != null)
+				return result;
+			else
+				return this.childrenCache.get(element);
 		default:
 			return this.childrenCache.get(element);
 	}
 }
 
+protected double getMemoryRatio() {
+	if (this.memoryRatio == -1) {
+		long maxMemory = Runtime.getRuntime().maxMemory();		
+		// if max memory is infinite, set the ratio to 4d which corresponds to the 256MB that Eclipse defaults to
+		// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=111299)
+		this.memoryRatio = maxMemory == Long.MAX_VALUE ? 4d : ((double) maxMemory) / (64 * 0x100000); // 64MB is the base memory for most JVM	
+	}
+	return this.memoryRatio;
+}
+
 /**
  *  Returns the info for this element without
  *  disturbing the cache ordering.
@@ -102,6 +140,12 @@
 		case IJavaElement.COMPILATION_UNIT:
 		case IJavaElement.CLASS_FILE:
 			return this.openableCache.peek(element);
+		case IJavaElement.TYPE:
+			Object result = this.jarTypeCache.peek(element);
+			if (result != null)
+				return result;
+			else
+				return this.childrenCache.get(element);
 		default:
 			return this.childrenCache.get(element);
 	}
@@ -138,22 +182,22 @@
 /**
  * Removes the info of the element from the cache.
  */
-protected void removeInfo(IJavaElement element) {
+protected void removeInfo(JavaElement element) {
 	switch (element.getElementType()) {
 		case IJavaElement.JAVA_MODEL:
 			this.modelInfo = null;
 			break;
 		case IJavaElement.JAVA_PROJECT:
 			this.projectCache.remove(element);
-			this.rootCache.resetSpaceLimit(DEFAULT_ROOT_SIZE, element);
+			this.rootCache.resetSpaceLimit((int) (DEFAULT_ROOT_SIZE * getMemoryRatio()), element);
 			break;
 		case IJavaElement.PACKAGE_FRAGMENT_ROOT:
 			this.rootCache.remove(element);
-			this.pkgCache.resetSpaceLimit(DEFAULT_PKG_SIZE, element);
+			this.pkgCache.resetSpaceLimit((int) (DEFAULT_PKG_SIZE * getMemoryRatio()), element);
 			break;
 		case IJavaElement.PACKAGE_FRAGMENT:
 			this.pkgCache.remove(element);
-			this.openableCache.resetSpaceLimit(DEFAULT_OPENABLE_SIZE, element);
+			this.openableCache.resetSpaceLimit((int) (DEFAULT_OPENABLE_SIZE * getMemoryRatio()), element);
 			break;
 		case IJavaElement.COMPILATION_UNIT:
 		case IJavaElement.CLASS_FILE:
@@ -163,6 +207,12 @@
 			this.childrenCache.remove(element);
 	}
 }
+protected void resetJarTypeCache() {
+	this.jarTypeCache = new LRUCache((int) (DEFAULT_OPENABLE_SIZE * getMemoryRatio()));
+}
+public String toString() {
+	return toStringFillingRation(""); //$NON-NLS-1$
+}
 public String toStringFillingRation(String prefix) {
 	StringBuffer buffer = new StringBuffer();
 	buffer.append(prefix);
@@ -170,23 +220,17 @@
 	buffer.append(this.projectCache.size());
 	buffer.append(" projects\n"); //$NON-NLS-1$
 	buffer.append(prefix);
-	buffer.append("Root cache["); //$NON-NLS-1$
-	buffer.append(this.rootCache.getSpaceLimit());
-	buffer.append("]: "); //$NON-NLS-1$
-	buffer.append(NumberFormat.getInstance().format(this.rootCache.fillingRatio()));
-	buffer.append("%\n"); //$NON-NLS-1$
+	buffer.append(this.rootCache.toStringFillingRation("Root cache")); //$NON-NLS-1$
+	buffer.append('\n');
 	buffer.append(prefix);
-	buffer.append("Package cache["); //$NON-NLS-1$
-	buffer.append(this.pkgCache.getSpaceLimit());
-	buffer.append("]: "); //$NON-NLS-1$
-	buffer.append(NumberFormat.getInstance().format(this.pkgCache.fillingRatio()));
-	buffer.append("%\n"); //$NON-NLS-1$
+	buffer.append(this.pkgCache.toStringFillingRation("Package cache")); //$NON-NLS-1$
+	buffer.append('\n');
 	buffer.append(prefix);
-	buffer.append("Openable cache["); //$NON-NLS-1$
-	buffer.append(this.openableCache.getSpaceLimit());
-	buffer.append("]: "); //$NON-NLS-1$
-	buffer.append(NumberFormat.getInstance().format(this.openableCache.fillingRatio()));
-	buffer.append("%\n"); //$NON-NLS-1$
+	buffer.append(this.openableCache.toStringFillingRation("Openable cache")); //$NON-NLS-1$
+	buffer.append('\n');
+	buffer.append(prefix);
+	buffer.append(this.jarTypeCache.toStringFillingRation("Jar type cache")); //$NON-NLS-1$
+	buffer.append('\n');
 	return buffer.toString();
 }
 }
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 2451d41..3f020e2 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 c1758f4..4c5263f 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -7,11 +7,17 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ *     Theodora Yeung (tyeung@bea.com) - ensure that JarPackageFragmentRoot make it into cache
+ *                                                           before its contents
+ *                                                           (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=102422) 
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
 import java.io.*;
+import java.net.URI;
+import java.text.MessageFormat;
 import java.util.*;
+import java.util.Map.Entry;
 import java.util.zip.ZipFile;
 
 import javax.xml.parsers.DocumentBuilder;
@@ -20,28 +26,42 @@
 
 import org.eclipse.core.resources.*;
 import org.eclipse.core.runtime.*;
+import org.eclipse.core.runtime.content.IContentTypeManager.ContentTypeChangeEvent;
+import org.eclipse.core.runtime.content.IContentTypeManager.IContentTypeChangeListener;
 import org.eclipse.core.runtime.jobs.Job;
 import org.eclipse.core.runtime.preferences.DefaultScope;
 import org.eclipse.core.runtime.preferences.IEclipsePreferences;
 import org.eclipse.core.runtime.preferences.IPreferencesService;
+import org.eclipse.core.runtime.preferences.IScopeContext;
 import org.eclipse.core.runtime.preferences.InstanceScope;
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.core.compiler.CompilationParticipant;
 import org.eclipse.jdt.core.compiler.IProblem;
+import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants;
 import org.eclipse.jdt.internal.codeassist.CompletionEngine;
 import org.eclipse.jdt.internal.codeassist.SelectionEngine;
+import org.eclipse.jdt.internal.compiler.AbstractAnnotationProcessorManager;
 import org.eclipse.jdt.internal.compiler.Compiler;
-import org.eclipse.jdt.internal.compiler.util.WeakHashSet;
-import org.eclipse.jdt.internal.compiler.util.WeakHashSetOfCharArray;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.env.AccessRestriction;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.jdt.internal.compiler.util.HashtableOfObjectToInt;
+import org.eclipse.jdt.internal.core.JavaProjectElementInfo.ProjectCache;
 import org.eclipse.jdt.internal.core.builder.JavaBuilder;
 import org.eclipse.jdt.internal.core.hierarchy.TypeHierarchy;
 import org.eclipse.jdt.internal.core.search.AbstractSearchScope;
 import org.eclipse.jdt.internal.core.search.BasicSearchEngine;
+import org.eclipse.jdt.internal.core.search.IRestrictedAccessTypeRequestor;
 import org.eclipse.jdt.internal.core.search.JavaWorkspaceScope;
 import org.eclipse.jdt.internal.core.search.indexing.IndexManager;
 import org.eclipse.jdt.internal.core.search.processing.JobManager;
+import org.eclipse.jdt.internal.core.util.HashtableOfArrayToObject;
+import org.eclipse.jdt.internal.core.util.LRUCache;
 import org.eclipse.jdt.internal.core.util.Messages;
 import org.eclipse.jdt.internal.core.util.Util;
+import org.eclipse.jdt.internal.core.util.WeakHashSet;
+import org.eclipse.jdt.internal.core.util.WeakHashSetOfCharArray;
 import org.osgi.service.prefs.BackingStoreException;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
@@ -57,7 +77,7 @@
  * The single instance of <code>JavaModelManager</code> is available from
  * the static method <code>JavaModelManager.getJavaModelManager()</code>.
  */
-public class JavaModelManager implements ISaveParticipant { 	
+public class JavaModelManager implements ISaveParticipant, IContentTypeChangeListener { 	
  
 	/**
 	 * Unique handle onto the JavaModel
@@ -68,9 +88,12 @@
 	 * Classpath variables pool
 	 */
 	public HashMap variables = new HashMap(5);
+	public HashSet variablesWithInitializer = new HashSet(5);
+	public HashMap deprecatedVariables = new HashMap(5);
+	public HashSet readOnlyVariables = new HashSet(5);
 	public HashMap previousSessionVariables = new HashMap(5);
 	private ThreadLocal variableInitializationInProgress = new ThreadLocal();
-		
+
 	/**
 	 * Classpath containers pool
 	 */
@@ -78,6 +101,7 @@
 	public HashMap previousSessionContainers = new HashMap(5);
 	private ThreadLocal containerInitializationInProgress = new ThreadLocal();
 	public boolean batchContainerInitializations = false;
+	public ThreadLocal batchContainerInitializationsProgress = new ThreadLocal();
 	public HashMap containerInitializersCache = new HashMap(5);
 	
 	/*
@@ -96,12 +120,24 @@
 	 */
 	private WeakHashSet stringSymbols = new WeakHashSet(5);
 	private WeakHashSetOfCharArray charArraySymbols = new WeakHashSetOfCharArray(5);
+	
+	/*
+	 * Extension used to construct Java 6 annotation processor managers
+	 */
+	private IConfigurationElement annotationProcessorManagerFactory = null;
+	
+	/* 
+	 * Map from a package fragment root's path to a source attachment property (source path + ATTACHMENT_PROPERTY_DELIMITER + source root path)
+	 */
+	public Map rootPathToAttachments = new HashMap();
 
 	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 final static IPath CP_ENTRY_IGNORE_PATH = new Path(CP_ENTRY_IGNORE);
+	public final static String TRUE = "true"; //$NON-NLS-1$
 	
-	private final static int VARIABLES_AND_CONTAINERS_FILE_VERSION = 1;
+	private final static int VARIABLES_AND_CONTAINERS_FILE_VERSION = 2;
 
 	/**
 	 * Name of the extension point for contributing classpath variable initializers
@@ -119,10 +155,15 @@
 	public static final String FORMATTER_EXTPOINT_ID = "codeFormatter" ; //$NON-NLS-1$
 	
 	/**
-	 * Value of the content-type for Java source files
+	 * Name of the extension point for contributing a compilation participant
 	 */
-	public static final String JAVA_SOURCE_CONTENT_TYPE = JavaCore.PLUGIN_ID+".javaSource" ; //$NON-NLS-1$
-
+	public static final String COMPILATION_PARTICIPANT_EXTPOINT_ID = "compilationParticipant" ; //$NON-NLS-1$
+	
+	/**
+	 * Name of the extension point for contributing the Java 6 annotation processor manager
+	 */
+	public static final String ANNOTATION_PROCESSOR_MANAGER_EXTPOINT_ID = "annotationProcessorManager" ;  //$NON-NLS-1$
+	
 	/**
 	 * Special value used for recognizing ongoing initialization and breaking initialization cycles
 	 */
@@ -139,7 +180,9 @@
 	private static final String INDEX_MANAGER_DEBUG = JavaCore.PLUGIN_ID + "/debug/indexmanager" ; //$NON-NLS-1$
 	private static final String COMPILER_DEBUG = JavaCore.PLUGIN_ID + "/debug/compiler" ; //$NON-NLS-1$
 	private static final String JAVAMODEL_DEBUG = JavaCore.PLUGIN_ID + "/debug/javamodel" ; //$NON-NLS-1$
+	private static final String JAVAMODELCACHE_DEBUG = JavaCore.PLUGIN_ID + "/debug/javamodel/cache" ; //$NON-NLS-1$
 	private static final String CP_RESOLVE_DEBUG = JavaCore.PLUGIN_ID + "/debug/cpresolution" ; //$NON-NLS-1$
+	private static final String CP_RESOLVE_ADVANCED_DEBUG = JavaCore.PLUGIN_ID + "/debug/cpresolution/advanced" ; //$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$
@@ -159,6 +202,8 @@
 	public static final String CONTAINER_INITIALIZER_PERF = JavaCore.PLUGIN_ID + "/perf/containerinitializer" ; //$NON-NLS-1$
 	public static final String RECONCILE_PERF = JavaCore.PLUGIN_ID + "/perf/reconcile" ; //$NON-NLS-1$
 	
+	private final static String INDEXED_SECONDARY_TYPES = "#@*_indexing secondary cache_*@#"; //$NON-NLS-1$
+
 	public static boolean PERF_VARIABLE_INITIALIZER = false;
 	public static boolean PERF_CONTAINER_INITIALIZER = false;
 	
@@ -172,6 +217,186 @@
 	static final int PREF_INSTANCE = 0;
 	static final int PREF_DEFAULT = 1;
 
+	static final Object[][] NO_PARTICIPANTS = new Object[0][];
+	
+	public static class CompilationParticipants {
+		
+		private final static int MAX_SOURCE_LEVEL = 7; // 1.1 to 1.7
+	
+		/*
+		 * The registered compilation participants (a table from int (source level) to Object[])
+		 * The Object array contains first IConfigurationElements when not resolved yet, then
+		 * it contains CompilationParticipants.
+		 */
+		private Object[][] registeredParticipants = null;
+		private HashSet managedMarkerTypes;
+				
+		public CompilationParticipant[] getCompilationParticipants(IJavaProject project) {
+			final Object[][] participantsPerSource = getRegisteredParticipants();
+			if (participantsPerSource == NO_PARTICIPANTS)
+				return null;
+			String sourceLevel = project.getOption(JavaCore.COMPILER_SOURCE, true/*inherit options*/);
+			final int sourceLevelIndex = indexForSourceLevel(sourceLevel);
+			final Object[] participants = participantsPerSource[sourceLevelIndex];
+			int length = participants.length;
+			CompilationParticipant[] result = new CompilationParticipant[length];
+			int index = 0;
+			for (int i = 0; i < length; i++) {
+				if (participants[i] instanceof IConfigurationElement) {
+					final IConfigurationElement configElement = (IConfigurationElement) participants[i];
+					final int participantIndex = i;
+					SafeRunner.run(new ISafeRunnable() {
+						public void handleException(Throwable exception) {
+							Util.log(exception, "Exception occurred while creating compilation participant"); //$NON-NLS-1$
+						}
+						public void run() throws Exception {
+							Object executableExtension = configElement.createExecutableExtension("class"); //$NON-NLS-1$ 
+							for (int j = sourceLevelIndex; j < MAX_SOURCE_LEVEL; j++)
+								participantsPerSource[j][participantIndex] = executableExtension;
+						}
+					});
+				} 
+				CompilationParticipant participant = (CompilationParticipant) participants[i];
+				if (participant != null && participant.isActive(project))
+					result[index++] = participant;
+			}
+			if (index == 0)
+				return null;
+			if (index < length)
+				System.arraycopy(result, 0, result = new CompilationParticipant[index], 0, index);
+			return result;
+		}
+		
+		public HashSet managedMarkerTypes() {
+			if (this.managedMarkerTypes == null) {
+				// force extension points to be read
+				getRegisteredParticipants();
+			}
+			return this.managedMarkerTypes;
+		}
+		
+		private synchronized Object[][] getRegisteredParticipants() {
+			if (this.registeredParticipants != null) {
+				return this.registeredParticipants;
+			}
+			this.managedMarkerTypes = new HashSet();
+			IExtensionPoint extension = Platform.getExtensionRegistry().getExtensionPoint(JavaCore.PLUGIN_ID, COMPILATION_PARTICIPANT_EXTPOINT_ID);
+			if (extension == null)
+				return this.registeredParticipants = NO_PARTICIPANTS;
+			final ArrayList modifyingEnv = new ArrayList();
+			final ArrayList creatingProblems = new ArrayList();
+			final ArrayList others = new ArrayList();
+			IExtension[] extensions = extension.getExtensions();
+			// for all extensions of this point...
+			for(int i = 0; i < extensions.length; i++) {
+				IConfigurationElement[] configElements = extensions[i].getConfigurationElements();
+				// for all config elements named "compilationParticipant"
+				for(int j = 0; j < configElements.length; j++) {
+					final IConfigurationElement configElement = configElements[j];
+					String elementName =configElement.getName();
+					if (!("compilationParticipant".equals(elementName))) { //$NON-NLS-1$
+						continue;
+					}
+					// add config element in the group it belongs to
+					if (TRUE.equals(configElement.getAttribute("modifiesEnvironment"))) //$NON-NLS-1$
+						modifyingEnv.add(configElement);
+					else if (TRUE.equals(configElement.getAttribute("createsProblems"))) //$NON-NLS-1$
+						creatingProblems.add(configElement);
+					else
+						others.add(configElement);
+					// add managed marker types
+					IConfigurationElement[] managedMarkers = configElement.getChildren("managedMarker"); //$NON-NLS-1$
+					for (int k = 0, length = managedMarkers.length; k < length; k++) {
+						IConfigurationElement element = managedMarkers[k];
+						String markerType = element.getAttribute("markerType"); //$NON-NLS-1$
+						if (markerType != null)
+							this.managedMarkerTypes.add(markerType);
+					}
+				}
+			}
+			int size = modifyingEnv.size() + creatingProblems.size() + others.size();
+			if (size == 0)
+				return this.registeredParticipants = NO_PARTICIPANTS;
+			
+			// sort config elements in each group
+			IConfigurationElement[] configElements = new IConfigurationElement[size];
+			int index = 0;
+			index = sortParticipants(modifyingEnv, configElements, index);
+			index = sortParticipants(creatingProblems, configElements, index);
+			index = sortParticipants(others, configElements, index);
+			
+			// create result table
+			Object[][] result = new Object[MAX_SOURCE_LEVEL][];
+			int length = configElements.length;
+			for (int i = 0; i < MAX_SOURCE_LEVEL; i++) {
+				result[i] = new Object[length];
+			}
+			for (int i = 0; i < length; i++) {
+				String sourceLevel = configElements[i].getAttribute("requiredSourceLevel"); //$NON-NLS-1$
+				int sourceLevelIndex = indexForSourceLevel(sourceLevel);
+				for (int j = sourceLevelIndex; j < MAX_SOURCE_LEVEL; j++) {
+					result[j][i] = configElements[i];
+				}
+			}
+			return this.registeredParticipants = result;
+		}
+		
+		/*
+		 * 1.1 -> 0
+		 * 1.2 -> 1
+		 * ...
+		 * 1.6 -> 5
+		 * 1.7 -> 6
+		 * null -> 0
+		 */
+		private int indexForSourceLevel(String sourceLevel) {
+			if (sourceLevel == null) return 0;
+			int majVersion = (int) (CompilerOptions.versionToJdkLevel(sourceLevel) >>> 16);
+			switch (majVersion) {
+				case ClassFileConstants.MAJOR_VERSION_1_2:
+					return 1;
+				case ClassFileConstants.MAJOR_VERSION_1_3:
+					return 2;
+				case ClassFileConstants.MAJOR_VERSION_1_4:
+					return 3;
+				case ClassFileConstants.MAJOR_VERSION_1_5:
+					return 4;
+				case ClassFileConstants.MAJOR_VERSION_1_6:
+					return 5;
+				case ClassFileConstants.MAJOR_VERSION_1_7:
+					return 6;
+				default:
+					// all other cases including ClassFileConstants.MAJOR_VERSION_1_1
+					return 0;
+			}
+		}
+		
+		private int sortParticipants(ArrayList group, IConfigurationElement[] configElements, int index) {
+			int size = group.size();
+			if (size == 0) return index;
+			Object[] elements = group.toArray();
+			Util.sort(elements, new Util.Comparer() {
+				public int compare(Object a, Object b) {
+					if (a == b) return 0;
+					String id = ((IConfigurationElement) a).getAttribute("id"); //$NON-NLS-1$
+					if (id == null) return -1;
+					IConfigurationElement[] requiredElements = ((IConfigurationElement) b).getChildren("requires"); //$NON-NLS-1$
+					for (int i = 0, length = requiredElements.length; i < length; i++) {
+						IConfigurationElement required = requiredElements[i];
+						if (id.equals(required.getAttribute("id"))) //$NON-NLS-1$
+							return 1;
+					}
+					return -1;
+				}
+			});
+			for (int i = 0; i < size; i++)
+				configElements[index+i] = (IConfigurationElement) elements[i];
+			return index + size;
+		}
+	}
+			
+	public final CompilationParticipants compilationParticipants = new CompilationParticipants();
+	
 	/**
 	 * Returns whether the given full path (for a package) conflicts with the output location
 	 * of the given project.
@@ -186,7 +411,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/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
+				IClasspathEntry[] classpath = project.getResolvedClasspath();
 				boolean isOutputUsed = false;
 				for (int i = 0, length = classpath.length; i < length; i++) {
 					IClasspathEntry entry = classpath[i];
@@ -210,8 +435,7 @@
 
 	public synchronized IClasspathContainer containerGet(IJavaProject project, IPath containerPath) {	
 		// check initialization in progress first
-		HashSet projectInitializations = containerInitializationInProgress(project);
-		if (projectInitializations.contains(containerPath)) {
+		if (containerIsInitializationInProgress(project, containerPath)) {
 			return CONTAINER_INITIALIZATION_IN_PROGRESS;
 		}
 		
@@ -223,6 +447,16 @@
 		return container;
 	}
 	
+	public synchronized IClasspathContainer containerGetDefaultToPreviousSession(IJavaProject project, IPath containerPath) {	
+		Map projectContainers = (Map)this.containers.get(project);
+		if (projectContainers == null)
+			return getPreviousSessionContainer(containerPath, project);
+		IClasspathContainer container = (IClasspathContainer)projectContainers.get(containerPath);
+		if (container == null)
+			return getPreviousSessionContainer(containerPath, project);
+		return container;
+	}
+	
 	private synchronized Map containerClone(IJavaProject project) {
 		Map originalProjectContainers = (Map)this.containers.get(project);
 		if (originalProjectContainers == null) return null;
@@ -231,37 +465,39 @@
 		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) {
+	private boolean containerIsInitializationInProgress(IJavaProject project, IPath containerPath) {
 		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 (initializations == null)
+			return false;
+		HashSet projectInitializations = (HashSet) initializations.get(project);
+		if (projectInitializations == null)
+			return false;
+		return projectInitializations.contains(containerPath);
 	}
 
+	private void containerAddInitializationInProgress(IJavaProject project, IPath containerPath) {
+		Map initializations = (Map)this.containerInitializationInProgress.get();
+		if (initializations == null)
+			this.containerInitializationInProgress.set(initializations = new HashMap());
+		HashSet projectInitializations = (HashSet) initializations.get(project);
+		if (projectInitializations == null)
+			initializations.put(project, projectInitializations = new HashSet());
+		projectInitializations.add(containerPath);
+	}
+	
 	public synchronized void containerPut(IJavaProject project, IPath containerPath, IClasspathContainer container){
 
 		// set/unset the initialization in progress
 		if (container == CONTAINER_INITIALIZATION_IN_PROGRESS) {
-			HashSet projectInitializations = containerInitializationInProgress(project);
-			projectInitializations.add(containerPath);
+			containerAddInitializationInProgress(project, containerPath);
 			
 			// do not write out intermediate initialization value
 			return;
 		} else {
 			containerRemoveInitializationInProgress(project, containerPath);
 
-			Map projectContainers = (Map)this.containers.get(project);
-			if (projectContainers == null){
+			Map projectContainers = (Map)this.containers.get(project);	
+ 			if (projectContainers == null){
 				projectContainers = new HashMap(1);
 				this.containers.put(project, projectContainers);
 			}
@@ -269,7 +505,7 @@
 			if (container == null) {
 				projectContainers.remove(containerPath);
 			} else {
-   				projectContainers.put(containerPath, container);
+  				projectContainers.put(containerPath, container);
 			}
 			// discard obsoleted information about previous session
 			Map previousContainers = (Map)this.previousSessionContainers.get(project);
@@ -281,109 +517,174 @@
 	}
 	
 	/*
-	 * Optimize startup case where a container for 1 project is initialized at a time with the same entries as on shutdown.
+	 * The given project is being removed. Remove all containers for this project from the cache.
 	 */
+	public synchronized void containerRemove(IJavaProject project) {
+		Map initializations = (Map) this.containerInitializationInProgress.get();
+		if (initializations != null) {
+			initializations.remove(project);
+		}
+		this.containers.remove(project);
+	}
+	
 	public boolean containerPutIfInitializingWithSameEntries(IPath containerPath, IJavaProject[] projects, IClasspathContainer[] respectiveContainers) {
 		int projectLength = projects.length;
 		if (projectLength != 1) 
 			return false;
 		final IClasspathContainer container = respectiveContainers[0];
-		if (container == null)
-			return false;
 		IJavaProject project = projects[0];
-		if (!containerInitializationInProgress(project).contains(containerPath))
+		// optimize only if initializing, otherwise we are in a regular setContainer(...) call
+		if (!containerIsInitializationInProgress(project, containerPath)) 
 			return false;
-		IClasspathContainer previousSessionContainer = getPreviousSessionContainer(containerPath, project);
+		IClasspathContainer previousContainer = containerGetDefaultToPreviousSession(project, containerPath);
+		if (container == null) {
+			if (previousContainer == null) {
+				containerPut(project, containerPath, null);
+				return true;
+			}
+			return false;
+		}
 		final IClasspathEntry[] newEntries = container.getClasspathEntries();
-		if (previousSessionContainer == null) 
+		if (previousContainer == null) 
 			if (newEntries.length == 0) {
 				containerPut(project, containerPath, container);
 				return true;
 			} else {
+				if (CP_RESOLVE_VERBOSE)
+					verbose_missbehaving_container(containerPath, projects, respectiveContainers, container, newEntries, null/*no old entries*/);
 				return false;
 			}
-		final IClasspathEntry[] oldEntries = previousSessionContainer.getClasspathEntries();
-		if (oldEntries.length != newEntries.length) 
+		final IClasspathEntry[] oldEntries = previousContainer.getClasspathEntries();
+		if (oldEntries.length != newEntries.length) {
+			if (CP_RESOLVE_VERBOSE)
+				verbose_missbehaving_container(containerPath, projects, respectiveContainers, container, newEntries, oldEntries);
 			return false;
+		}
 		for (int i = 0, length = newEntries.length; i < length; i++) {
+			if (newEntries[i] == null) {
+				if (CP_RESOLVE_VERBOSE)
+					verbose_missbehaving_container(project, containerPath, newEntries);
+				return false;
+			}
 			if (!newEntries[i].equals(oldEntries[i])) {
-				if (CP_RESOLVE_VERBOSE) {
-					Util.verbose(
-						"CPContainer SET  - missbehaving container\n" + //$NON-NLS-1$
-						"	container path: " + containerPath + '\n' + //$NON-NLS-1$
-						"	projects: {" +//$NON-NLS-1$
-						org.eclipse.jdt.internal.compiler.util.Util.toString(
-							projects, 
-							new org.eclipse.jdt.internal.compiler.util.Util.Displayable(){ 
-								public String displayString(Object o) { return ((IJavaProject) o).getElementName(); }
-							}) +
-						"}\n	values on previous session: {\n"  +//$NON-NLS-1$
-						org.eclipse.jdt.internal.compiler.util.Util.toString(
-							respectiveContainers, 
-							new org.eclipse.jdt.internal.compiler.util.Util.Displayable(){ 
-								public String displayString(Object o) { 
-									StringBuffer buffer = new StringBuffer("		"); //$NON-NLS-1$
-									if (o == null) {
-										buffer.append("<null>"); //$NON-NLS-1$
-										return buffer.toString();
-									}
-									buffer.append(container.getDescription());
-									buffer.append(" {\n"); //$NON-NLS-1$
-									for (int j = 0; j < oldEntries.length; j++){
-										buffer.append(" 			"); //$NON-NLS-1$
-										buffer.append(oldEntries[j]); 
-										buffer.append('\n'); 
-									}
-									buffer.append(" 		}"); //$NON-NLS-1$
-									return buffer.toString();
-								}
-							}) +
-						"}\n	new values: {\n"  +//$NON-NLS-1$
-						org.eclipse.jdt.internal.compiler.util.Util.toString(
-							respectiveContainers, 
-							new org.eclipse.jdt.internal.compiler.util.Util.Displayable(){ 
-								public String displayString(Object o) { 
-									StringBuffer buffer = new StringBuffer("		"); //$NON-NLS-1$
-									if (o == null) {
-										buffer.append("<null>"); //$NON-NLS-1$
-										return buffer.toString();
-									}
-									buffer.append(container.getDescription());
-									buffer.append(" {\n"); //$NON-NLS-1$
-									for (int j = 0; j < newEntries.length; j++){
-										buffer.append(" 			"); //$NON-NLS-1$
-										buffer.append(newEntries[j]); 
-										buffer.append('\n'); 
-									}
-									buffer.append(" 		}"); //$NON-NLS-1$
-									return buffer.toString();
-								}
-							}) +
-						"\n	}"); //$NON-NLS-1$
-				}
+				if (CP_RESOLVE_VERBOSE)
+					verbose_missbehaving_container(containerPath, projects, respectiveContainers, container, newEntries, oldEntries);
 				return false;
 			}
 		}
 		containerPut(project, containerPath, container);
 		return true;
 	}
+
+	private void verbose_missbehaving_container(
+			IPath containerPath,
+			IJavaProject[] projects,
+			IClasspathContainer[] respectiveContainers,
+			final IClasspathContainer container,
+			final IClasspathEntry[] newEntries,
+			final IClasspathEntry[] oldEntries) {
+		Util.verbose(
+			"CPContainer SET  - missbehaving container\n" + //$NON-NLS-1$
+			"	container path: " + containerPath + '\n' + //$NON-NLS-1$
+			"	projects: {" +//$NON-NLS-1$
+			org.eclipse.jdt.internal.compiler.util.Util.toString(
+				projects, 
+				new org.eclipse.jdt.internal.compiler.util.Util.Displayable(){ 
+					public String displayString(Object o) { return ((IJavaProject) o).getElementName(); }
+				}) +
+			"}\n	values on previous session: {\n"  +//$NON-NLS-1$
+			org.eclipse.jdt.internal.compiler.util.Util.toString(
+				respectiveContainers, 
+				new org.eclipse.jdt.internal.compiler.util.Util.Displayable(){ 
+					public String displayString(Object o) { 
+						StringBuffer buffer = new StringBuffer("		"); //$NON-NLS-1$
+						if (o == null) {
+							buffer.append("<null>"); //$NON-NLS-1$
+							return buffer.toString();
+						}
+						buffer.append(container.getDescription());
+						buffer.append(" {\n"); //$NON-NLS-1$
+						if (oldEntries == null) {
+							buffer.append(" 			"); //$NON-NLS-1$
+							buffer.append("<null>\n"); //$NON-NLS-1$
+						} else {
+							for (int j = 0; j < oldEntries.length; j++){
+								buffer.append(" 			"); //$NON-NLS-1$
+								buffer.append(oldEntries[j]); 
+								buffer.append('\n'); 
+							}
+						}
+						buffer.append(" 		}"); //$NON-NLS-1$
+						return buffer.toString();
+					}
+				}) +
+			"}\n	new values: {\n"  +//$NON-NLS-1$
+			org.eclipse.jdt.internal.compiler.util.Util.toString(
+				respectiveContainers, 
+				new org.eclipse.jdt.internal.compiler.util.Util.Displayable(){ 
+					public String displayString(Object o) { 
+						StringBuffer buffer = new StringBuffer("		"); //$NON-NLS-1$
+						if (o == null) {
+							buffer.append("<null>"); //$NON-NLS-1$
+							return buffer.toString();
+						}
+						buffer.append(container.getDescription());
+						buffer.append(" {\n"); //$NON-NLS-1$
+						for (int j = 0; j < newEntries.length; j++){
+							buffer.append(" 			"); //$NON-NLS-1$
+							buffer.append(newEntries[j]); 
+							buffer.append('\n'); 
+						}
+						buffer.append(" 		}"); //$NON-NLS-1$
+						return buffer.toString();
+					}
+				}) +
+			"\n	}"); //$NON-NLS-1$
+	}
 	
+	void verbose_missbehaving_container(IJavaProject project, IPath containerPath, IClasspathEntry[] classpathEntries) {
+		Util.verbose(
+			"CPContainer GET - missbehaving container (returning null classpath entry)\n" + //$NON-NLS-1$
+			"	project: " + project.getElementName() + '\n' + //$NON-NLS-1$
+			"	container path: " + containerPath + '\n' + //$NON-NLS-1$
+			"	classpath entries: {\n" + //$NON-NLS-1$
+			org.eclipse.jdt.internal.compiler.util.Util.toString(
+				classpathEntries, 
+				new org.eclipse.jdt.internal.compiler.util.Util.Displayable(){ 
+					public String displayString(Object o) { 
+						StringBuffer buffer = new StringBuffer("		"); //$NON-NLS-1$
+						if (o == null) {
+							buffer.append("<null>"); //$NON-NLS-1$
+							return buffer.toString();
+						}
+						buffer.append(o);
+						return buffer.toString();
+					}
+				}) +
+			"\n	}" //$NON-NLS-1$
+		);
+	}
+
 	private void containerRemoveInitializationInProgress(IJavaProject project, IPath containerPath) {
-		HashSet projectInitializations = containerInitializationInProgress(project);
+		Map initializations = (Map)this.containerInitializationInProgress.get();
+		if (initializations == null)
+			return;
+		HashSet projectInitializations = (HashSet) initializations.get(project);
+		if (projectInitializations == null)
+			return;
 		projectInitializations.remove(containerPath);
-		if (projectInitializations.size() == 0) {
-			Map initializations = (Map)this.containerInitializationInProgress.get();
+		if (projectInitializations.size() == 0)
 			initializations.remove(project);
-		}
+		if (initializations.size() == 0)
+			this.containerInitializationInProgress.set(null);
 	}
 	
 	private synchronized void containersReset(String[] containerIDs) {
 		for (int i = 0; i < containerIDs.length; i++) {
 			String containerID = containerIDs[i];
-			Iterator projectIterator = this.containers.keySet().iterator();
+			Iterator projectIterator = this.containers.values().iterator();
 			while (projectIterator.hasNext()){
-				IJavaProject project = (IJavaProject)projectIterator.next();
-				Map projectContainers = (Map)this.containers.get(project);
+				Map projectContainers = (Map) projectIterator.next();
 				if (projectContainers != null){
 					Iterator containerIterator = projectContainers.keySet().iterator();
 					while (containerIterator.hasNext()){
@@ -505,14 +806,7 @@
 		} else {
 			element = determineIfOnClasspath(folder, project);
 		}
-		
-		if (conflictsWithOutputLocation(folder.getFullPath(), (JavaProject)project)
-		 	|| (folder.getName().indexOf('.') >= 0 
-		 		&& !(element instanceof IPackageFragmentRoot))) {
-			return null; // only package fragment roots are allowed with dot names
-		} else {
-			return element;
-		}
+		return element;
 	}
 
 	/**
@@ -580,13 +874,9 @@
 		// Create a jar package fragment root only if on the classpath
 		IPath resourcePath = file.getFullPath();
 		try {
-			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();
-				if (rootPath.equals(resourcePath)) {
-					return project.getPackageFragmentRoot(file);
-				}
+			IClasspathEntry entry = ((JavaProject)project).getClasspathEntryFor(resourcePath);
+			if (entry != null) {
+				return project.getPackageFragmentRoot(file);
 			}
 		} catch (JavaModelException e) {
 			// project doesn't exist: return null
@@ -605,35 +895,49 @@
 			
 		IPath resourcePath = resource.getFullPath();
 		try {
+			JavaProjectElementInfo projectInfo = (JavaProjectElementInfo) getJavaModelManager().getInfo(project);
+			ProjectCache projectCache = projectInfo == null ? null : projectInfo.projectCache;
+			HashtableOfArrayToObject allPkgFragmentsCache = projectCache == null ? null : projectCache.allPkgFragmentsCache;
 			IClasspathEntry[] entries = 
 				org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(resourcePath.lastSegment())
 					? project.getRawClasspath() // JAVA file can only live inside SRC folder (on the raw path)
-					: ((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];
-				if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) continue;
-				IPath rootPath = entry.getPath();
-				if (rootPath.equals(resourcePath)) {
-					return project.getPackageFragmentRoot(resource);
-				} 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
-						PackageFragmentRoot root =(PackageFragmentRoot) ((JavaProject) project).getFolderPackageFragmentRoot(rootPath);
-						if (root == null) return null;
-						IPath pkgPath = resourcePath.removeFirstSegments(rootPath.segmentCount());
+					: ((JavaProject)project).getResolvedClasspath();
+			
+			int length	= entries.length;
+			if (length > 0) {
+				String sourceLevel = project.getOption(JavaCore.COMPILER_SOURCE, true);
+				String complianceLevel = project.getOption(JavaCore.COMPILER_COMPLIANCE, true);
+				for (int i = 0; i < length; i++) {
+					IClasspathEntry entry = entries[i];
+					if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) continue;
+					IPath rootPath = entry.getPath();
+					if (rootPath.equals(resourcePath)) {
+						return project.getPackageFragmentRoot(resource);
+					} 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
+							PackageFragmentRoot root =(PackageFragmentRoot) ((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);
+							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 = pkgPath.segments();
+							
+							// if package name is in the cache, then it has already been validated
+							// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=133141)
+							if (allPkgFragmentsCache != null && allPkgFragmentsCache.containsKey(pkgName))
+								return root.getPackageFragment(pkgName);
+							
+							if (pkgName.length != 0 && JavaConventions.validatePackageName(Util.packageName(pkgPath, sourceLevel, complianceLevel), sourceLevel, complianceLevel).getSeverity() == IStatus.ERROR) {
+								return null;
+							}
+							return root.getPackageFragment(pkgName);
 						}
-						String[] pkgName = pkgPath.segments();
-						if (pkgName.length != 0 && JavaConventions.validatePackageName(Util.packageName(pkgPath)).getSeverity() == IStatus.ERROR) {
-							return null;
-						}
-						return root.getPackageFragment(pkgName);
 					}
 				}
 			}
@@ -651,7 +955,7 @@
 	/**
 	 * Infos cache.
 	 */
-	public JavaModelCache cache = new JavaModelCache();
+	private JavaModelCache cache;
 	
 	/*
 	 * Temporary cache of newly opened elements
@@ -661,14 +965,14 @@
 	/**
 	 * Set of elements which are out of sync with their buffers.
 	 */
-	protected Map elementsOutOfSynchWithBuffers = new HashMap(11);
+	protected HashSet elementsOutOfSynchWithBuffers = new HashSet(11);
 	
 	/**
 	 * Holds the state used for delta processing.
 	 */
 	public DeltaProcessingState deltaState = new DeltaProcessingState();
 
-	public IndexManager indexManager = new IndexManager();
+	public IndexManager indexManager = null;
 	
 	/**
 	 * Table from IProject to PerProjectInfo.
@@ -688,23 +992,30 @@
 	protected WeakHashMap searchScopes = new WeakHashMap();
 
 	public static class PerProjectInfo {
+		private static final int JAVADOC_CACHE_INITIAL_SIZE = 10;
 		
 		public IProject project;
 		public Object savedState;
 		public boolean triedRead;
 		public IClasspathEntry[] rawClasspath;
+		public IJavaModelStatus rawClasspathStatus;
 		public IClasspathEntry[] resolvedClasspath;
-		public Map resolvedPathToRawEntries; // reverse map from resolved path to raw entries
+		public IJavaModelStatus unresolvedEntryStatus;
+		public Map rootPathToRawEntries; // reverse map from a package fragment root's path to the raw entry
+		public Map rootPathToResolvedEntries; // map from a package fragment root's path to the resolved entry
 		public IPath outputLocation;
 		
 		public IEclipsePreferences preferences;
 		public Hashtable options;
+		public Hashtable secondaryTypes;
+		public LRUCache javadocCache;
 		
 		public PerProjectInfo(IProject project) {
 
 			this.triedRead = false;
 			this.savedState = null;
 			this.project = project;
+			this.javadocCache = new LRUCache(JAVADOC_CACHE_INITIAL_SIZE);
 		}
 		
 		public void rememberExternalLibTimestamps() {
@@ -727,13 +1038,82 @@
 			}
 		}
 		
-		// updating raw classpath need to flush obsoleted cached information about resolved entries
-		public synchronized void updateClasspathInformation(IClasspathEntry[] newRawClasspath) {
-
-			this.rawClasspath = newRawClasspath;
-			this.resolvedClasspath = null;
-			this.resolvedPathToRawEntries = null;
+		public synchronized void resetResolvedClasspath() {
+			// null out resolved information
+			setClasspath(this.rawClasspath, this.outputLocation, this.rawClasspathStatus, null, null, null, null);
 		}
+		
+		public synchronized void setClasspath(IClasspathEntry[] newRawClasspath, IPath newOutputLocation, IJavaModelStatus newRawClasspathStatus, IClasspathEntry[] newResolvedClasspath, Map newRootPathToRawEntries, Map newRootPathToResolvedEntries, IJavaModelStatus newUnresolvedEntryStatus) {
+			// remember old info
+			JavaModelManager manager = JavaModelManager.getJavaModelManager();
+			DeltaProcessor deltaProcessor = manager.deltaState.getDeltaProcessor();
+			deltaProcessor.addClasspathChange(this.project, this.rawClasspath, this.outputLocation, this.resolvedClasspath);
+			
+			this.rawClasspath = newRawClasspath;
+			this.outputLocation = newOutputLocation;
+			this.rawClasspathStatus = newRawClasspathStatus;
+			this.resolvedClasspath = newResolvedClasspath;
+			this.rootPathToRawEntries = newRootPathToRawEntries;
+			this.rootPathToResolvedEntries = newRootPathToResolvedEntries;
+			this.unresolvedEntryStatus = newUnresolvedEntryStatus;
+			this.javadocCache = new LRUCache(JAVADOC_CACHE_INITIAL_SIZE);
+		}
+		
+		/*
+		 * Reads the raw classpath and output location from disk, and remember them.
+		 * Return the raw classpath, or JavaProject#INVALID_CLASSPATH if unable to read it.
+		 */
+		public synchronized IClasspathEntry[] readAndCacheClasspath(JavaProject javaProject) {
+			// read file entries and update status
+			IClasspathEntry[] classpath;
+			IJavaModelStatus status;
+			try {
+				classpath = javaProject.readFileEntriesWithException(null/*not interested in unknown elements*/);
+				status = JavaModelStatus.VERIFIED_OK;
+			} catch (CoreException e) {
+				classpath = JavaProject.INVALID_CLASSPATH;
+				status = 
+					new JavaModelStatus(
+						IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
+						Messages.bind(Messages.classpath_cannotReadClasspathFile, javaProject.getElementName()));
+			} catch (IOException e) {
+				classpath = JavaProject.INVALID_CLASSPATH;
+				if (Messages.file_badFormat.equals(e.getMessage()))
+					status = 
+						new JavaModelStatus(
+							IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
+							Messages.bind(Messages.classpath_xmlFormatError, javaProject.getElementName(), Messages.file_badFormat));
+				else				
+					status = 
+						new JavaModelStatus(
+							IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
+							Messages.bind(Messages.classpath_cannotReadClasspathFile, javaProject.getElementName()));
+			} catch (AssertionFailedException e) {
+				classpath = JavaProject.INVALID_CLASSPATH;
+				status =  
+					new JavaModelStatus(
+						IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
+						Messages.bind(Messages.classpath_illegalEntryInClasspathFile, new String[] {javaProject.getElementName(), e.getMessage()}));
+			}
+		
+			// extract out the output location
+			IPath output = null;
+			if (classpath.length > 0) {
+				IClasspathEntry entry = classpath[classpath.length - 1];
+				if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) {
+					output = entry.getPath();
+					IClasspathEntry[] copy = new IClasspathEntry[classpath.length - 1];
+					System.arraycopy(classpath, 0, copy, 0, copy.length);
+					classpath = copy;
+				}
+			}
+			
+			// store new raw classpath, new output and new status, and null out resolved info
+			setClasspath(classpath, output, status, null, null, null, null);
+			
+			return classpath;
+		}
+		
 		public String toString() {
 			StringBuffer buffer = new StringBuffer();
 			buffer.append("Info for "); //$NON-NLS-1$
@@ -772,28 +1152,38 @@
 	public static class PerWorkingCopyInfo implements IProblemRequestor {
 		int useCount = 0;
 		IProblemRequestor problemRequestor;
-		ICompilationUnit workingCopy;
-		public PerWorkingCopyInfo(ICompilationUnit workingCopy, IProblemRequestor problemRequestor) {
+		CompilationUnit workingCopy;
+		public PerWorkingCopyInfo(CompilationUnit workingCopy, IProblemRequestor problemRequestor) {
 			this.workingCopy = workingCopy;
 			this.problemRequestor = problemRequestor;
 		}
 		public void acceptProblem(IProblem problem) {
-			if (this.problemRequestor == null) return;
-			this.problemRequestor.acceptProblem(problem);
+			IProblemRequestor requestor = getProblemRequestor();
+			if (requestor == null) return;
+			requestor.acceptProblem(problem);
 		}
 		public void beginReporting() {
-			if (this.problemRequestor == null) return;
-			this.problemRequestor.beginReporting();
+			IProblemRequestor requestor = getProblemRequestor();
+			if (requestor == null) return;
+			requestor.beginReporting();
 		}
 		public void endReporting() {
-			if (this.problemRequestor == null) return;
-			this.problemRequestor.endReporting();
+			IProblemRequestor requestor = getProblemRequestor();
+			if (requestor == null) return;
+			requestor.endReporting();
+		}
+		public IProblemRequestor getProblemRequestor() {
+			if (this.problemRequestor == null && this.workingCopy.owner != null) {
+				return this.workingCopy.owner.getProblemRequestor(this.workingCopy);
+			}
+			return this.problemRequestor;
 		}
 		public ICompilationUnit getWorkingCopy() {
 			return this.workingCopy;
 		}
 		public boolean isActive() {
-			return this.problemRequestor != null && this.problemRequestor.isActive();
+			IProblemRequestor requestor = getProblemRequestor();
+			return requestor != null && requestor.isActive();
 		}
 		public String toString() {
 			StringBuffer buffer = new StringBuffer();
@@ -803,12 +1193,18 @@
 			buffer.append(this.useCount);
 			buffer.append("\nProblem requestor:\n  "); //$NON-NLS-1$
 			buffer.append(this.problemRequestor);
+			if (this.problemRequestor == null) {
+				IProblemRequestor requestor = getProblemRequestor();
+				buffer.append("\nOwner problem requestor:\n  "); //$NON-NLS-1$
+				buffer.append(requestor);
+			}
 			return buffer.toString();
 		}
 	}
 	
 	public static boolean VERBOSE = false;
 	public static boolean CP_RESOLVE_VERBOSE = false;
+	public static boolean CP_RESOLVE_VERBOSE_ADVANCED = false;
 	public static boolean ZIP_ACCESS_VERBOSE = false;
 	
 	/**
@@ -817,29 +1213,76 @@
 	 */
 	private ThreadLocal zipFiles = new ThreadLocal();
 	
+	private UserLibraryManager userLibraryManager;
 	
 	/**
 	 * Update the classpath variable cache
 	 */
-	public static class EclipsePreferencesListener implements IEclipsePreferences.IPreferenceChangeListener {
+	public class EclipsePreferencesListener implements IEclipsePreferences.IPreferenceChangeListener {
 		/**
-		 * @see org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener#preferenceChange(org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent)
-		 */
-		public void preferenceChange(IEclipsePreferences.PreferenceChangeEvent event) {
-			String propertyName = event.getKey();
-			if (propertyName.startsWith(CP_VARIABLE_PREFERENCES_PREFIX)) {
-				String varName = propertyName.substring(CP_VARIABLE_PREFERENCES_PREFIX.length());
-				String newValue = (String)event.getNewValue();
-				if (newValue != null && !(newValue = newValue.trim()).equals(CP_ENTRY_IGNORE)) {
-					getJavaModelManager().variables.put(varName, new Path(newValue));
-				} else {
-					getJavaModelManager().variables.remove(varName);
+         * @see org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener#preferenceChange(org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent)
+         */
+        public void preferenceChange(IEclipsePreferences.PreferenceChangeEvent event) {
+        	String propertyName = event.getKey();
+        	if (propertyName.startsWith(CP_VARIABLE_PREFERENCES_PREFIX)) {
+        		String varName = propertyName.substring(CP_VARIABLE_PREFERENCES_PREFIX.length());
+        		JavaModelManager manager = getJavaModelManager();
+        		if (manager.variablesWithInitializer.contains(varName)) {
+        			// revert preference value as we will not apply it to JavaCore classpath variable
+        			String oldValue = (String) event.getOldValue();
+        			if (oldValue == null) {
+        				// unexpected old value => remove variable from set
+        				manager.variablesWithInitializer.remove(varName);
+        			} else {
+        				manager.getInstancePreferences().put(varName, oldValue);
+        			}
+        		} else {
+        			String newValue = (String)event.getNewValue();
+        			IPath newPath;
+        			if (newValue != null && !(newValue = newValue.trim()).equals(CP_ENTRY_IGNORE)) {
+        				newPath = new Path(newValue);
+        			} else {
+        				newPath = null;
+        			}
+        			try {
+        				SetVariablesOperation operation = new SetVariablesOperation(new String[] {varName}, new IPath[] {newPath}, false/*don't update preferences*/);
+        				operation.runOperation(null/*no progress available*/);
+        			} catch (JavaModelException e) {
+        				Util.log(e, "Could not set classpath variable " + varName + " to " + newPath); //$NON-NLS-1$ //$NON-NLS-2$
+        			}
+        		}
+        	} else if (propertyName.startsWith(CP_CONTAINER_PREFERENCES_PREFIX)) {
+        		recreatePersistedContainer(propertyName, (String)event.getNewValue(), false);
+        	} else if (propertyName.equals(JavaCore.CORE_JAVA_BUILD_CLEAN_OUTPUT_FOLDER) ||
+				propertyName.equals(JavaCore.CORE_JAVA_BUILD_RESOURCE_COPY_FILTER) ||
+				propertyName.equals(JavaCore.CORE_JAVA_BUILD_DUPLICATE_RESOURCE) ||
+				propertyName.equals(JavaCore.CORE_JAVA_BUILD_RECREATE_MODIFIED_CLASS_FILES_IN_OUTPUT_FOLDER) ||
+				propertyName.equals(JavaCore.CORE_JAVA_BUILD_INVALID_CLASSPATH) ||
+				propertyName.equals(JavaCore.CORE_ENABLE_CLASSPATH_EXCLUSION_PATTERNS) ||
+				propertyName.equals(JavaCore.CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS) ||
+				propertyName.equals(JavaCore.CORE_INCOMPLETE_CLASSPATH) ||
+				propertyName.equals(JavaCore.CORE_CIRCULAR_CLASSPATH) ||
+				propertyName.equals(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL)) {
+				JavaModelManager manager = JavaModelManager.getJavaModelManager();
+				IJavaModel model = manager.getJavaModel();
+				IJavaProject[] projects;
+				try {
+					projects = model.getJavaProjects();
+					for (int i = 0, pl = projects.length; i < pl; i++) {
+						JavaProject javaProject = (JavaProject) projects[i];
+						manager.deltaState.addClasspathValidation(javaProject);
+						try {
+							// need to touch the project to force validation by DeltaProcessor
+				            javaProject.getProject().touch(null);
+				        } catch (CoreException e) {
+				            // skip
+				        }
+					}
+				} catch (JavaModelException e) {
+					// skip
 				}
-			}
-			if (propertyName.startsWith(CP_CONTAINER_PREFERENCES_PREFIX)) {
-				recreatePersistedContainer(propertyName, (String)event.getNewValue(), false);
-			}
-		}
+        	}
+        }
 	}
 
 	/**
@@ -847,6 +1290,7 @@
 	 */
 	private JavaModelManager() {
 		// singleton: prevent others from creating a new instance
+		if (Platform.isRunning()) this.indexManager = new IndexManager();
 	}
 
 	/**
@@ -886,52 +1330,58 @@
 	public void configurePluginDebugOptions(){
 		if(JavaCore.getPlugin().isDebugging()){
 			String option = Platform.getDebugOption(BUFFER_MANAGER_DEBUG);
-			if(option != null) BufferManager.VERBOSE = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
+			if(option != null) BufferManager.VERBOSE = option.equalsIgnoreCase(TRUE) ;
 			
 			option = Platform.getDebugOption(BUILDER_DEBUG);
-			if(option != null) JavaBuilder.DEBUG = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
+			if(option != null) JavaBuilder.DEBUG = option.equalsIgnoreCase(TRUE) ;
 			
 			option = Platform.getDebugOption(COMPILER_DEBUG);
-			if(option != null) Compiler.DEBUG = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
+			if(option != null) Compiler.DEBUG = option.equalsIgnoreCase(TRUE) ;
 
 			option = Platform.getDebugOption(COMPLETION_DEBUG);
-			if(option != null) CompletionEngine.DEBUG = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
+			if(option != null) CompletionEngine.DEBUG = option.equalsIgnoreCase(TRUE) ;
 			
 			option = Platform.getDebugOption(CP_RESOLVE_DEBUG);
-			if(option != null) JavaModelManager.CP_RESOLVE_VERBOSE = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
+			if(option != null) JavaModelManager.CP_RESOLVE_VERBOSE = option.equalsIgnoreCase(TRUE) ;
+
+			option = Platform.getDebugOption(CP_RESOLVE_ADVANCED_DEBUG);
+			if(option != null) JavaModelManager.CP_RESOLVE_VERBOSE_ADVANCED = option.equalsIgnoreCase(TRUE) ;
 
 			option = Platform.getDebugOption(DELTA_DEBUG);
-			if(option != null) DeltaProcessor.DEBUG = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
+			if(option != null) DeltaProcessor.DEBUG = option.equalsIgnoreCase(TRUE) ;
 
 			option = Platform.getDebugOption(DELTA_DEBUG_VERBOSE);
-			if(option != null) DeltaProcessor.VERBOSE = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
+			if(option != null) DeltaProcessor.VERBOSE = option.equalsIgnoreCase(TRUE) ;
 
 			option = Platform.getDebugOption(HIERARCHY_DEBUG);
-			if(option != null) TypeHierarchy.DEBUG = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
+			if(option != null) TypeHierarchy.DEBUG = option.equalsIgnoreCase(TRUE) ;
 
 			option = Platform.getDebugOption(INDEX_MANAGER_DEBUG);
-			if(option != null) JobManager.VERBOSE = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
+			if(option != null) JobManager.VERBOSE = option.equalsIgnoreCase(TRUE) ;
 			
 			option = Platform.getDebugOption(JAVAMODEL_DEBUG);
-			if(option != null) JavaModelManager.VERBOSE = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
+			if(option != null) JavaModelManager.VERBOSE = option.equalsIgnoreCase(TRUE) ;
+
+			option = Platform.getDebugOption(JAVAMODELCACHE_DEBUG);
+			if(option != null) JavaModelCache.VERBOSE = option.equalsIgnoreCase(TRUE) ;
 
 			option = Platform.getDebugOption(POST_ACTION_DEBUG);
-			if(option != null) JavaModelOperation.POST_ACTION_VERBOSE = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
+			if(option != null) JavaModelOperation.POST_ACTION_VERBOSE = option.equalsIgnoreCase(TRUE) ;
 
 			option = Platform.getDebugOption(RESOLUTION_DEBUG);
-			if(option != null) NameLookup.VERBOSE = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
+			if(option != null) NameLookup.VERBOSE = option.equalsIgnoreCase(TRUE) ;
 
 			option = Platform.getDebugOption(SEARCH_DEBUG);
-			if(option != null) BasicSearchEngine.VERBOSE = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
+			if(option != null) BasicSearchEngine.VERBOSE = option.equalsIgnoreCase(TRUE) ;
 
 			option = Platform.getDebugOption(SELECTION_DEBUG);
-			if(option != null) SelectionEngine.DEBUG = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
+			if(option != null) SelectionEngine.DEBUG = option.equalsIgnoreCase(TRUE) ;
 
 			option = Platform.getDebugOption(ZIP_ACCESS_DEBUG);
-			if(option != null) JavaModelManager.ZIP_ACCESS_VERBOSE = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
+			if(option != null) JavaModelManager.ZIP_ACCESS_VERBOSE = option.equalsIgnoreCase(TRUE) ;
 			
 			option = Platform.getDebugOption(SOURCE_MAPPER_DEBUG_VERBOSE);
-			if(option != null) SourceMapper.VERBOSE = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
+			if(option != null) SourceMapper.VERBOSE = option.equalsIgnoreCase(TRUE) ;
 		}
 		
 		// configure performance options
@@ -946,6 +1396,55 @@
 	}
 	
 	/*
+	 * Return a new Java 6 annotation processor manager.  The manager will need to
+	 * be configured before it can be used.  Returns null if a manager cannot be
+	 * created, ie if the current VM does not support Java 6 annotation processing.
+	 */
+	public AbstractAnnotationProcessorManager createAnnotationProcessorManager() {
+		synchronized(this) {
+			if (this.annotationProcessorManagerFactory == null) {
+				IExtensionPoint extension = Platform.getExtensionRegistry().getExtensionPoint(JavaCore.PLUGIN_ID, ANNOTATION_PROCESSOR_MANAGER_EXTPOINT_ID);
+				if (extension == null)
+					return null;
+				IExtension[] extensions = extension.getExtensions();
+				for(int i = 0; i < extensions.length; i++) {
+					if (i > 0) {
+						Util.log(null, "An annotation processor manager is already registered: ignoring " + extensions[i].getUniqueIdentifier()); //$NON-NLS-1$
+						break;
+					}
+					IConfigurationElement[] configElements = extensions[i].getConfigurationElements();
+					for(int j = 0; j < configElements.length; j++) {
+						final IConfigurationElement configElement = configElements[j];
+						if ("annotationProcessorManager".equals(configElement.getName())) { //$NON-NLS-1$
+							this.annotationProcessorManagerFactory = configElement;
+							break;
+						}
+					}
+				}
+			}
+		}
+		
+		if (this.annotationProcessorManagerFactory == null) {
+			return null;
+		}
+		final AbstractAnnotationProcessorManager[] apm = new AbstractAnnotationProcessorManager[1];
+		apm[0] = null;
+		final IConfigurationElement factory = this.annotationProcessorManagerFactory;
+		SafeRunner.run(new ISafeRunnable() {
+			public void handleException(Throwable exception) {
+				Util.log(exception, "Exception occurred while loading annotation processor manager"); //$NON-NLS-1$
+			}
+			public void run() throws Exception {
+				Object executableExtension = factory.createExecutableExtension("class"); //$NON-NLS-1$ 
+				if (executableExtension instanceof AbstractAnnotationProcessorManager) {
+					apm[0] = (AbstractAnnotationProcessorManager) executableExtension;
+				}
+			}
+		});
+		return apm[0];
+	}
+	
+	/*
 	 * Discards the per working copy info for the given working copy (making it a compilation unit)
 	 * if its use count was 1. Otherwise, just decrement the use count.
 	 * If the working copy is primary, computes the delta between its state and the original compilation unit
@@ -960,7 +1459,7 @@
 		// 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()) {
+		if (workingCopy.isPrimary() && workingCopy.hasUnsavedChanges()) {
 			deltaBuilder = new JavaElementDeltaBuilder(workingCopy);
 		}
 		PerWorkingCopyInfo info = null;
@@ -989,7 +1488,7 @@
 			// 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)) {
+				if (deltaBuilder.delta != null) {
 					getDeltaProcessor().registerJavaModelDelta(deltaBuilder.delta);
 				}
 			}
@@ -1026,18 +1525,26 @@
 		}
 	}
 	
-	public IClasspathContainer getClasspathContainer(IPath containerPath, IJavaProject project) throws JavaModelException {
+	private synchronized boolean batchContainerInitializations() {
+		if (this.batchContainerInitializations) {
+			this.batchContainerInitializations = false;
+			return true;
+		}
+		return false;
+	}
+	
+	public IClasspathContainer getClasspathContainer(final IPath containerPath, final IJavaProject project) throws JavaModelException {
 
 		IClasspathContainer container = containerGet(project, containerPath);
 
 		if (container == null) {
-			if (this.batchContainerInitializations) {
+			if (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);
+				container = initializeAllContainers(project, containerPath);
+			} else {
+				container = initializeContainer(project, containerPath);
 			}
-			return initializeContainer(project, containerPath);
 		}
 		return container;			
 	}
@@ -1049,7 +1556,7 @@
 	/** 
 	 * Returns the set of elements which are out of synch with their buffers.
 	 */
-	protected Map getElementsOutOfSynchWithBuffers() {
+	protected HashSet getElementsOutOfSynchWithBuffers() {
 		return this.elementsOutOfSynchWithBuffers;
 	}
 
@@ -1078,11 +1585,13 @@
 		return preferencesLookup[PREF_INSTANCE];
 	}
  
+	// If modified, also modify the method getDefaultOptionsNoInitialization()
 	public Hashtable getDefaultOptions(){
-	
+
 		Hashtable defaultOptions = new Hashtable(10);
 
 		// see JavaCorePreferenceInitializer#initializeDefaultPluginPreferences() for changing default settings
+		// If modified, also modify the method getDefaultOptionsNoInitialization()
 		IEclipsePreferences defaultPreferences = getDefaultPreferences();
 		
 		// initialize preferences to their default
@@ -1170,6 +1679,9 @@
 		// return cached options if already computed
 		if (this.optionsCache != null) return new Hashtable(this.optionsCache);
 
+		if (!Platform.isRunning()) {
+			return this.optionsCache = getDefaultOptionsNoInitialization();
+		}
 		// init
 		Hashtable options = new Hashtable(10);
 		IPreferencesService service = Platform.getPreferencesService();
@@ -1196,6 +1708,59 @@
 		// return built map
 		return options;
 	}
+
+	// Do not modify without modifying getDefaultOptions()
+	private Hashtable getDefaultOptionsNoInitialization() {
+		Map defaultOptionsMap = new CompilerOptions().getMap(); // compiler defaults
+		
+		// Override some compiler defaults
+		defaultOptionsMap.put(JavaCore.COMPILER_LOCAL_VARIABLE_ATTR, JavaCore.GENERATE);
+		defaultOptionsMap.put(JavaCore.COMPILER_CODEGEN_UNUSED_LOCAL, JavaCore.PRESERVE);
+		defaultOptionsMap.put(JavaCore.COMPILER_TASK_TAGS, JavaCore.DEFAULT_TASK_TAGS);
+		defaultOptionsMap.put(JavaCore.COMPILER_TASK_PRIORITIES, JavaCore.DEFAULT_TASK_PRIORITIES);
+		defaultOptionsMap.put(JavaCore.COMPILER_TASK_CASE_SENSITIVE, JavaCore.ENABLED);
+		defaultOptionsMap.put(JavaCore.COMPILER_DOC_COMMENT_SUPPORT, JavaCore.ENABLED);
+		defaultOptionsMap.put(JavaCore.COMPILER_PB_FORBIDDEN_REFERENCE, JavaCore.ERROR);
+		
+		// Builder settings
+		defaultOptionsMap.put(JavaCore.CORE_JAVA_BUILD_RESOURCE_COPY_FILTER, ""); //$NON-NLS-1$
+		defaultOptionsMap.put(JavaCore.CORE_JAVA_BUILD_INVALID_CLASSPATH, JavaCore.ABORT); 
+		defaultOptionsMap.put(JavaCore.CORE_JAVA_BUILD_DUPLICATE_RESOURCE, JavaCore.WARNING); 
+		defaultOptionsMap.put(JavaCore.CORE_JAVA_BUILD_CLEAN_OUTPUT_FOLDER, JavaCore.CLEAN); 
+
+		// JavaCore settings
+		defaultOptionsMap.put(JavaCore.CORE_JAVA_BUILD_ORDER, JavaCore.IGNORE); 
+		defaultOptionsMap.put(JavaCore.CORE_INCOMPLETE_CLASSPATH, JavaCore.ERROR); 
+		defaultOptionsMap.put(JavaCore.CORE_CIRCULAR_CLASSPATH, JavaCore.ERROR); 
+		defaultOptionsMap.put(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL, JavaCore.IGNORE); 
+		defaultOptionsMap.put(JavaCore.CORE_ENABLE_CLASSPATH_EXCLUSION_PATTERNS, JavaCore.ENABLED); 
+		defaultOptionsMap.put(JavaCore.CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS, JavaCore.ENABLED); 
+
+		// Formatter settings
+		defaultOptionsMap.putAll(DefaultCodeFormatterConstants.getEclipseDefaultSettings());
+
+		// CodeAssist settings
+		defaultOptionsMap.put(JavaCore.CODEASSIST_VISIBILITY_CHECK, JavaCore.DISABLED);
+		defaultOptionsMap.put(JavaCore.CODEASSIST_DEPRECATION_CHECK, JavaCore.DISABLED);
+		defaultOptionsMap.put(JavaCore.CODEASSIST_IMPLICIT_QUALIFICATION, JavaCore.DISABLED);
+		defaultOptionsMap.put(JavaCore.CODEASSIST_FIELD_PREFIXES, ""); //$NON-NLS-1$
+		defaultOptionsMap.put(JavaCore.CODEASSIST_STATIC_FIELD_PREFIXES, ""); //$NON-NLS-1$
+		defaultOptionsMap.put(JavaCore.CODEASSIST_LOCAL_PREFIXES, ""); //$NON-NLS-1$
+		defaultOptionsMap.put(JavaCore.CODEASSIST_ARGUMENT_PREFIXES, ""); //$NON-NLS-1$
+		defaultOptionsMap.put(JavaCore.CODEASSIST_FIELD_SUFFIXES, ""); //$NON-NLS-1$
+		defaultOptionsMap.put(JavaCore.CODEASSIST_STATIC_FIELD_SUFFIXES, ""); //$NON-NLS-1$
+		defaultOptionsMap.put(JavaCore.CODEASSIST_LOCAL_SUFFIXES, ""); //$NON-NLS-1$
+		defaultOptionsMap.put(JavaCore.CODEASSIST_ARGUMENT_SUFFIXES, ""); //$NON-NLS-1$
+		defaultOptionsMap.put(JavaCore.CODEASSIST_FORBIDDEN_REFERENCE_CHECK, JavaCore.ENABLED);
+		defaultOptionsMap.put(JavaCore.CODEASSIST_DISCOURAGED_REFERENCE_CHECK, JavaCore.DISABLED);
+		defaultOptionsMap.put(JavaCore.CODEASSIST_CAMEL_CASE_MATCH, JavaCore.ENABLED);
+		defaultOptionsMap.put(JavaCore.CODEASSIST_SUGGEST_STATIC_IMPORTS, JavaCore.ENABLED);
+		
+		// Time out for parameter names
+		defaultOptionsMap.put(JavaCore.TIMEOUT_FOR_PARAMETER_NAME_FROM_ATTACHED_JAVADOC, "50"); //$NON-NLS-1$
+		
+		return new Hashtable(defaultOptionsMap);
+	}
 	
 	/*
 	 * Returns the per-project info for the given project. If specified, create the info if the info doesn't exist.
@@ -1262,31 +1827,34 @@
 			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$
-					}			    
+					if (JavaModelManager.CP_RESOLVE_VERBOSE_ADVANCED)
+						verbose_reentering_project_container_access(containerPath, project, previousContainer);
 					return previousContainer;
 			    }
 			}
 		    return null; // break cycle if none found
 	}
+
+	private void verbose_reentering_project_container_access(	IPath containerPath, IJavaProject project, IClasspathContainer previousContainer) {
+		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$
+	}
 	
 	/**
 	 * Returns a persisted container from previous session if any
@@ -1294,18 +1862,21 @@
 	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$
-			}
+			if (CP_RESOLVE_VERBOSE_ADVANCED)
+				verbose_reentering_variable_access(variableName, previousPath);
 			return previousPath;
 		}
 	    return null; // break cycle
 	}
-	
+
+	private void verbose_reentering_variable_access(String variableName, IPath previousPath) {
+		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$
+	}
+
 	/**
 	 * Returns the temporary cache for newly opened elements for the current thread.
 	 * Creates it if not already created.
@@ -1382,6 +1953,20 @@
 		return workingLocation.append("state.dat").toFile(); //$NON-NLS-1$
 	}
 	
+	public static UserLibraryManager getUserLibraryManager() {
+		JavaModelManager modelManager = getJavaModelManager();
+		if (modelManager.userLibraryManager == null) {
+			UserLibraryManager libraryManager = new UserLibraryManager();
+			synchronized(modelManager) {
+				if (modelManager.userLibraryManager == null) { // ensure another library manager was not set while creating the instance above
+					modelManager.userLibraryManager = libraryManager;
+					modelManager.getInstancePreferences().addPreferenceChangeListener(libraryManager);
+				}
+			}
+		}
+		return modelManager.userLibraryManager;
+	}
+	
 	/*
 	 * Returns all the working copies which have the given owner.
 	 * Adds the working copies of the primary owner if specified.
@@ -1424,9 +2009,13 @@
 	}
 	
 	/**
-	 * Returns the open ZipFile at the given location. If the ZipFile
+	 * Returns the open ZipFile at the given path. If the ZipFile
 	 * does not yet exist, it is created, opened, and added to the cache
-	 * of open ZipFiles. The path must be absolute.
+	 * of open ZipFiles. 
+	 * 
+	 * The path must be a file system path if representing an external 
+	 * zip/jar, or it must be an absolute workspace relative path if 
+	 * representing a zip/jar inside the workspace.
 	 *
 	 * @exception CoreException If unable to create/open the ZipFile
 	 */
@@ -1439,26 +2028,28 @@
 				
 			return zipFile;
 		}
-		String fileSystemPath= null;
+		File localFile = null;
 		IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
 		IResource file = root.findMember(path);
 		if (file != null) {
 			// internal resource
-			IPath location;
-			if (file.getType() != IResource.FILE || (location = file.getLocation()) == null) {
+			URI location;
+			if (file.getType() != IResource.FILE || (location = file.getLocationURI()) == null) {
 				throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.bind(Messages.file_notFound, path.toString()), null)); 
 			}
-			fileSystemPath= location.toOSString();
+			localFile = Util.toLocalFile(location, null/*no progress availaible*/);
+			if (localFile == null)
+				throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.bind(Messages.file_notFound, path.toString()), null)); 
 		} else {
-			// external resource
-			fileSystemPath= path.toOSString();
+			// external resource -> it is ok to use toFile()
+			localFile= path.toFile();
 		}
 
 		try {
 			if (ZIP_ACCESS_VERBOSE) {
-				System.out.println("(" + Thread.currentThread() + ") [JavaModelManager.getZipFile(IPath)] Creating ZipFile on " + fileSystemPath ); //$NON-NLS-1$ //$NON-NLS-2$
+				System.out.println("(" + Thread.currentThread() + ") [JavaModelManager.getZipFile(IPath)] Creating ZipFile on " + localFile ); //$NON-NLS-1$ //$NON-NLS-2$
 			}
-			zipFile = new ZipFile(fileSystemPath);
+			zipFile = new ZipFile(localFile);
 			if (map != null) {
 				map.put(path, zipFile);
 			}
@@ -1480,21 +2071,17 @@
 	 * 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$
-		}
+		if (CP_RESOLVE_VERBOSE_ADVANCED)
+			verbose_batching_containers_initialization(javaProjectToInit, containerToInit);
 
 		// collect all container paths
-		HashMap allContainerPaths = new HashMap();
+		final 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;
+			HashSet paths = (HashSet) allContainerPaths.get(javaProject);
 			IClasspathEntry[] rawClasspath = javaProject.getRawClasspath();
 			for (int j = 0, length2 = rawClasspath.length; j < length2; j++) {
 				IClasspathEntry entry = rawClasspath[j];
@@ -1506,6 +2093,8 @@
 						allContainerPaths.put(javaProject, paths);
 					}
 					paths.add(path);
+					// mark container as being initialized
+					containerAddInitializationInProgress(javaProject, path);
 				}
 			}
 			/* TODO (frederic) put back when JDT/UI dummy project will be thrown away...
@@ -1527,31 +2116,60 @@
 			allContainerPaths.put(javaProjectToInit, containerPaths);
 		}
 		containerPaths.add(containerToInit);
+		// mark container as being initialized
+		containerAddInitializationInProgress(javaProjectToInit, containerToInit);
 		// end block
 		
-		// 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);
-				}
-			}
+			// if possible run inside an IWokspaceRunnable with AVOID_UPATE to avoid unwanted builds
+			// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=118507)
+			IWorkspaceRunnable runnable = 				
+				new IWorkspaceRunnable() {
+					public void run(IProgressMonitor monitor) throws CoreException {
+						try {
+							Set entrySet = allContainerPaths.entrySet();
+							int length = entrySet.size();
+							if (monitor != null)
+								monitor.beginTask("", length); //$NON-NLS-1$
+							Map.Entry[] entries = new Map.Entry[length]; // clone as the following will have a side effect
+							entrySet.toArray(entries);
+							for (int i = 0; i < length; i++) {
+								Map.Entry entry = entries[i];
+								IJavaProject javaProject = (IJavaProject) entry.getKey();
+								HashSet pathSet = (HashSet) entry.getValue();
+								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);
+								}
+								if (monitor != null)
+									monitor.worked(1);
+							}
+						} finally {
+							if (monitor != null)
+								monitor.done();
+						}
+					}
+				};
+			IProgressMonitor monitor = (IProgressMonitor) this.batchContainerInitializationsProgress.get();
+			IWorkspace workspace = ResourcesPlugin.getWorkspace();
+			if (workspace.isTreeLocked())
+				runnable.run(monitor);
+			else
+				workspace.run(
+					runnable,
+					null/*don't take any lock*/,
+					IWorkspace.AVOID_UPDATE,
+					monitor);
 			ok = true;
+		} catch (CoreException e) {
+			// ignore
+			Util.log(e, "Exception while initializing all containers"); //$NON-NLS-1$
 		} finally {
 			if (!ok) { 
 				// if we're being traversed by an exception, ensure that that containers are 
@@ -1564,20 +2182,26 @@
 		return containerGet(javaProjectToInit, containerToInit);
 	}
 
-	private IClasspathContainer initializeContainer(IJavaProject project, IPath containerPath) throws JavaModelException {
+	private void verbose_batching_containers_initialization(IJavaProject javaProjectToInit, IPath containerToInit) {
+		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$
+	}
 
+	IClasspathContainer initializeContainer(IJavaProject project, IPath containerPath) throws JavaModelException {
+
+		IProgressMonitor monitor = (IProgressMonitor) this.batchContainerInitializationsProgress.get();
+		if (monitor != null && monitor.isCanceled())
+			throw new OperationCanceledException();
+		
 		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$
-			}
+			if (CP_RESOLVE_VERBOSE)
+				verbose_triggering_container_initialization(project, containerPath, initializer);
+			if (CP_RESOLVE_VERBOSE_ADVANCED)
+				verbose_triggering_container_initialization_invocation_trace();
 			PerformanceStats stats = null;
 			if(JavaModelManager.PERF_CONTAINER_INITIALIZER) {
 				stats = PerformanceStats.getStats(JavaModelManager.CONTAINER_INITIALIZER_PERF, this);
@@ -1586,13 +2210,30 @@
 			containerPut(project, containerPath, CONTAINER_INITIALIZATION_IN_PROGRESS); // avoid initialization cycles
 			boolean ok = false;
 			try {
+				if (monitor != null)
+					monitor.subTask(Messages.bind(Messages.javamodel_configuring, initializer.getDescription(containerPath, project)));
+				
 				// let OperationCanceledException go through
 				// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=59363)
 				initializer.initialize(containerPath, project);
 				
+				if (monitor != null)
+					monitor.subTask(""); //$NON-NLS-1$
+				
 				// retrieve value (if initialization was successful)
 				container = containerGet(project, containerPath);
-				if (container == CONTAINER_INITIALIZATION_IN_PROGRESS) return null; // break cycle
+				if (container == CONTAINER_INITIALIZATION_IN_PROGRESS) {
+					// initializer failed to do its job: redirect to the failure container
+					container = initializer.getFailureContainer(containerPath, project);
+					if (container == null) {
+						if (CP_RESOLVE_VERBOSE)
+							verbose_container_null_failure_container(project, containerPath, initializer);
+						return null; // break cycle
+					}
+					if (CP_RESOLVE_VERBOSE)
+						verbose_container_using_failure_container(project, containerPath, initializer);
+					containerPut(project, containerPath, container);
+				}
 				ok = true;
 			} catch (CoreException e) {
 				if (e instanceof JavaModelException) {
@@ -1601,14 +2242,12 @@
 					throw new JavaModelException(e);
 				}
 			} catch (RuntimeException e) {
-				if (JavaModelManager.CP_RESOLVE_VERBOSE) {
+				if (JavaModelManager.CP_RESOLVE_VERBOSE)
 					e.printStackTrace();
-				}
 				throw e;
 			} catch (Error e) {
-				if (JavaModelManager.CP_RESOLVE_VERBOSE) {
+				if (JavaModelManager.CP_RESOLVE_VERBOSE)
 					e.printStackTrace();
-				}
 				throw e;
 			} finally {
 				if(JavaModelManager.PERF_CONTAINER_INITIALIZER) {
@@ -1618,62 +2257,108 @@
 					// just remove initialization in progress and keep previous session container so as to avoid a full build
 					// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=92588
 					containerRemoveInitializationInProgress(project, containerPath); 
-					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) 
+						verbose_container_initialization_failed(project, containerPath, container, initializer);
 				}
 			}
-			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());
-			}
+			if (CP_RESOLVE_VERBOSE_ADVANCED)
+				verbose_container_value_after_initialization(project, containerPath, container);
 		} 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$
-			}
+			// create a dummy initializer and get the default failure container
+			container = (new ClasspathContainerInitializer() {
+				public void initialize(IPath path, IJavaProject javaProject) throws CoreException {
+					// not used
+				}
+			}).getFailureContainer(containerPath, project);
+			if (CP_RESOLVE_VERBOSE_ADVANCED)
+				verbose_no_container_initializer_found(project, containerPath);
 		}
 		return container;
 	}
 
+	private void verbose_no_container_initializer_found(IJavaProject project, IPath containerPath) {
+		Util.verbose(
+			"CPContainer INIT - no initializer found\n" + //$NON-NLS-1$
+			"	project: " + project.getElementName() + '\n' + //$NON-NLS-1$
+			"	container path: " + containerPath); //$NON-NLS-1$
+	}
+
+	private void verbose_container_value_after_initialization(IJavaProject project, IPath containerPath, IClasspathContainer container) {
+		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());
+	}
+
+	private void verbose_container_initialization_failed(IJavaProject project, IPath containerPath, IClasspathContainer container, ClasspathContainerInitializer initializer) {
+		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$
+		}
+	}
+
+	private void verbose_container_null_failure_container(IJavaProject project, IPath containerPath,  ClasspathContainerInitializer initializer) {
+		Util.verbose(
+			"CPContainer INIT - FAILED (and failure container is null)\n" + //$NON-NLS-1$
+			"	project: " + project.getElementName() + '\n' + //$NON-NLS-1$
+			"	container path: " + containerPath + '\n' + //$NON-NLS-1$
+			"	initializer: " + initializer); //$NON-NLS-1$
+	}
+
+	private void verbose_container_using_failure_container(IJavaProject project, IPath containerPath,  ClasspathContainerInitializer initializer) {
+		Util.verbose(
+			"CPContainer INIT - FAILED (using failure container)\n" + //$NON-NLS-1$
+			"	project: " + project.getElementName() + '\n' + //$NON-NLS-1$
+			"	container path: " + containerPath + '\n' + //$NON-NLS-1$
+			"	initializer: " + initializer); //$NON-NLS-1$
+	}
+
+	private void verbose_triggering_container_initialization(IJavaProject project, IPath containerPath,  ClasspathContainerInitializer initializer) {
+		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); //$NON-NLS-1$
+	}
+	
+	private void verbose_triggering_container_initialization_invocation_trace() {
+		Util.verbose(
+			"CPContainer INIT - triggering initialization\n" + //$NON-NLS-1$
+			"	invocation trace:"); //$NON-NLS-1$
+		new Exception("<Fake exception>").printStackTrace(System.out); //$NON-NLS-1$
+	}
+
 	/**
 	 * Initialize preferences lookups for JavaCore plugin.
 	 */
 	public void initializePreferences() {
 		
 		// Create lookups
-		preferencesLookup[PREF_INSTANCE] = new InstanceScope().getNode(JavaCore.PLUGIN_ID);
-		preferencesLookup[PREF_DEFAULT] = new DefaultScope().getNode(JavaCore.PLUGIN_ID);
+		preferencesLookup[PREF_INSTANCE] = ((IScopeContext) new InstanceScope()).getNode(JavaCore.PLUGIN_ID);
+		preferencesLookup[PREF_DEFAULT] = ((IScopeContext) new DefaultScope()).getNode(JavaCore.PLUGIN_ID);
 
 		// Listen to instance preferences node removal from parent in order to refresh stored one
 		IEclipsePreferences.INodeChangeListener listener = new IEclipsePreferences.INodeChangeListener() {
@@ -1682,7 +2367,7 @@
 			}
 			public void removed(IEclipsePreferences.NodeChangeEvent event) {
 				if (event.getChild() == preferencesLookup[PREF_INSTANCE]) {
-					preferencesLookup[PREF_INSTANCE] = new InstanceScope().getNode(JavaCore.PLUGIN_ID);
+					preferencesLookup[PREF_INSTANCE] = ((IScopeContext) new InstanceScope()).getNode(JavaCore.PLUGIN_ID);
 					preferencesLookup[PREF_INSTANCE].addPreferenceChangeListener(new EclipsePreferencesListener());
 				}
 			}
@@ -1697,7 +2382,7 @@
 			}
 			public void removed(IEclipsePreferences.NodeChangeEvent event) {
 				if (event.getChild() == preferencesLookup[PREF_DEFAULT]) {
-					preferencesLookup[PREF_DEFAULT] = new DefaultScope().getNode(JavaCore.PLUGIN_ID);
+					preferencesLookup[PREF_DEFAULT] = ((IScopeContext) new DefaultScope()).getNode(JavaCore.PLUGIN_ID);
 				}
 			}
 		};
@@ -1803,7 +2488,75 @@
 		}
 
 		// backward compatibility, load variables and containers from preferences into cache
-		IEclipsePreferences preferences = getInstancePreferences();
+		loadVariablesAndContainers(getDefaultPreferences());
+		loadVariablesAndContainers(getInstancePreferences());
+
+		// load variables and containers from saved file into cache
+		File file = getVariableAndContainersFile();
+		DataInputStream in = null;
+		try {
+			in = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
+			switch (in.readInt()) {
+				case 2 :
+					new VariablesAndContainersLoadHelper(in).load();
+					break;
+				case 1 : // backward compatibility, load old format
+					// variables
+					int size = in.readInt();
+					while (size-- > 0) {
+						String varName = in.readUTF();
+						String pathString = in.readUTF();
+						if (CP_ENTRY_IGNORE.equals(pathString))
+							continue;
+						IPath varPath = Path.fromPortableString(pathString);
+						this.variables.put(varName, varPath);
+						this.previousSessionVariables.put(varName, varPath);
+					}
+					
+					// containers
+					IJavaModel model = getJavaModel();
+					int projectSize = in.readInt();
+					while (projectSize-- > 0) {
+						String projectName = in.readUTF();
+						IJavaProject project = model.getJavaProject(projectName);
+						int containerSize = in.readInt();
+						while (containerSize-- > 0) {
+							IPath containerPath = Path.fromPortableString(in.readUTF());
+							int length = in.readInt();
+							byte[] containerString = new byte[length];
+							in.readFully(containerString);
+							recreatePersistedContainer(project, containerPath, new String(containerString), true/*add to container values*/);
+						}
+					}
+					break;
+			}
+		} catch (IOException e) {
+			if (file.exists())
+				Util.log(e, "Unable to read variable and containers file"); //$NON-NLS-1$
+		} catch (RuntimeException e) {
+			if (file.exists())
+				Util.log(e, "Unable to read variable and containers file (file is corrupt)"); //$NON-NLS-1$
+		} finally {
+			if (in != null) {
+				try {
+					in.close();
+				} catch (IOException e) {
+					// nothing we can do: ignore
+				}
+			}
+		}
+
+		// override persisted values for variables which have a registered initializer
+		String[] registeredVariables = getRegisteredVariableNames();
+		for (int i = 0; i < registeredVariables.length; i++) {
+			String varName = registeredVariables[i];
+			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
+		containersReset(getRegisteredContainerIDs());
+	}
+
+	private void loadVariablesAndContainers(IEclipsePreferences preferences) {
 		try {
 			// only get variable from preferences not set to their default
 			String[] propertyNames = preferences.keys();
@@ -1841,63 +2594,285 @@
 		} catch (BackingStoreException e1) {
 			// TODO (frederic) see if it's necessary to report this failure...
 		}
+	}
 
-		// load variables and containers from saved file into cache
-		File file = getVariableAndContainersFile();
-		DataInputStream in = null;
-		try {
-			in = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
-			if (VARIABLES_AND_CONTAINERS_FILE_VERSION == in.readInt()) {
-				
-				// variables
-				int size = in.readInt();
-				while (size-- > 0) {
-					String varName = in.readUTF();
-					String pathString = in.readUTF();
-					if (CP_ENTRY_IGNORE.equals(pathString))
-						continue;
-					IPath varPath = Path.fromPortableString(pathString);
-					this.variables.put(varName, varPath);
-					this.previousSessionVariables.put(varName, varPath);
-				}
-				
-				// containers
-				IJavaModel model = getJavaModel();
-				int projectSize = in.readInt();
-				while (projectSize-- > 0) {
-					String projectName = in.readUTF();
-					IJavaProject project = model.getJavaProject(projectName);
-					int containerSize = in.readInt();
-					while (containerSize-- > 0) {
-						IPath containerPath = Path.fromPortableString(in.readUTF());
-						int length = in.readInt();
-						byte[] containerString = new byte[length];
-						in.readFully(containerString);
-						recreatePersistedContainer(project, containerPath, new String(containerString), true/*add to container values*/);
-					}
-				}
+	private static final class PersistedClasspathContainer implements
+			IClasspathContainer {
+
+		private final IPath containerPath;
+
+		private final IClasspathEntry[] entries;
+
+		private final IJavaProject project;
+
+		PersistedClasspathContainer(IJavaProject project, IPath containerPath,
+				IClasspathEntry[] entries) {
+			super();
+			this.containerPath = containerPath;
+			this.entries = entries;
+			this.project = project;
+		}
+
+		public IClasspathEntry[] getClasspathEntries() {
+			return entries;
+		}
+
+		public String getDescription() {
+			return "Persisted container [" + containerPath //$NON-NLS-1$
+					+ " for project [" + project.getElementName() //$NON-NLS-1$
+					+ "]]"; //$NON-NLS-1$  
+		}
+
+		public int getKind() {
+			return 0;
+		}
+
+		public IPath getPath() {
+			return containerPath;
+		}
+
+		public String toString() {
+			return getDescription();
+		}
+	}
+
+	private final class VariablesAndContainersLoadHelper {
+
+		private static final int ARRAY_INCREMENT = 200;
+
+		private IClasspathEntry[] allClasspathEntries;
+		private int allClasspathEntryCount;
+
+		private final Map allPaths; // String -> IPath
+
+		private String[] allStrings;
+		private int allStringsCount;
+
+		private final DataInputStream in;
+
+		VariablesAndContainersLoadHelper(DataInputStream in) {
+			super();
+			this.allClasspathEntries = null;
+			this.allClasspathEntryCount = 0;
+			this.allPaths = new HashMap();
+			this.allStrings = null;
+			this.allStringsCount = 0;
+			this.in = in;
+		}
+
+		void load() throws IOException {
+			loadProjects(JavaModelManager.this.getJavaModel());
+			loadVariables();
+		}
+
+		private IAccessRule loadAccessRule() throws IOException {
+			int problemId = loadInt();
+			IPath pattern = loadPath();
+			return new ClasspathAccessRule(pattern.toString().toCharArray(), problemId);
+		}
+
+		private IAccessRule[] loadAccessRules() throws IOException {
+			int count = loadInt();
+
+			if (count == 0)
+				return ClasspathEntry.NO_ACCESS_RULES;
+
+			IAccessRule[] rules = new IAccessRule[count];
+
+			for (int i = 0; i < count; ++i)
+				rules[i] = loadAccessRule();
+
+			return rules;
+		}
+
+		private IClasspathAttribute loadAttribute() throws IOException {
+			String name = loadString();
+			String value = loadString();
+
+			return new ClasspathAttribute(name, value);
+		}
+
+		private IClasspathAttribute[] loadAttributes() throws IOException {
+			int count = loadInt();
+
+			if (count == 0)
+				return ClasspathEntry.NO_EXTRA_ATTRIBUTES;
+
+			IClasspathAttribute[] attributes = new IClasspathAttribute[count];
+
+			for (int i = 0; i < count; ++i)
+				attributes[i] = loadAttribute();
+
+			return attributes;
+		}
+
+		private boolean loadBoolean() throws IOException {
+			return this.in.readBoolean();
+		}
+
+		private IClasspathEntry[] loadClasspathEntries() throws IOException {
+			int count = loadInt();
+			IClasspathEntry[] entries = new IClasspathEntry[count];
+
+			for (int i = 0; i < count; ++i)
+				entries[i] = loadClasspathEntry();
+
+			return entries;
+		}
+
+		private IClasspathEntry loadClasspathEntry() throws IOException {
+			int id = loadInt();
+
+			if (id < 0 || id > this.allClasspathEntryCount)
+				throw new IOException("Unexpected classpathentry id"); //$NON-NLS-1$
+
+			if (id < this.allClasspathEntryCount)
+				return this.allClasspathEntries[id];
+
+			int contentKind = loadInt();
+			int entryKind = loadInt();
+			IPath path = loadPath();
+			IPath[] inclusionPatterns = loadPaths();
+			IPath[] exclusionPatterns = loadPaths();
+			IPath sourceAttachmentPath = loadPath();
+			IPath sourceAttachmentRootPath = loadPath();
+			IPath specificOutputLocation = loadPath();
+			boolean isExported = loadBoolean();
+			IAccessRule[] accessRules = loadAccessRules();
+			boolean combineAccessRules = loadBoolean();
+			IClasspathAttribute[] extraAttributes = loadAttributes();
+
+			IClasspathEntry entry = new ClasspathEntry(contentKind, entryKind,
+					path, inclusionPatterns, exclusionPatterns,
+					sourceAttachmentPath, sourceAttachmentRootPath,
+					specificOutputLocation, isExported, accessRules,
+					combineAccessRules, extraAttributes);
+
+			IClasspathEntry[] array = this.allClasspathEntries;
+
+			if (array == null || id == array.length) {
+				array = new IClasspathEntry[id + ARRAY_INCREMENT];
+
+				if (id != 0)
+					System.arraycopy(this.allClasspathEntries, 0, array, 0, id);
+
+				this.allClasspathEntries = array;
 			}
-		} catch (IOException e) {
-			if (file.exists())
-				Util.log(e, "Unable to read variable and containers file"); //$NON-NLS-1$
-		} finally {
-			if (in != null) {
-				try {
-					in.close();
-				} catch (IOException e) {
-					// nothing we can do: ignore
+
+			array[id] = entry;
+			this.allClasspathEntryCount = id + 1;
+
+			return entry;
+		}
+
+		private void loadContainers(IJavaProject project) throws IOException {
+			boolean projectIsAccessible = project.getProject().isAccessible();
+			int count = loadInt();
+			for (int i = 0; i < count; ++i) {
+				IPath path = loadPath();
+				IClasspathEntry[] entries = loadClasspathEntries();
+				
+				if (!projectIsAccessible) 
+					// avoid leaking deleted project's persisted container,
+					// but still read the container as it is is part of the file format
+					continue; 
+
+				IClasspathContainer container = new PersistedClasspathContainer(project, path, entries);
+
+				JavaModelManager.this.containerPut(project, path, container);
+
+				Map oldContainers = (Map) JavaModelManager.this.previousSessionContainers.get(project);
+
+				if (oldContainers == null) {
+					oldContainers = new HashMap();
+					JavaModelManager.this.previousSessionContainers.put(project, oldContainers);
 				}
+
+				oldContainers.put(path, container);
 			}
 		}
 
-		// override persisted values for variables which have a registered initializer
-		String[] registeredVariables = getRegisteredVariableNames();
-		for (int i = 0; i < registeredVariables.length; i++) {
-			String varName = registeredVariables[i];
-			this.variables.put(varName, null); // reset variable, but leave its entry in the Map, so it will be part of variable names.
+		private int loadInt() throws IOException {
+			return this.in.readInt();
 		}
-		// override persisted values for containers which have a registered initializer
-		containersReset(getRegisteredContainerIDs());
+
+		private IPath loadPath() throws IOException {
+			if (loadBoolean())
+				return null;
+
+			String portableString = loadString();
+			IPath path = (IPath) this.allPaths.get(portableString);
+
+			if (path == null) {
+				path = Path.fromPortableString(portableString);
+				this.allPaths.put(portableString, path);
+			}
+
+			return path;
+		}
+
+		private IPath[] loadPaths() throws IOException {
+			int count = loadInt();
+			IPath[] pathArray = new IPath[count];
+
+			for (int i = 0; i < count; ++i)
+				pathArray[i] = loadPath();
+
+			return pathArray;
+		}
+
+		private void loadProjects(IJavaModel model) throws IOException {
+			int count = loadInt();
+
+			for (int i = 0; i < count; ++i) {
+				String projectName = loadString();
+
+				loadContainers(model.getJavaProject(projectName));
+			}
+		}
+
+		private String loadString() throws IOException {
+			int id = loadInt();
+
+			if (id < 0 || id > this.allStringsCount)
+				throw new IOException("Unexpected string id"); //$NON-NLS-1$
+
+			if (id < this.allStringsCount)
+				return this.allStrings[id];
+
+			String string = this.in.readUTF();
+			String[] array = this.allStrings;
+
+			if (array == null || id == array.length) {
+				array = new String[id + ARRAY_INCREMENT];
+
+				if (id != 0)
+					System.arraycopy(this.allStrings, 0, array, 0, id);
+
+				this.allStrings = array;
+			}
+
+			array[id] = string;
+			this.allStringsCount = id + 1;
+
+			return string;
+		}
+
+		private void loadVariables() throws IOException {
+			int size = loadInt();
+			Map loadedVars = new HashMap(size);
+
+			for (int i = 0; i < size; ++i) {
+				String varName = loadString();
+				IPath varPath = loadPath();
+
+				if (varPath != null)
+					loadedVars.put(varName, varPath);
+			}
+
+			JavaModelManager.this.previousSessionVariables.putAll(loadedVars);
+			JavaModelManager.this.variables.putAll(loadedVars);
+		}
 	}
 
 	/**
@@ -1943,13 +2918,39 @@
 			}
 		}
 		
-		Iterator iterator = newElements.keySet().iterator();
+		// Need to put any JarPackageFragmentRoot in first.
+		// This is due to the way the LRU cache flushes entries.
+		// When a JarPackageFragment is flused from the LRU cache, the entire
+		// jar is flushed by removing the JarPackageFragmentRoot and all of its
+		// children (see ElementCache.close()). If we flush the JarPackageFragment 
+		// when its JarPackageFragmentRoot is not in the cache and the root is about to be 
+		// added (during the 'while' loop), we will end up in an inconsist state. 
+		// Subsequent resolution against package in the jar would fail as a result.
+		// https://bugs.eclipse.org/bugs/show_bug.cgi?id=102422
+		// (theodora)
+		for(Iterator it = newElements.entrySet().iterator(); it.hasNext(); ) {
+			Map.Entry entry = (Map.Entry)it.next();
+			IJavaElement element = (IJavaElement)entry.getKey();
+			if( element instanceof JarPackageFragmentRoot ){
+				Object info = entry.getValue();
+				it.remove();
+				this.cache.putInfo(element, info);
+			}
+		}	
+	
+		Iterator iterator = newElements.entrySet().iterator();	
 		while (iterator.hasNext()) {
-			IJavaElement element = (IJavaElement)iterator.next();
-			Object info = newElements.get(element);
-			this.cache.putInfo(element, info);
+			Map.Entry entry = (Map.Entry) iterator.next();
+			this.cache.putInfo((IJavaElement) entry.getKey(), entry.getValue());
 		}
 	}
+	
+	/*
+	 * Remember the info for the jar binary type
+	 */
+	protected synchronized void putJarTypeInfo(IJavaElement type, Object info) {
+		this.cache.jarTypeCache.put(type, info);
+	}
 
 	/**
 	 * Reads the build state for the relevant project.
@@ -2003,8 +3004,15 @@
 		if (containerString == null) {
 			getJavaModelManager().containerPut(project, containerPath, null);
 		} else {
-			final IClasspathEntry[] containerEntries = ((JavaProject) project).decodeClasspath(containerString, false, false);
-			if (containerEntries != null && containerEntries != JavaProject.INVALID_CLASSPATH) {
+			IClasspathEntry[] entries;
+			try {
+				entries = ((JavaProject) project).decodeClasspath(containerString, null/*not interested in unknown elements*/);
+			} catch (IOException e) {
+				Util.log(e, "Could not recreate persisted container: \n" + containerString); //$NON-NLS-1$
+				entries = JavaProject.INVALID_CLASSPATH;
+			}
+			if (entries != JavaProject.INVALID_CLASSPATH) {
+				final IClasspathEntry[] containerEntries = entries;
 				IClasspathContainer container = new IClasspathContainer() {
 					public IClasspathEntry[] getClasspathEntries() {
 						return containerEntries;
@@ -2055,7 +3063,7 @@
 		if (info != null) {
 			boolean wasVerbose = false;
 			try {
-				if (VERBOSE) {
+				if (JavaModelCache.VERBOSE) {
 					String elementType;
 					switch (element.getElementType()) {
 						case IJavaElement.JAVA_PROJECT:
@@ -2078,7 +3086,7 @@
 					}
 					System.out.println(Thread.currentThread() + " CLOSING "+ elementType + " " + element.toStringWithAncestors());  //$NON-NLS-1$//$NON-NLS-2$
 					wasVerbose = true;
-					VERBOSE = false;
+					JavaModelCache.VERBOSE = false;
 				}
 				element.closing(info);
 				if (element instanceof IParent && info instanceof JavaElementInfo) {
@@ -2093,7 +3101,7 @@
 					System.out.println(this.cache.toStringFillingRation("-> ")); //$NON-NLS-1$
 				}
 			} finally {
-				JavaModelManager.VERBOSE = wasVerbose;
+				JavaModelCache.VERBOSE = wasVerbose;
 			}
 			return info;
 		}
@@ -2142,6 +3150,13 @@
 	}
 	
 	/*
+	 * Resets the cache that holds on binary type in jar files
+	 */
+	protected synchronized void resetJarTypeCache() {
+		this.cache.resetJarTypeCache();
+	}
+
+	/*
 	 * Resets the temporary cache for newly created elements to null.
 	 */
 	public void resetTemporaryCache() {
@@ -2212,72 +3227,80 @@
 		}
 	}
 	
-	private void saveVariablesAndContainers() throws CoreException {
+	private void saveVariablesAndContainers(ISaveContext context) throws CoreException {
 		File file = getVariableAndContainersFile();
 		DataOutputStream out = null;
 		try {
 			out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
 			out.writeInt(VARIABLES_AND_CONTAINERS_FILE_VERSION);
-			
-			// variables
-			out.writeInt(this.variables.size());
-			Iterator variableNames = this.variables.keySet().iterator();
-			while (variableNames.hasNext()) {
-				String variableName = (String) variableNames.next();
-				out.writeUTF(variableName);
-				IPath path = (IPath) this.variables.get(variableName);
-				out.writeUTF(path == null ? CP_ENTRY_IGNORE : path.toPortableString());
+			if (VARIABLES_AND_CONTAINERS_FILE_VERSION != 1)
+				new VariablesAndContainersSaveHelper(out).save(context);
+			else {
+				// old code retained for performance comparisons
+    			
+    			// variables
+    			out.writeInt(this.variables.size());
+    			Iterator iterator = this.variables.entrySet().iterator();
+    			while (iterator.hasNext()) {
+    				Map.Entry entry = (Map.Entry) iterator.next();
+    				String variableName = (String) entry.getKey();
+    				out.writeUTF(variableName);
+    				IPath path = (IPath) entry.getValue();
+    				out.writeUTF(path == null ? CP_ENTRY_IGNORE : path.toPortableString());
+    			}
+    			
+    			// containers
+    			IJavaProject[] projects = getJavaModel().getJavaProjects();
+    			int length = projects.length;
+    			out.writeInt(length);
+    			for (int i = 0; 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);
+    				out.writeUTF(project.getElementName());
+    				if (projectContainers == null) {
+    					out.writeInt(0);
+    					continue;
+    				}
+    				HashMap containersToSave = new HashMap();
+    				for (iterator = projectContainers.entrySet().iterator(); iterator.hasNext();) {
+    					Map.Entry entry = (Map.Entry) iterator.next();
+    				    IPath containerPath = (IPath) entry.getKey();
+    				    IClasspathContainer container = (IClasspathContainer) entry.getValue();
+    					String containerString = null;
+    					try {
+    						if (container == null) {
+    							// container has not been initialized yet, use previous session value
+    							// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=73969)
+    							container = getPreviousSessionContainer(containerPath, project);
+    						}
+    						if (container != null) {
+    							IClasspathEntry[] entries = container.getClasspathEntries();
+    							containerString = ((JavaProject)project).encodeClasspath(
+    									entries, 
+    									null, 
+    									false,
+    									null/*not interested in unknown elements*/);
+    						}
+    					} catch(JavaModelException e){
+    						// could not encode entry: will not persist
+    						Util.log(e, "Could not persist container " + containerPath + " for project " + project.getElementName()); //$NON-NLS-1$ //$NON-NLS-2$
+    					}
+    					if (containerString != null)
+    						containersToSave.put(containerPath, containerString);
+    				}
+    				out.writeInt(containersToSave.size());
+    				iterator = containersToSave.entrySet().iterator();
+    				while (iterator.hasNext()) {
+    					Map.Entry entry = (Map.Entry) iterator.next();
+    					IPath containerPath = (IPath) entry.getKey();
+    					out.writeUTF(containerPath.toPortableString());
+    					String containerString = (String) entry.getValue();
+    					out.writeInt(containerString.length());
+    					out.writeBytes(containerString);
+    				}
+    			}
 			}
-			
-			// containers
-			IJavaProject[] projects = getJavaModel().getJavaProjects();
-			int length = projects.length;
-			out.writeInt(length);
-			for (int i = 0; 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);
-				out.writeUTF(project.getElementName());
-				if (projectContainers == null) {
-					out.writeInt(0);
-					continue;
-				}
-				HashMap containersToSave = new HashMap();
-				for (Iterator iterator = projectContainers.keySet().iterator(); iterator.hasNext();) {
-				    IPath containerPath = (IPath) iterator.next();
-				    IClasspathContainer container = (IClasspathContainer) projectContainers.get(containerPath);
-					String containerString = null;
-					try {
-						if (container == null) {
-							// container has not been initialized yet, use previous session value
-							// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=73969)
-							container = getPreviousSessionContainer(containerPath, project);
-						}
-						if (container != null) {
-							IClasspathEntry[] entries = container.getClasspathEntries();
-							containerString = ((JavaProject)project).encodeClasspath(
-									entries, 
-									null, 
-									false);
-						}
-					} catch(JavaModelException e){
-						// could not encode entry: will not persist
-						Util.log(e, "Could not persist container " + containerPath + " for project " + project.getElementName()); //$NON-NLS-1$ //$NON-NLS-2$
-					}
-					if (containerString != null)
-						containersToSave.put(containerPath, containerString);
-				}
-				out.writeInt(containersToSave.size());
-				Iterator iterator = containersToSave.keySet().iterator();
-				while (iterator.hasNext()) {
-					IPath containerPath = (IPath) iterator.next();
-					out.writeUTF(containerPath.toPortableString());
-					String containerString = (String) containersToSave.get(containerPath);
-					out.writeInt(containerString.length());
-					out.writeBytes(containerString);
-				}
-			}
-			
 		} catch (IOException e) {
 			IStatus status = new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, IStatus.ERROR, "Problems while saving variables and containers", e); //$NON-NLS-1$
 			throw new CoreException(status);
@@ -2292,13 +3315,241 @@
 		}
 	}
 	
+	private final class VariablesAndContainersSaveHelper {
+
+		private final HashtableOfObjectToInt classpathEntryIds; // IClasspathEntry -> int
+		private final DataOutputStream out;
+		private final HashtableOfObjectToInt stringIds; // Strings -> int
+
+		VariablesAndContainersSaveHelper(DataOutputStream out) {
+			super();
+			this.classpathEntryIds = new HashtableOfObjectToInt();
+			this.out = out;
+			this.stringIds = new HashtableOfObjectToInt();
+		}
+
+		void save(ISaveContext context) throws IOException, JavaModelException {
+			IProject project = context.getProject();
+			if (project == null) { // save all projects if none specified (snapshot or full save)
+				saveProjects(JavaModelManager.this.getJavaModel().getJavaProjects());
+			}
+			else {
+				saveProjects(new IJavaProject[] {JavaCore.create(project)});
+			}
+			
+			switch (context.getKind()) {
+				case ISaveContext.FULL_SAVE :
+					// TODO (eric) - investigate after 3.3 if variables should be saved for a SNAPSHOT
+				case ISaveContext.SNAPSHOT :
+					// remove variables that should not be saved
+					HashMap varsToSave = null;
+					Iterator iterator = JavaModelManager.this.variables.entrySet().iterator();
+					IEclipsePreferences defaultPreferences = getDefaultPreferences();
+					while (iterator.hasNext()) {
+						Map.Entry entry = (Map.Entry) iterator.next();
+						String varName = (String) entry.getKey();
+						if (defaultPreferences.get(CP_VARIABLE_PREFERENCES_PREFIX + varName, null) != null // don't save classpath variables from the default preferences as there is no delta if they are removed
+								|| CP_ENTRY_IGNORE_PATH.equals(entry.getValue())) {
+						
+							if (varsToSave == null)
+								varsToSave = new HashMap(JavaModelManager.this.variables);
+							varsToSave.remove(varName);
+						}
+					}				
+					saveVariables(varsToSave != null ? varsToSave : JavaModelManager.this.variables);
+					break;
+				default :
+					// do nothing
+			}
+		}
+
+		private void saveAccessRule(ClasspathAccessRule rule) throws IOException {
+			saveInt(rule.problemId);
+			savePath(rule.getPattern());
+		}
+
+		private void saveAccessRules(IAccessRule[] rules) throws IOException {
+			int count = rules == null ? 0 : rules.length;
+
+			saveInt(count);
+			for (int i = 0; i < count; ++i)
+				saveAccessRule((ClasspathAccessRule) rules[i]);
+		}
+
+		private void saveAttribute(IClasspathAttribute attribute)
+				throws IOException {
+			saveString(attribute.getName());
+			saveString(attribute.getValue());
+		}
+
+		private void saveAttributes(IClasspathAttribute[] attributes)
+				throws IOException {
+			int count = attributes == null ? 0 : attributes.length;
+
+			saveInt(count);
+			for (int i = 0; i < count; ++i)
+				saveAttribute(attributes[i]);
+		}
+
+		private void saveClasspathEntries(IClasspathEntry[] entries)
+				throws IOException {
+			int count = entries == null ? 0 : entries.length;
+
+			saveInt(count);
+			for (int i = 0; i < count; ++i)
+				saveClasspathEntry(entries[i]);
+		}
+
+		private void saveClasspathEntry(IClasspathEntry entry)
+				throws IOException {
+			if (saveNewId(entry, this.classpathEntryIds)) {
+				saveInt(entry.getContentKind());
+				saveInt(entry.getEntryKind());
+				savePath(entry.getPath());
+				savePaths(entry.getInclusionPatterns());
+				savePaths(entry.getExclusionPatterns());
+				savePath(entry.getSourceAttachmentPath());
+				savePath(entry.getSourceAttachmentRootPath());
+				savePath(entry.getOutputLocation());
+				this.out.writeBoolean(entry.isExported());
+				saveAccessRules(entry.getAccessRules());
+				this.out.writeBoolean(entry.combineAccessRules());
+				saveAttributes(entry.getExtraAttributes());
+			}
+		}
+
+		private void saveContainers(IJavaProject project, Map containerMap)
+				throws IOException {
+			saveInt(containerMap.size());
+
+			for (Iterator i = containerMap.entrySet().iterator(); i.hasNext();) {
+				Entry entry = (Entry) i.next();
+				IPath path = (IPath) entry.getKey();
+				IClasspathContainer container = (IClasspathContainer) entry.getValue();
+				IClasspathEntry[] cpEntries = null;
+
+				if (container == null) {
+					// container has not been initialized yet, use previous
+					// session value
+					// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=73969)
+					container = JavaModelManager.this.getPreviousSessionContainer(path, project);
+				}
+
+				if (container != null)
+					cpEntries = container.getClasspathEntries();
+
+				savePath(path);
+				saveClasspathEntries(cpEntries);
+			}
+		}
+
+		private void saveInt(int value) throws IOException {
+			this.out.writeInt(value);
+		}
+
+		private boolean saveNewId(Object key, HashtableOfObjectToInt map) throws IOException {
+			int id = map.get(key);
+
+			if (id == -1) {
+				int newId = map.size();
+
+				map.put(key, newId);
+
+				saveInt(newId);
+
+				return true;
+			} else {
+				saveInt(id);
+
+				return false;
+			}
+		}
+
+		private void savePath(IPath path) throws IOException {
+			if (path == null) {
+				this.out.writeBoolean(true);
+			} else {
+				this.out.writeBoolean(false);
+				saveString(path.toPortableString());
+			}
+		}
+
+		private void savePaths(IPath[] paths) throws IOException {
+			int count = paths == null ? 0 : paths.length;
+
+			saveInt(count);
+			for (int i = 0; i < count; ++i)
+				savePath(paths[i]);
+		}
+
+		private void saveProjects(IJavaProject[] projects) throws IOException,
+				JavaModelException {
+			int count = projects.length;
+
+			saveInt(count);
+
+			for (int i = 0; i < count; ++i) {
+				IJavaProject project = projects[i];
+
+				saveString(project.getElementName());
+
+				Map containerMap = (Map) JavaModelManager.this.containers.get(project);
+
+				if (containerMap == null) {
+					containerMap = Collections.EMPTY_MAP;
+				} else {
+					// clone while iterating
+					// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=59638)
+					containerMap = new HashMap(containerMap);
+				}
+
+				saveContainers(project, containerMap);
+			}
+		}
+
+		private void saveString(String string) throws IOException {
+			if (saveNewId(string, this.stringIds))
+				this.out.writeUTF(string);
+		}
+
+		private void saveVariables(Map map) throws IOException {
+			saveInt(map.size());
+
+			for (Iterator i = map.entrySet().iterator(); i.hasNext();) {
+				Entry entry = (Entry) i.next();
+				String varName = (String) entry.getKey();
+				IPath varPath = (IPath) entry.getValue();
+
+				saveString(varName);
+				savePath(varPath);
+			}
+		}
+	}
+
+	private void traceVariableAndContainers(String action, long start) {
+
+		Long delta = new Long(System.currentTimeMillis() - start);
+		Long length = new Long(getVariableAndContainersFile().length());
+		String pattern = "{0} {1} bytes in variablesAndContainers.dat in {2}ms"; //$NON-NLS-1$
+		String message = MessageFormat.format(pattern, new Object[]{action, length, delta});
+
+		System.out.println(message);
+	}
+
 	/**
 	 * @see ISaveParticipant
 	 */
 	public void saving(ISaveContext context) throws CoreException {
 		
-	    // save variable and container values on snapshot/full save
-		saveVariablesAndContainers();
+	    long start = -1;
+		if (VERBOSE)
+			start = System.currentTimeMillis();
+
+		// save variable and container values on snapshot/full save
+		saveVariablesAndContainers(context);
+
+		if (VERBOSE)
+			traceVariableAndContainers("Saved", start); //$NON-NLS-1$
 		
 		if (context.getKind() == ISaveContext.FULL_SAVE) {
 			// will need delta since this save (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=38658)
@@ -2329,18 +3580,16 @@
 		synchronized(this.perProjectInfos) {
 			values = new ArrayList(this.perProjectInfos.values());
 		}
-		if (values != null) {
-			Iterator iterator = values.iterator();
-			while (iterator.hasNext()) {
-				try {
-					PerProjectInfo info = (PerProjectInfo) iterator.next();
-					saveState(info, context);
-					info.rememberExternalLibTimestamps();
-				} catch (CoreException e) {
-					if (vStats == null)
-						vStats= new ArrayList();
-					vStats.add(e.getStatus());
-				}
+		Iterator iterator = values.iterator();
+		while (iterator.hasNext()) {
+			try {
+				PerProjectInfo info = (PerProjectInfo) iterator.next();
+				saveState(info, context);
+				info.rememberExternalLibTimestamps();
+			} catch (CoreException e) {
+				if (vStats == null)
+					vStats= new ArrayList();
+				vStats.add(e.getStatus());
 			}
 		}
 		if (vStats != null) {
@@ -2354,6 +3603,412 @@
 	}
 
 	/**
+	 * Add a secondary type in temporary indexing cache for a project got from given path.
+	 * 
+	 * Current secondary types cache is not modified as we want to wait that indexing
+	 * was finished before taking new secondary types into account.
+	 * 
+	 * Indexing cache is a specific entry in secondary types cache which key is
+	 * {@link #INDEXED_SECONDARY_TYPES } and value a map with same structure than
+	 * secondary types cache itself.
+	 * 
+	 * @see #secondaryTypes(IJavaProject, boolean, IProgressMonitor)
+	 */
+	public void secondaryTypeAdding(String path, char[] typeName, char[] packageName) {
+		if (VERBOSE) {
+			StringBuffer buffer = new StringBuffer("JavaModelManager.addSecondaryType("); //$NON-NLS-1$
+			buffer.append(path);
+			buffer.append(',');
+			buffer.append('[');
+			buffer.append(new String(packageName));
+			buffer.append('.');
+			buffer.append(new String(typeName));
+			buffer.append(']');
+			buffer.append(')');
+			Util.verbose(buffer.toString());
+		}
+		IWorkspaceRoot wRoot = ResourcesPlugin.getWorkspace().getRoot();
+		IResource resource = wRoot.findMember(path);
+		if (resource != null) {
+			if (org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(path) && resource.getType() == IResource.FILE) {
+				IProject project = resource.getProject();
+				try {
+					PerProjectInfo projectInfo = getPerProjectInfoCheckExistence(project);
+					// Get or create map to cache secondary types while indexing (can be not synchronized as indexing insure a non-concurrent usage)
+					HashMap indexedSecondaryTypes = null;
+					if (projectInfo.secondaryTypes == null) {
+						projectInfo.secondaryTypes = new Hashtable(3);
+						indexedSecondaryTypes = new HashMap(3);
+						projectInfo.secondaryTypes.put(INDEXED_SECONDARY_TYPES, indexedSecondaryTypes);
+					} else {
+						indexedSecondaryTypes = (HashMap) projectInfo.secondaryTypes.get(INDEXED_SECONDARY_TYPES);
+						if (indexedSecondaryTypes == null) {
+							indexedSecondaryTypes = new HashMap(3);
+							projectInfo.secondaryTypes.put(INDEXED_SECONDARY_TYPES, indexedSecondaryTypes);
+						}
+					}
+					// Store the secondary type in temporary cache (these are just handles => no problem to create it now...)
+					HashMap allTypes = (HashMap) indexedSecondaryTypes.get(resource);
+					if (allTypes == null) {
+						allTypes = new HashMap(3);
+						indexedSecondaryTypes.put(resource, allTypes);
+					}
+					ICompilationUnit unit = JavaModelManager.createCompilationUnitFrom((IFile)resource, null);
+					if (unit != null) {
+						String typeString = new String(typeName);
+						String packageString = new String(packageName);
+						HashMap packageTypes = (HashMap) allTypes.get(packageString);
+						if (packageTypes == null) {
+							packageTypes = new HashMap(3);
+							allTypes.put(packageString, packageTypes);
+						}
+						packageTypes.put(typeString, unit.getType(typeString));
+					}
+					if (VERBOSE) {
+						Util.verbose("	- indexing cache:"); //$NON-NLS-1$
+						Iterator entries = indexedSecondaryTypes.entrySet().iterator();
+						while (entries.hasNext()) {
+							Map.Entry entry = (Map.Entry) entries.next();
+							IFile file = (IFile) entry.getKey();
+							Util.verbose("		+ "+file.getFullPath()+':'+ entry.getValue()); //$NON-NLS-1$
+						}
+					}
+				}
+				catch (JavaModelException jme) {
+					// do nothing
+				}
+			}
+		}
+	}
+
+	/**
+	 * Get all secondary types for a project and store result in per project info cache.
+	 * 
+	 * This cache is an Hashtable<String, HashMap<String, IType>>:
+	 * 	- key: package name
+	 * 	- value:
+	 * 		+ key: type name
+	 * 		+ value: java model handle for the secondary type
+	 * Hashtable was used to protect callers from possible concurrent access.
+	 * 
+	 * Note that this map may have a specific entry which key is {@link #INDEXED_SECONDARY_TYPES }
+	 * and value is a map containing all secondary types created during indexing.
+	 * When this key is in cache and indexing is finished, returned map is merged
+	 * with the value of this special key. If indexing is not finished and caller does
+	 * not wait for the end of indexing, returned map is the current secondary
+	 * types cache content which may be invalid...
+	 * 
+	 * @param project Project we want get secondary types from
+	 * @return HashMap Table of secondary type names->path for given project
+	 */
+	public Map secondaryTypes(IJavaProject project, boolean waitForIndexes, IProgressMonitor monitor) throws JavaModelException {
+		if (VERBOSE) {
+			StringBuffer buffer = new StringBuffer("JavaModelManager.secondaryTypes("); //$NON-NLS-1$
+			buffer.append(project.getElementName());
+			buffer.append(',');
+			buffer.append(waitForIndexes);
+			buffer.append(')');
+			Util.verbose(buffer.toString());
+		}
+
+		// Return cache if not empty and there's no new secondary types created during indexing
+		final PerProjectInfo projectInfo = getPerProjectInfoCheckExistence(project.getProject());
+		Map indexingSecondaryCache = projectInfo.secondaryTypes == null ? null : (Map) projectInfo.secondaryTypes.get(INDEXED_SECONDARY_TYPES);
+		if (projectInfo.secondaryTypes != null && indexingSecondaryCache == null) {
+			return projectInfo.secondaryTypes;
+		}
+
+		// Perform search request only if secondary types cache is not initialized yet (this will happen only once!)
+		if (projectInfo.secondaryTypes == null) {
+			return secondaryTypesSearching(project, waitForIndexes, monitor, projectInfo);
+		}
+
+		// New secondary types have been created while indexing secondary types cache
+		// => need to know whether the indexing is finished or not
+		boolean indexing = this.indexManager.awaitingJobsCount() > 0;
+		if (indexing) {
+			if (!waitForIndexes)  {
+				// Indexing is running but caller cannot wait => return current cache
+				return projectInfo.secondaryTypes;
+			}
+
+			// Wait for the end of indexing or a cancel
+			while (this.indexManager.awaitingJobsCount() > 0) {
+				if (monitor != null && monitor.isCanceled()) {
+					return projectInfo.secondaryTypes;
+				}
+				try {
+					Thread.sleep(10);
+				} catch (InterruptedException e) {
+					return projectInfo.secondaryTypes;
+				}
+			}
+		}
+
+		// Indexing is finished => merge caches and return result
+		return secondaryTypesMerging(projectInfo.secondaryTypes);
+	}
+	
+	/*
+	 * Return secondary types cache merged with new secondary types created while indexing
+	 * Note that merge result is directly stored in given parameter map.
+	 */
+	private Hashtable secondaryTypesMerging(Hashtable secondaryTypes) {
+		if (VERBOSE) {
+			Util.verbose("JavaModelManager.getSecondaryTypesMerged()"); //$NON-NLS-1$
+			Util.verbose("	- current cache to merge:"); //$NON-NLS-1$
+			Iterator entries = secondaryTypes.entrySet().iterator();
+			while (entries.hasNext()) {
+				Map.Entry entry = (Map.Entry) entries.next();
+				String packName = (String) entry.getKey();
+				Util.verbose("		+ "+packName+':'+ entry.getValue() ); //$NON-NLS-1$
+			}
+		}
+
+		// Return current cache if there's no indexing cache (double check, this should not happen)
+		HashMap indexedSecondaryTypes = (HashMap) secondaryTypes.remove(INDEXED_SECONDARY_TYPES);
+		if (indexedSecondaryTypes == null) {
+			return secondaryTypes;
+		}
+
+		// Merge indexing cache in secondary types one
+		Iterator entries = indexedSecondaryTypes.entrySet().iterator();
+		while (entries.hasNext()) {
+			Map.Entry entry = (Map.Entry) entries.next();
+			IFile file = (IFile) entry.getKey();
+	
+			// Remove all secondary types of indexed file from cache
+			secondaryTypesRemoving(secondaryTypes, file);
+			
+			// Add all indexing file secondary types in given secondary types cache
+			HashMap fileSecondaryTypes = (HashMap) entry.getValue();
+			Iterator entries2 = fileSecondaryTypes.entrySet().iterator();
+			while (entries2.hasNext()) {
+				Map.Entry entry2 = (Map.Entry) entries2.next();
+				String packageName = (String) entry2.getKey();
+				HashMap cachedTypes = (HashMap) secondaryTypes.get(packageName);
+				if (cachedTypes == null) {
+					secondaryTypes.put(packageName, entry2.getValue());
+				} else {
+					HashMap types = (HashMap) entry2.getValue();
+					Iterator entries3 = types.entrySet().iterator();
+					while (entries3.hasNext()) {
+						Map.Entry entry3 = (Map.Entry) entries3.next();
+						String typeName = (String) entry3.getKey();
+						cachedTypes.put(typeName, entry3.getValue());
+					}
+				}
+			}
+		}
+		if (VERBOSE) {
+			Util.verbose("	- secondary types cache merged:"); //$NON-NLS-1$
+			entries = secondaryTypes.entrySet().iterator();
+			while (entries.hasNext()) {
+				Map.Entry entry = (Map.Entry) entries.next();
+				String packName = (String) entry.getKey();
+				Util.verbose("		+ "+packName+':'+ entry.getValue()); //$NON-NLS-1$
+			}
+		}
+		return secondaryTypes;
+	}
+
+	/*
+	 * Perform search request to get all secondary types of a given project.
+	 * If not waiting for indexes and indexing is running, will return types found in current built indexes...
+	 */
+	private Map secondaryTypesSearching(IJavaProject project, boolean waitForIndexes, IProgressMonitor monitor, final PerProjectInfo projectInfo) throws JavaModelException {
+		if (VERBOSE || BasicSearchEngine.VERBOSE) {
+			StringBuffer buffer = new StringBuffer("JavaModelManager.secondaryTypesSearch("); //$NON-NLS-1$
+			buffer.append(project.getElementName());
+			buffer.append(',');
+			buffer.append(waitForIndexes);
+			buffer.append(')');
+			Util.verbose(buffer.toString());
+		}
+
+		final Hashtable secondaryTypes = new Hashtable(3);
+		IRestrictedAccessTypeRequestor nameRequestor = new IRestrictedAccessTypeRequestor() {
+			public void acceptType(int modifiers, char[] packageName, char[] simpleTypeName, char[][] enclosingTypeNames, String path, AccessRestriction access) {
+				String key = packageName==null ? "" : new String(packageName); //$NON-NLS-1$
+				HashMap types = (HashMap) secondaryTypes.get(key);
+				if (types == null) types = new HashMap(3);
+				types.put(new String(simpleTypeName), path);
+				secondaryTypes.put(key, types);
+			}
+		};
+
+		// Build scope using prereq projects but only source folders
+		IPackageFragmentRoot[] allRoots = project.getAllPackageFragmentRoots();
+		int length = allRoots.length, size = 0;
+		IPackageFragmentRoot[] allSourceFolders = new IPackageFragmentRoot[length];
+		for (int i=0; i<length; i++) {
+			if (allRoots[i].getKind() == IPackageFragmentRoot.K_SOURCE) {
+				allSourceFolders[size++] = allRoots[i];
+			}
+		}
+		if (size < length) {
+			System.arraycopy(allSourceFolders, 0, allSourceFolders = new IPackageFragmentRoot[size], 0, size);
+		}
+
+		// Search all secondary types on scope
+		new BasicSearchEngine().searchAllSecondaryTypeNames(allSourceFolders, nameRequestor, waitForIndexes, monitor);
+
+		// Build types from paths
+		Iterator packages = secondaryTypes.values().iterator();
+		while (packages.hasNext()) {
+			HashMap types = (HashMap) packages.next();
+			Iterator names = types.entrySet().iterator();
+			while (names.hasNext()) {
+				Map.Entry entry = (Map.Entry) names.next();
+				String typeName = (String) entry.getKey();
+				String path = (String) entry.getValue();
+				if (org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(path)) {
+					IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(path));
+					ICompilationUnit unit = JavaModelManager.createCompilationUnitFrom(file, null);
+					IType type = unit.getType(typeName);
+					types.put(typeName, type); // replace stored path with type itself
+				}
+			}
+		}
+
+		// Store result in per project info cache if still null or there's still an indexing cache (may have been set by another thread...)
+		if (projectInfo.secondaryTypes == null || projectInfo.secondaryTypes.get(INDEXED_SECONDARY_TYPES) != null) {
+			projectInfo.secondaryTypes = secondaryTypes;
+			if (VERBOSE || BasicSearchEngine.VERBOSE) {
+				System.out.print(Thread.currentThread() + "	-> secondary paths stored in cache: ");  //$NON-NLS-1$
+				System.out.println();
+				Iterator entries = secondaryTypes.entrySet().iterator();
+				while (entries.hasNext()) {
+					Map.Entry entry = (Map.Entry) entries.next();
+					String qualifiedName = (String) entry.getKey();
+					Util.verbose("		- "+qualifiedName+'-'+ entry.getValue()); //$NON-NLS-1$
+				}
+			}
+		}
+		return projectInfo.secondaryTypes;
+	}
+
+	/**
+	 * Remove from secondary types cache all types belonging to a given file.
+	 * Clean secondary types cache built while indexing if requested.
+	 * 
+	 * Project's secondary types cache is found using file location.
+	 * 
+	 * @param file File to remove
+	 */
+	public void secondaryTypesRemoving(IFile file, boolean cleanIndexCache) {
+		if (VERBOSE) {
+			StringBuffer buffer = new StringBuffer("JavaModelManager.removeFromSecondaryTypesCache("); //$NON-NLS-1$
+			buffer.append(file.getName());
+			buffer.append(')');
+			Util.verbose(buffer.toString());
+		}
+		if (file != null) {
+			PerProjectInfo projectInfo = getPerProjectInfo(file.getProject(), false);
+			if (projectInfo != null && projectInfo.secondaryTypes != null) {
+				if (VERBOSE) {
+					Util.verbose("-> remove file from cache of project: "+file.getProject().getName()); //$NON-NLS-1$
+				}
+
+				// Clean current cache
+				secondaryTypesRemoving(projectInfo.secondaryTypes, file);
+				
+				// Clean indexing cache if necessary
+				if (!cleanIndexCache) return;
+				HashMap indexingCache = (HashMap) projectInfo.secondaryTypes.get(INDEXED_SECONDARY_TYPES);
+				if (indexingCache != null) {
+					Set keys = indexingCache.keySet();
+					int filesSize = keys.size(), filesCount = 0;
+					IFile[] removed = null;
+					Iterator cachedFiles = keys.iterator();
+					while (cachedFiles.hasNext()) {
+						IFile cachedFile = (IFile) cachedFiles.next();
+						if (file.equals(cachedFile)) {
+							if (removed == null) removed = new IFile[filesSize];
+							filesSize--;
+							removed[filesCount++] = cachedFile;
+						}
+					}
+					if (removed != null) {
+						for (int i=0; i<filesCount; i++) {
+							indexingCache.remove(removed[i]);
+						}
+					}
+				}
+			}
+		}
+	}
+
+	/*
+	 * Remove from a given cache map all secondary types belonging to a given file.
+	 * Note that there can have several secondary types per file...
+	 */
+	private void secondaryTypesRemoving(Hashtable secondaryTypesMap, IFile file) {
+		if (VERBOSE) {
+			StringBuffer buffer = new StringBuffer("JavaModelManager.removeSecondaryTypesFromMap("); //$NON-NLS-1$
+			Iterator entries = secondaryTypesMap.entrySet().iterator();
+			while (entries.hasNext()) {
+				Map.Entry entry = (Map.Entry) entries.next();
+				String qualifiedName = (String) entry.getKey();
+				buffer.append(qualifiedName+':'+ entry.getValue());
+			}
+			buffer.append(',');
+			buffer.append(file.getFullPath());
+			buffer.append(')');
+			Util.verbose(buffer.toString());
+		}
+		Set packageEntries = secondaryTypesMap.entrySet();
+		int packagesSize = packageEntries.size(), removedPackagesCount = 0;
+		String[] removedPackages = null;
+		Iterator packages = packageEntries.iterator();
+		while (packages.hasNext()) {
+			Map.Entry entry = (Map.Entry) packages.next();
+			String packName = (String) entry.getKey();
+			if (packName != INDEXED_SECONDARY_TYPES) { // skip indexing cache entry if present (!= is intentional)
+				HashMap types = (HashMap) entry.getValue();
+				Set nameEntries = types.entrySet();
+				int namesSize = nameEntries.size(), removedNamesCount = 0;
+				String[] removedNames = null;
+				Iterator names = nameEntries.iterator();
+				while (names.hasNext()) {
+					Map.Entry entry2 = (Map.Entry) names.next();
+					String typeName = (String) entry2.getKey();
+					IType type = (IType) entry2.getValue();
+					if (file.equals(type.getResource())) {
+						if (removedNames == null) removedNames = new String[namesSize];
+						namesSize--;
+						removedNames[removedNamesCount++] = typeName;
+					}
+				}
+				if (removedNames != null) {
+					for (int i=0; i<removedNamesCount; i++) {
+						types.remove(removedNames[i]);
+					}
+				}
+				if (types.size() == 0) {
+					if (removedPackages == null) removedPackages = new String[packagesSize];
+					packagesSize--;
+					removedPackages[removedPackagesCount++] = packName;
+				}
+			}
+		}
+		if (removedPackages != null) {
+			for (int i=0; i<removedPackagesCount; i++) {
+				secondaryTypesMap.remove(removedPackages[i]);
+			}
+		}
+		if (VERBOSE) {
+			Util.verbose("	- new secondary types map:"); //$NON-NLS-1$
+			Iterator entries = secondaryTypesMap.entrySet().iterator();
+			while (entries.hasNext()) {
+				Map.Entry entry = (Map.Entry) entries.next();
+				String qualifiedName = (String) entry.getKey();
+				Util.verbose("		+ "+qualifiedName+':'+ entry.getValue()); //$NON-NLS-1$
+			}
+		}
+	}
+
+	/**
 	 * Record the order in which to build the java projects (batch build). This order is based
 	 * on the projects classpath settings.
 	 */
@@ -2466,6 +4121,9 @@
 	public void startup() throws CoreException {
 		try {
 			configurePluginDebugOptions();
+			
+			// initialize Java model cache
+			this.cache = new JavaModelCache();
 
 			// request state folder creation (workaround 19885)
 			JavaCore.getPlugin().getStateLocation();
@@ -2480,13 +4138,22 @@
 				}
 			};
 			JavaCore.getPlugin().getPluginPreferences().addPropertyChangeListener(propertyListener);
+			
+			// Listen to content-type changes
+			 Platform.getContentTypeManager().addContentTypeChangeListener(this);
 
 			// retrieve variable values
-			loadVariablesAndContainers();
+			long start = -1;
+			if (VERBOSE)
+				start = System.currentTimeMillis();
+ 			loadVariablesAndContainers();
+ 			if (VERBOSE)
+				traceVariableAndContainers("Loaded", start); //$NON-NLS-1$
 
 			final IWorkspace workspace = ResourcesPlugin.getWorkspace();
 			workspace.addResourceChangeListener(
 				this.deltaState,
+				/* update spec in JavaCore#addPreProcessingResourceChangedListener(...) if adding more event types */
 				IResourceChangeEvent.PRE_BUILD
 					| IResourceChangeEvent.POST_BUILD
 					| IResourceChangeEvent.POST_CHANGE
@@ -2544,6 +4211,13 @@
 		IWorkspace workspace = ResourcesPlugin.getWorkspace();
 		workspace.removeResourceChangeListener(this.deltaState);
 		workspace.removeSaveParticipant(javaCore);
+		
+		// Stop listening to content-type changes
+		Platform.getContentTypeManager().removeContentTypeChangeListener(this);
+		
+		// Stop listening to user library changes
+		if (this.userLibraryManager != null)
+			getInstancePreferences().removePreferenceChangeListener(this.userLibraryManager);
 	
 		if (this.indexManager != null){ // no more indexing
 			this.indexManager.shutdown();
@@ -2551,14 +4225,14 @@
 		
 		// wait for the initialization job to finish
 		try {
-			Platform.getJobManager().join(JavaCore.PLUGIN_ID, null);
+			Job.getJobManager().join(JavaCore.PLUGIN_ID, null);
 		} catch (InterruptedException e) {
 			// ignore
 		}
 		
 		// Note: no need to close the Java model as this just removes Java element infos from the Java model cache
 	}
-		
+
 	public synchronized IPath variableGet(String variableName){
 		// check initialization in progress first
 		HashSet initializations = variableInitializationInProgress();
@@ -2568,164 +4242,13 @@
 		return (IPath)this.variables.get(variableName);
 	}
 
-	/*
-	 * 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$
-		}
-		
-		if (variablePutIfInitializingWithSameValue(variableNames, variablePaths))
-			return;
-
-		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.DO_NOT_SET_OUTPUT,
-										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);
-				}
-			}
-		}
+	private synchronized IPath variableGetDefaultToPreviousSession(String variableName){
+		IPath variablePath = (IPath)this.variables.get(variableName);
+		if (variablePath == null)
+			return getPreviousSessionVariable(variableName);
+		return variablePath;
 	}
-	
+
 	/*
 	 * Returns the set of variable names that are being initialized in the current thread.
 	 */
@@ -2748,7 +4271,7 @@
 		}
 		return result;
 	}
-	
+
 	public synchronized void variablePut(String variableName, IPath variablePath){		
 
 		// set/unset the initialization in progress
@@ -2763,26 +4286,32 @@
 
 			// update cache - do not only rely on listener refresh		
 			if (variablePath == null) {
-				this.variables.remove(variableName);
+				// if path is null, record that the variable was removed to avoid asking the initializer to initialize it again
+				// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=112609
+				this.variables.put(variableName, CP_ENTRY_IGNORE_PATH);
 			} else {
 				this.variables.put(variableName, variablePath);
 			}
 			// discard obsoleted information about previous session
 			this.previousSessionVariables.remove(variableName);
 		}
-	
+	}
+
+	public void variablePreferencesPut(String variableName, IPath variablePath) {
 		String variableKey = CP_VARIABLE_PREFERENCES_PREFIX+variableName;
-		if (variablePath == null)
+		if (variablePath == null) {
+			this.variablesWithInitializer.remove(variableName);
 			getInstancePreferences().remove(variableKey);
-		else
+		} else {
 			getInstancePreferences().put(variableKey, variablePath.toString());
+		}
 		try {
 			getInstancePreferences().flush();
 		} catch (BackingStoreException e) {
 			// ignore exception
 		}
 	}
-	
+
 	/*
 	 * Optimize startup case where 1 variable is initialized at a time with the same value as on shutdown.
 	 */
@@ -2790,7 +4319,7 @@
 		if (variableNames.length != 1)
 			return false;
 		String variableName = variableNames[0];
-		IPath oldPath = getPreviousSessionVariable(variableName);
+		IPath oldPath = variableGetDefaultToPreviousSession(variableName);
 		if (oldPath == null)
 			return false;
 		IPath newPath = variablePaths[0];
@@ -2799,4 +4328,13 @@
 		variablePut(variableName, newPath);
 		return true;
 	}
+
+	public void contentTypeChanged(ContentTypeChangeEvent event) {
+		Util.resetJavaLikeExtensions();
+		
+	}
+
+	public synchronized String cacheToString(String prefix) {
+		return this.cache.toStringFillingRation(prefix);
+	}
 }
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 7a58ae6..b029e4c 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -61,8 +61,8 @@
 	protected HashMap attributes;
 
 	public static final String HAS_MODIFIED_RESOURCE_ATTR = "hasModifiedResource"; //$NON-NLS-1$
-	public static final String TRUE = "true"; //$NON-NLS-1$
-	//public static final String FALSE = "false"; //$NON-NLS-1$
+	public static final String TRUE = JavaModelManager.TRUE;
+	//public static final String FALSE = "false";
 		
 	/**
 	 * The elements this operation operates on,
@@ -93,7 +93,7 @@
 	/**
 	 * The progress monitor passed into this operation
 	 */
-	protected IProgressMonitor progressMonitor= null;
+	public IProgressMonitor progressMonitor= null;
 	/**
 	 * A flag indicating whether this operation is nested.
 	 */
@@ -181,6 +181,12 @@
 				JavaElementDelta child = (JavaElementDelta)children[i];
 				previousDelta.insertDeltaTree(child.getElement(), child);
 			}
+			// note that the last delta's AST always takes precedence over the existing delta's AST
+			// since it is the result of the last reconcile operation
+			if ((delta.getFlags() & IJavaElementDelta.F_AST_AFFECTED) != 0) {
+				previousDelta.changedAST(delta.getCompilationUnitAST());
+			}
+						
 		} else {
 			reconcileDeltas.put(workingCopy, delta);
 		}
@@ -241,7 +247,7 @@
 		IWorkspace workspace = resources[0].getWorkspace();
 		try {
 			workspace.copy(resources, destinationPath, false, subProgressMonitor);
-			this.setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); 
+			setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); 
 		} catch (CoreException e) {
 			throw new JavaModelException(e);
 		}
@@ -256,7 +262,7 @@
 				contents, 
 				forceFlag ? IResource.FORCE | IResource.KEEP_HISTORY : IResource.KEEP_HISTORY, 
 				getSubProgressMonitor(1));
-				this.setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); 
+				setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); 
 		} catch (CoreException e) {
 			throw new JavaModelException(e);
 		}
@@ -272,7 +278,7 @@
 				forceFlag ? IResource.FORCE | IResource.KEEP_HISTORY : IResource.KEEP_HISTORY,
 				true, // local
 				getSubProgressMonitor(1));
-			this.setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); 
+			setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); 
 		} catch (CoreException e) {
 			throw new JavaModelException(e);
 		}
@@ -292,7 +298,7 @@
 			resource.delete(
 				forceFlag ? IResource.FORCE | IResource.KEEP_HISTORY : IResource.KEEP_HISTORY, 
 				getSubProgressMonitor(1));
-			this.setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); 
+			setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); 
 			while (resource instanceof IFolder) {
 				// deleting a package: delete the parent if it is empty (eg. deleting x.y where folder x doesn't have resources but y)
 				// without deleting the package fragment root
@@ -301,7 +307,7 @@
 					resource.delete(
 						forceFlag ? IResource.FORCE | IResource.KEEP_HISTORY : IResource.KEEP_HISTORY, 
 						getSubProgressMonitor(1));
-					this.setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); 
+					setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); 
 				}
 			}
 		} catch (CoreException e) {
@@ -314,7 +320,7 @@
 	protected void deleteResource(IResource resource,int flags) throws JavaModelException {
 		try {
 			resource.delete(flags, getSubProgressMonitor(1));
-			this.setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); 
+			setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); 
 		} catch (CoreException e) {
 			throw new JavaModelException(e);
 		}
@@ -331,7 +337,7 @@
 				resources,
 				forceFlag ? IResource.FORCE | IResource.KEEP_HISTORY : IResource.KEEP_HISTORY, 
 				subProgressMonitor);
-				this.setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); 
+				setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); 
 		} catch (CoreException e) {
 			throw new JavaModelException(e);
 		}
@@ -391,8 +397,8 @@
 	 * Returns the attribute registered at the given key with the top level operation.
 	 * Returns null if no such attribute is found.
 	 */
-	protected Object getAttribute(Object key) {
-		ArrayList stack = this.getCurrentOperationStack();
+	protected static Object getAttribute(Object key) {
+		ArrayList stack = getCurrentOperationStack();
 		if (stack.size() == 0) return null;
 		JavaModelOperation topLevelOp = (JavaModelOperation)stack.get(0);
 		if (topLevelOp.attributes == null) {
@@ -414,7 +420,7 @@
 	 * Returns the stack of operations running in the current thread.
 	 * Returns an empty stack if no operations are currently running in this thread. 
 	 */
-	protected ArrayList getCurrentOperationStack() {
+	protected static ArrayList getCurrentOperationStack() {
 		ArrayList stack = (ArrayList)operationStacks.get();
 		if (stack == null) {
 			stack = new ArrayList();
@@ -452,11 +458,7 @@
 	 * Returns the Java Model this operation is operating in.
 	 */
 	public IJavaModel getJavaModel() {
-		if (elementsToProcess == null || elementsToProcess.length == 0) {
-			return getParentElement().getJavaModel();
-		} else {
-			return elementsToProcess[0].getJavaModel();
-		}
+		return JavaModelManager.getJavaModelManager().getJavaModel();
 	}
 	protected IPath[] getNestedFolders(IPackageFragmentRoot root) throws JavaModelException {
 		IPath rootPath = root.getPath();
@@ -522,7 +524,7 @@
 	 * Returns false if this operation has not been executed yet.
 	 */
 	public boolean hasModifiedResource() {
-		return !this.isReadOnly() && this.getAttribute(HAS_MODIFIED_RESOURCE_ATTR) == TRUE; 
+		return !this.isReadOnly() && getAttribute(HAS_MODIFIED_RESOURCE_ATTR) == TRUE; 
 	}
 	public void internalWorked(double work) {
 		if (progressMonitor != null) {
@@ -551,7 +553,7 @@
 	protected boolean isTopLevelOperation() {
 		ArrayList stack;
 		return 
-			(stack = this.getCurrentOperationStack()).size() > 0
+			(stack = getCurrentOperationStack()).size() > 0
 			&& stack.get(0) == this;
 	}
 	/*
@@ -578,7 +580,7 @@
 		IWorkspace workspace = resources[0].getWorkspace();
 		try {
 			workspace.move(resources, destinationPath, false, subProgressMonitor);
-			this.setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); 
+			setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); 
 		} catch (CoreException e) {
 			throw new JavaModelException(e);
 		}
@@ -743,10 +745,11 @@
 					switch (element.getElementType()) {
 						case IJavaElement.PACKAGE_FRAGMENT_ROOT:
 						case IJavaElement.PACKAGE_FRAGMENT:
-							((JavaProject) element.getJavaProject()).resetCaches();
+							deltaProcessor.projectCachesToReset.add(element.getJavaProject());
 							break;
 					}
 				}
+				deltaProcessor.resetProjectCaches();
 				
 				// fire only iff:
 				// - the operation is a top level operation
@@ -807,8 +810,11 @@
 	/*
 	 * Registers the given attribute at the given key with the top level operation.
 	 */
-	protected void setAttribute(Object key, Object attribute) {
-		JavaModelOperation topLevelOp = (JavaModelOperation)this.getCurrentOperationStack().get(0);
+	protected static void setAttribute(Object key, Object attribute) {
+		ArrayList operationStack = getCurrentOperationStack();
+		if (operationStack.size() == 0)
+			return;
+		JavaModelOperation topLevelOp = (JavaModelOperation) operationStack.get(0);
 		if (topLevelOp.attributes == null) {
 			topLevelOp.attributes = new HashMap();
 		}
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 5f2895b..e84d486 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -126,7 +126,7 @@
 		this(code, new IJavaElement[]{element});
 		this.string = string;
 	}
-	
+
 	/**
 	 * Constructs an Java model status with the given corresponding
 	 * element and path
@@ -134,7 +134,8 @@
 	public JavaModelStatus(int code, IJavaElement element, IPath path) {
 		this(code, new IJavaElement[]{element});
 		this.path = path;
-	}	
+	}
+
 	/**
 	 * Constructs an Java model status with the given corresponding
 	 * element, path and string
@@ -144,7 +145,19 @@
 		this.path = path;
 		this.string = string;
 	}	
+
 	/**
+     * Constructs an Java model status with the given corresponding
+     * element and path
+     */
+    public JavaModelStatus(int severity, int code, IJavaElement element, IPath path, String msg) {
+    	super(severity, JavaCore.PLUGIN_ID, code, "JavaModelStatus", null); //$NON-NLS-1$
+    	this.elements= new IJavaElement[]{element};
+    	this.path = path;
+    	this.string = msg;
+    }
+
+    /**
 	 * Constructs an Java model status with no corresponding elements.
 	 */
 	public JavaModelStatus(CoreException coreException) {
@@ -326,45 +339,64 @@
 					if (description == null) description = path.makeRelative().toString();
 					return Messages.bind(Messages.classpath_invalidContainer, new String[] {description, javaProject.getElementName()}); 
 
-			case CP_VARIABLE_PATH_UNBOUND:
-				javaProject = (IJavaProject)elements[0];
-				return Messages.bind(Messages.classpath_unboundVariablePath, new String[] {path.makeRelative().toString(), javaProject.getElementName()}); 
-					
-			case CLASSPATH_CYCLE: 
-				javaProject = (IJavaProject)elements[0];
-				return Messages.bind(Messages.classpath_cycle, javaProject.getElementName()); 
-												 
-			case DISABLED_CP_EXCLUSION_PATTERNS:
-				javaProject = (IJavaProject)elements[0];
-				String projectName = javaProject.getElementName();
-				IPath newPath = path;
-				if (path.segment(0).toString().equals(projectName)) {
-					newPath = path.removeFirstSegments(1);
-				}
-				return Messages.bind(Messages.classpath_disabledInclusionExclusionPatterns, new String[] {newPath.makeRelative().toString(), projectName}); 
-
-			case DISABLED_CP_MULTIPLE_OUTPUT_LOCATIONS:
-				javaProject = (IJavaProject)elements[0];
-				projectName = javaProject.getElementName();
-				newPath = path;
-				if (path.segment(0).toString().equals(projectName)) {
-					newPath = path.removeFirstSegments(1);
-				}
-				return Messages.bind(Messages.classpath_disabledMultipleOutputLocations, new String[] {newPath.makeRelative().toString(), projectName}); 
-
-			case INCOMPATIBLE_JDK_LEVEL:
+				case CP_VARIABLE_PATH_UNBOUND:
 					javaProject = (IJavaProject)elements[0];
-					return Messages.bind(Messages.classpath_incompatibleLibraryJDKLevel, new String[]{	
-						javaProject.getElementName(), 
-						javaProject.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, true), 
-						path.makeRelative().toString(),
-						string,
-					});
+					return Messages.bind(Messages.classpath_unboundVariablePath, new String[] {path.makeRelative().toString(), javaProject.getElementName()}); 
+
+				case CLASSPATH_CYCLE: 
+					javaProject = (IJavaProject)elements[0];
+					return Messages.bind(Messages.classpath_cycle, javaProject.getElementName()); 
+
+				case DISABLED_CP_EXCLUSION_PATTERNS:
+					javaProject = (IJavaProject)elements[0];
+					String projectName = javaProject.getElementName();
+					IPath newPath = path;
+					if (path.segment(0).toString().equals(projectName)) {
+						newPath = path.removeFirstSegments(1);
+					}
+					return Messages.bind(Messages.classpath_disabledInclusionExclusionPatterns, new String[] {newPath.makeRelative().toString(), projectName}); 
+
+				case DISABLED_CP_MULTIPLE_OUTPUT_LOCATIONS:
+					javaProject = (IJavaProject)elements[0];
+					projectName = javaProject.getElementName();
+					newPath = path;
+					if (path.segment(0).toString().equals(projectName)) {
+						newPath = path.removeFirstSegments(1);
+					}
+					return Messages.bind(Messages.classpath_disabledMultipleOutputLocations, new String[] {newPath.makeRelative().toString(), projectName}); 
+
+				case INCOMPATIBLE_JDK_LEVEL:
+						javaProject = (IJavaProject)elements[0];
+						return Messages.bind(Messages.classpath_incompatibleLibraryJDKLevel, new String[]{	
+							javaProject.getElementName(), 
+							javaProject.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, true), 
+							path.makeRelative().toString(),
+							string,
+						});
+
+				case CANNOT_RETRIEVE_ATTACHED_JAVADOC :
+					if (elements != null && elements.length == 1) {
+						if (this.string != null) {
+							return Messages.bind(Messages.status_cannot_retrieve_attached_javadoc, ((JavaElement)elements[0]).toStringWithAncestors(), this.string); 
+						}
+						return Messages.bind(Messages.status_cannot_retrieve_attached_javadoc, ((JavaElement)elements[0]).toStringWithAncestors(), ""); //$NON-NLS-1$
+					}
+					if (this.string != null) {
+						return Messages.bind(Messages.status_cannot_retrieve_attached_javadoc, this.string, "");//$NON-NLS-1$
+					}
+					break;
+
+				case UNKNOWN_JAVADOC_FORMAT :
+					return Messages.bind(Messages.status_unknown_javadoc_format, ((JavaElement)elements[0]).toStringWithAncestors()); 
+
+				case DEPRECATED_VARIABLE :
+					javaProject = (IJavaProject)elements[0];
+					return Messages.bind(Messages.classpath_deprecated_variable, new String[] {path.segment(0).toString(), javaProject.getElementName(), this.string}); 
 			}
 			if (string != null) {
 				return string;
 			} else {
-				return ""; // //$NON-NLS-1$
+				return ""; //$NON-NLS-1$
 			}
 		} else {
 			String message = exception.getMessage();
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 a5ea949..a0c7dfc 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -11,12 +11,14 @@
 package org.eclipse.jdt.internal.core;
 
 import java.io.*;
+import java.net.URI;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.Map;
+
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
@@ -32,9 +34,11 @@
 import org.eclipse.core.resources.IWorkspaceRoot;
 import org.eclipse.core.resources.ProjectScope;
 import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.AssertionFailedException;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Path;
 import org.eclipse.core.runtime.Preferences;
 import org.eclipse.core.runtime.QualifiedName;
@@ -56,10 +60,14 @@
 import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.WorkingCopyOwner;
+import org.eclipse.jdt.core.compiler.CategorizedProblem;
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.eval.IEvaluationContext;
 import org.eclipse.jdt.internal.compiler.util.ObjectVector;
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
+import org.eclipse.jdt.internal.core.JavaModelManager.PerProjectInfo;
+import org.eclipse.jdt.internal.core.JavaProjectElementInfo.ProjectCache;
+import org.eclipse.jdt.internal.core.builder.JavaBuilder;
 import org.eclipse.jdt.internal.core.eval.EvaluationContextWrapper;
 import org.eclipse.jdt.internal.core.util.MementoTokenizer;
 import org.eclipse.jdt.internal.core.util.Messages;
@@ -112,16 +120,23 @@
 	/**
 	 * An empty array of strings indicating that a project doesn't have any prerequesite projects.
 	 */
-	protected static final String[] NO_PREREQUISITES = new String[0];
+	protected static final String[] NO_PREREQUISITES = CharOperation.NO_STRINGS;
 
 	/**
 	 * Name of file containing custom project preferences
-	 * @deprecated WARNING Visibility will be reduce to private before M9
-	 * 	If you use this variable, change your implementation to avoid future compilation error...
 	 * @see <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=59258">bug 59258</a>
-	 * TODO (frederic) set visibility from public to private
 	 */
-	public static final String PREF_FILENAME = ".jprefs";  //$NON-NLS-1$
+	private static final String PREF_FILENAME = ".jprefs";  //$NON-NLS-1$
+	
+	/**
+	 * Name of directory containing preferences file
+	 */
+	public static final String DEFAULT_PREFERENCES_DIRNAME = ".settings"; //$NON-NLS-1$
+	
+	/**
+	 * Extension for file containing custom project preferences
+	 */
+	public static final String JAVA_CORE_PREFS_FILE = JavaCore.PLUGIN_ID+".prefs"; //$NON-NLS-1$
 	
 	/*
 	 * Value of project's resolved classpath while it is being resolved
@@ -134,6 +149,66 @@
 	protected IProject project;
 	
 	/**
+	 * Constructor needed for <code>IProject.getNature()</code> and <code>IProject.addNature()</code>.
+	 *
+	 * @see #setProject(IProject)
+	 */
+	public JavaProject() {
+		super(null);
+	}
+	
+	public JavaProject(IProject project, JavaElement parent) {
+		super(parent);
+		this.project = project;
+	}
+
+	public static boolean areClasspathsEqual(
+			IClasspathEntry[] firstClasspath, IClasspathEntry[] secondClasspath, 
+			IPath firstOutputLocation, IPath secondOutputLocation) {
+		int length = firstClasspath.length;
+		if (length != secondClasspath.length) return false;
+		for (int i = 0; i < length; i++) {
+			if (!firstClasspath[i].equals(secondClasspath[i]))
+				return false;
+		}
+		if (firstOutputLocation == null)
+			return secondOutputLocation == null;
+		return firstOutputLocation.equals(secondOutputLocation);
+	}
+
+	/**
+	 * Compare current classpath with given one to see if any different.
+	 * Note that the argument classpath contains its binary output.
+	 * @param newClasspath IClasspathEntry[]
+	 * @param newOutputLocation IPath
+	 * @param otherClasspathWithOutput IClasspathEntry[]
+	 * @return boolean
+	 */
+	private static boolean areClasspathsEqual(IClasspathEntry[] newClasspath, IPath newOutputLocation, IClasspathEntry[] otherClasspathWithOutput) {
+
+		if (otherClasspathWithOutput == null || otherClasspathWithOutput.length == 0)
+			return false;
+
+		int length = otherClasspathWithOutput.length;
+		if (length != newClasspath.length + 1) 
+				// output is amongst file entries (last one)
+				return false;
+		
+		
+		// compare classpath entries
+		for (int i = 0; i < length - 1; i++) {
+			if (!otherClasspathWithOutput[i].equals(newClasspath[i]))
+				return false;
+		}
+		// compare binary outputs
+		IClasspathEntry output = otherClasspathWithOutput[length - 1];
+		if (output.getContentKind() != ClasspathEntry.K_OUTPUT
+				|| !output.getPath().equals(newOutputLocation))
+			return false;
+		return true;
+	}
+
+	/**
 	 * Returns a canonicalized path from the given external path.
 	 * Note that the return path contains the same number of segments
 	 * and it contains a device only if the given path contained one.
@@ -147,12 +222,12 @@
 			return null;
 
 //		if (JavaModelManager.VERBOSE) {
-//			System.out.println("JAVA MODEL - Canonicalizing " + externalPath.toString()); //$NON-NLS-1$
+//			System.out.println("JAVA MODEL - Canonicalizing " + externalPath.toString());
 //		}
 
 		if (IS_CASE_SENSITIVE) {
 //			if (JavaModelManager.VERBOSE) {
-//				System.out.println("JAVA MODEL - Canonical path is original path (file system is case sensitive)"); //$NON-NLS-1$
+//				System.out.println("JAVA MODEL - Canonical path is original path (file system is case sensitive)");
 //			}
 			return externalPath;
 		}
@@ -162,7 +237,7 @@
 		if (workspace == null) return externalPath; // protection during shutdown (30487)
 		if (workspace.getRoot().findMember(externalPath) != null) {
 //			if (JavaModelManager.VERBOSE) {
-//				System.out.println("JAVA MODEL - Canonical path is original path (member of workspace)"); //$NON-NLS-1$
+//				System.out.println("JAVA MODEL - Canonical path is original path (member of workspace)");
 //			}
 			return externalPath;
 		}
@@ -174,7 +249,7 @@
 		} catch (IOException e) {
 			// default to original path
 //			if (JavaModelManager.VERBOSE) {
-//				System.out.println("JAVA MODEL - Canonical path is original path (IOException)"); //$NON-NLS-1$
+//				System.out.println("JAVA MODEL - Canonical path is original path (IOException)");
 //			}
 			return externalPath;
 		}
@@ -184,7 +259,7 @@
 		if (canonicalLength == 0) {
 			// the java.io.File canonicalization failed
 //			if (JavaModelManager.VERBOSE) {
-//				System.out.println("JAVA MODEL - Canonical path is original path (canonical path is empty)"); //$NON-NLS-1$
+//				System.out.println("JAVA MODEL - Canonical path is original path (canonical path is empty)");
 //			}
 			return externalPath;
 		} else if (externalPath.isAbsolute()) {
@@ -197,7 +272,7 @@
 				result = canonicalPath.removeFirstSegments(canonicalLength - externalLength);
 			} else {
 //				if (JavaModelManager.VERBOSE) {
-//					System.out.println("JAVA MODEL - Canonical path is original path (canonical path is " + canonicalPath.toString() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
+//					System.out.println("JAVA MODEL - Canonical path is original path (canonical path is " + canonicalPath.toString() + ")");
 //				}
 				return externalPath;
 			}
@@ -208,11 +283,11 @@
 			result = result.setDevice(null);
 		} 
 //		if (JavaModelManager.VERBOSE) {
-//			System.out.println("JAVA MODEL - Canonical path is " + result.toString()); //$NON-NLS-1$
+//			System.out.println("JAVA MODEL - Canonical path is " + result.toString());
 //		}
 		return result;
 	}
-	
+
 	/**
 	 * Returns true if the given project is accessible and it has
 	 * a java nature, otherwise false.
@@ -223,17 +298,20 @@
 		try {
 			return project.hasNature(JavaCore.NATURE_ID);
 		} catch (CoreException e) {
+			if (ExternalJavaProject.EXTERNAL_PROJECT_NAME.equals(project.getName()))
+				return true;
 			// project does not exist or is not open
 		}
 		return false;
 	}
 
-	/**
-	 * Update cycle markers for all java projects
+	/*
+	 * Detect cycles in the classpath of the workspace's projects
+	 * and create markers if necessary.
 	 * @param preferredClasspaths Map
 	 * @throws JavaModelException
 	 */
-	public static void updateAllCycleMarkers(Map preferredClasspaths) throws JavaModelException {
+	public static void validateCycles(Map preferredClasspaths) throws JavaModelException {
 
 		//long start = System.currentTimeMillis();
 
@@ -288,20 +366,6 @@
 	}
 
 	/**
-	 * Constructor needed for <code>IProject.getNature()</code> and <code>IProject.addNature()</code>.
-	 *
-	 * @see #setProject(IProject)
-	 */
-	public JavaProject() {
-		super(null);
-	}
-
-	public JavaProject(IProject project, JavaElement parent) {
-		super(parent);
-		this.project = project;
-	}
-
-	/**
 	 * Adds a builder to the build spec for the given project.
 	 */
 	protected void addToBuildSpec(String builderID) throws CoreException {
@@ -317,19 +381,18 @@
 			setJavaCommand(description, command);
 		}
 	}
-
 	/**
 	 * @see Openable
 	 */
 	protected boolean buildStructure(OpenableElementInfo info, IProgressMonitor pm, Map newElements, IResource underlyingResource) throws JavaModelException {
 	
 		// check whether the java project can be opened
-		if (!underlyingResource.isAccessible()) {
+		if (!hasJavaNature((IProject) underlyingResource)) {
 			throw newNotPresentException();
 		}
 		
 		// cannot refresh cp markers on opening (emulate cp check on startup) since can create deadlocks (see bug 37274)
-		IClasspathEntry[] resolvedClasspath = getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
+		IClasspathEntry[] resolvedClasspath = getResolvedClasspath();
 
 		// compute the pkg fragment roots
 		info.setChildren(computePackageFragmentRoots(resolvedClasspath, false, null /*no reverse map*/));	
@@ -340,19 +403,6 @@
 		return true;
 	}
 
-	protected void closing(Object info) {
-		
-		// forget source attachment recommendations
-		Object[] children = ((JavaElementInfo)info).children;
-		for (int i = 0, length = children.length; i < length; i++) {
-			Object child = children[i];
-			if (child instanceof JarPackageFragmentRoot){
-				((JarPackageFragmentRoot)child).setSourceAttachmentProperty(null); 
-			}
-		}
-		
-		super.closing(info);
-	}
 	/**
 	 * Computes the collection of package fragment roots (local ones) and set it on the given info.
 	 * Need to check *all* package fragment roots in order to reset NameLookup
@@ -360,7 +410,7 @@
 	 * @throws JavaModelException
 	 */
 	public void computeChildren(JavaProjectElementInfo info) throws JavaModelException {
-		IClasspathEntry[] classpath = getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
+		IClasspathEntry[] classpath = getResolvedClasspath();
 		JavaProjectElementInfo.ProjectCache projectCache = info.projectCache;
 		if (projectCache != null) {
 			IPackageFragmentRoot[] newRoots = computePackageFragmentRoots(classpath, true, null /*no reverse map*/);
@@ -381,20 +431,14 @@
 			computePackageFragmentRoots(classpath, false, null /*no reverse map*/));		
 	}
 	
-
-
 	/**
 	 * Internal computation of an expanded classpath. It will eliminate duplicates, and produce copies
 	 * of exported or restricted classpath entries to avoid possible side-effects ever after.
 	 */			
 	private void computeExpandedClasspath(
 		ClasspathEntry referringEntry,
-		boolean ignoreUnresolvedVariable,
-		boolean generateMarkerOnError,
 		HashSet rootIDs,
-		ObjectVector accumulatedEntries,
-		Map preferredClasspaths,
-		Map preferredOutputs) throws JavaModelException {
+		ObjectVector accumulatedEntries) throws JavaModelException {
 		
 		String projectRootId = this.rootID();
 		if (rootIDs.contains(projectRootId)){
@@ -402,17 +446,12 @@
 		}
 		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 /*no reverse map*/)
-				: getResolvedClasspath(ignoreUnresolvedVariable, generateMarkerOnError, false/*don't returnResolutionInProgress*/);
+		IClasspathEntry[] resolvedClasspath = getResolvedClasspath();
 			
 		IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
 		boolean isInitialProject = referringEntry == null;
-		for (int i = 0, length = immediateClasspath.length; i < length; i++){
-			ClasspathEntry entry = (ClasspathEntry) immediateClasspath[i];
+		for (int i = 0, length = resolvedClasspath.length; i < length; i++){
+			ClasspathEntry entry = (ClasspathEntry) resolvedClasspath[i];
 			if (isInitialProject || entry.isExported()){
 				String rootID = entry.rootID();
 				if (rootIDs.contains(rootID)) {
@@ -431,12 +470,8 @@
 							JavaProject javaProject = (JavaProject) JavaCore.create(projRsc);
 							javaProject.computeExpandedClasspath(
 								combinedEntry, 
-								ignoreUnresolvedVariable, 
-								false /* no marker when recursing in prereq*/,
-								rootIDs,
-								accumulatedEntries,
-								preferredClasspaths,
-								preferredOutputs);
+								rootIDs, 
+								accumulatedEntries);
 						}
 					}
 				} else {
@@ -445,7 +480,7 @@
 			}			
 		}
 	}
-
+	
 	/**
 	 * Computes the package fragment roots identified by the given entry.
 	 * Only works with resolved entry
@@ -464,7 +499,7 @@
 			return new IPackageFragmentRoot[] {};
 		}
 	}
-	
+
 	/**
 	 * Returns the package fragment roots identified by the given entry. In case it refers to
 	 * a project, it will follow its classpath so as to find exported roots as well.
@@ -549,7 +584,7 @@
 						rootIDs.add(rootID);
 						JavaProject requiredProject = (JavaProject)JavaCore.create(requiredProjectRsc);
 						requiredProject.computePackageFragmentRoots(
-							requiredProject.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/), 
+							requiredProject.getResolvedClasspath(), 
 							accumulatedRoots, 
 							rootIDs, 
 							rootToResolvedEntries == null ? resolvedEntry : ((ClasspathEntry)resolvedEntry).combineWith((ClasspathEntry) referringEntry), // only combine if need to build the reverse map 
@@ -566,7 +601,7 @@
 			if (rootToResolvedEntries != null) rootToResolvedEntries.put(root, ((ClasspathEntry)resolvedEntry).combineWith((ClasspathEntry) referringEntry));
 		}
 	}
-	
+
 	/**
 	 * Returns (local/all) the package fragment roots identified by the given project's classpath.
 	 * Note: this follows project classpath references to find required project contributions,
@@ -595,7 +630,7 @@
 		accumulatedRoots.copyInto(rootArray);
 		return rootArray;
 	}
-
+	
 	/**
 	 * Returns (local/all) the package fragment roots identified by the given project's classpath.
 	 * Note: this follows project classpath references to find required project contributions,
@@ -632,7 +667,6 @@
 				rootToResolvedEntries);
 		}
 	}
-
 	/**
 	 * Compute the file name to use for a given shared property
 	 * @param qName QualifiedName
@@ -642,7 +676,7 @@
 
 		return '.' + qName.getLocalName();
 	}
-	
+
 	/**
 	 * Configure the project with Java nature.
 	 */
@@ -651,6 +685,7 @@
 		// register Java builder
 		addToBuildSpec(JavaCore.BUILDER_ID);
 	}
+	
 	/*
 	 * Returns whether the given resource is accessible through the children or the non-Java resources of this project.
 	 * Returns true if the resource is not in the project.
@@ -661,7 +696,7 @@
 		IClasspathEntry[] classpath;
 		IPath output;
 		try {
-			classpath = getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
+			classpath = getResolvedClasspath();
 			output = getOutputLocation();
 		} catch (JavaModelException e) {
 			return false;
@@ -711,11 +746,11 @@
 	/**
 	 * Record a new marker denoting a classpath problem
 	 */
-	void createClasspathProblemMarker(IJavaModelStatus status) {
+	public void createClasspathProblemMarker(IJavaModelStatus status) {
 			
 		IMarker marker = null;
 		int severity;
-		String[] arguments = new String[0];
+		String[] arguments = CharOperation.NO_STRINGS;
 		boolean isCycleProblem = false, isClasspathFileFormatProblem = false;
 		switch (status.getCode()) {
 	
@@ -747,7 +782,8 @@
 			default:
 				IPath path = status.getPath();
 				if (path != null) arguments = new String[] { path.toString() };
-				if (JavaCore.ERROR.equals(getOption(JavaCore.CORE_INCOMPLETE_CLASSPATH, true))) {
+				if (JavaCore.ERROR.equals(getOption(JavaCore.CORE_INCOMPLETE_CLASSPATH, true)) &&
+					status.getSeverity() != IStatus.WARNING) {
 					severity = IMarker.SEVERITY_ERROR;
 				} else {
 					severity = IMarker.SEVERITY_WARNING;
@@ -766,6 +802,8 @@
 					IJavaModelMarker.CLASSPATH_FILE_FORMAT,
 					IJavaModelMarker.ID,
 					IJavaModelMarker.ARGUMENTS ,
+					IJavaModelMarker.CATEGORY_ID,
+					IMarker.SOURCE_ID,
 				},
 				new Object[] {
 					status.getMessage(),
@@ -775,6 +813,8 @@
 					isClasspathFileFormatProblem ? "true" : "false",//$NON-NLS-1$ //$NON-NLS-2$
 					new Integer(status.getCode()),
 					Util.getProblemArgumentsForMarker(arguments) ,
+					new Integer(CategorizedProblem.CAT_BUILDPATH),
+					JavaBuilder.SOURCE_ID,
 				}
 			);
 		} catch (CoreException e) {
@@ -784,7 +824,7 @@
 			}
 		}
 	}
-	
+
 	/**
 	 * Returns a new element info for this element.
 	 */
@@ -792,84 +832,83 @@
 		return new JavaProjectElementInfo();
 	}
 
-	/**
+	/*
 	 * Reads and decode an XML classpath string
 	 */
-	protected IClasspathEntry[] decodeClasspath(String xmlClasspath, boolean createMarker, boolean logProblems) {
-
+	public IClasspathEntry[] decodeClasspath(String xmlClasspath, Map unknownElements) throws IOException, AssertionFailedException {
+	
 		ArrayList paths = new ArrayList();
 		IClasspathEntry defaultOutput = null;
+		StringReader reader = new StringReader(xmlClasspath);
+		Element cpElement;
 		try {
-			if (xmlClasspath == null) return null;
-			StringReader reader = new StringReader(xmlClasspath);
-			Element cpElement;
-	
-			try {
-				DocumentBuilder parser =
-					DocumentBuilderFactory.newInstance().newDocumentBuilder();
-				cpElement = parser.parse(new InputSource(reader)).getDocumentElement();
-			} catch (SAXException e) {
-				throw new IOException(Messages.file_badFormat); 
-			} catch (ParserConfigurationException e) {
-				throw new IOException(Messages.file_badFormat); 
-			} finally {
-				reader.close();
-			}
-	
-			if (!cpElement.getNodeName().equalsIgnoreCase("classpath")) { //$NON-NLS-1$
-				throw new IOException(Messages.file_badFormat); 
-			}
-			NodeList list = cpElement.getElementsByTagName("classpathentry"); //$NON-NLS-1$
-			int length = list.getLength();
-	
-			for (int i = 0; i < length; ++i) {
-				Node node = list.item(i);
-				if (node.getNodeType() == Node.ELEMENT_NODE) {
-					IClasspathEntry entry = ClasspathEntry.elementDecode((Element)node, this);
-					if (entry != null){
-						if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) { 
-							defaultOutput = entry; // separate output
-						} else {
-							paths.add(entry);
-				}
-			}
-				}
-			}
-		} catch (IOException e) {
-			// bad format
-			if (createMarker && this.project.isAccessible()) {
-					this.createClasspathProblemMarker(new JavaModelStatus(
-							IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
-							Messages.bind(Messages.classpath_xmlFormatError, new String[] {this.getElementName(), e.getMessage()}))); 
-			}
-			if (logProblems) {
-				Util.log(e, 
-					"Exception while retrieving "+ this.getPath() //$NON-NLS-1$
-					+"/.classpath, will mark classpath as invalid"); //$NON-NLS-1$
-			}
-			return INVALID_CLASSPATH;
-		} catch (Assert.AssertionFailedException e) { 
-			// failed creating CP entries from file
-			if (createMarker && this.project.isAccessible()) {
-				this.createClasspathProblemMarker(new JavaModelStatus(
-						IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
-						Messages.bind(Messages.classpath_illegalEntryInClasspathFile, new String[] {this.getElementName(), e.getMessage()}))); 
-			}
-			if (logProblems) {
-				Util.log(e, 
-					"Exception while retrieving "+ this.getPath() //$NON-NLS-1$
-					+"/.classpath, will mark classpath as invalid"); //$NON-NLS-1$
-			}
-			return INVALID_CLASSPATH;
+			DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+			cpElement = parser.parse(new InputSource(reader)).getDocumentElement();
+		} catch (SAXException e) {
+			throw new IOException(Messages.file_badFormat); 
+		} catch (ParserConfigurationException e) {
+			throw new IOException(Messages.file_badFormat); 
+		} finally {
+			reader.close();
 		}
-		// return an empty classpath is it size is 0, to differenciate from a null classpath
+	
+		if (!cpElement.getNodeName().equalsIgnoreCase("classpath")) { //$NON-NLS-1$
+			throw new IOException(Messages.file_badFormat); 
+		}
+		NodeList list = cpElement.getElementsByTagName("classpathentry"); //$NON-NLS-1$
+		int length = list.getLength();
+	
+		for (int i = 0; i < length; ++i) {
+			Node node = list.item(i);
+			if (node.getNodeType() == Node.ELEMENT_NODE) {
+				IClasspathEntry entry = ClasspathEntry.elementDecode((Element)node, this, unknownElements);
+				if (entry != null){
+					if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) { 
+						defaultOutput = entry; // separate output
+					} else {
+						paths.add(entry);
+			}
+		}
+			}
+		}
+		// return a new empty classpath is it size is 0, to differenciate from an INVALID_CLASSPATH
 		int pathSize = paths.size();
 		IClasspathEntry[] entries = new IClasspathEntry[pathSize + (defaultOutput == null ? 0 : 1)];
 		paths.toArray(entries);
 		if (defaultOutput != null) entries[pathSize] = defaultOutput; // ensure output is last item
 		return entries;
 	}
+	
+	public IClasspathEntry decodeClasspathEntry(String encodedEntry) {
 
+		try {
+			if (encodedEntry == null) return null;
+			StringReader reader = new StringReader(encodedEntry);
+			Element node;
+	
+			try {
+				DocumentBuilder parser =
+					DocumentBuilderFactory.newInstance().newDocumentBuilder();
+				node = parser.parse(new InputSource(reader)).getDocumentElement();
+			} catch (SAXException e) {
+				return null;
+			} catch (ParserConfigurationException e) {
+				return null;
+			} finally {
+				reader.close();
+			}
+	
+			if (!node.getNodeName().equalsIgnoreCase("classpathentry") //$NON-NLS-1$
+					|| node.getNodeType() != Node.ELEMENT_NODE) {
+				return null; 
+			}
+			return ClasspathEntry.elementDecode(node, this, null/*not interested in unknown elements*/);
+		} catch (IOException e) {
+			// bad format
+			return null;
+		}
+	}
+	
 	/**
 	/**
 	 * Removes the Java nature from the project.
@@ -878,6 +917,9 @@
 
 		// deregister Java builder
 		removeFromBuildSpec(JavaCore.BUILDER_ID);
+		
+		// remove .classpath file
+//		getProject().getFile(ClasspathHelper.CLASSPATH_FILENAME).delete(false, null);
 	}
 
 	/**
@@ -889,7 +931,7 @@
 		return new IClasspathEntry[] {
 			 JavaCore.newSourceEntry(this.project.getFullPath())};
 	}
-
+	
 	/**
 	 * Returns a default output location.
 	 * This is the project bin folder
@@ -901,15 +943,15 @@
 	/**
 	 * Returns the XML String encoding of the class path.
 	 */
-	protected String encodeClasspath(IClasspathEntry[] classpath, IPath outputLocation, boolean indent) throws JavaModelException {
+	protected String encodeClasspath(IClasspathEntry[] classpath, IPath outputLocation, boolean indent, Map unknownElements) throws JavaModelException {
 		try {
 			ByteArrayOutputStream s = new ByteArrayOutputStream();
 			OutputStreamWriter writer = new OutputStreamWriter(s, "UTF8"); //$NON-NLS-1$
-			XMLWriter xmlWriter = new XMLWriter(writer, this);
+			XMLWriter xmlWriter = new XMLWriter(writer, this, true/*print XML version*/);
 			
 			xmlWriter.startTag(ClasspathEntry.TAG_CLASSPATH, indent);
 			for (int i = 0; i < classpath.length; ++i) {
-				((ClasspathEntry)classpath[i]).elementEncode(xmlWriter, this.project.getFullPath(), indent, true);
+				((ClasspathEntry)classpath[i]).elementEncode(xmlWriter, this.project.getFullPath(), indent, true, unknownElements);
 			}
 	
 			if (outputLocation != null) {
@@ -921,15 +963,31 @@
 				xmlWriter.printTag(ClasspathEntry.TAG_CLASSPATHENTRY, parameters, indent, true, true);
 			}
 	
-			xmlWriter.endTag(ClasspathEntry.TAG_CLASSPATH, indent);
+			xmlWriter.endTag(ClasspathEntry.TAG_CLASSPATH, indent, true/*insert new line*/);
 			writer.flush();
 			writer.close();
 			return s.toString("UTF8");//$NON-NLS-1$
 		} catch (IOException e) {
 			throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
 		}
-	}
+	}	
+
+	public String encodeClasspathEntry(IClasspathEntry classpathEntry) {
+		try {
+			ByteArrayOutputStream s = new ByteArrayOutputStream();
+			OutputStreamWriter writer = new OutputStreamWriter(s, "UTF8"); //$NON-NLS-1$
+			XMLWriter xmlWriter = new XMLWriter(writer, this, false/*don't print XML version*/);
+			
+			((ClasspathEntry)classpathEntry).elementEncode(xmlWriter, this.project.getFullPath(), true/*indent*/, true/*insert new line*/, null/*not interested in unknown elements*/);
 	
+			writer.flush();
+			writer.close();
+			return s.toString("UTF8");//$NON-NLS-1$
+		} catch (IOException e) {
+			return null; // never happens since all is done in memory
+		}
+	}
+
 	/**
 	 * Returns true if this handle represents the same Java project
 	 * as the given handle. Two handles represent the same
@@ -951,18 +1009,23 @@
 	}
 
 	public boolean exists() {
-		return hasJavaNature(this.project);
-	}	
+		try {
+			return this.project.hasNature(JavaCore.NATURE_ID);
+		} catch (CoreException e) {
+			// project does not exist or is not open
+		}
+		return false;
+	}
 
 	/**
-	 * @see IJavaProject
+	 * @see IJavaProject#findElement(IPath)
 	 */
 	public IJavaElement findElement(IPath path) throws JavaModelException {
 		return findElement(path, DefaultWorkingCopyOwner.PRIMARY);
 	}
 
 	/**
-	 * @see IJavaProject
+	 * @see IJavaProject#findElement(IPath, WorkingCopyOwner)
 	 */
 	public IJavaElement findElement(IPath path, WorkingCopyOwner owner) throws JavaModelException {
 		
@@ -1008,13 +1071,17 @@
 
 				// lookup type
 				NameLookup lookup = newNameLookup(owner);
-				IType type = lookup.findType(
+				NameLookup.Answer answer = lookup.findType(
 					qualifiedName,
 					false,
-					NameLookup.ACCEPT_ALL);
+					NameLookup.ACCEPT_ALL,
+					true/* consider secondary types */,
+					false/* do NOT wait for indexes */,
+					false/*don't check restrictions*/,
+					null);
 
-				if (type != null) {
-					return type.getParent();
+				if (answer != null) {
+					return answer.type.getParent();
 				} else {
 					return null;
 				}
@@ -1040,7 +1107,6 @@
 
 		return findPackageFragment0(JavaProject.canonicalizedPath(path));
 	}
-
 	/*
 	 * non path canonicalizing version
 	 */
@@ -1059,7 +1125,6 @@
 
 		return findPackageFragmentRoot0(JavaProject.canonicalizedPath(path));
 	}
-
 	/*
 	 * no path canonicalization 
 	 */
@@ -1088,7 +1153,7 @@
 				if (classpath[i].equals(entry)) { // entry may need to be resolved
 					return 
 						computePackageFragmentRoots(
-							getResolvedClasspath(new IClasspathEntry[] {entry}, null, true, false, null/*no reverse map*/), 
+							resolveClasspath(new IClasspathEntry[] {entry}), 
 							false, // don't retrieve exported roots
 							null); /*no reverse map*/
 				}
@@ -1098,59 +1163,116 @@
 		}
 		return new IPackageFragmentRoot[] {};
 	}
-	
 	/**
 	 * @see IJavaProject#findType(String)
 	 */
 	public IType findType(String fullyQualifiedName) throws JavaModelException {
 		return findType(fullyQualifiedName, DefaultWorkingCopyOwner.PRIMARY);
 	}
-	
 	/**
-	 * @see IJavaProject#findType(String, String)
+	 * @see IJavaProject#findType(String, IProgressMonitor)
 	 */
-	public IType findType(String packageName, String typeQualifiedName) throws JavaModelException {
-		return findType(packageName, typeQualifiedName, DefaultWorkingCopyOwner.PRIMARY);
+	public IType findType(String fullyQualifiedName, IProgressMonitor progressMonitor) throws JavaModelException {
+		return findType(fullyQualifiedName, DefaultWorkingCopyOwner.PRIMARY, progressMonitor);
 	}
 
-	/**
-	 * @see IJavaProject#findType(String, String, WorkingCopyOwner)
+	/*
+	 * Internal findType with instanciated name lookup
 	 */
-	public IType findType(String packageName, String typeQualifiedName, WorkingCopyOwner owner) throws JavaModelException {
-		NameLookup lookup = newNameLookup(owner);
-		return lookup.findType(
-			typeQualifiedName, 
-			packageName,
-			false,
-			NameLookup.ACCEPT_ALL);
-	}	
-
-	/**
-	 * @see IJavaProject#findType(String, WorkingCopyOwner)
-	 */
-	public IType findType(String fullyQualifiedName, WorkingCopyOwner owner) throws JavaModelException {
-		
-		NameLookup lookup = newNameLookup(owner);
-		IType type = lookup.findType(
+	IType findType(String fullyQualifiedName, NameLookup lookup, boolean considerSecondaryTypes, IProgressMonitor progressMonitor) throws JavaModelException {
+		NameLookup.Answer answer = lookup.findType(
 			fullyQualifiedName,
 			false,
-			NameLookup.ACCEPT_ALL);
-		if (type == null) {
+			NameLookup.ACCEPT_ALL,
+			considerSecondaryTypes,
+			true, /* wait for indexes (only if consider secondary types)*/
+			false/*don't check restrictions*/,
+			progressMonitor);
+		if (answer == null) {
 			// try to find enclosing type
 			int lastDot = fullyQualifiedName.lastIndexOf('.');
 			if (lastDot == -1) return null;
-			type = this.findType(fullyQualifiedName.substring(0, lastDot));
+			IType type = findType(fullyQualifiedName.substring(0, lastDot), lookup, considerSecondaryTypes, progressMonitor);
 			if (type != null) {
 				type = type.getType(fullyQualifiedName.substring(lastDot+1));
 				if (!type.exists()) {
 					return null;
 				}
 			}
+			return type;
 		}
-		return type;
+		return answer.type;
 	}
+	/**
+	 * @see IJavaProject#findType(String, String)
+	 */
+	public IType findType(String packageName, String typeQualifiedName) throws JavaModelException {
+		return findType(packageName, typeQualifiedName, DefaultWorkingCopyOwner.PRIMARY);
+	}
+	/**
+	 * @see IJavaProject#findType(String, String, IProgressMonitor)
+	 */
+	public IType findType(String packageName, String typeQualifiedName, IProgressMonitor progressMonitor) throws JavaModelException {
+		return findType(packageName, typeQualifiedName, DefaultWorkingCopyOwner.PRIMARY, progressMonitor);
+	}	
+	/*
+	 * Internal findType with instanciated name lookup
+	 */
+	IType findType(String packageName, String typeQualifiedName, NameLookup lookup, boolean considerSecondaryTypes, IProgressMonitor progressMonitor) throws JavaModelException {
+		NameLookup.Answer answer = lookup.findType(
+			typeQualifiedName, 
+			packageName,
+			false,
+			NameLookup.ACCEPT_ALL,
+			considerSecondaryTypes,
+			true, // wait for indexes (in case we need to consider secondary types)
+			false/*don't check restrictions*/,
+			progressMonitor);
+		return answer == null ? null : answer.type;
+	}	
+	/**
+	 * @see IJavaProject#findType(String, String, WorkingCopyOwner)
+	 */
+	public IType findType(String packageName, String typeQualifiedName, WorkingCopyOwner owner) throws JavaModelException {
+		NameLookup lookup = newNameLookup(owner);
+		return findType(
+			packageName,
+			typeQualifiedName, 
+			lookup,
+			false, // do not consider secondary types
+			null);
+	}	
 	
 	/**
+	 * @see IJavaProject#findType(String, String, WorkingCopyOwner, IProgressMonitor)
+	 */
+	public IType findType(String packageName, String typeQualifiedName, WorkingCopyOwner owner, IProgressMonitor progressMonitor) throws JavaModelException {
+		NameLookup lookup = newNameLookup(owner);
+		return findType(
+			packageName,
+			typeQualifiedName, 
+			lookup,
+			true, // consider secondary types
+			progressMonitor);
+	}
+
+	/**
+	 * @see IJavaProject#findType(String, WorkingCopyOwner)
+	 */
+	public IType findType(String fullyQualifiedName, WorkingCopyOwner owner) throws JavaModelException {
+		NameLookup lookup = newNameLookup(owner);
+		return findType(fullyQualifiedName, lookup, false, null);
+	}	
+
+	/**
+	 * @see IJavaProject#findType(String, WorkingCopyOwner, IProgressMonitor)
+	 */
+	public IType findType(String fullyQualifiedName, WorkingCopyOwner owner, IProgressMonitor progressMonitor) throws JavaModelException {
+		NameLookup lookup = newNameLookup(owner);
+		return findType(fullyQualifiedName, lookup, true, progressMonitor);
+	}
+
+	/**
 	 * Remove all markers denoting classpath problems
 	 */ //TODO (philippe) should improve to use a bitmask instead of booleans (CYCLE, FORMAT, VALID)
 	protected void flushClasspathProblemMarkers(boolean flushCycleMarkers, boolean flushClasspathFormatMarkers) {
@@ -1178,108 +1300,7 @@
 			}
 		}
 	}
-
-	/*
-	 * Force the project to reload its <code>.classpath</code> file from disk and update the classpath accordingly.
-	 * Usually, a change to the <code>.classpath</code> file is automatically noticed and reconciled at the next 
-	 * resource change notification event. If required to consider such a change prior to the next automatic
-	 * refresh, then this functionnality should be used to trigger a refresh. In particular, if a change to the file is performed,
-	 * during an operation where this change needs to be reflected before the operation ends, then an explicit refresh is
-	 * necessary.
-	 * Note that classpath markers are NOT created.
-	 * 
-	 * @param monitor a progress monitor for reporting operation progress
-	 * @exception JavaModelException if the classpath could not be updated. Reasons
-	 * include:
-	 * <ul>
-	 * <li> This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
-	 * <li> Two or more entries specify source roots with the same or overlapping paths (NAME_COLLISION)
-	 * <li> A entry of kind <code>CPE_PROJECT</code> refers to this project (INVALID_PATH)
-	 *  <li>This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
-	 *	<li>The output location path refers to a location not contained in this project (<code>PATH_OUTSIDE_PROJECT</code>)
-	 *	<li>The output location path is not an absolute path (<code>RELATIVE_PATH</code>)
-	 *  <li>The output location path is nested inside a package fragment root of this project (<code>INVALID_PATH</code>)
-	 * <li> The classpath is being modified during resource change event notification (CORE_EXCEPTION)
-	 * </ul>
-	 */
-	protected void forceClasspathReload(IProgressMonitor monitor) throws JavaModelException {
-
-		if (monitor != null && monitor.isCanceled()) return;
-		
-		// check if any actual difference
-		boolean wasSuccessful = false; // flag recording if .classpath file change got reflected
-		try {
-			// force to (re)read the property file
-			IClasspathEntry[] fileEntries = readClasspathFile(false/*don't create markers*/, false/*don't log problems*/);
-			if (fileEntries == null) {
-				return; // could not read, ignore 
-			}
-			JavaModelManager.PerProjectInfo info = getPerProjectInfo();
-			if (info.rawClasspath != null) { // if there is an in-memory classpath
-				if (isClasspathEqualsTo(info.rawClasspath, info.outputLocation, fileEntries)) {
-					wasSuccessful = true;
-					return;
-				}
-			}
-
-			// will force an update of the classpath/output location based on the file information
-			// extract out the output location
-			IPath outputLocation = SetClasspathOperation.DO_NOT_SET_OUTPUT; 
-			if (fileEntries != null && fileEntries.length > 0) {
-				IClasspathEntry entry = fileEntries[fileEntries.length - 1];
-				if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) {
-					outputLocation = entry.getPath();
-					IClasspathEntry[] copy = new IClasspathEntry[fileEntries.length - 1];
-					System.arraycopy(fileEntries, 0, copy, 0, copy.length);
-					fileEntries = copy;
-				}
-			}
-			IClasspathEntry[] oldResolvedClasspath = info.resolvedClasspath;
-			setRawClasspath(
-				fileEntries, 
-				outputLocation,
-				monitor, 
-				!ResourcesPlugin.getWorkspace().isTreeLocked(), // canChangeResource
-				oldResolvedClasspath != null ? oldResolvedClasspath : getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/),
-				true, // needValidation
-				false); // no need to save
-			
-			// if reach that far, the classpath file change got absorbed
-			wasSuccessful = true;
-		} catch (RuntimeException e) {
-			// setRawClasspath might fire a delta, and a listener may throw an exception
-			if (this.project.isAccessible()) {
-				Util.log(e, "Could not set classpath for "+ getPath()); //$NON-NLS-1$
-			}
-			throw e; // rethrow 
-		} catch (JavaModelException e) { // CP failed validation
-			if (!ResourcesPlugin.getWorkspace().isTreeLocked()) {
-				if (this.project.isAccessible()) {
-					if (e.getJavaModelStatus().getException() instanceof CoreException) {
-						// happens if the .classpath could not be written to disk
-						createClasspathProblemMarker(new JavaModelStatus(
-								IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
-								Messages.bind(Messages.classpath_couldNotWriteClasspathFile, new String[] {getElementName(), e.getMessage()}))); 
-					} else {
-						createClasspathProblemMarker(new JavaModelStatus(
-								IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
-								Messages.bind(Messages.classpath_invalidClasspathInClasspathFile, new String[] {getElementName(), e.getMessage()}))); 
-					}			
-				}
-			}
-			throw e; // rethrow
-		} finally {
-			if (!wasSuccessful) { 
-				try {
-					this.getPerProjectInfo().updateClasspathInformation(JavaProject.INVALID_CLASSPATH);
-					updatePackageFragmentRoots();
-				} catch (JavaModelException e) {
-					// ignore
-				}
-			}
-		}
-	}	
-
+	
 	/** 
 	 * Returns the set of patterns corresponding to this project visibility given rules
 	 * @return an array of IPath or null if none
@@ -1307,10 +1328,10 @@
 
 		return getAllPackageFragmentRoots(null /*no reverse map*/);
 	}
-	
+
 	public IPackageFragmentRoot[] getAllPackageFragmentRoots(Map rootToResolvedEntries) throws JavaModelException {
 
-		return computePackageFragmentRoots(getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/), true/*retrieveExportedRoots*/, rootToResolvedEntries);
+		return computePackageFragmentRoots(getResolvedClasspath(), true/*retrieveExportedRoots*/, rootToResolvedEntries);
 	}
 
 	/**
@@ -1320,18 +1341,17 @@
 	 * @return IClasspathEntry
 	 * @throws JavaModelException
 	 */
-	public IClasspathEntry getClasspathEntryFor(IPath path)
-		throws JavaModelException {
-
-		IClasspathEntry[] entries = getExpandedClasspath(true);
-		for (int i = 0; i < entries.length; i++) {
-			if (entries[i].getPath().equals(path)) {
-				return entries[i];
-			}
-		}
-		return null;
+	public IClasspathEntry getClasspathEntryFor(IPath path) throws JavaModelException {
+		getResolvedClasspath(); // force resolution
+		PerProjectInfo perProjectInfo = getPerProjectInfo();
+		if (perProjectInfo == null)
+			return null;
+		Map rootPathToResolvedEntries = perProjectInfo.rootPathToResolvedEntries;
+		if (rootPathToResolvedEntries == null)
+			return null;
+		return (IClasspathEntry) rootPathToResolvedEntries.get(path);
 	}
-
+	
 	/*
 	 * Returns the cycle marker associated with this project or null if none.
 	 */
@@ -1353,49 +1373,66 @@
 		return null;
 	}
 
-	/**
-	 * Returns the project custom preference pool.
-	 * Project preferences may include custom encoding.
-	 * @return IEclipsePreferences
-	 */
-	public IEclipsePreferences getEclipsePreferences(){
-		if (!JavaProject.hasJavaNature(this.project)) return null;
-		// Get cached preferences if exist
-		JavaModelManager.PerProjectInfo perProjectInfo = JavaModelManager.getJavaModelManager().getPerProjectInfo(this.project, true);
-		if (perProjectInfo.preferences != null) return perProjectInfo.preferences;
-		// Init project preferences
-		IScopeContext context = new ProjectScope(getProject());
-		final IEclipsePreferences eclipsePreferences = context.getNode(JavaCore.PLUGIN_ID);
-		updatePreferences(eclipsePreferences);
-		perProjectInfo.preferences = eclipsePreferences;
-
-		// Listen to node removal from parent in order to reset cache (see bug 68993)
-		IEclipsePreferences.INodeChangeListener nodeListener = new IEclipsePreferences.INodeChangeListener() {
-			public void added(IEclipsePreferences.NodeChangeEvent event) {
-				// do nothing
-			}
-			public void removed(IEclipsePreferences.NodeChangeEvent event) {
-				if (event.getChild() == eclipsePreferences) {
-					JavaModelManager.getJavaModelManager().resetProjectPreferences(JavaProject.this);
-				}
-			}
-		};
-		((IEclipsePreferences) eclipsePreferences.parent()).addNodeChangeListener(nodeListener);
-
-		// Listen to preference changes
-		IEclipsePreferences.IPreferenceChangeListener preferenceListener = new IEclipsePreferences.IPreferenceChangeListener() {
-			public void preferenceChange(IEclipsePreferences.PreferenceChangeEvent event) {
-				JavaModelManager.getJavaModelManager().resetProjectOptions(JavaProject.this);
-			}
-		};
-		eclipsePreferences.addPreferenceChangeListener(preferenceListener);
-		return eclipsePreferences;
-	}
-
+		/**
+    	 * Returns the project custom preference pool.
+    	 * Project preferences may include custom encoding.
+    	 * @return IEclipsePreferences
+    	 */
+    	public IEclipsePreferences getEclipsePreferences(){
+    		if (!JavaProject.hasJavaNature(this.project)) return null;
+    		// Get cached preferences if exist
+    		JavaModelManager.PerProjectInfo perProjectInfo = JavaModelManager.getJavaModelManager().getPerProjectInfo(this.project, true);
+    		if (perProjectInfo.preferences != null) return perProjectInfo.preferences;
+    		// Init project preferences
+    		IScopeContext context = new ProjectScope(getProject());
+    		final IEclipsePreferences eclipsePreferences = context.getNode(JavaCore.PLUGIN_ID);
+    		updatePreferences(eclipsePreferences);
+    		perProjectInfo.preferences = eclipsePreferences;
+    
+    		// Listen to node removal from parent in order to reset cache (see bug 68993)
+    		IEclipsePreferences.INodeChangeListener nodeListener = new IEclipsePreferences.INodeChangeListener() {
+    			public void added(IEclipsePreferences.NodeChangeEvent event) {
+    				// do nothing
+    			}
+    			public void removed(IEclipsePreferences.NodeChangeEvent event) {
+    				if (event.getChild() == eclipsePreferences) {
+    					JavaModelManager.getJavaModelManager().resetProjectPreferences(JavaProject.this);
+    				}
+    			}
+    		};
+    		((IEclipsePreferences) eclipsePreferences.parent()).addNodeChangeListener(nodeListener);
+    
+    		// Listen to preference changes
+    		IEclipsePreferences.IPreferenceChangeListener preferenceListener = new IEclipsePreferences.IPreferenceChangeListener() {
+    			public void preferenceChange(IEclipsePreferences.PreferenceChangeEvent event) {
+    				String propertyName = event.getKey();
+					JavaModelManager manager = JavaModelManager.getJavaModelManager();
+					if (propertyName.startsWith(JavaCore.PLUGIN_ID)) {
+						if (propertyName.equals(JavaCore.CORE_JAVA_BUILD_CLEAN_OUTPUT_FOLDER) ||
+							propertyName.equals(JavaCore.CORE_JAVA_BUILD_RESOURCE_COPY_FILTER) ||
+							propertyName.equals(JavaCore.CORE_JAVA_BUILD_DUPLICATE_RESOURCE) ||
+							propertyName.equals(JavaCore.CORE_JAVA_BUILD_RECREATE_MODIFIED_CLASS_FILES_IN_OUTPUT_FOLDER) ||
+							propertyName.equals(JavaCore.CORE_JAVA_BUILD_INVALID_CLASSPATH) ||
+							propertyName.equals(JavaCore.CORE_ENABLE_CLASSPATH_EXCLUSION_PATTERNS) ||
+							propertyName.equals(JavaCore.CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS) ||
+							propertyName.equals(JavaCore.CORE_INCOMPLETE_CLASSPATH) ||
+							propertyName.equals(JavaCore.CORE_CIRCULAR_CLASSPATH) ||
+							propertyName.equals(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL))
+						{
+							manager.deltaState.addClasspathValidation(JavaProject.this);
+						}
+						manager.resetProjectOptions(JavaProject.this);
+    				}
+    			}
+    		};
+    		eclipsePreferences.addPreferenceChangeListener(preferenceListener);
+    		return eclipsePreferences;
+    	}
+		
 	public String getElementName() {
 		return this.project.getName();
 	}
-	
+
 	/**
 	 * @see IJavaElement
 	 */
@@ -1407,39 +1444,18 @@
 	 * This is a helper method returning the expanded classpath for the project, as a list of classpath entries, 
 	 * where all classpath variable entries have been resolved and substituted with their final target entries.
 	 * All project exports have been appended to project entries.
-	 * @param ignoreUnresolvedVariable boolean
 	 * @return IClasspathEntry[]
 	 * @throws JavaModelException
 	 */
-	public IClasspathEntry[] getExpandedClasspath(boolean ignoreUnresolvedVariable)	throws JavaModelException {
+	public IClasspathEntry[] getExpandedClasspath()	throws JavaModelException {
 			
-			return getExpandedClasspath(ignoreUnresolvedVariable, false/*don't create markers*/, null, null);
-	}
-		
-	/**
-	 * Internal variant which can create marker on project for invalid entries,
-	 * it will also perform classpath expansion in presence of project prerequisites
-	 * exporting their entries.
-	 * @param ignoreUnresolvedVariable boolean
-	 * @param generateMarkerOnError boolean
-	 * @param preferredClasspaths Map
-	 * @param preferredOutputs Map
-	 * @return IClasspathEntry[]
-	 * @throws JavaModelException
-	 */
-	public IClasspathEntry[] getExpandedClasspath(
-		boolean ignoreUnresolvedVariable,
-		boolean generateMarkerOnError,
-		Map preferredClasspaths,
-		Map preferredOutputs) throws JavaModelException {
-	
-		ObjectVector accumulatedEntries = new ObjectVector();		
-		computeExpandedClasspath(null, ignoreUnresolvedVariable, generateMarkerOnError, new HashSet(5), accumulatedEntries, preferredClasspaths, preferredOutputs);
-		
-		IClasspathEntry[] expandedPath = new IClasspathEntry[accumulatedEntries.size()];
-		accumulatedEntries.copyInto(expandedPath);
-
-		return expandedPath;
+			ObjectVector accumulatedEntries = new ObjectVector();		
+			computeExpandedClasspath(null, new HashSet(5), accumulatedEntries);
+			
+			IClasspathEntry[] expandedPath = new IClasspathEntry[accumulatedEntries.size()];
+			accumulatedEntries.copyInto(expandedPath);
+			
+			return expandedPath;
 	}
 
 	/**
@@ -1503,7 +1519,7 @@
 		}
 		return -1;
 	}
-
+	
 	/**
 	 * Convenience method that returns the specific type of info for a Java project.
 	 */
@@ -1520,7 +1536,7 @@
 
 		return ((JavaProjectElementInfo) getElementInfo()).getNonJavaResources(this);
 	}
-
+	
 	/**
 	 * @see org.eclipse.jdt.core.IJavaProject#getOption(String, boolean)
 	 */	
@@ -1577,10 +1593,11 @@
 
 		// Inherit from JavaCore options if specified
 		if (inheritJavaCoreOptions) {
-			Iterator propertyNames = projectOptions.keySet().iterator();
+			Iterator propertyNames = projectOptions.entrySet().iterator();
 			while (propertyNames.hasNext()) {
-				String propertyName = (String) propertyNames.next();
-				String propertyValue = (String) projectOptions.get(propertyName);
+				Map.Entry entry = (Map.Entry) propertyNames.next();
+				String propertyName = (String) entry.getKey();
+				String propertyValue = (String) entry.getValue();
 				if (propertyValue != null && optionNames.contains(propertyName)){
 					options.put(propertyName, propertyValue.trim());
 				}
@@ -1594,31 +1611,21 @@
 	 * @see IJavaProject
 	 */
 	public IPath getOutputLocation() throws JavaModelException {
-		// Do not create marker but log problems while getting output location
-		return this.getOutputLocation(false, true);
-	}
-	
-	/**
-	 * @param createMarkers boolean
-	 * @param logProblems boolean
-	 * @return IPath
-	 * @throws JavaModelException
-	 */
-	public IPath getOutputLocation(boolean createMarkers, boolean logProblems) throws JavaModelException {
-
-		JavaModelManager.PerProjectInfo perProjectInfo = getPerProjectInfo();
+		// Do not create marker while getting output location
+		JavaModelManager.PerProjectInfo perProjectInfo = this.getPerProjectInfo();
 		IPath outputLocation = perProjectInfo.outputLocation;
 		if (outputLocation != null) return outputLocation;
-
+		
 		// force to read classpath - will position output location as well
-		this.getRawClasspath(createMarkers, logProblems);
+		getRawClasspath();
+		
 		outputLocation = perProjectInfo.outputLocation;
 		if (outputLocation == null) {
-			return defaultOutputLocation();
+			return this.defaultOutputLocation();
 		}
 		return outputLocation;
 	}
-
+	
 	/**
 	 * @param path IPath
 	 * @return A handle to the package fragment root identified by the given path.
@@ -1649,12 +1656,16 @@
 						return getPackageFragmentRoot(resource);
 					}
 					return getPackageFragmentRoot0(path);
+				} else if (segmentCount == 1) {
+					// lib being another project
+					return getPackageFragmentRoot(this.project.getWorkspace().getRoot().getProject(path.lastSegment()));
 				} else {
+					// lib being a folder
 					return getPackageFragmentRoot(this.project.getWorkspace().getRoot().getFolder(path));
 				}
 		}
 	}
-	
+
 	/**
 	 * @see IJavaProject
 	 */
@@ -1670,7 +1681,7 @@
 			case IResource.FOLDER:
 				return new PackageFragmentRoot(resource, this);
 			case IResource.PROJECT:
-				return new PackageFragmentRoot(resource, this); //$NON-NLS-1$
+				return new PackageFragmentRoot(resource, this);
 			default:
 				return null;
 		}
@@ -1683,7 +1694,7 @@
 
 		return getPackageFragmentRoot0(JavaProject.canonicalizedPath(new Path(jarPath)));
 	}
-	
+
 	/*
 	 * no path canonicalization
 	 */
@@ -1719,27 +1730,7 @@
 	public IPackageFragmentRoot[] getPackageFragmentRoots(IClasspathEntry entry) {
 		return findPackageFragmentRoots(entry);
 	}
-
-	/**
-	 * Returns the package fragment root prefixed by the given path, or
-	 * an empty collection if there are no such elements in the model.
-	 */
-	protected IPackageFragmentRoot[] getPackageFragmentRoots(IPath path)
-
-		throws JavaModelException {
-		IPackageFragmentRoot[] roots = getAllPackageFragmentRoots();
-		ArrayList matches = new ArrayList();
-
-		for (int i = 0; i < roots.length; ++i) {
-			if (path.isPrefixOf(roots[i].getPath())) {
-				matches.add(roots[i]);
-			}
-		}
-		IPackageFragmentRoot[] copy = new IPackageFragmentRoot[matches.size()];
-		matches.toArray(copy);
-		return copy;
-	}
-
+	
 	/**
 	 * @see IJavaProject
 	 */
@@ -1772,22 +1763,22 @@
 		IPackageFragment[] fragments = new IPackageFragment[frags.size()];
 		frags.toArray(fragments);
 		return fragments;
-	}
-	
+	}	
+
 	/**
 	 * @see IJavaElement
 	 */
 	public IPath getPath() {
 		return this.project.getFullPath();
 	}
-	
+
 	public JavaModelManager.PerProjectInfo getPerProjectInfo() throws JavaModelException {
 		return JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(this.project);
 	}
 
 	private IPath getPluginWorkingLocation() {
 		return this.project.getWorkingLocation(JavaCore.PLUGIN_ID);
-	}	
+	}
 
 	/**
 	 * Returns the project custom preference pool.
@@ -1812,273 +1803,90 @@
 		*/
 		return new Preferences();
 	}
-
+	
 	/**
 	 * @see IJavaProject#getProject()
 	 */
 	public IProject getProject() {
 		return this.project;
 	}
+	
+	public ProjectCache getProjectCache() throws JavaModelException {
+		return ((JavaProjectElementInfo) getElementInfo()).getProjectCache(this);
+	}
 
 	/**
 	 * @see IJavaProject
 	 */
 	public IClasspathEntry[] getRawClasspath() throws JavaModelException {
-		// Do not create marker but log problems while getting raw classpath
-		return getRawClasspath(false, true);
-	}
+		JavaModelManager.PerProjectInfo perProjectInfo = getPerProjectInfo();
+		IClasspathEntry[] classpath = perProjectInfo.rawClasspath;
+		if (classpath != null) return classpath;
+		
+		classpath = perProjectInfo.readAndCacheClasspath(this);
 
-	/*
-	 * Internal variant allowing to parameterize problem creation/logging
-	 */
-	public IClasspathEntry[] getRawClasspath(boolean createMarkers, boolean logProblems) throws JavaModelException {
-
-		JavaModelManager.PerProjectInfo perProjectInfo = null;
-		IClasspathEntry[] classpath;
-		if (createMarkers) {
-			this.flushClasspathProblemMarkers(false/*cycle*/, true/*format*/);
-			classpath = this.readClasspathFile(createMarkers, logProblems);
-		} else {
-			perProjectInfo = getPerProjectInfo();
-			classpath = perProjectInfo.rawClasspath;
-			if (classpath != null) return classpath;
-			classpath = this.readClasspathFile(createMarkers, logProblems);
-		}
-		// extract out the output location
-		IPath outputLocation = null;
-		if (classpath != null && classpath.length > 0) {
-			IClasspathEntry entry = classpath[classpath.length - 1];
-			if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) {
-				outputLocation = entry.getPath();
-				IClasspathEntry[] copy = new IClasspathEntry[classpath.length - 1];
-				System.arraycopy(classpath, 0, copy, 0, copy.length);
-				classpath = copy;
-			}
-		}
-		if (classpath == null) {
+		if (classpath == JavaProject.INVALID_CLASSPATH)
 			return defaultClasspath();
-		}
-		/* Disable validate: classpath can contain CP variables and container that need to be resolved 
-		if (classpath != INVALID_CLASSPATH
-				&& !JavaConventions.validateClasspath(this, classpath, outputLocation).isOK()) {
-			classpath = INVALID_CLASSPATH;
-		}
-		*/
-		if (!createMarkers) {
-			perProjectInfo.rawClasspath = classpath;
-			perProjectInfo.outputLocation = outputLocation;
-		}
+		
 		return classpath;
 	}
+	
 	/**
 	 * @see IJavaProject#getRequiredProjectNames()
 	 */
 	public String[] getRequiredProjectNames() throws JavaModelException {
 
-		return this.projectPrerequisites(getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/));
-	}
-
-	/**
-	 * @see IJavaProject
-	 */
-	public IClasspathEntry[] getResolvedClasspath(boolean ignoreUnresolvedEntry)
-		throws JavaModelException {
-
-		return 
-			getResolvedClasspath(
-				ignoreUnresolvedEntry, 
-				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.
-	 * If requested, return a special classpath (RESOLUTION_IN_PROGRESS) if the classpath is being resolved.
-	 */
-	public IClasspathEntry[] getResolvedClasspath(
-		boolean ignoreUnresolvedEntry,
-		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;
-				} 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 rawReverseMap = perProjectInfo == null ? null : new HashMap(5);
-		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,
-				rawReverseMap);
-		} finally {
-			if (nullOldResolvedCP) perProjectInfo.resolvedClasspath = null;
-		}
-
-		if (perProjectInfo != null){
-			if (perProjectInfo.rawClasspath == null // .classpath file could not be read
-				&& generateMarkerOnError 
-				&& JavaProject.hasJavaNature(this.project)) {
-					// flush .classpath format markers (bug 39877), but only when file cannot be read (bug 42366)
-					this.flushClasspathProblemMarkers(false, true);
-					this.createClasspathProblemMarker(new JavaModelStatus(
-						IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
-						Messages.bind(Messages.classpath_cannotReadClasspathFile, this.getElementName()))); 
-			}
-
-			perProjectInfo.resolvedClasspath = resolvedPath;
-			perProjectInfo.resolvedPathToRawEntries = rawReverseMap;
-			manager.setClasspathBeingResolved(this, false);
-		}
-		return resolvedPath;
+		return this.projectPrerequisites(getResolvedClasspath());
 	}
 	
-	/**
-	 * Internal variant which can process any arbitrary classpath
-	 * @param classpathEntries IClasspathEntry[] 
-	 * @param projectOutputLocation IPath
-	 * @param ignoreUnresolvedEntry boolean
-	 * @param generateMarkerOnError boolean
-	 * @param rawReverseMap Map
-	 * @return IClasspathEntry[] 
-	 * @throws JavaModelException
+	/*
+	 * Returns the cached resolved classpath, or compute it ignoring unresolved entries and cache it.
 	 */
-	public IClasspathEntry[] getResolvedClasspath(
-		IClasspathEntry[] classpathEntries,
-		IPath projectOutputLocation, // only set if needing full classpath validation (and markers)
-		boolean ignoreUnresolvedEntry, // if unresolved entries are met, should it trigger initializations
-		boolean generateMarkerOnError,
-		Map rawReverseMap) // can be null if not interested in reverse mapping
-		throws JavaModelException {
+	public IClasspathEntry[] getResolvedClasspath() throws JavaModelException {
+		PerProjectInfo perProjectInfo = getPerProjectInfo();
+		if (perProjectInfo.resolvedClasspath == null)
+			resolveClasspath(perProjectInfo);
+		return perProjectInfo.resolvedClasspath;
+	}
 
-		IJavaModelStatus status;
-		if (generateMarkerOnError){
-			flushClasspathProblemMarkers(false, false);
+	/**
+	 * @see IJavaProject
+	 */
+	public IClasspathEntry[] getResolvedClasspath(boolean ignoreUnresolvedEntry) throws JavaModelException {
+		if  (JavaModelManager.getJavaModelManager().isClasspathBeingResolved(this)) {
+			if (JavaModelManager.CP_RESOLVE_VERBOSE_ADVANCED)
+				verbose_reentering_classpath_resolution();
+		    return RESOLUTION_IN_PROGRESS;
 		}
+		PerProjectInfo perProjectInfo = getPerProjectInfo();
 
-		int length = classpathEntries.length;
-		ArrayList resolvedEntries = new ArrayList();
+		// use synchronized block to ensure consistency
+		IClasspathEntry[] resolvedClasspath;
+		IJavaModelStatus unresolvedEntryStatus;
+		synchronized (perProjectInfo) {
+			resolvedClasspath = perProjectInfo.resolvedClasspath;
+			unresolvedEntryStatus = perProjectInfo.unresolvedEntryStatus;
+		}
 		
-		for (int i = 0; i < length; i++) {
-
-			IClasspathEntry rawEntry = classpathEntries[i];
-			IPath resolvedPath;
-			status = null;
-			
-			/* validation if needed */
-			if (generateMarkerOnError || !ignoreUnresolvedEntry) {
-				status = ClasspathEntry.validateClasspathEntry(this, rawEntry, false /*ignore src attach*/, false /*do not recurse in containers, done later to accumulate*/);
-				if (generateMarkerOnError && !status.isOK()) createClasspathProblemMarker(status);
+		if (resolvedClasspath == null 
+				|| (unresolvedEntryStatus != null && !unresolvedEntryStatus.isOK())) { // force resolution to ensure initializers are run again
+			resolveClasspath(perProjectInfo);
+			synchronized (perProjectInfo) {
+				resolvedClasspath = perProjectInfo.resolvedClasspath;
+				unresolvedEntryStatus = perProjectInfo.unresolvedEntryStatus;
 			}
-
-			switch (rawEntry.getEntryKind()){
-				
-				case IClasspathEntry.CPE_VARIABLE :
-				
-					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 {
-						if (rawReverseMap != null) {
-							if (rawReverseMap.get(resolvedPath = resolvedEntry.getPath()) == null) rawReverseMap.put(resolvedPath , rawEntry);
-						}
-						resolvedEntries.add(resolvedEntry);
-					}
-					break; 
-
-				case IClasspathEntry.CPE_CONTAINER :
-				
-					IClasspathContainer container = JavaCore.getClasspathContainer(rawEntry.getPath(), this);
-					if (container == null){
-						if (!ignoreUnresolvedEntry) throw new JavaModelException(status);
-						break;
-					}
-
-					IClasspathEntry[] containerEntries = container.getClasspathEntries();
-					if (containerEntries == null) break;
-
-					// container was bound
-					for (int j = 0, containerLength = containerEntries.length; j < containerLength; j++){
-						ClasspathEntry cEntry = (ClasspathEntry) containerEntries[j];
-						if (generateMarkerOnError) {
-							IJavaModelStatus containerStatus = ClasspathEntry.validateClasspathEntry(this, cEntry, false, true /*recurse*/);
-							if (!containerStatus.isOK()) createClasspathProblemMarker(containerStatus);
-						}
-						// if container is exported or restricted, then its nested entries must in turn be exported  (21749) and/or propagate restrictions
-						cEntry = cEntry.combineWith((ClasspathEntry) rawEntry);
-						if (rawReverseMap != null) {
-							if (rawReverseMap.get(resolvedPath = cEntry.getPath()) == null) rawReverseMap.put(resolvedPath , rawEntry);
-						}
-						resolvedEntries.add(cEntry);
-					}
-					break;
-										
-				default :
-
-					if (rawReverseMap != null) {
-						if (rawReverseMap.get(resolvedPath = rawEntry.getPath()) == null) rawReverseMap.put(resolvedPath , rawEntry);
-					}
-					resolvedEntries.add(rawEntry);
-				
-			}					
 		}
+		if (!ignoreUnresolvedEntry && unresolvedEntryStatus != null && !unresolvedEntryStatus.isOK())
+			throw new JavaModelException(unresolvedEntryStatus);
+		return resolvedClasspath;
+	}
 
-		IClasspathEntry[] resolvedPath = new IClasspathEntry[resolvedEntries.size()];
-		resolvedEntries.toArray(resolvedPath);
-
-		if (generateMarkerOnError && projectOutputLocation != null) {
-			status = ClasspathEntry.validateClasspath(this, resolvedPath, projectOutputLocation);
-			if (!status.isOK()) createClasspathProblemMarker(status);
-		}
-		return resolvedPath;
+	private void verbose_reentering_classpath_resolution() {
+		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$
 	}
 
 	/**
@@ -2106,7 +1914,7 @@
 		if (rscFile.exists()) {
 			byte[] bytes = Util.getResourceContentsAsByteArray(rscFile);
 			try {
-				property = new String(bytes, "UTF-8"); //$NON-NLS-1$ // .classpath always encoded with UTF-8
+				property = new String(bytes, org.eclipse.jdt.internal.compiler.util.Util.UTF_8); // .classpath always encoded with UTF-8
 			} catch (UnsupportedEncodingException e) {
 				Util.log(e, "Could not read .classpath with UTF-8 encoding"); //$NON-NLS-1$
 				// fallback to default
@@ -2116,26 +1924,29 @@
 			// when a project is imported, we get a first delta for the addition of the .project, but the .classpath is not accessible
 			// so default to using java.io.File
 			// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=96258
-			File file  = rscFile.getLocation().toFile();
-			if (file.exists()) {
-				byte[] bytes;
-				try {
-					bytes = org.eclipse.jdt.internal.compiler.util.Util.getFileByteContent(file);
-				} catch (IOException e) {
-					return null;
-				}
-				try {
-					property = new String(bytes, "UTF-8"); //$NON-NLS-1$ // .classpath always encoded with UTF-8
-				} catch (UnsupportedEncodingException e) {
-					Util.log(e, "Could not read .classpath with UTF-8 encoding"); //$NON-NLS-1$
-					// fallback to default
-					property = new String(bytes);
+			URI location = rscFile.getLocationURI();
+			if (location != null) {
+				File file = Util.toLocalFile(location, null/*no progress monitor available*/);
+				if (file != null && file.exists()) {
+					byte[] bytes;
+					try {
+						bytes = org.eclipse.jdt.internal.compiler.util.Util.getFileByteContent(file);
+					} catch (IOException e) {
+						return null;
+					}
+					try {
+						property = new String(bytes, org.eclipse.jdt.internal.compiler.util.Util.UTF_8); // .classpath always encoded with UTF-8
+					} catch (UnsupportedEncodingException e) {
+						Util.log(e, "Could not read .classpath with UTF-8 encoding"); //$NON-NLS-1$
+						// fallback to default
+						property = new String(bytes);
+					}
 				}
 			}
 		}
 		return property;
 	}
-
+	
 	/**
 	 * @see JavaElement
 	 */
@@ -2143,7 +1954,7 @@
 
 		return null;
 	}
-	
+
 	/**
 	 * @see IJavaElement
 	 */
@@ -2159,7 +1970,7 @@
 
 		return JavaModelManager.getJavaModelManager().getLastBuiltState(this.project, null) != null;
 	}
-
+	
 	/**
 	 * @see IJavaProject
 	 */
@@ -2170,15 +1981,15 @@
 		updateCycleParticipants(new ArrayList(2), cycleParticipants, ResourcesPlugin.getWorkspace().getRoot(), new HashSet(2), preferredClasspaths);
 		return !cycleParticipants.isEmpty();
 	}
-	
+
 	public boolean hasCycleMarker(){
 		return this.getCycleMarker() != null;
 	}
-
+	
 	public int hashCode() {
 		return this.project.hashCode();
 	}
-	
+
 	/**
 	 * Answers true if the project potentially contains any source. A project which has no source is immutable.
 	 * @return boolean
@@ -2200,38 +2011,6 @@
 		}
 		return false;
 	}
-
-	/**
-	 * Compare current classpath with given one to see if any different.
-	 * Note that the argument classpath contains its binary output.
-	 * @param newClasspath IClasspathEntry[]
-	 * @param newOutputLocation IPath
-	 * @param otherClasspathWithOutput IClasspathEntry[]
-	 * @return boolean
-	 */
-	public boolean isClasspathEqualsTo(IClasspathEntry[] newClasspath, IPath newOutputLocation, IClasspathEntry[] otherClasspathWithOutput) {
-
-		if (otherClasspathWithOutput == null || otherClasspathWithOutput.length == 0)
-			return false;
-
-		int length = otherClasspathWithOutput.length;
-		if (length != newClasspath.length + 1) 
-				// output is amongst file entries (last one)
-				return false;
-		
-		
-		// compare classpath entries
-		for (int i = 0; i < length - 1; i++) {
-			if (!otherClasspathWithOutput[i].equals(newClasspath[i]))
-				return false;
-		}
-		// compare binary outputs
-		IClasspathEntry output = otherClasspathWithOutput[length - 1];
-		if (output.getContentKind() != ClasspathEntry.K_OUTPUT
-				|| !output.getPath().equals(newOutputLocation))
-			return false;
-		return true;
-	}
 	
 
 	
@@ -2307,6 +2086,12 @@
 					// container was bound
 					for (int j = 0, containerLength = containerEntries.length; j < containerLength; j++){
 						IClasspathEntry resolvedEntry = containerEntries[j];
+						if (resolvedEntry == null) {
+							if (JavaModelManager.CP_RESOLVE_VERBOSE) {
+								JavaModelManager.getJavaModelManager().verbose_missbehaving_container(this, rawEntry.getPath(), containerEntries);
+							}
+							return false;
+						}
 						if (isOnClasspathEntry(elementPath, isFolderPath, isPackageFragmentRoot, resolvedEntry))
 							return true;
 					}					
@@ -2324,20 +2109,6 @@
 		return false;
 	}
 	
-	private boolean isOnClasspathEntry(IPath elementPath, boolean isFolderPath, boolean isPackageFragmentRoot, IClasspathEntry entry) {
-		IPath entryPath = entry.getPath();
-		if (isPackageFragmentRoot) {
-			// package fragment roots must match exactly entry pathes (no exclusion there)
-			if (entryPath.equals(elementPath))
-				return true;
-		} else {
-			if (entryPath.isPrefixOf(elementPath) 
-					&& !Util.isExcluded(elementPath, ((ClasspathEntry)entry).fullInclusionPatternChars(), ((ClasspathEntry)entry).fullExclusionPatternChars(), isFolderPath)) 
-				return true;
-		}
-		return false;
-	}
-
 	/*
 	 * @see IJavaProject
 	 */
@@ -2346,11 +2117,12 @@
 		IPath path = exactPath;
 		
 		// ensure that folders are only excluded if all of their children are excluded
-		boolean isFolderPath = resource.getType() == IResource.FOLDER;
+		int resourceType = resource.getType();
+		boolean isFolderPath = resourceType == IResource.FOLDER || resourceType == IResource.PROJECT;
 		
 		IClasspathEntry[] classpath;
 		try {
-			classpath = this.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
+			classpath = this.getResolvedClasspath();
 		} catch(JavaModelException e){
 			return false; // not a Java project
 		}
@@ -2368,14 +2140,24 @@
 		return false;
 	}
 
+	private boolean isOnClasspathEntry(IPath elementPath, boolean isFolderPath, boolean isPackageFragmentRoot, IClasspathEntry entry) {
+		IPath entryPath = entry.getPath();
+		if (isPackageFragmentRoot) {
+			// package fragment roots must match exactly entry pathes (no exclusion there)
+			if (entryPath.equals(elementPath))
+				return true;
+		} else {
+			if (entryPath.isPrefixOf(elementPath) 
+					&& !Util.isExcluded(elementPath, ((ClasspathEntry)entry).fullInclusionPatternChars(), ((ClasspathEntry)entry).fullExclusionPatternChars(), isFolderPath)) 
+				return true;
+		}
+		return false;
+	}
+
 	/**
 	 * load preferences from a shareable format (VCM-wise)
-	 * @deprecated WARNING, visibility of this method will be decreased soon
-	 * 	to private and won't be usable in the future.
-	 * @see <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=59258">bug 59258</a>
-	 * TODO (frederic) set visibility from public to private
 	 */
-	 public Preferences loadPreferences() {
+	 private Preferences loadPreferences() {
 	 	
 	 	Preferences preferences = new Preferences();
 	 	IPath projectMetaLocation = getPluginWorkingLocation();
@@ -2513,7 +2295,7 @@
 			
 		ArrayList prerequisites = new ArrayList();
 		// need resolution
-		entries = getResolvedClasspath(entries, null, true, false, null/*no reverse map*/);
+		entries = resolveClasspath(entries);
 		for (int i = 0, length = entries.length; i < length; i++) {
 			IClasspathEntry entry = entries[i];
 			if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) {
@@ -2530,51 +2312,85 @@
 		}
 	}
 
-
-	/**
-	 * Reads the .classpath file from disk and returns the list of entries it contains (including output location entry)
-	 * Returns null if .classfile is not present.
-	 * Returns INVALID_CLASSPATH if it has a format problem.
+	/*
+	 * Reads the classpath file entries of this project's .classpath file.
+	 * This includes the output entry.
+	 * As a side effect, unknown elements are stored in the given map (if not null)
+	 * Throws exceptions if the file cannot be accessed or is malformed.
 	 */
-	protected IClasspathEntry[] readClasspathFile(boolean createMarker, boolean logProblems) {
-
-		try {
-			String xmlClasspath = getSharedProperty(CLASSPATH_FILENAME);
-			if (xmlClasspath == null) {
-				if (createMarker && this.project.isAccessible()) {
-						this.createClasspathProblemMarker(new JavaModelStatus(
-							IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
-							Messages.bind(Messages.classpath_cannotReadClasspathFile, this.getElementName()))); 
-				}
-				return null;
+	public IClasspathEntry[] readFileEntriesWithException(Map unknownElements) throws CoreException, IOException, AssertionFailedException {
+		String xmlClasspath;
+		IFile rscFile = this.project.getFile(JavaProject.CLASSPATH_FILENAME);
+		if (rscFile.exists()) {
+			byte[] bytes = Util.getResourceContentsAsByteArray(rscFile);
+			try {
+				xmlClasspath = new String(bytes, org.eclipse.jdt.internal.compiler.util.Util.UTF_8); // .classpath always encoded with UTF-8
+			} catch (UnsupportedEncodingException e) {
+				Util.log(e, "Could not read .classpath with UTF-8 encoding"); //$NON-NLS-1$
+				// fallback to default
+				xmlClasspath = new String(bytes);
 			}
-			return decodeClasspath(xmlClasspath, createMarker, logProblems);
-		} catch(CoreException e) {
-			// file does not exist (or not accessible)
-			if (createMarker && this.project.isAccessible()) {
-					this.createClasspathProblemMarker(new JavaModelStatus(
-						IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
-						Messages.bind(Messages.classpath_cannotReadClasspathFile, this.getElementName()))); 
+		} else {
+			// when a project is imported, we get a first delta for the addition of the .project, but the .classpath is not accessible
+			// so default to using java.io.File
+			// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=96258
+			URI location = rscFile.getLocationURI();
+			if (location == null)
+				throw new IOException("Cannot obtain a location URI for " + rscFile); //$NON-NLS-1$
+			File file = Util.toLocalFile(location, null/*no progress monitor available*/);
+			if (file == null)
+				throw new IOException("Unable to fetch file from " + location); //$NON-NLS-1$
+			byte[] bytes;
+			try {
+				bytes = org.eclipse.jdt.internal.compiler.util.Util.getFileByteContent(file);
+			} catch (IOException e) {
+				if (!file.exists())
+					return defaultClasspath();
+				throw e;
 			}
-			if (logProblems) {
-				Util.log(e, 
-					"Exception while retrieving "+ this.getPath() //$NON-NLS-1$
-					+"/.classpath, will revert to default classpath"); //$NON-NLS-1$
+			try {
+				xmlClasspath = new String(bytes, org.eclipse.jdt.internal.compiler.util.Util.UTF_8); // .classpath always encoded with UTF-8
+			} catch (UnsupportedEncodingException e) {
+				Util.log(e, "Could not read .classpath with UTF-8 encoding"); //$NON-NLS-1$
+				// fallback to default
+				xmlClasspath = new String(bytes);
 			}
 		}
-		return null;
+		return decodeClasspath(xmlClasspath, unknownElements);
+	}
+
+	/*
+	 * Reads the classpath file entries of this project's .classpath file.
+	 * This includes the output entry.
+	 * As a side effect, unknown elements are stored in the given map (if not null)
+	 */
+	private IClasspathEntry[] readFileEntries(Map unkwownElements) {
+		try {
+			return readFileEntriesWithException(unkwownElements);
+		} catch (CoreException e) {
+			Util.log(e, "Exception while reading " + getPath().append(JavaProject.CLASSPATH_FILENAME)); //$NON-NLS-1$
+			return JavaProject.INVALID_CLASSPATH;
+		} catch (IOException e) {
+			Util.log(e, "Exception while reading " + getPath().append(JavaProject.CLASSPATH_FILENAME)); //$NON-NLS-1$
+			return JavaProject.INVALID_CLASSPATH;
+		} catch (AssertionFailedException e) {
+			Util.log(e, "Exception while reading " + getPath().append(JavaProject.CLASSPATH_FILENAME)); //$NON-NLS-1$
+			return JavaProject.INVALID_CLASSPATH;
+		}
 	}
 
 	/**
 	 * @see IJavaProject
 	 */
 	public IPath readOutputLocation() {
-
 		// Read classpath file without creating markers nor logging problems
-		IClasspathEntry[] classpath = this.readClasspathFile(false, false);
+		IClasspathEntry[] classpath = readFileEntries(null/*not interested in unknown elements*/);
+		if (classpath == JavaProject.INVALID_CLASSPATH)
+			return defaultOutputLocation();
+		
 		// extract the output location
 		IPath outputLocation = null;
-		if (classpath != null && classpath.length > 0) {
+		if (classpath.length > 0) {
 			IClasspathEntry entry = classpath[classpath.length - 1];
 			if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) {
 				outputLocation = entry.getPath();
@@ -2582,16 +2398,18 @@
 		}
 		return outputLocation;
 	}
-
+	
 	/**
 	 * @see IJavaProject
 	 */
 	public IClasspathEntry[] readRawClasspath() {
-
 		// Read classpath file without creating markers nor logging problems
-		IClasspathEntry[] classpath = this.readClasspathFile(false, false);
+		IClasspathEntry[] classpath = readFileEntries(null/*not interested in unknown elements*/);
+		if (classpath == JavaProject.INVALID_CLASSPATH)
+			return defaultClasspath();
+		
 		// discard the output location
-		if (classpath != null && classpath.length > 0) {
+		if (classpath.length > 0) {
 			IClasspathEntry entry = classpath[classpath.length - 1];
 			if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) {
 				IClasspathEntry[] copy = new IClasspathEntry[classpath.length - 1];
@@ -2631,6 +2449,159 @@
 		}
 	}
 
+	/*
+	 * Resolve the given raw classpath.
+	 */
+	public IClasspathEntry[] resolveClasspath(IClasspathEntry[] rawClasspath) throws JavaModelException {
+		ArrayList resolvedEntries = new ArrayList();
+		for (int i = 0, length = rawClasspath.length; i < length; i++) {
+			IClasspathEntry rawEntry = rawClasspath[i];
+			switch (rawEntry.getEntryKind()){
+				case IClasspathEntry.CPE_VARIABLE:
+					IClasspathEntry resolvedEntry = null;
+					try {
+						resolvedEntry = JavaCore.getResolvedClasspathEntry(rawEntry);
+					} catch (AssertionFailedException e) {
+						// Catch the assertion failure
+						// see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=55992
+						break;
+					}
+					if (resolvedEntry != null)
+						resolvedEntries.add(resolvedEntry);
+					break;
+				case IClasspathEntry.CPE_CONTAINER:
+					IClasspathContainer container = JavaCore.getClasspathContainer(rawEntry.getPath(), this);
+					if (container == null)
+						break;
+					IClasspathEntry[] containerEntries = container.getClasspathEntries();
+					if (containerEntries == null) 
+						break;
+
+					// container was bound
+					for (int j = 0, containerLength = containerEntries.length; j < containerLength; j++){
+						ClasspathEntry cEntry = (ClasspathEntry) containerEntries[j];
+						if (cEntry == null) {
+							if (JavaModelManager.CP_RESOLVE_VERBOSE) {
+								JavaModelManager.getJavaModelManager().verbose_missbehaving_container(this, rawEntry.getPath(), containerEntries);
+							}
+							break;
+						}
+						// if container is exported or restricted, then its nested entries must in turn be exported  (21749) and/or propagate restrictions
+						cEntry = cEntry.combineWith((ClasspathEntry) rawEntry);
+						resolvedEntries.add(cEntry);
+					}
+					break;
+				default:
+					resolvedEntries.add(rawEntry);
+			}
+		}
+		IClasspathEntry[] result = new IClasspathEntry[resolvedEntries.size()];
+		resolvedEntries.toArray(result);
+		return result;
+	}
+
+	/*
+	 * Resolve the given perProjectInfo's raw classpath and store the resolved classpath in the perProjectInfo.
+	 */
+	public void resolveClasspath(PerProjectInfo perProjectInfo) throws JavaModelException {
+		JavaModelManager manager = JavaModelManager.getJavaModelManager();
+		try {
+			manager.setClasspathBeingResolved(this, true);
+			
+			// get raw info inside a synchronized block to ensure that it is consistent
+			IClasspathEntry[] rawClasspath;
+			IPath outputLocation;
+			IJavaModelStatus rawClasspathStatus;
+			synchronized (perProjectInfo) {
+				rawClasspath= perProjectInfo.rawClasspath;
+				if (rawClasspath == null)
+					rawClasspath = perProjectInfo.readAndCacheClasspath(this);
+				outputLocation = perProjectInfo.outputLocation;
+				rawClasspathStatus = perProjectInfo.rawClasspathStatus;
+			}
+			 			
+			IJavaModelStatus unresolvedEntryStatus = JavaModelStatus.VERIFIED_OK;
+			HashMap rawReverseMap = new HashMap();
+			Map rootPathToResolvedEntries = new HashMap();
+			
+			ArrayList resolvedEntries = new ArrayList();
+			int length = rawClasspath.length;
+			for (int i = 0; i < length; i++) {
+	
+				IClasspathEntry rawEntry = rawClasspath[i];
+				IPath resolvedPath;
+				
+				switch (rawEntry.getEntryKind()){
+					
+					case IClasspathEntry.CPE_VARIABLE :
+						IClasspathEntry resolvedEntry = null;
+						try {
+							resolvedEntry = JavaCore.getResolvedClasspathEntry(rawEntry);
+						} catch (AssertionFailedException e) {
+							// Catch the assertion failure and set ststus instead
+							// see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=55992
+							unresolvedEntryStatus = new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, e.getMessage());
+							break;
+						}
+						if (resolvedEntry == null) {
+							unresolvedEntryStatus = new JavaModelStatus(IJavaModelStatusConstants.CP_VARIABLE_PATH_UNBOUND, this, rawEntry.getPath());
+						} else {
+							if (rawReverseMap.get(resolvedPath = resolvedEntry.getPath()) == null) {
+								rawReverseMap.put(resolvedPath , rawEntry);
+								rootPathToResolvedEntries.put(resolvedPath, resolvedEntry);
+							}
+							resolvedEntries.add(resolvedEntry);
+						}
+						break; 
+	
+					case IClasspathEntry.CPE_CONTAINER :
+						IClasspathContainer container = JavaCore.getClasspathContainer(rawEntry.getPath(), this);
+						if (container == null){
+							unresolvedEntryStatus = new JavaModelStatus(IJavaModelStatusConstants.CP_CONTAINER_PATH_UNBOUND, this, rawEntry.getPath());
+							break;
+						}
+	
+						IClasspathEntry[] containerEntries = container.getClasspathEntries();
+						if (containerEntries == null) break;
+	
+						// container was bound
+						for (int j = 0, containerLength = containerEntries.length; j < containerLength; j++){
+							ClasspathEntry cEntry = (ClasspathEntry) containerEntries[j];
+							if (cEntry == null) {
+								if (JavaModelManager.CP_RESOLVE_VERBOSE) {
+									JavaModelManager.getJavaModelManager().verbose_missbehaving_container(this, rawEntry.getPath(), containerEntries);
+								}
+								break;
+							}
+							// if container is exported or restricted, then its nested entries must in turn be exported  (21749) and/or propagate restrictions
+							cEntry = cEntry.combineWith((ClasspathEntry) rawEntry);
+							if (rawReverseMap.get(resolvedPath = cEntry.getPath()) == null) {
+								rawReverseMap.put(resolvedPath , rawEntry);
+								rootPathToResolvedEntries.put(resolvedPath, cEntry);
+							}
+							resolvedEntries.add(cEntry);
+						}
+						break;
+											
+					default :
+						if (rawReverseMap.get(resolvedPath = rawEntry.getPath()) == null) {
+							rawReverseMap.put(resolvedPath , rawEntry);
+							rootPathToResolvedEntries.put(resolvedPath, rawEntry);
+						}
+						resolvedEntries.add(rawEntry);
+
+				}					
+			}
+	
+			// store resolved info along with the raw info to ensure consistency
+			IClasspathEntry[] resolvedClasspath = new IClasspathEntry[resolvedEntries.size()];
+			resolvedEntries.toArray(resolvedClasspath);
+			perProjectInfo.setClasspath(rawClasspath, outputLocation, rawClasspathStatus, resolvedClasspath, rawReverseMap, rootPathToResolvedEntries, unresolvedEntryStatus);
+		} finally {
+			manager.setClasspathBeingResolved(this, false);
+		}
+	}
+
 	/**
 	 * Answers an ID which is used to distinguish project/entries during package
 	 * fragment root computations
@@ -2639,7 +2610,7 @@
 	public String rootID(){
 		return "[PRJ]"+this.project.getFullPath(); //$NON-NLS-1$
 	}
-	
+
 	/**
 	 * Saves the classpath in a shareable format (VCM-wise) only when necessary, that is, if  it is semantically different
 	 * from the existing one in file. Will never write an identical one.
@@ -2653,15 +2624,16 @@
 
 		if (!this.project.isAccessible()) return false;
 
-		IClasspathEntry[] fileEntries = readClasspathFile(false /*don't create markers*/, false/*don't log problems*/);
-		if (fileEntries != null && isClasspathEqualsTo(newClasspath, newOutputLocation, fileEntries)) {
+		Map unknownElements = new HashMap();
+		IClasspathEntry[] fileEntries = readFileEntries(unknownElements);
+		if (fileEntries != JavaProject.INVALID_CLASSPATH && areClasspathsEqual(newClasspath, newOutputLocation, fileEntries)) {
 			// no need to save it, it is the same
 			return false;
 		}
 
 		// actual file saving
 		try {
-			setSharedProperty(CLASSPATH_FILENAME, encodeClasspath(newClasspath, newOutputLocation, true));
+			setSharedProperty(JavaProject.CLASSPATH_FILENAME, encodeClasspath(newClasspath, newOutputLocation, true, unknownElements));
 			return true;
 		} catch (CoreException e) {
 			throw new JavaModelException(e);
@@ -2701,15 +2673,21 @@
 	 */
 	public void setOption(String optionName, String optionValue) {
 		if (!JavaModelManager.getJavaModelManager().optionNames.contains(optionName)) return; // unrecognized option
+		if (optionValue == null) return; // invalid value
 		IEclipsePreferences projectPreferences = getEclipsePreferences();
 		String defaultValue = JavaCore.getOption(optionName);
-		if (defaultValue == null || !defaultValue.equals(optionValue)) {
+		if (optionValue.equals(defaultValue)) {
+			// set default value => remove preference
+			projectPreferences.remove(optionName);
+		} else {
 			projectPreferences.put(optionName, optionValue);
-			try {
-				projectPreferences.flush();
-			} catch (BackingStoreException e) {
-				// problem with pref store - quietly ignore
-			}
+		}
+		
+		// Dump changes
+		try {
+			projectPreferences.flush();
+		} catch (BackingStoreException e) {
+			// problem with pref store - quietly ignore
 		}
 	}
 
@@ -2723,13 +2701,13 @@
 			if (newOptions == null){
 				projectPreferences.clear();
 			} else {
-				Iterator keys = newOptions.keySet().iterator();
-				while (keys.hasNext()){
-					String key = (String)keys.next();
+				Iterator entries = newOptions.entrySet().iterator();
+				while (entries.hasNext()){
+					Map.Entry entry = (Map.Entry) entries.next();
+					String key = (String) entry.getKey();
 					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);
-					projectPreferences.put(key, value);
+					projectPreferences.put(key, (String) entry.getValue());
 				}
 				
 				// reset to default all options not in new map
@@ -2758,20 +2736,17 @@
 			// problem with pref store - quietly ignore
 		}
 	}
-
 	/**
 	 * @see IJavaProject
 	 */
-	public void setOutputLocation(IPath path, IProgressMonitor monitor)
-		throws JavaModelException {
-
+	public void setOutputLocation(IPath path, IProgressMonitor monitor) throws JavaModelException {
 		if (path == null) {
 			throw new IllegalArgumentException(Messages.path_nullPath); 
 		}
 		if (path.equals(getOutputLocation())) {
 			return;
 		}
-		this.setRawClasspath(SetClasspathOperation.DO_NOT_SET_ENTRIES, path, monitor);
+		setRawClasspath(getRawClasspath(), path, monitor);
 	}
 
 	/**
@@ -2788,6 +2763,49 @@
 	}
 
 	/**
+	 * @see IJavaProject#setRawClasspath(IClasspathEntry[],boolean,IProgressMonitor)
+	 */
+	public void setRawClasspath(
+		IClasspathEntry[] entries,
+		boolean canModifyResources,
+		IProgressMonitor monitor)
+		throws JavaModelException {
+
+		setRawClasspath(
+			entries, 
+			getOutputLocation()/*don't change output*/,
+			canModifyResources, 
+			monitor);
+	}
+
+	/**
+	 * @see IJavaProject#setRawClasspath(IClasspathEntry[],IPath,boolean,IProgressMonitor)
+	 */
+	public void setRawClasspath(
+			IClasspathEntry[] newRawClasspath,
+			IPath newOutputLocation,
+			boolean canModifyResources,
+			IProgressMonitor monitor)
+			throws JavaModelException {
+		
+		try {
+			if (newRawClasspath == null) //are we already with the default classpath
+				newRawClasspath = defaultClasspath();
+
+			SetClasspathOperation op =
+				new SetClasspathOperation(
+					this, 
+					newRawClasspath, 
+					newOutputLocation, 
+					canModifyResources);
+			op.runOperation(monitor);
+		} catch (JavaModelException e) {
+			JavaModelManager.getJavaModelManager().getDeltaProcessor().flush();
+			throw e;
+		}
+	}
+	
+	/**
 	 * @see IJavaProject#setRawClasspath(IClasspathEntry[],IPath,IProgressMonitor)
 	 */
 	public void setRawClasspath(
@@ -2799,46 +2817,10 @@
 		setRawClasspath(
 			entries, 
 			outputLocation,
-			monitor, 
-			true, // canChangeResource (as per API contract)
-			getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/),
-			true, // needValidation
-			true); // need to save
+			true/*can change resource (as per API contract)*/,
+			monitor);
 	}
-
-	public void setRawClasspath(
-		IClasspathEntry[] newEntries,
-		IPath newOutputLocation,
-		IProgressMonitor monitor,
-		boolean canChangeResource,
-		IClasspathEntry[] oldResolvedPath,
-		boolean needValidation,
-		boolean needSave)
-		throws JavaModelException {
-
-		JavaModelManager manager = JavaModelManager.getJavaModelManager();
-		try {
-			IClasspathEntry[] newRawPath = newEntries;
-			if (newRawPath == null) { //are we already with the default classpath
-				newRawPath = defaultClasspath();
-			}
-			SetClasspathOperation op =
-				new SetClasspathOperation(
-					this, 
-					oldResolvedPath, 
-					newRawPath, 
-					newOutputLocation,
-					canChangeResource, 
-					needValidation,
-					needSave);
-			op.runOperation(monitor);
-			
-		} catch (JavaModelException e) {
-			manager.getDeltaProcessor().flush();
-			throw e;
-		}
-	}
-
+	
 	/**
 	 * @see IJavaProject
 	 */
@@ -2849,12 +2831,9 @@
 
 		setRawClasspath(
 			entries, 
-			SetClasspathOperation.DO_NOT_SET_OUTPUT, 
-			monitor, 
-			true, // canChangeResource (as per API contract)
-			getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/),
-			true, // needValidation
-			true); // need to save
+			getOutputLocation()/*don't change output*/,
+			true/*can change resource (as per API contract)*/,
+			monitor);
 	}
 
 	/**
@@ -2876,7 +2855,7 @@
 		IFile rscFile = this.project.getFile(key);
 		byte[] bytes = null;
 		try {
-			bytes = value.getBytes("UTF-8"); //$NON-NLS-1$ // .classpath always encoded with UTF-8
+			bytes = value.getBytes(org.eclipse.jdt.internal.compiler.util.Util.UTF_8); // .classpath always encoded with UTF-8
 		} catch (UnsupportedEncodingException e) {
 			Util.log(e, "Could not write .classpath with UTF-8 encoding "); //$NON-NLS-1$
 			// fallback to default
@@ -2894,45 +2873,6 @@
 			rscFile.create(inputStream, IResource.FORCE, null);
 		}
 	}
-	
-	/*
-	 * Update .classpath format markers.
-	 */
-	public void updateClasspathMarkers(Map preferredClasspaths, Map preferredOutputs) {
-		
-		this.flushClasspathProblemMarkers(false/*cycle*/, true/*format*/);
-		this.flushClasspathProblemMarkers(false/*cycle*/, false/*format*/);
-
-		IClasspathEntry[] classpath = this.readClasspathFile(true/*marker*/, false/*log*/);
-		IPath output = null;
-		// discard the output location
-		if (classpath != null && classpath.length > 0) {
-			IClasspathEntry entry = classpath[classpath.length - 1];
-			if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) {
-				IClasspathEntry[] copy = new IClasspathEntry[classpath.length - 1];
-				System.arraycopy(classpath, 0, copy, 0, copy.length);
-				classpath = copy;
-				output = entry.getPath();
-			}
-		}					
-		// remember invalid path so as to avoid reupdating it again later on
-		if (preferredClasspaths != null) {
-			preferredClasspaths.put(this, classpath == null ? INVALID_CLASSPATH : classpath);
-		}
-		if (preferredOutputs != null) {
-			preferredOutputs.put(this, output == null ? defaultOutputLocation() : output);
-		}
-		
-		 // force classpath marker refresh
-		 if (classpath != null && output != null) {
-		 	for (int i = 0; i < classpath.length; i++) {
-				IJavaModelStatus status = ClasspathEntry.validateClasspathEntry(this, classpath[i], false/*src attach*/, true /*recurse in container*/);
-				if (!status.isOK()) this.createClasspathProblemMarker(status);					 
-			 }
-			IJavaModelStatus status = ClasspathEntry.validateClasspath(this, classpath, output);
-			if (!status.isOK()) this.createClasspathProblemMarker(status);
-		 }
-	}
 
 	/**
 	 * If a cycle is detected, then cycleParticipants contains all the paths of projects involved in this cycle (directly and indirectly),
@@ -2956,7 +2896,7 @@
 		try {
 			IClasspathEntry[] classpath = null;
 			if (preferredClasspaths != null) classpath = (IClasspathEntry[])preferredClasspaths.get(this);
-			if (classpath == null) classpath = getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
+			if (classpath == null) classpath = getResolvedClasspath();
 			for (int i = 0, length = classpath.length; i < length; i++) {
 				IClasspathEntry entry = classpath[i];
 				
@@ -2983,7 +2923,7 @@
 		}
 		prereqChain.remove(path);
 	}
-	
+
 	/**
 	 * Reset the collection of package fragment roots (local ones) - only if opened.
 	 */
@@ -3020,7 +2960,7 @@
 			    }
 			}
 			try {
-				// save immediately old preferences
+				// save immediately new preferences
 				preferences.flush();
 			} catch (BackingStoreException e) {
 				// fails silently
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 ca3bb9a..69b1c82 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -18,9 +18,7 @@
 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.HashSetOfArray;
 import org.eclipse.jdt.internal.core.util.Util;
 import org.eclipse.jdt.internal.core.util.HashtableOfArrayToObject;
 
@@ -36,12 +34,14 @@
 
 /* package */
 class JavaProjectElementInfo extends OpenableElementInfo {
+	
+	static final IPackageFragmentRoot[] NO_ROOTS = new IPackageFragmentRoot[0];
 
 	static class ProjectCache {
-		ProjectCache(IPackageFragmentRoot[] allPkgFragmentRootsCache, HashtableOfArrayToObject allPkgFragmentsCache, Map pathToResolvedEntries) {
+		ProjectCache(IPackageFragmentRoot[] allPkgFragmentRootsCache, Map rootToResolvedEntries, Map pkgFragmentsCaches) {
 			this.allPkgFragmentRootsCache = allPkgFragmentRootsCache;
-			this.allPkgFragmentsCache = allPkgFragmentsCache;
-			this.pathToResolvedEntries = pathToResolvedEntries;
+			this.rootToResolvedEntries = rootToResolvedEntries;
+			this.pkgFragmentsCaches = pkgFragmentsCaches;
 		}
 		
 		/*
@@ -51,11 +51,17 @@
 		
 		/*
 		 * A cache of all package fragments in this project.
-		 * (a map from String[] (the package name) to IPackageFragmentRoot[] (the package fragment roots that contain a package fragment with this name)
+		 * (a map from String[] (the package name) to IPackageFragmentRoot[] (the package fragment roots that contain a package fragment with this name))
 		 */
 		public HashtableOfArrayToObject allPkgFragmentsCache;
-	
-		public Map pathToResolvedEntries;		
+		
+		/*
+		 * A cache of package fragments for each package fragment root of this project
+		 * (a map from IPackageFragmentRoot to a set of String[] (the package name))
+		 */
+		public Map pkgFragmentsCaches;
+		
+		public Map rootToResolvedEntries;		
 	}
 	
 	/**
@@ -65,6 +71,19 @@
 	
 	ProjectCache projectCache;
 	
+	/*
+	 * Adds the given name and its super names to the given set
+	 * (e.g. for {"a", "b", "c"}, adds {"a", "b", "c"}, {"a", "b"}, and {"a"})
+	 */
+	static void addSuperPackageNames(String[] pkgName, HashtableOfArrayToObject packageFragments) {
+		for (int i = pkgName.length-1; i > 0; i--) {
+			if (packageFragments.getKey(pkgName, i) == null) {
+				System.arraycopy(pkgName, 0, pkgName = new String[i], 0, i);
+				packageFragments.put(pkgName, NO_ROOTS);
+			}
+		}
+	}
+	
 	/**
 	 * Create and initialize a new instance of the receiver
 	 */
@@ -83,81 +102,83 @@
 		boolean binIsProject = false;
 		char[][] inclusionPatterns = null;
 		char[][] exclusionPatterns = null;
-		IClasspathEntry[] classpath = null;
 		IPath projectOutput = null;
+		boolean isClasspathResolved = true;
 		try {
-			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;
-				}
+			IClasspathEntry entry = project.getClasspathEntryFor(projectPath);
+			if (entry != null) {
+				srcIsProject = true;
+				inclusionPatterns = ((ClasspathEntry)entry).fullInclusionPatternChars();
+				exclusionPatterns = ((ClasspathEntry)entry).fullExclusionPatternChars();
 			}
 			projectOutput = project.getOutputLocation();
 			binIsProject = projectPath.equals(projectOutput);
 		} catch (JavaModelException e) {
-			// ignore
+			isClasspathResolved = false;
 		}
 
 		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++) {
-				IResource res = members[i];
-				switch (res.getType()) {
-					case IResource.FILE :
-						IPath resFullPath = res.getFullPath();
-						String resName = res.getName();
+			int length = members.length;
+			if (length > 0) {
+				String sourceLevel = project.getOption(JavaCore.COMPILER_SOURCE, true);
+				String complianceLevel = project.getOption(JavaCore.COMPILER_COMPLIANCE, true);
+				IClasspathEntry[] classpath = project.getResolvedClasspath();
+				for (int i = 0; i < length; i++) {
+					IResource res = members[i];
+					switch (res.getType()) {
+						case IResource.FILE :
+							IPath resFullPath = res.getFullPath();
+							String resName = res.getName();
 						
-						// ignore a jar file on the classpath
-						if (org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(resName) && this.isClasspathEntryOrOutputLocation(resFullPath, classpath, projectOutput)) {
+							// ignore a jar file on the classpath
+							if (isClasspathResolved && org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(resName) && this.isClasspathEntryOrOutputLocation(resFullPath, classpath, projectOutput)) {
+								break;
+							}
+							// ignore .java file if src == project
+							if (srcIsProject 
+									&& Util.isValidCompilationUnitName(resName, sourceLevel, complianceLevel)
+									&& !Util.isExcluded(res, inclusionPatterns, exclusionPatterns)) {
+								break;
+							}
+							// ignore .class file if bin == project
+							if (binIsProject && Util.isValidClassFileName(resName, sourceLevel, complianceLevel)) {
+								break;
+							}
+							// else add non java resource
+							if (resources.length == resourcesCounter) {
+								// resize
+								System.arraycopy(
+										resources,
+										0,
+										(resources = new IResource[resourcesCounter * 2]),
+										0,
+										resourcesCounter);
+							}
+							resources[resourcesCounter++] = res;
 							break;
-						}
-						// ignore .java file if src == project
-						if (srcIsProject 
-							&& Util.isValidCompilationUnitName(resName)
-							&& !Util.isExcluded(res, inclusionPatterns, exclusionPatterns)) {
-							break;
-						}
-						// ignore .class file if bin == project
-						if (binIsProject && Util.isValidClassFileName(resName)) {
-							break;
-						}
-						// else add non java resource
-						if (resources.length == resourcesCounter) {
-							// resize
-							System.arraycopy(
-								resources,
-								0,
-								(resources = new IResource[resourcesCounter * 2]),
-								0,
-								resourcesCounter);
-						}
-						resources[resourcesCounter++] = res;
-						break;
-					case IResource.FOLDER :
-						resFullPath = res.getFullPath();
+						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, inclusionPatterns, exclusionPatterns) && Util.isValidFolderNameForPackage(res.getName()))
-								|| this.isClasspathEntryOrOutputLocation(resFullPath, classpath, projectOutput)) {
-							break;
-						}
-						// else add non java resource
-						if (resources.length == resourcesCounter) {
-							// resize
-							System.arraycopy(
-								resources,
-								0,
-								(resources = new IResource[resourcesCounter * 2]),
-								0,
-								resourcesCounter);
-						}
-						resources[resourcesCounter++] = res;
+							// ignore non-excluded folders on the classpath or that correspond to an output location
+							if ((srcIsProject && !Util.isExcluded(res, inclusionPatterns, exclusionPatterns) && Util.isValidFolderNameForPackage(res.getName(), sourceLevel, complianceLevel))
+									|| (isClasspathResolved && this.isClasspathEntryOrOutputLocation(resFullPath, classpath, projectOutput))) {
+								break;
+							}
+							// else add non java resource
+							if (resources.length == resourcesCounter) {
+								// resize
+								System.arraycopy(
+										resources,
+										0,
+										(resources = new IResource[resourcesCounter * 2]),
+										0,
+										resourcesCounter);
+							}
+							resources[resourcesCounter++] = res;
+					}
 				}
 			}
 			if (resources.length != resourcesCounter) {
@@ -187,36 +208,22 @@
 				roots = new IPackageFragmentRoot[0];
 				reverseMap.clear();
 			}
-			HashtableOfArrayToObject fragmentsCache = new HashtableOfArrayToObject();
-			for (int i = 0, length = roots.length; i < length; i++) {
+			
+			HashMap rootInfos = JavaModelManager.getJavaModelManager().deltaState.roots;
+			HashMap pkgFragmentsCaches = new HashMap();
+			int length = roots.length;
+			for (int i = 0; i < length; i++) {
 				IPackageFragmentRoot root = roots[i];
-				IJavaElement[] frags = null;
-				try {
-					frags = root.getChildren();
-				} catch (JavaModelException e) {
-					// root doesn't exist: ignore
-					continue;
-				}
-				for (int j = 0, length2 = frags.length; j < length2; j++) {
-					PackageFragment fragment= (PackageFragment) frags[j];
-					String[] pkgName = fragment.names;
-					Object existing = fragmentsCache.get(pkgName);
-					if (existing == null) {
-						fragmentsCache.put(pkgName, root);
-					} else {
-						if (existing instanceof PackageFragmentRoot) {
-							fragmentsCache.put(pkgName, new IPackageFragmentRoot[] {(PackageFragmentRoot) existing, root});
-						} else {
-							IPackageFragmentRoot[] entry= (IPackageFragmentRoot[]) existing;
-							IPackageFragmentRoot[] copy= new IPackageFragmentRoot[entry.length + 1];
-							System.arraycopy(entry, 0, copy, 0, entry.length);
-							copy[entry.length]= root;
-							fragmentsCache.put(pkgName, copy);
-						}
-					}
+				DeltaProcessor.RootInfo rootInfo = (DeltaProcessor.RootInfo) rootInfos.get(root.getPath());
+				if (rootInfo == null || rootInfo.project.equals(project)) {
+					// compute fragment cache
+					HashSetOfArray fragmentsCache = new HashSetOfArray();
+					initializePackageNames(root, fragmentsCache);
+					pkgFragmentsCaches.put(root, fragmentsCache);
 				}
 			}
-			cache = new ProjectCache(roots, fragmentsCache, reverseMap);
+			
+			cache = new ProjectCache(roots, reverseMap, pkgFragmentsCaches);
 			this.projectCache = cache;
 		}
 		return cache;
@@ -232,6 +239,24 @@
 		}
 		return this.nonJavaResources;
 	}
+	
+	private void initializePackageNames(IPackageFragmentRoot root, HashSetOfArray fragmentsCache) {
+		IJavaElement[] frags = null;
+		try {
+			if (!root.isOpen()) {
+				PackageFragmentRootInfo info = root.isArchive() ? new JarPackageFragmentRootInfo() : new PackageFragmentRootInfo();
+				((PackageFragmentRoot) root).computeChildren(info, new HashMap());
+				frags = info.children;
+			} else 
+				frags = root.getChildren();
+		} catch (JavaModelException e) {
+			// root doesn't exist: ignore
+			return;
+		}
+		for (int j = 0, length2 = frags.length; j < length2; j++) {
+			fragmentsCache.add(((PackageFragment) frags[j]).names);
+		}
+	}
 
 	/*
 	 * Returns whether the given path is a classpath entry or an output location.
@@ -258,7 +283,62 @@
 	 */
 	NameLookup newNameLookup(JavaProject project, ICompilationUnit[] workingCopies) {
 		ProjectCache cache = getProjectCache(project);
-		return new NameLookup(cache.allPkgFragmentRootsCache, cache.allPkgFragmentsCache, workingCopies, cache.pathToResolvedEntries);
+		HashtableOfArrayToObject allPkgFragmentsCache = cache.allPkgFragmentsCache;
+		if (allPkgFragmentsCache == null) {
+			HashMap rootInfos = JavaModelManager.getJavaModelManager().deltaState.roots;
+			IPackageFragmentRoot[] allRoots = cache.allPkgFragmentRootsCache;
+			int length = allRoots.length;
+			allPkgFragmentsCache = new HashtableOfArrayToObject();
+			for (int i = 0; i < length; i++) {
+				IPackageFragmentRoot root = allRoots[i];
+				DeltaProcessor.RootInfo rootInfo = (DeltaProcessor.RootInfo) rootInfos.get(root.getPath());
+				JavaProject rootProject = rootInfo == null ? project : rootInfo.project;
+				HashSetOfArray fragmentsCache;
+				if (rootProject.equals(project)) {
+					// retrieve package fragments cache from this project
+					fragmentsCache = (HashSetOfArray) cache.pkgFragmentsCaches.get(root);
+				} else {
+					// retrieve package fragments  cache from the root's project
+					ProjectCache rootProjectCache;
+					try {
+						rootProjectCache = rootProject.getProjectCache();
+					} catch (JavaModelException e) {
+						// project doesn't exit
+						continue;
+					}
+					fragmentsCache = (HashSetOfArray) rootProjectCache.pkgFragmentsCaches.get(root);
+				}
+				if (fragmentsCache == null) { // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=183833
+					fragmentsCache = new HashSetOfArray();
+					initializePackageNames(root, fragmentsCache);
+				}
+				Object[][] set = fragmentsCache.set;
+				for (int j = 0, length2 = set.length; j < length2; j++) {
+					String[] pkgName = (String[]) set[j];
+					if (pkgName == null)
+						continue;
+					Object existing = allPkgFragmentsCache.get(pkgName);
+					if (existing == null || existing == NO_ROOTS) {
+						allPkgFragmentsCache.put(pkgName, root);
+						// ensure super packages (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=119161)
+						// are also in the map
+						addSuperPackageNames(pkgName, allPkgFragmentsCache);
+					} else {
+						if (existing instanceof PackageFragmentRoot) {
+							allPkgFragmentsCache.put(pkgName, new IPackageFragmentRoot[] {(PackageFragmentRoot) existing, root});
+						} else {
+							IPackageFragmentRoot[] roots = (IPackageFragmentRoot[]) existing;
+							int rootLength = roots.length;
+							System.arraycopy(roots, 0, roots = new IPackageFragmentRoot[rootLength+1], 0, rootLength);
+							roots[rootLength] = root;
+							allPkgFragmentsCache.put(pkgName, roots);
+						}
+					}
+				}
+			}
+			cache.allPkgFragmentsCache = allPkgFragmentsCache;
+		}
+		return new NameLookup(cache.allPkgFragmentRootsCache, cache.allPkgFragmentsCache, workingCopies, cache.rootToResolvedEntries);
 	}
 	
 	/*
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavadocConstants.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavadocConstants.java
new file mode 100755
index 0000000..bb9f4ba
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavadocConstants.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core;
+
+public interface JavadocConstants {
+
+	String ANCHOR_PREFIX_END = "\""; //$NON-NLS-1$
+	String ANCHOR_PREFIX_START = "<A NAME=\""; //$NON-NLS-1$
+	String ANCHOR_SUFFIX = "</A>"; //$NON-NLS-1$
+	int ANCHOR_SUFFIX_LENGTH = JavadocConstants.ANCHOR_SUFFIX.length();
+	String CONSTRUCTOR_DETAIL = "<!-- ========= CONSTRUCTOR DETAIL ======== -->"; //$NON-NLS-1$
+	String CONSTRUCTOR_SUMMARY = "<!-- ======== CONSTRUCTOR SUMMARY ======== -->"; //$NON-NLS-1$
+	String FIELD_SUMMARY = "<!-- =========== FIELD SUMMARY =========== -->"; //$NON-NLS-1$
+	String ENUM_CONSTANT_SUMMARY = "<!-- =========== ENUM CONSTANT SUMMARY =========== -->"; //$NON-NLS-1$
+	String ANNOTATION_TYPE_REQUIRED_MEMBER_SUMMARY = "<!-- =========== ANNOTATION TYPE REQUIRED MEMBER SUMMARY =========== -->"; //$NON-NLS-1$
+	String ANNOTATION_TYPE_OPTIONAL_MEMBER_SUMMARY = "<!-- =========== ANNOTATION TYPE OPTIONAL MEMBER SUMMARY =========== -->"; //$NON-NLS-1$
+	String END_OF_CLASS_DATA = "<!-- ========= END OF CLASS DATA ========= -->"; //$NON-NLS-1$
+	String HTML_EXTENSION = ".html"; //$NON-NLS-1$
+	String INDEX_FILE_NAME = "index.html"; //$NON-NLS-1$
+	String METHOD_DETAIL = "<!-- ============ METHOD DETAIL ========== -->"; //$NON-NLS-1$
+	String METHOD_SUMMARY = "<!-- ========== METHOD SUMMARY =========== -->"; //$NON-NLS-1$
+	String NESTED_CLASS_SUMMARY = "<!-- ======== NESTED CLASS SUMMARY ======== -->"; //$NON-NLS-1$
+	String PACKAGE_FILE_NAME = "package-summary.html"; //$NON-NLS-1$
+	String START_OF_CLASS_DATA = "<!-- ======== START OF CLASS DATA ======== -->"; //$NON-NLS-1$
+	int START_OF_CLASS_DATA_LENGTH = JavadocConstants.START_OF_CLASS_DATA.length();
+}
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 a1b8cf8..631670e 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 c70d140..6d89f76 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 e30ad29..4d8054e 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -11,17 +11,13 @@
 package org.eclipse.jdt.internal.core;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 
 import org.eclipse.jdt.core.*;
-import org.eclipse.jdt.core.Flags;
-import org.eclipse.jdt.core.IClassFile;
-import org.eclipse.jdt.core.IJavaElement;
-import org.eclipse.jdt.core.IMember;
-import org.eclipse.jdt.core.IMethod;
-import org.eclipse.jdt.core.ISourceRange;
-import org.eclipse.jdt.core.IType;
-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.IScanner;
+import org.eclipse.jdt.core.compiler.ITerminalSymbols;
+import org.eclipse.jdt.core.compiler.InvalidInputException;
 import org.eclipse.jdt.internal.compiler.impl.Constant;
 import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
 import org.eclipse.jdt.internal.core.util.MementoTokenizer;
@@ -31,7 +27,7 @@
  */
 
 public abstract class Member extends SourceRefElement implements IMember {
-
+	
 protected Member(JavaElement parent) {
 	super(parent);
 }
@@ -104,7 +100,7 @@
 		simpleNames[i] = Signature.getSimpleName(Signature.toString(erasure));
 	}
 	ArrayList list = new ArrayList();
-	next: for (int i = 0, length = methods.length; i < length; i++) {
+	for (int i = 0, length = methods.length; i < length; i++) {
 		IMethod existingMethod = methods[i];
 		if (areSimilarMethods(
 				elementName,
@@ -124,11 +120,32 @@
 		return result;
 	}
 }
+public String[] getCategories() throws JavaModelException {
+	IType type = (IType) getAncestor(IJavaElement.TYPE);
+	if (type == null) return CharOperation.NO_STRINGS;
+	if (type.isBinary()) {
+		return CharOperation.NO_STRINGS;
+	} else {
+		SourceTypeElementInfo info = (SourceTypeElementInfo) ((SourceType) type).getElementInfo();
+		HashMap map = info.getCategories();
+		if (map == null) return CharOperation.NO_STRINGS;
+		String[] categories = (String[]) map.get(this);
+		if (categories == null) return CharOperation.NO_STRINGS;
+		return categories;
+	}
+}
 /**
  * @see IMember
  */
 public IClassFile getClassFile() {
-	return ((JavaElement)getParent()).getClassFile();
+	IJavaElement element = getParent();
+	while (element instanceof IMember) {
+		element= element.getParent();
+	}
+	if (element instanceof IClassFile) {
+		return (IClassFile) element;
+	}
+	return null;
 }
 /**
  * @see IMember
@@ -240,6 +257,53 @@
 	} 
 	return lastLocalContext;
 }
+public ISourceRange getJavadocRange() throws JavaModelException {
+	ISourceRange range= this.getSourceRange();
+	if (range == null) return null;
+	IBuffer buf= null;
+	if (this.isBinary()) {
+		buf = this.getClassFile().getBuffer();
+	} else {
+		ICompilationUnit compilationUnit = this.getCompilationUnit();
+		if (!compilationUnit.isConsistent()) {
+			return null;
+		}
+		buf = compilationUnit.getBuffer();
+	}
+	final int start= range.getOffset();
+	final int length= range.getLength();
+	if (length > 0 && buf.getChar(start) == '/') {
+		IScanner scanner= ToolFactory.createScanner(true, false, false, false);
+		scanner.setSource(buf.getText(start, length).toCharArray());
+		try {
+			int docOffset= -1;
+			int docEnd= -1;
+			
+			int terminal= scanner.getNextToken();
+			loop: while (true) {
+				switch(terminal) {
+					case ITerminalSymbols.TokenNameCOMMENT_JAVADOC :
+						docOffset= scanner.getCurrentTokenStartPosition();
+						docEnd= scanner.getCurrentTokenEndPosition() + 1;
+						terminal= scanner.getNextToken();
+						break;
+					case ITerminalSymbols.TokenNameCOMMENT_LINE :
+					case ITerminalSymbols.TokenNameCOMMENT_BLOCK :
+						terminal= scanner.getNextToken();
+						continue loop;
+					default :
+						break loop;
+				}
+			}
+			if (docOffset != -1) {
+				return new SourceRange(docOffset + start, docEnd - docOffset + 1);
+			}
+		} catch (InvalidInputException ex) {
+			// try if there is inherited Javadoc
+		}
+	}
+	return null;
+}
 /**
  * @see IMember
  */
@@ -260,6 +324,16 @@
 	}
 }
 /**
+ * @see IMember#getTypeRoot()
+ */
+public ITypeRoot getTypeRoot() {
+	IJavaElement element = getParent();
+	while (element instanceof IMember) {
+		element= element.getParent();
+	}
+	return (ITypeRoot) element;
+}
+/**
  * @see IMember
  */
 public boolean isBinary() {
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 9dbb32c..26ec1a2 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -17,7 +17,7 @@
 	/**
 	 * The modifiers associated with this member.
 	 *
-	 * @see org.eclipse.jdt.internal.compiler.env.IConstants
+	 * @see org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants
 	 */
 	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 edd4215..d9c2834 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -128,8 +128,10 @@
 				JavaModelManager.getJavaModelManager().getIndexManager().reset();
 				break;
 			case IJavaElement.JAVA_PROJECT :
-				JavaModelManager.getJavaModelManager().removePerProjectInfo(
-					(JavaProject) element);
+				JavaModelManager manager = JavaModelManager.getJavaModelManager();
+				JavaProject javaProject = (JavaProject) element;
+				manager.removePerProjectInfo(javaProject);
+				manager.containerRemove(javaProject);
 				break;
 			case IJavaElement.PACKAGE_FRAGMENT_ROOT :
 				this.projectsToUpdate.add(element.getJavaProject());
@@ -150,7 +152,7 @@
 	public void processJavaDelta(IJavaElementDelta delta) {
 
 //		if (DeltaProcessor.VERBOSE){
-//			System.out.println("UPDATING Model with Delta: ["+Thread.currentThread()+":" + delta + "]:");//$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
+//			System.out.println("UPDATING Model with Delta: ["+Thread.currentThread()+":" + delta + "]:");
 //		}
 
 		try {
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 e613044..e1271d7 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 1e669d4..5ac70c0 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -45,6 +45,27 @@
 					System.arraycopy(classpath, 0, newClasspath, 0, i);
 					newCPIndex = i;
 				}
+			} else if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
+				// update exclusion/inclusion patterns
+				IPath projectRelativePath = rootPath.removeFirstSegments(1);
+				IPath[] newExclusionPatterns = renamePatterns(projectRelativePath, entry.getExclusionPatterns());
+				IPath[] newInclusionPatterns = renamePatterns(projectRelativePath, entry.getInclusionPatterns());
+				if (newExclusionPatterns != null || newInclusionPatterns != null) {
+					if (newClasspath == null) {
+						newClasspath = new IClasspathEntry[cpLength];
+						System.arraycopy(classpath, 0, newClasspath, 0, i);
+						newCPIndex = i;
+					}
+					newClasspath[newCPIndex++] = 
+						JavaCore.newSourceEntry(
+							entry.getPath(), 
+							newInclusionPatterns == null ? entry.getInclusionPatterns() : newInclusionPatterns, 
+							newExclusionPatterns == null ? entry.getExclusionPatterns() : newExclusionPatterns, 
+							entry.getOutputLocation(), 
+							entry.getExtraAttributes());
+				} else if (newClasspath != null) {
+					newClasspath[newCPIndex++] = entry;
+				}
 			} else if (newClasspath != null) {
 				newClasspath[newCPIndex++] = entry;
 			}
@@ -54,10 +75,33 @@
 			if (newCPIndex < newClasspath.length) {
 				System.arraycopy(newClasspath, 0, newClasspath = new IClasspathEntry[newCPIndex], 0, newCPIndex);
 			}
-			project.setRawClasspath(newClasspath, progressMonitor);
+			IJavaModelStatus status = JavaConventions.validateClasspath(project, newClasspath, project.getOutputLocation());
+			if (status.isOK())
+				project.setRawClasspath(newClasspath, progressMonitor);
+			// don't update classpath if status is not ok to avoid JavaModelException (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=129991)
 		}
 	}
 
+	private IPath[] renamePatterns(IPath rootPath, IPath[] patterns) {
+		IPath[] newPatterns = null;
+		int newPatternsIndex = -1;
+		for (int i = 0, length = patterns.length; i < length; i++) {
+			IPath pattern = patterns[i];
+			if (pattern.equals(rootPath)) {
+				if (newPatterns == null) {
+					newPatterns = new IPath[length];
+					System.arraycopy(patterns, 0, newPatterns, 0, i);
+					newPatternsIndex = i;
+				}
+				IPath newPattern = this.destination.removeFirstSegments(1);
+				if (pattern.hasTrailingSeparator())
+					newPattern = newPattern.addTrailingSeparator();
+				newPatterns[newPatternsIndex++] = newPattern;
+			}
+		}
+		return newPatterns;
+	}
+
 	public MovePackageFragmentRootOperation(
 		IPackageFragmentRoot root,
 		IPath destination,
@@ -180,7 +224,7 @@
 				throw new JavaModelException(e);
 			}
 		}
-		this.setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); 
+		setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); 
 	}
 	/*
 	 * Renames the classpath entries equal to the given path in all Java projects.
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 3cde822..bbc99e5 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 898192e..4eef804 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -153,32 +153,35 @@
 	 * be completed.
 	 */
 	protected void processElements() throws JavaModelException {
-		beginTask(getMainTaskName(), this.elementsToProcess.length);
-		IJavaModelStatus[] errors = new IJavaModelStatus[3];
-		int errorsCounter = 0;
-		for (int i = 0; i < this.elementsToProcess.length; i++) {
-			try {
-				verify(this.elementsToProcess[i]);
-				processElement(this.elementsToProcess[i]);
-			} catch (JavaModelException jme) {
-				if (errorsCounter == errors.length) {
-					// resize
-					System.arraycopy(errors, 0, (errors = new IJavaModelStatus[errorsCounter*2]), 0, errorsCounter);
+		try {
+			beginTask(getMainTaskName(), this.elementsToProcess.length);
+			IJavaModelStatus[] errors = new IJavaModelStatus[3];
+			int errorsCounter = 0;
+			for (int i = 0; i < this.elementsToProcess.length; i++) {
+				try {
+					verify(this.elementsToProcess[i]);
+					processElement(this.elementsToProcess[i]);
+				} catch (JavaModelException jme) {
+					if (errorsCounter == errors.length) {
+						// resize
+						System.arraycopy(errors, 0, (errors = new IJavaModelStatus[errorsCounter*2]), 0, errorsCounter);
+					}
+					errors[errorsCounter++] = jme.getJavaModelStatus();
+				} finally {
+					worked(1);
 				}
-				errors[errorsCounter++] = jme.getJavaModelStatus();
-			} finally {
-				worked(1);
 			}
-		}
-		done();
-		if (errorsCounter == 1) {
-			throw new JavaModelException(errors[0]);
-		} else if (errorsCounter > 1) {
-			if (errorsCounter != errors.length) {
-				// resize
-				System.arraycopy(errors, 0, (errors = new IJavaModelStatus[errorsCounter]), 0, errorsCounter);
+			if (errorsCounter == 1) {
+				throw new JavaModelException(errors[0]);
+			} else if (errorsCounter > 1) {
+				if (errorsCounter != errors.length) {
+					// resize
+					System.arraycopy(errors, 0, (errors = new IJavaModelStatus[errorsCounter]), 0, errorsCounter);
+				}
+				throw new JavaModelException(JavaModelStatus.newMultiStatus(errors));
 			}
-			throw new JavaModelException(JavaModelStatus.newMultiStatus(errors));
+		} finally {
+			done();
 		}
 	}
 	/**
@@ -266,23 +269,25 @@
 	protected void verifyRenaming(IJavaElement element) throws JavaModelException {
 		String newName = getNewNameFor(element);
 		boolean isValid = true;
-	
+	    IJavaProject project = element.getJavaProject();
+	    String sourceLevel = project.getOption(JavaCore.COMPILER_SOURCE, true);
+	    String complianceLevel = project.getOption(JavaCore.COMPILER_COMPLIANCE, true);
 		switch (element.getElementType()) {
 			case IJavaElement.PACKAGE_FRAGMENT :
 				if (((IPackageFragment) element).isDefaultPackage()) {
 					// don't allow renaming of default package (see PR #1G47GUM)
 					throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.NAME_COLLISION, element));
 				}
-				isValid = JavaConventions.validatePackageName(newName).getSeverity() != IStatus.ERROR;
+				isValid = JavaConventions.validatePackageName(newName, sourceLevel, complianceLevel).getSeverity() != IStatus.ERROR;
 				break;
 			case IJavaElement.COMPILATION_UNIT :
-				isValid = JavaConventions.validateCompilationUnitName(newName).getSeverity() != IStatus.ERROR;
+				isValid = JavaConventions.validateCompilationUnitName(newName,sourceLevel, complianceLevel).getSeverity() != IStatus.ERROR;
 				break;
 			case IJavaElement.INITIALIZER :
 				isValid = false; //cannot rename initializers
 				break;
 			default :
-				isValid = JavaConventions.validateIdentifier(newName).getSeverity() != IStatus.ERROR;
+				isValid = JavaConventions.validateIdentifier(newName, sourceLevel, complianceLevel).getSeverity() != IStatus.ERROR;
 				break;
 		}
 	
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 da25a32..73f2309 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -12,34 +12,26 @@
 
 import java.io.File;
 import java.util.*;
-import java.util.ArrayList;
-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.runtime.IPath;
-import org.eclipse.core.runtime.Path;
-import org.eclipse.core.runtime.OperationCanceledException;
-import org.eclipse.jdt.core.IClassFile;
+import org.eclipse.core.runtime.IProgressMonitor;
 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.compiler.CharOperation;
-import org.eclipse.jdt.core.search.*;
-import org.eclipse.jdt.core.search.IJavaSearchConstants;
-import org.eclipse.jdt.core.search.SearchEngine;
 import org.eclipse.jdt.internal.compiler.ast.ASTNode;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.compiler.env.AccessRestriction;
+import org.eclipse.jdt.internal.compiler.env.AccessRuleSet;
 import org.eclipse.jdt.internal.compiler.env.IBinaryType;
-import org.eclipse.jdt.internal.compiler.env.IConstants;
-import org.eclipse.jdt.internal.compiler.env.IGenericType;
+import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
 import org.eclipse.jdt.internal.core.util.HashtableOfArrayToObject;
 import org.eclipse.jdt.internal.core.util.Messages;
@@ -62,6 +54,29 @@
  *
  */
 public class NameLookup implements SuffixConstants {
+	public static class Answer {
+		public IType type;
+		AccessRestriction restriction;
+		Answer(IType type, AccessRestriction restriction) {
+			this.type = type;
+			this.restriction = restriction;
+		}
+		public boolean ignoreIfBetter() {
+			return this.restriction != null && this.restriction.ignoreIfBetter();
+		}
+		/*
+		 * Returns whether this answer is better than the other awswer.
+		 * (accessible is better than discouraged, which is better than
+		 * non-accessible)
+		 */
+		public boolean isBetter(Answer otherAnswer) {
+			if (otherAnswer == null) return true;
+			if (this.restriction == null) return true;
+			return otherAnswer.restriction != null 
+				&& this.restriction.getProblemId() < otherAnswer.restriction.getProblemId();
+		}
+	}
+
 	// TODO (jerome) suppress the accept flags (qualified name is sufficient to find a type)
 	/**
 	 * Accept flag for specifying classes.
@@ -89,6 +104,8 @@
 	public static final int ACCEPT_ALL = ACCEPT_CLASSES | ACCEPT_INTERFACES | ACCEPT_ENUMS | ACCEPT_ANNOTATIONS;
 
 	public static boolean VERBOSE = false;
+	
+	private static final IType[] NO_TYPES = {};
 
 	/**
 	 * The <code>IPackageFragmentRoot</code>'s associated
@@ -107,7 +124,7 @@
 	 * replaces the array.
 	 */
 	protected HashtableOfArrayToObject packageFragments;
-
+	
 	/**
 	 * Reverse map from root path to corresponding resolved CP entry
 	 * (so as to be able to figure inclusion/exclusion rules)
@@ -115,55 +132,68 @@
 	protected Map rootToResolvedEntries;
 	
 	/**
-	 * A map from package handles to a map from type name to an IType of an IType[].
+	 * A map from package handles to a map from type name to an IType or an IType[].
 	 * Allows working copies to take precedence over compilation units.
 	 */
-	protected HashMap unitsToLookInside;
-	
+	protected HashMap typesInWorkingCopies;
+
 	public long timeSpentInSeekTypesInSourcePackage = 0;
 	public long timeSpentInSeekTypesInBinaryPackage = 0;
 
-	public NameLookup(IPackageFragmentRoot[] packageFragmentRoots, HashtableOfArrayToObject packageFragments, ICompilationUnit[] workingCopies, Map rootToResolvedEntries) {
+	public NameLookup(
+			IPackageFragmentRoot[] packageFragmentRoots, 
+			HashtableOfArrayToObject packageFragments, 
+			ICompilationUnit[] workingCopies, 
+			Map rootToResolvedEntries) {
 		long start = -1;
 		if (VERBOSE) {
-			System.out.println(Thread.currentThread() + " BUILDING NameLoopkup");  //$NON-NLS-1$
-			System.out.println(Thread.currentThread() + " -> pkg roots size: " + (packageFragmentRoots == null ? 0 : packageFragmentRoots.length));  //$NON-NLS-1$
-			System.out.println(Thread.currentThread() + " -> pkgs size: " + (packageFragments == null ? 0 : packageFragments.size()));  //$NON-NLS-1$
-			System.out.println(Thread.currentThread() + " -> working copy size: " + (workingCopies == null ? 0 : workingCopies.length));  //$NON-NLS-1$
+			Util.verbose(" BUILDING NameLoopkup");  //$NON-NLS-1$
+			Util.verbose(" -> pkg roots size: " + (packageFragmentRoots == null ? 0 : packageFragmentRoots.length));  //$NON-NLS-1$
+			Util.verbose(" -> pkgs size: " + (packageFragments == null ? 0 : packageFragments.size()));  //$NON-NLS-1$
+			Util.verbose(" -> working copy size: " + (workingCopies == null ? 0 : workingCopies.length));  //$NON-NLS-1$
 			start = System.currentTimeMillis();
 		}
 		this.packageFragmentRoots = packageFragmentRoots;
-		try {
-			this.packageFragments = (HashtableOfArrayToObject) packageFragments.clone();
-		} catch (CloneNotSupportedException e1) {
-			// ignore (implementation of HashtableOfArrayToObject supports cloning)
-		}
-		if (workingCopies != null) {
-			this.unitsToLookInside = new HashMap();
+		if (workingCopies == null) {
+			this.packageFragments = packageFragments;
+		} else {
+			// clone tables as we're adding packages from working copies
+			try {
+				this.packageFragments = (HashtableOfArrayToObject) packageFragments.clone();
+			} catch (CloneNotSupportedException e1) {
+				// ignore (implementation of HashtableOfArrayToObject supports cloning)
+			}
+			this.typesInWorkingCopies = new HashMap();
 			for (int i = 0, length = workingCopies.length; i < length; i++) {
 				ICompilationUnit workingCopy = workingCopies[i];
 				PackageFragment pkg = (PackageFragment) workingCopy.getParent();
-				HashMap typeMap = (HashMap) this.unitsToLookInside.get(pkg);
+				HashMap typeMap = (HashMap) this.typesInWorkingCopies.get(pkg);
 				if (typeMap == null) {
 					typeMap = new HashMap();
-					this.unitsToLookInside.put(pkg, typeMap);
+					this.typesInWorkingCopies.put(pkg, typeMap);
 				}
 				try {
 					IType[] types = workingCopy.getTypes();
-					for (int j = 0, typeLength = types.length; j < typeLength; j++) {
-						IType type = types[j];
-						String typeName = type.getElementName();
-						Object existing = typeMap.get(typeName);
-						if (existing == null) {
-							typeMap.put(typeName, type);
-						} else if (existing instanceof IType) {
-							typeMap.put(typeName, new IType[] {(IType) existing, type});
-						} else {
-							IType[] existingTypes = (IType[]) existing;
-							int existingTypeLength = existingTypes.length;
-							System.arraycopy(existingTypes, 0, existingTypes = new IType[existingTypeLength+1], 0, existingTypeLength);
-							existingTypes[existingTypeLength] = type;
-							typeMap.put(typeName, existingTypes);
+					int typeLength = types.length;
+					if (typeLength == 0) {
+						String typeName = Util.getNameWithoutJavaLikeExtension(workingCopy.getElementName());
+						typeMap.put(typeName, NO_TYPES);
+					} else {
+						for (int j = 0; j < typeLength; j++) {
+							IType type = types[j];
+							String typeName = type.getElementName();
+							Object existing = typeMap.get(typeName);
+							if (existing == null) {
+								typeMap.put(typeName, type);
+							} else if (existing instanceof IType) {
+								typeMap.put(typeName, new IType[] {(IType) existing, type});
+							} else {
+								IType[] existingTypes = (IType[]) existing;
+								int existingTypeLength = existingTypes.length;
+								System.arraycopy(existingTypes, 0, existingTypes = new IType[existingTypeLength+1], 0, existingTypeLength);
+								existingTypes[existingTypeLength] = type;
+								typeMap.put(typeName, existingTypes);
+							}
 						}
 					}
 				} catch (JavaModelException e) {
@@ -174,8 +204,11 @@
 				IPackageFragmentRoot root = (IPackageFragmentRoot) pkg.getParent();
 				String[] pkgName = pkg.names;
 				Object existing = this.packageFragments.get(pkgName);
-				if (existing == null) {
+				if (existing == null || existing == JavaProjectElementInfo.NO_ROOTS) {
 					this.packageFragments.put(pkgName, root);
+					// ensure super packages (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=119161)
+					// are also in the map
+					JavaProjectElementInfo.addSuperPackageNames(pkgName, this.packageFragments);
 				} else {
 					if (existing instanceof PackageFragmentRoot) {
 						if (!existing.equals(root))
@@ -199,9 +232,10 @@
 				}
 			}
 		}
+		
 		this.rootToResolvedEntries = rootToResolvedEntries;
         if (VERBOSE) {
-            System.out.println(Thread.currentThread() + " -> spent: " + (start - System.currentTimeMillis()) + "ms");  //$NON-NLS-1$ //$NON-NLS-2$
+            Util.verbose(" -> spent: " + (System.currentTimeMillis() - start) + "ms");  //$NON-NLS-1$ //$NON-NLS-2$
         }
 	}
 
@@ -221,14 +255,14 @@
 			return true; // no flags or all flags, always accepted
 		try {
 			int kind = isSourceType
-					? ((SourceTypeElementInfo) ((SourceType) type).getElementInfo()).getKind() 
-					: ((IBinaryType) ((BinaryType) type).getElementInfo()).getKind();
+					? TypeDeclaration.kind(((SourceTypeElementInfo) ((SourceType) type).getElementInfo()).getModifiers())
+					: TypeDeclaration.kind(((IBinaryType) ((BinaryType) type).getElementInfo()).getModifiers());
 			switch (kind) {
-				case IGenericType.CLASS_DECL :
+				case TypeDeclaration.CLASS_DECL :
 					return (acceptFlags & ACCEPT_CLASSES) != 0;
-				case IGenericType.INTERFACE_DECL :
+				case TypeDeclaration.INTERFACE_DECL :
 					return (acceptFlags & ACCEPT_INTERFACES) != 0;
-				case IGenericType.ENUM_DECL :
+				case TypeDeclaration.ENUM_DECL :
 					return (acceptFlags & ACCEPT_ENUMS) != 0;
 				default:
 					//case IGenericType.ANNOTATION_TYPE :
@@ -389,13 +423,18 @@
 						if (entry != null) {
 							IPackageFragmentRoot root =
 								project.getPackageFragmentRoot(project.getResource());
-							IPackageFragmentRoot[] roots = (IPackageFragmentRoot[]) this.packageFragments.get(CharOperation.NO_STRINGS);
-							if (roots == null) {
+							Object defaultPkgRoot = this.packageFragments.get(CharOperation.NO_STRINGS);
+							if (defaultPkgRoot == null) {
 								return null;
 							}
-							for (int i = 0; i < roots.length; i++) {
-								if (roots[i].equals(root)) {
-									return  ((PackageFragmentRoot) root).getPackageFragment(CharOperation.NO_STRINGS);
+							if (defaultPkgRoot instanceof PackageFragmentRoot && defaultPkgRoot.equals(root))
+								return  ((PackageFragmentRoot) root).getPackageFragment(CharOperation.NO_STRINGS);
+							else {
+								IPackageFragmentRoot[] roots = (IPackageFragmentRoot[]) defaultPkgRoot;
+								for (int i = 0; i < roots.length; i++) {
+									if (roots[i].equals(root)) {
+										return  ((PackageFragmentRoot) root).getPackageFragment(CharOperation.NO_STRINGS);
+									}
 								}
 							}
 						}
@@ -415,37 +454,48 @@
 	 * (qualified) name, or <code>null</code> if none exist.
 	 *
 	 * The name can be:
-	 *	- empty: ""
-	 *	- qualified: "pack.pack1.pack2"
+	 * <ul>
+	 *		<li>empty: ""</li>
+	 *		<li>qualified: "pack.pack1.pack2"</li>
+	 * </ul>
 	 * @param partialMatch partial name matches qualify when <code>true</code>,
 	 *	only exact name matches qualify when <code>false</code>
 	 */
 	public IPackageFragment[] findPackageFragments(String name, boolean partialMatch) {
-		if (partialMatch) {
+		return findPackageFragments(name, partialMatch, false);
+	}
+
+	/**
+	 * Returns the package fragments whose name matches the given
+	 * (qualified) name or pattern, or <code>null</code> if none exist.
+	 *
+	 * The name can be:
+	 * <ul>
+	 *		<li>empty: ""</li>
+	 *		<li>qualified: "pack.pack1.pack2"</li>
+	 * 	<li>a pattern: "pack.*.util"</li>
+	 * </ul>
+	 * @param partialMatch partial name matches qualify when <code>true</code>,
+	 * @param patternMatch <code>true</code> when the given name might be a pattern,
+	 *		<code>false</code> otherwise.
+	 */
+	public IPackageFragment[] findPackageFragments(String name, boolean partialMatch, boolean patternMatch) {
+		boolean hasPatternChars = patternMatch && (name.indexOf('*') >= 0 || name.indexOf('?') >= 0);
+		if (partialMatch || hasPatternChars) {
 			String[] splittedName = Util.splitOn('.', name, 0, name.length());
 			IPackageFragment[] oneFragment = null;
 			ArrayList pkgs = null;
 			Object[][] keys = this.packageFragments.keyTable;
 			for (int i = 0, length = keys.length; i < length; i++) {
 				String[] pkgName = (String[]) keys[i];
-				if (pkgName != null && Util.startsWithIgnoreCase(pkgName, splittedName)) {
-					Object value = this.packageFragments.valueTable[i];
-					if (value instanceof PackageFragmentRoot) {
-						IPackageFragment pkg = ((PackageFragmentRoot) value).getPackageFragment(pkgName);
-						if (oneFragment == null) {
-							oneFragment = new IPackageFragment[] {pkg};
-						} else {
-							if (pkgs == null) {
-								pkgs = new ArrayList();
-								pkgs.add(oneFragment[0]);
-							}
-							pkgs.add(pkg);
-						}
-					} else {
-						IPackageFragmentRoot[] roots = (IPackageFragmentRoot[]) value;
-						for (int j = 0, length2 = roots.length; j < length2; j++) {
-							PackageFragmentRoot root = (PackageFragmentRoot) roots[j];
-							IPackageFragment pkg = root.getPackageFragment(pkgName);
+				if (pkgName != null) {
+					boolean match = hasPatternChars
+						? Util.matchesWithIgnoreCase(pkgName, name)
+						: Util.startsWithIgnoreCase(pkgName, splittedName, partialMatch);
+					if (match) {
+						Object value = this.packageFragments.valueTable[i];
+						if (value instanceof PackageFragmentRoot) {
+							IPackageFragment pkg = ((PackageFragmentRoot) value).getPackageFragment(pkgName);
 							if (oneFragment == null) {
 								oneFragment = new IPackageFragment[] {pkg};
 							} else {
@@ -455,6 +505,21 @@
 								}
 								pkgs.add(pkg);
 							}
+						} else {
+							IPackageFragmentRoot[] roots = (IPackageFragmentRoot[]) value;
+							for (int j = 0, length2 = roots.length; j < length2; j++) {
+								PackageFragmentRoot root = (PackageFragmentRoot) roots[j];
+								IPackageFragment pkg = root.getPackageFragment(pkgName);
+								if (oneFragment == null) {
+									oneFragment = new IPackageFragment[] {pkg};
+								} else {
+									if (pkgs == null) {
+										pkgs = new ArrayList();
+										pkgs.add(oneFragment[0]);
+									}
+									pkgs.add(pkg);
+								}
+							}
 						}
 					}
 				}
@@ -467,50 +532,187 @@
 		} else {
 			String[] splittedName = Util.splitOn('.', name, 0, name.length());
 			Object value = this.packageFragments.get(splittedName);
+			if (value == null)
+				return null;
 			if (value instanceof PackageFragmentRoot) {
 				return new IPackageFragment[] {((PackageFragmentRoot) value).getPackageFragment(splittedName)};
 			} else {
 				IPackageFragmentRoot[] roots = (IPackageFragmentRoot[]) value;
-				if (roots != null) {
-					IPackageFragment[] result = new IPackageFragment[roots.length];
-					for (int i= 0; i < roots.length; i++) {
-						result[i] = ((PackageFragmentRoot) roots[i]).getPackageFragment(splittedName);
+				IPackageFragment[] result = new IPackageFragment[roots.length];
+				for (int i= 0; i < roots.length; i++) {
+					result[i] = ((PackageFragmentRoot) roots[i]).getPackageFragment(splittedName);
+				}
+				return result;
+			}
+		}
+	}
+
+	/*
+	 * Find secondary type for a project.
+	 */
+	private IType findSecondaryType(String packageName, String typeName, IJavaProject project, boolean waitForIndexes, IProgressMonitor monitor) {
+		if (JavaModelManager.VERBOSE) {
+			Util.verbose("NameLookup FIND SECONDARY TYPES:"); //$NON-NLS-1$
+			Util.verbose(" -> pkg name: " + packageName);  //$NON-NLS-1$
+			Util.verbose(" -> type name: " + typeName);  //$NON-NLS-1$
+			Util.verbose(" -> project: "+project.getElementName()); //$NON-NLS-1$
+		}
+		JavaModelManager manager = JavaModelManager.getJavaModelManager();
+		try {
+			IJavaProject javaProject = project;
+			Map secondaryTypePaths = manager.secondaryTypes(javaProject, waitForIndexes, monitor);
+			if (secondaryTypePaths.size() > 0) {
+				Map types = (Map) secondaryTypePaths.get(packageName==null?"":packageName); //$NON-NLS-1$
+				if (types != null && types.size() > 0) {
+					IType type = (IType) types.get(typeName);
+					if (type != null) {
+						if (JavaModelManager.VERBOSE) {
+							Util.verbose(" -> type: " + type.getElementName());  //$NON-NLS-1$
+						}
+						return type;
 					}
-					return result;
 				}
 			}
 		}
+		catch (JavaModelException jme) {
+			// give up
+		}
 		return null;
 	}
 
 	/**
-	 * 
+	 * Find type considering secondary types but without waiting for indexes.
+	 * It means that secondary types may be not found under certain circumstances...
+	 * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=118789"
 	 */
-	public IType findType(String typeName, String packageName, boolean partialMatch, int acceptFlags) {
+	public Answer findType(String typeName, String packageName, boolean partialMatch, int acceptFlags, boolean checkRestrictions) {
+		return findType(typeName,
+			packageName,
+			partialMatch,
+			acceptFlags,
+			true/* consider secondary types */,
+			false/* do NOT wait for indexes */,
+			checkRestrictions,
+			null);
+	}
+
+	/**
+	 * Find type. Considering secondary types and waiting for indexes depends on given corresponding parameters.
+	 */
+	public Answer findType(
+			String typeName, 
+			String packageName, 
+			boolean partialMatch, 
+			int acceptFlags, 
+			boolean considerSecondaryTypes, 
+			boolean waitForIndexes, 
+			boolean checkRestrictions,
+			IProgressMonitor monitor) {
 		if (packageName == null || packageName.length() == 0) {
 			packageName= IPackageFragment.DEFAULT_PACKAGE_NAME;
-		} else if (typeName.length() > 0 && Character.isLowerCase(typeName.charAt(0))) {
+		} else if (typeName.length() > 0 && ScannerHelper.isLowerCase(typeName.charAt(0))) {
 			// see if this is a known package and not a type
 			if (findPackageFragments(packageName + "." + typeName, false) != null) return null; //$NON-NLS-1$
 		}
+
+		// Look for concerned package fragments
 		JavaElementRequestor elementRequestor = new JavaElementRequestor();
 		seekPackageFragments(packageName, false, elementRequestor);
 		IPackageFragment[] packages= elementRequestor.getPackageFragments();
 
-		for (int i= 0, length= packages.length; i < length; i++) {
-			IType type= findType(typeName, packages[i], partialMatch, acceptFlags);
-			if (type != null)
-				return type;
+		// Try to find type in package fragments list
+		IType type = null;
+		int length= packages.length;
+		HashSet projects = null;
+		IJavaProject javaProject = null;
+		Answer suggestedAnswer = null;
+		for (int i= 0; i < length; i++) {
+			type = findType(typeName, packages[i], partialMatch, acceptFlags);
+			if (type != null) {
+				AccessRestriction accessRestriction = null;
+				if (checkRestrictions) {
+					accessRestriction = getViolatedRestriction(typeName, packageName, type, accessRestriction);
+				}
+				Answer answer = new Answer(type, accessRestriction);
+				if (!answer.ignoreIfBetter()) {
+					if (answer.isBetter(suggestedAnswer))
+						return answer;
+				} else if (answer.isBetter(suggestedAnswer))
+					// remember suggestion and keep looking
+					suggestedAnswer = answer;
+			}
+			else if (suggestedAnswer == null && considerSecondaryTypes) {
+				if (javaProject == null) {
+					javaProject = packages[i].getJavaProject();
+				} else if (projects == null)  {
+					if (!javaProject.equals(packages[i].getJavaProject())) {
+						projects = new HashSet(3);
+						projects.add(javaProject);
+						projects.add(packages[i].getJavaProject());
+					}
+				} else {
+					projects.add(packages[i].getJavaProject());
+				}
+			}
 		}
-		return null;
+		if (suggestedAnswer != null)
+			// no better answer was found
+			return suggestedAnswer;
+
+		// If type was not found, try to find it as secondary in source folders
+		if (considerSecondaryTypes && javaProject != null) {
+			if (projects == null) {
+				type = findSecondaryType(packageName, typeName, javaProject, waitForIndexes, monitor);
+			} else {
+				Iterator allProjects = projects.iterator();
+				while (type == null && allProjects.hasNext()) {
+					type = findSecondaryType(packageName, typeName, (IJavaProject) allProjects.next(), waitForIndexes, monitor);
+				}
+			}
+		}
+		return type == null ? null : new Answer(type, null);
 	}
-	
-	private IType getMemberType(IType type, String name, int dot) {
-		while (dot != -1) {
-			int start = dot+1;
-			dot = name.indexOf('.', start);
-			String typeName = name.substring(start, dot == -1 ? name.length() : dot);
-			type = type.getType(typeName);
+
+	private AccessRestriction getViolatedRestriction(String typeName, String packageName, IType type, AccessRestriction accessRestriction) {
+		PackageFragmentRoot root = (PackageFragmentRoot) type.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
+		ClasspathEntry entry = (ClasspathEntry) this.rootToResolvedEntries.get(root);
+		if (entry != null) { // reverse map always contains resolved CP entry
+			AccessRuleSet accessRuleSet = entry.getAccessRuleSet();
+			if (accessRuleSet != null) {
+				// TODO (philippe) improve char[] <-> String conversions to avoid performing them on the fly
+				char[][] packageChars = CharOperation.splitOn('.', packageName.toCharArray());
+				char[] typeChars = typeName.toCharArray();
+				accessRestriction = accessRuleSet.getViolatedRestriction(CharOperation.concatWith(packageChars, typeChars, '/'));
+			}
+		}
+		return accessRestriction;
+	}
+
+	/**
+	 * Returns the first type in the given package whose name
+	 * matches the given (unqualified) name, or <code>null</code> if none
+	 * exist. Specifying a <code>null</code> package will result in no matches.
+	 * The domain of the search is bounded by the Java project from which 
+	 * this name lookup was obtained.
+	 *
+	 * @param name the name of the type to find
+	 * @param pkg the package to search
+	 * @param partialMatch partial name matches qualify when <code>true</code>,
+	 *	only exact name matches qualify when <code>false</code>
+	 * @param acceptFlags a bit mask describing if classes, interfaces or both classes and interfaces
+	 * 	are desired results. If no flags are specified, all types are returned.
+	 * @param considerSecondaryTypes flag to know whether secondary types has to be considered
+	 * 	during the search
+	 *
+	 * @see #ACCEPT_CLASSES
+	 * @see #ACCEPT_INTERFACES
+	 * @see #ACCEPT_ENUMS
+	 * @see #ACCEPT_ANNOTATIONS
+	 */
+	public IType findType(String name, IPackageFragment pkg, boolean partialMatch, int acceptFlags, boolean considerSecondaryTypes) {
+		IType type = findType(name, pkg, partialMatch, acceptFlags);
+		if (type == null && considerSecondaryTypes) {
+			type = findSecondaryType(pkg.getElementName(), name, pkg.getJavaProject(), false, null);
 		}
 		return type;
 	}
@@ -521,7 +723,9 @@
 	 * exist. Specifying a <code>null</code> package will result in no matches.
 	 * The domain of the search is bounded by the Java project from which 
 	 * this name lookup was obtained.
-	 *
+	 * <br>
+	 *	Note that this method does not find secondary types.
+	 * <br>
 	 * @param name the name of the type to find
 	 * @param pkg the package to search
 	 * @param partialMatch partial name matches qualify when <code>true</code>,
@@ -540,68 +744,7 @@
 		// Return first found (ignore duplicates).
 		SingleTypeRequestor typeRequestor = new SingleTypeRequestor();
 		seekTypes(name, pkg, partialMatch, acceptFlags, typeRequestor);
-		IType type = typeRequestor.getType();
-//		if (type == null)
-//			type = findSecondaryType(name, pkg, partialMatch, acceptFlags);
-		return type;
-	}
-
-	// TODO (kent) enable once index support is in
-	IType findSecondaryType(String typeName, IPackageFragment pkg, boolean partialMatch, final int acceptFlags) {
-		try {
-			final ArrayList paths = new ArrayList();
-			TypeNameRequestor nameRequestor = new TypeNameRequestor() {
-				public void acceptType(int modifiers, char[] packageName, char[] simpleTypeName, char[][] enclosingTypeNames, String path) {
-					if (enclosingTypeNames == null || enclosingTypeNames.length == 0) { // accept only top level types
-						int kind = modifiers & (IConstants.AccInterface+IConstants.AccEnum+IConstants.AccAnnotation);
-						switch (kind) {
-							case IConstants.AccAnnotation:
-							case IConstants.AccAnnotation+IConstants.AccInterface:
-								if ((acceptFlags & ACCEPT_ANNOTATIONS) != 0) paths.add(path);
-								break;
-							case IConstants.AccEnum:
-								if ((acceptFlags & ACCEPT_ENUMS) != 0) paths.add(path);
-								break;
-							case IConstants.AccInterface:
-								if ((acceptFlags & ACCEPT_INTERFACES) != 0) paths.add(path);
-								break;
-							default:
-								if ((acceptFlags & ACCEPT_CLASSES) != 0) paths.add(path);
-								break;
-						}
-					}
-				}
-			};
-
-			int matchMode = partialMatch ? SearchPattern.R_PREFIX_MATCH : SearchPattern.R_EXACT_MATCH;
-			int matchRule = !partialMatch ? matchMode | SearchPattern.R_CASE_SENSITIVE : matchMode;
-			new SearchEngine().searchAllTypeNames(
-				pkg.getElementName().toCharArray(),
-				typeName.toCharArray(),
-				matchRule,
-				IJavaSearchConstants.TYPE,
-				SearchEngine.createJavaSearchScope(new IJavaElement[] {pkg}, false),
-				nameRequestor,
-				IJavaSearchConstants.CANCEL_IF_NOT_READY_TO_SEARCH,
-				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.core.util.Util.isJavaLikeFileName(pathname)) {
-						IFile file = workspace.getRoot().getFile(new Path(pathname));
-						ICompilationUnit unit = JavaCore.createCompilationUnitFrom(file);
-						return unit.getType(typeName);
-					}
-				}
-			}
-		} catch (JavaModelException e) {
-			// ignore
-		} catch (OperationCanceledException ignore) {
-			// ignore
-		}
-		return null;
+		return typeRequestor.getType();
 	}
 
 	/**
@@ -621,6 +764,14 @@
 	 * @see #ACCEPT_ANNOTATIONS
 	 */
 	public IType findType(String name, boolean partialMatch, int acceptFlags) {
+		NameLookup.Answer answer = findType(name, partialMatch, acceptFlags, false/*don't check restrictions*/);
+		return answer == null ? null : answer.type;
+	}
+		
+	public Answer findType(String name, boolean partialMatch, int acceptFlags, boolean checkRestrictions) {
+		return findType(name, partialMatch, acceptFlags, true/*consider secondary types*/, true/*wait for indexes*/, checkRestrictions, null);
+	}
+	public Answer findType(String name, boolean partialMatch, int acceptFlags, boolean considerSecondaryTypes, boolean waitForIndexes, boolean checkRestrictions, IProgressMonitor monitor) {
 		int index= name.lastIndexOf('.');
 		String className= null, packageName= null;
 		if (index == -1) {
@@ -630,7 +781,21 @@
 			packageName= name.substring(0, index);
 			className= name.substring(index + 1);
 		}
-		return findType(className, packageName, partialMatch, acceptFlags);
+		return findType(className, packageName, partialMatch, acceptFlags, considerSecondaryTypes, waitForIndexes, checkRestrictions, monitor);
+	}
+
+	private IType getMemberType(IType type, String name, int dot) {
+		while (dot != -1) {
+			int start = dot+1;
+			dot = name.indexOf('.', start);
+			String typeName = name.substring(start, dot == -1 ? name.length() : dot);
+			type = type.getType(typeName);
+		}
+		return type;
+	}
+	
+	public boolean isPackage(String[] pkgName) {
+		return this.packageFragments.get(pkgName) != null;
 	}
 
 	/**
@@ -681,9 +846,9 @@
 	 */
 	public void seekPackageFragments(String name, boolean partialMatch, IJavaElementRequestor requestor) {
 /*		if (VERBOSE) {
-			System.out.println(Thread.currentThread() + " SEEKING PACKAGE FRAGMENTS");  //$NON-NLS-1$
-			System.out.println(Thread.currentThread() + " -> name: " + name);  //$NON-NLS-1$
-			System.out.println(Thread.currentThread() + " -> partial match:" + partialMatch);  //$NON-NLS-1$
+			Util.verbose(" SEEKING PACKAGE FRAGMENTS");  //$NON-NLS-1$
+			Util.verbose(" -> name: " + name);  //$NON-NLS-1$
+			Util.verbose(" -> partial match:" + partialMatch);  //$NON-NLS-1$
 		}
 */		if (partialMatch) {
 			String[] splittedName = Util.splitOn('.', name, 0, name.length());
@@ -692,7 +857,7 @@
 				if (requestor.isCanceled())
 					return;
 				String[] pkgName = (String[]) keys[i];
-				if (pkgName != null && Util.startsWithIgnoreCase(pkgName, splittedName)) {
+				if (pkgName != null && Util.startsWithIgnoreCase(pkgName, splittedName, partialMatch)) {
 					Object value = this.packageFragments.valueTable[i];
 					if (value instanceof PackageFragmentRoot) {
 						PackageFragmentRoot root = (PackageFragmentRoot) value;
@@ -749,10 +914,10 @@
 	 */
 	public void seekTypes(String name, IPackageFragment pkg, boolean partialMatch, int acceptFlags, IJavaElementRequestor requestor) {
 /*		if (VERBOSE) {
-			System.out.println(Thread.currentThread() + " SEEKING TYPES");  //$NON-NLS-1$
-			System.out.println(Thread.currentThread() + " -> name: " + name);  //$NON-NLS-1$
-			System.out.println(Thread.currentThread() + " -> pkg: " + ((JavaElement) pkg).toStringWithAncestors());  //$NON-NLS-1$
-			System.out.println(Thread.currentThread() + " -> partial match:" + partialMatch);  //$NON-NLS-1$
+			Util.verbose(" SEEKING TYPES");  //$NON-NLS-1$
+			Util.verbose(" -> name: " + name);  //$NON-NLS-1$
+			Util.verbose(" -> pkg: " + ((JavaElement) pkg).toStringWithAncestors());  //$NON-NLS-1$
+			Util.verbose(" -> partial match:" + partialMatch);  //$NON-NLS-1$
 		}
 */
 		String matchName= partialMatch ? name.toLowerCase() : name;
@@ -762,15 +927,29 @@
 		}
 		IPackageFragmentRoot root= (IPackageFragmentRoot) pkg.getParent();
 		try {
+
+			// look in working copies first
+			int firstDot = -1;
+			String topLevelTypeName = null;
 			int packageFlavor= root.getKind();
+			if (this.typesInWorkingCopies != null || packageFlavor == IPackageFragmentRoot.K_SOURCE) {
+				firstDot = matchName.indexOf('.');
+				if (!partialMatch)
+					topLevelTypeName = firstDot == -1 ? matchName : matchName.substring(0, firstDot);
+			}
+			if (this.typesInWorkingCopies != null) {
+				if (seekTypesInWorkingCopies(matchName, pkg, firstDot, partialMatch, topLevelTypeName, acceptFlags, requestor))
+					return;
+			}
+			
+			// look in model
 			switch (packageFlavor) {
 				case IPackageFragmentRoot.K_BINARY :
 					matchName= matchName.replace('.', '$');
 					seekTypesInBinaryPackage(matchName, pkg, partialMatch, acceptFlags, requestor);
 					break;
 				case IPackageFragmentRoot.K_SOURCE :
-					matchName= matchName.replace('$', '.');
-					seekTypesInSourcePackage(matchName, pkg, partialMatch, acceptFlags, requestor);
+					seekTypesInSourcePackage(matchName, pkg, firstDot, partialMatch, topLevelTypeName, acceptFlags, requestor);
 					break;
 				default :
 					return;
@@ -788,44 +967,46 @@
 		if (VERBOSE)
 			start = System.currentTimeMillis();
 		try {
-			IClassFile[] classFiles= null;
-			try {
-				classFiles= pkg.getClassFiles();
-			} catch (JavaModelException npe) {
-				return; // the package is not present
-			}
-			int length= classFiles.length;
-	
-			String unqualifiedName= name;
-			int index= name.lastIndexOf('$');
-			if (index != -1) {
-				//the type name of the inner type
-				unqualifiedName= Util.localTypeName(name, index, name.length());
-				// unqualifiedName is empty if the name ends with a '$' sign.
-				// See http://dev.eclipse.org/bugs/show_bug.cgi?id=14642
-			}
-			String matchName= partialMatch ? name.toLowerCase() : name;
-			for (int i= 0; i < length; i++) {
-				if (requestor.isCanceled())
-					return;
-				IClassFile classFile= classFiles[i];
-				String elementName = classFile.getElementName();
-				if (partialMatch) elementName = elementName.toLowerCase();
-	
-				/**
-				 * Must use startWith because matchName will never have the 
-				 * extension ".class" and the elementName always will.
-				 */
-				if (elementName.startsWith(matchName)) {
-					IType type= null;
-					try {
-						type= classFile.getType();
-					} catch (JavaModelException npe) {
-						continue; // the classFile is not present
+			if (!partialMatch) {
+				// exact match
+				if (requestor.isCanceled()) return;
+				ClassFile classFile =  new ClassFile((PackageFragment) pkg, name);
+				if (classFile.existsUsingJarTypeCache()) {
+					IType type = classFile.getType();
+					if (acceptType(type, acceptFlags, false/*not a source type*/)) {
+						requestor.acceptType(type);
 					}
-					if (!partialMatch || (type.getElementName().length() > 0 && !Character.isDigit(type.getElementName().charAt(0)))) { //not an anonymous type
-						if (nameMatches(unqualifiedName, type, partialMatch) && acceptType(type, acceptFlags, false/*not a source type*/))
-							requestor.acceptType(type);
+				}
+			} else {
+				IJavaElement[] classFiles= null;
+				try {
+					classFiles= pkg.getChildren();
+				} catch (JavaModelException npe) {
+					return; // the package is not present
+				}
+				int length= classFiles.length;
+				String unqualifiedName = name;
+				int index = name.lastIndexOf('$');
+				if (index != -1) {
+					//the type name of the inner type
+					unqualifiedName = Util.localTypeName(name, index, name.length());
+					// unqualifiedName is empty if the name ends with a '$' sign.
+					// See http://dev.eclipse.org/bugs/show_bug.cgi?id=14642
+				}
+				int matchLength = name.length();
+				for (int i = 0; i < length; i++) {
+					if (requestor.isCanceled())
+						return;
+					IJavaElement classFile= classFiles[i];
+					// MatchName will never have the extension ".class" and the elementName always will.
+					String elementName = classFile.getElementName();
+					if (elementName.regionMatches(true /*ignore case*/, 0, name, 0, matchLength)) {
+						IType type = ((ClassFile) classFile).getType();
+						String typeName = type.getElementName();
+						if (typeName.length() > 0 && !Character.isDigit(typeName.charAt(0))) { //not an anonymous type
+							if (nameMatches(unqualifiedName, type, true/*partial match*/) && acceptType(type, acceptFlags, false/*not a source type*/))
+								requestor.acceptType(type);
+						}
 					}
 				}
 			}
@@ -838,52 +1019,31 @@
 	/**
 	 * Performs type search in a source package.
 	 */
-	protected void seekTypesInSourcePackage(String name, IPackageFragment pkg, boolean partialMatch, int acceptFlags, IJavaElementRequestor requestor) {
+	protected void seekTypesInSourcePackage(
+			String name, 
+			IPackageFragment pkg, 
+			int firstDot, 
+			boolean partialMatch, 
+			String topLevelTypeName, 
+			int acceptFlags,
+			IJavaElementRequestor requestor) {
 		
 		long start = -1;
 		if (VERBOSE)
 			start = System.currentTimeMillis();
 		try {
 			if (!partialMatch) {
-				int firstDot = name.indexOf('.');
-				String topLevelTypeName = firstDot == -1 ? name : name.substring(0, firstDot);
-				
-				// look in unitsToLookInside first
-				HashMap typeMap = (HashMap) (this.unitsToLookInside == null ? null : this.unitsToLookInside.get(pkg));
-				if (typeMap != null) {
-					Object object = typeMap.get(topLevelTypeName);
-					if (object instanceof IType) {
-						IType type = getMemberType((IType) object, name, firstDot);
-						if (acceptType(type, acceptFlags, true/*a source type*/)) {
-							requestor.acceptType(type);
-							return; // don't continue with compilation unit
-						}
-					} else if (object instanceof IType[]) {
-						IType[] topLevelTypes = (IType[]) object;
-						for (int i = 0, length = topLevelTypes.length; i < length; i++) {
-							if (requestor.isCanceled())
-								return;
-							IType type = getMemberType(topLevelTypes[i], name, firstDot);
-							if (acceptType(type, acceptFlags, true/*a source type*/)) {
-								requestor.acceptType(type);
-								return; // return the first one
-							}
-						}
-					}
-				}
-				
-				// look in compilation units
 				try {
-					ICompilationUnit[] compilationUnits = pkg.getCompilationUnits();
+					IJavaElement[] compilationUnits = pkg.getChildren();
 					for (int i = 0, length = compilationUnits.length; i < length; i++) {
 						if (requestor.isCanceled())
 							return;
-						ICompilationUnit cu = compilationUnits[i];
+						IJavaElement cu = compilationUnits[i];
 						String cuName = cu.getElementName();
 						int lastDot = cuName.lastIndexOf('.');
-						if (!topLevelTypeName.equals(cuName.substring(0, lastDot))) 
+						if (lastDot != topLevelTypeName.length() || !topLevelTypeName.regionMatches(0, cuName, 0, lastDot)) 
 							continue;
-						IType type = cu.getType(topLevelTypeName);
+						IType type = ((ICompilationUnit) cu).getType(topLevelTypeName);
 						type = getMemberType(type, name, firstDot);
 						if (acceptType(type, acceptFlags, true/*a source type*/)) { // accept type checks for existence
 							requestor.acceptType(type);
@@ -894,41 +1054,19 @@
 					// package doesn't exist -> ignore
 				}
 			} else {
-				String prefix = name.toLowerCase();
-				int firstDot = prefix.indexOf('.');
-				
-				// look in unitsToLookInside first
-				HashMap typeMap = (HashMap) (this.unitsToLookInside == null ? null : this.unitsToLookInside.get(pkg));
-				if (typeMap != null) {
-					Iterator iterator = typeMap.values().iterator();
-					while (iterator.hasNext()) {
-						if (requestor.isCanceled())
-							return;
-						Object object = iterator.next();
-						if (object instanceof IType) {
-							seekTypesInTopLevelType(prefix, firstDot, (IType) object, requestor, acceptFlags);
-						} else if (object instanceof IType[]) {
-							IType[] topLevelTypes = (IType[]) object;
-							for (int i = 0, length = topLevelTypes.length; i < length; i++)
-								seekTypesInTopLevelType(prefix, firstDot, topLevelTypes[i], requestor, acceptFlags);
-						}
-					}
-				}
-				
-				// look in compilation units
 				try {
-					String cuPrefix = firstDot == -1 ? prefix : prefix.substring(0, firstDot);
-					ICompilationUnit[] compilationUnits = pkg.getCompilationUnits();
+					String cuPrefix = firstDot == -1 ? name : name.substring(0, firstDot);
+					IJavaElement[] compilationUnits = pkg.getChildren();
 					for (int i = 0, length = compilationUnits.length; i < length; i++) {
 						if (requestor.isCanceled())
 							return;
-						ICompilationUnit cu = compilationUnits[i];
+						IJavaElement cu = compilationUnits[i];
 						if (!cu.getElementName().toLowerCase().startsWith(cuPrefix))
 							continue;
 						try {
-							IType[] types = cu.getTypes();
+							IType[] types = ((ICompilationUnit) cu).getTypes();
 							for (int j = 0, typeLength = types.length; j < typeLength; j++)
-								seekTypesInTopLevelType(prefix, firstDot, types[j], requestor, acceptFlags);
+								seekTypesInTopLevelType(name, firstDot, types[j], requestor, acceptFlags);
 						} catch (JavaModelException e) {
 							// cu doesn't exist -> ignore
 						}
@@ -942,22 +1080,22 @@
 				this.timeSpentInSeekTypesInSourcePackage += System.currentTimeMillis()-start;
 		}
 	}
-
+	
 	/**
 	 * Notifies the given requestor of all types (classes and interfaces) in the
 	 * given type with the given (possibly qualified) name. Checks
 	 * the requestor at regular intervals to see if the requestor
 	 * has canceled.
 	 */
-	protected void seekTypesInType(String prefix, int firstDot, IType type, IJavaElementRequestor requestor, int acceptFlags) {
+	protected boolean seekTypesInType(String prefix, int firstDot, IType type, IJavaElementRequestor requestor, int acceptFlags) {
 		IType[] types= null;
 		try {
 			types= type.getTypes();
 		} catch (JavaModelException npe) {
-			return; // the enclosing type is not present
+			return false; // the enclosing type is not present
 		}
 		int length= types.length;
-		if (length == 0) return; 
+		if (length == 0) return false; 
 		
 		String memberPrefix = prefix;
 		boolean isMemberTypePrefix = false;
@@ -967,27 +1105,92 @@
 		}
 		for (int i= 0; i < length; i++) {
 			if (requestor.isCanceled())
-				return;
+				return false;
 			IType memberType= types[i];
 			if (memberType.getElementName().toLowerCase().startsWith(memberPrefix))
 				if (isMemberTypePrefix) {
 					String subPrefix = prefix.substring(firstDot + 1, prefix.length());
-					seekTypesInType(subPrefix, subPrefix.indexOf('.'), memberType, requestor, acceptFlags);
+					return seekTypesInType(subPrefix, subPrefix.indexOf('.'), memberType, requestor, acceptFlags);
 				} else {
-					if (acceptType(memberType, acceptFlags, true/*a source type*/)) 
+					if (acceptType(memberType, acceptFlags, true/*a source type*/)) {
 						requestor.acceptMemberType(memberType);
+						return true;
+					}
 				}
 		}
+		return false;
 	}
 	
-	protected void seekTypesInTopLevelType(String prefix, int firstDot, IType topLevelType, IJavaElementRequestor requestor, int acceptFlags) {
+	protected boolean seekTypesInTopLevelType(String prefix, int firstDot, IType topLevelType, IJavaElementRequestor requestor, int acceptFlags) {
 		if (!topLevelType.getElementName().toLowerCase().startsWith(prefix))
-			return;
+			return false;
 		if (firstDot == -1) {
-			if (acceptType(topLevelType, acceptFlags, true/*a source type*/))
+			if (acceptType(topLevelType, acceptFlags, true/*a source type*/)) {
 				requestor.acceptType(topLevelType);
+				return true;
+			}
 		} else {
-			seekTypesInType(prefix, firstDot, topLevelType, requestor, acceptFlags);
+			return seekTypesInType(prefix, firstDot, topLevelType, requestor, acceptFlags);
 		}
+		return false;
 	}
+	
+	/*
+	 * Seeks the type with the given name in the map of types with precedence (coming from working copies)
+	 * Return whether a type has been found.
+	 */
+	protected boolean seekTypesInWorkingCopies(
+			String name, 
+			IPackageFragment pkg, 
+			int firstDot, 
+			boolean partialMatch, 
+			String topLevelTypeName, 
+			int acceptFlags,
+			IJavaElementRequestor requestor) {
+
+		if (!partialMatch) {
+			HashMap typeMap = (HashMap) (this.typesInWorkingCopies == null ? null : this.typesInWorkingCopies.get(pkg));
+			if (typeMap != null) {
+				Object object = typeMap.get(topLevelTypeName);
+				if (object instanceof IType) {
+					IType type = getMemberType((IType) object, name, firstDot);
+					if (acceptType(type, acceptFlags, true/*a source type*/)) {
+						requestor.acceptType(type);
+						return true; // don't continue with compilation unit
+					}
+				} else if (object instanceof IType[]) {
+					if (object == NO_TYPES) return true; // all types where deleted -> type is hidden
+					IType[] topLevelTypes = (IType[]) object;
+					for (int i = 0, length = topLevelTypes.length; i < length; i++) {
+						if (requestor.isCanceled())
+							return false;
+						IType type = getMemberType(topLevelTypes[i], name, firstDot);
+						if (acceptType(type, acceptFlags, true/*a source type*/)) {
+							requestor.acceptType(type);
+							return true; // return the first one
+						}
+					}
+				}
+			}
+		} else {
+			HashMap typeMap = (HashMap) (this.typesInWorkingCopies == null ? null : this.typesInWorkingCopies.get(pkg));
+			if (typeMap != null) {
+				Iterator iterator = typeMap.values().iterator();
+				while (iterator.hasNext()) {
+					if (requestor.isCanceled())
+						return false;
+					Object object = iterator.next();
+					if (object instanceof IType) {
+						seekTypesInTopLevelType(name, firstDot, (IType) object, requestor, acceptFlags);
+					} else if (object instanceof IType[]) {
+						IType[] topLevelTypes = (IType[]) object;
+						for (int i = 0, length = topLevelTypes.length; i < length; i++)
+							seekTypesInTopLevelType(name, firstDot, topLevelTypes[i], requestor, acceptFlags);
+					}
+				}
+			}
+		}
+		return false;
+	}
+	
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/NamedMember.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/NamedMember.java
index 1de6701..c305503 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/NamedMember.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/NamedMember.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004, 2005 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -21,6 +21,7 @@
 import org.eclipse.jdt.core.ITypeParameter;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.Signature;
+import org.eclipse.jdt.core.compiler.CharOperation;
 
 public abstract class NamedMember extends Member {
 
@@ -89,6 +90,28 @@
 		String selector = method.getElementName();
 		key.append(selector);
 		
+		// type parameters
+		if (forceOpen) {
+			ITypeParameter[] typeParameters = method.getTypeParameters();
+			int length = typeParameters.length;
+			if (length > 0) {
+				key.append('<');
+				for (int i = 0; i < length; i++) {
+					ITypeParameter typeParameter = typeParameters[i];
+					String[] bounds = typeParameter.getBounds();
+					int boundsLength = bounds.length;
+					char[][] boundSignatures = new char[boundsLength][];
+					for (int j = 0; j < boundsLength; j++) {
+						boundSignatures[j] = Signature.createCharArrayTypeSignature(bounds[j].toCharArray(), method.isBinary());
+						CharOperation.replace(boundSignatures[j], '.', '/');
+					}
+					char[] sig = Signature.createTypeParameterSignature(typeParameter.getElementName().toCharArray(), boundSignatures);
+					key.append(sig);
+				}
+				key.append('>');
+			}
+		}
+		
 		// parameters
 		key.append('(');
 		String[] parameters = method.getParameterTypes();
@@ -98,7 +121,7 @@
 		
 		// return type
 		if (forceOpen)
-			key.append(method.getReturnType());
+			key.append(method.getReturnType().replace('.', '/'));
 		else
 			key.append('V');
 		
@@ -140,7 +163,6 @@
 		buffer.append('<');
 		for (int i = 0; i < length; i++) {
 			String typeArgument = typeArguments[i];
-			typeArgument.replace('/', '.');
 			buffer.append(Signature.toString(typeArgument));
 			if (i < length-1)
 				buffer.append(',');
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/NullBuffer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/NullBuffer.java
new file mode 100755
index 0000000..a6cd755
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/NullBuffer.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.jdt.core.IOpenable;
+
+/**
+ * This class represents a null buffer. This buffer is used to represent a buffer for a class file
+ * that has no source attached.
+ */
+public class NullBuffer extends Buffer {
+	/**
+	 * Creates a new null buffer on an underlying resource.
+	 */
+	public NullBuffer(IFile file, IOpenable owner, boolean readOnly) {
+		super(file, owner, readOnly);
+	}
+}
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 15cbcd5..e221294 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,21 +10,18 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
-import java.util.*;
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Map;
 
 import org.eclipse.core.resources.*;
-import org.eclipse.core.resources.IContainer;
-import org.eclipse.core.resources.IResource;
-import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.OperationCanceledException;
 import org.eclipse.core.runtime.PerformanceStats;
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.internal.codeassist.CompletionEngine;
 import org.eclipse.jdt.internal.codeassist.SelectionEngine;
+import org.eclipse.jdt.internal.core.util.Util;
 
 
 /**
@@ -51,7 +48,7 @@
 		JavaModelManager.getJavaModelManager().getElementsOutOfSynchWithBuffers().remove(this);
 		getBufferManager().removeBuffer(event.getBuffer());
 	} else {
-		JavaModelManager.getJavaModelManager().getElementsOutOfSynchWithBuffers().put(this, this);
+		JavaModelManager.getJavaModelManager().getElementsOutOfSynchWithBuffers().add(this);
 	}
 }	
 /**
@@ -102,13 +99,11 @@
 	if (requestor == null) {
 		throw new IllegalArgumentException("Completion requestor cannot be null"); //$NON-NLS-1$
 	}
-	PerformanceStats stats = null;
-	if(CompletionEngine.PERF) {
-		stats = PerformanceStats.getStats(JavaModelManager.COMPLETION_PERF, this);
-		stats.startRun(
-				new String(cu.getFileName()) +
-				" at " + //$NON-NLS-1$
-				position);
+	PerformanceStats performanceStats = CompletionEngine.PERF
+		? PerformanceStats.getStats(JavaModelManager.COMPLETION_PERF, this)
+		: null;
+	if(performanceStats != null) {
+		performanceStats.startRun(new String(cu.getFileName()) + " at " + position); //$NON-NLS-1$
 	}
 	IBuffer buffer = getBuffer();
 	if (buffer == null) {
@@ -126,8 +121,8 @@
 	// code complete
 	CompletionEngine engine = new CompletionEngine(environment, requestor, project.getOptions(true), project);
 	engine.complete(cu, position, 0);
-	if(CompletionEngine.PERF) {
-		stats.endRun();
+	if(performanceStats != null) {
+		performanceStats.endRun();
 	}
 	if (NameLookup.VERBOSE) {
 		System.out.println(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInSourcePackage: " + environment.nameLookup.timeSpentInSeekTypesInSourcePackage + "ms");  //$NON-NLS-1$ //$NON-NLS-2$
@@ -135,16 +130,11 @@
 	}
 }
 protected IJavaElement[] codeSelect(org.eclipse.jdt.internal.compiler.env.ICompilationUnit cu, int offset, int length, WorkingCopyOwner owner) throws JavaModelException {
-	PerformanceStats stats = null;
-	if(SelectionEngine.PERF) {
-		stats = PerformanceStats.getStats(JavaModelManager.SELECTION_PERF, this);
-		stats.startRun(
-				new String(cu.getFileName()) +
-				" at [" + //$NON-NLS-1$
-				offset +
-				"," + //$NON-NLS-1$
-				length +
-				"]"); //$NON-NLS-1$
+	PerformanceStats performanceStats = SelectionEngine.PERF
+		? PerformanceStats.getStats(JavaModelManager.SELECTION_PERF, this)
+		: null;
+	if(performanceStats != null) {
+		performanceStats.startRun(new String(cu.getFileName()) + " at [" + offset + "," + length + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 	}
 	
 	JavaProject project = (JavaProject)getJavaProject();
@@ -163,8 +153,9 @@
 	// fix for 1FVXGDK
 	SelectionEngine engine = new SelectionEngine(environment, requestor, project.getOptions(true));
 	engine.select(cu, offset, offset + length - 1);
-	if(SelectionEngine.PERF) {
-		stats.endRun();
+	
+	if(performanceStats != null) {
+		performanceStats.endRun();
 	}
 	if (NameLookup.VERBOSE) {
 		System.out.println(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInSourcePackage: " + environment.nameLookup.timeSpentInSeekTypesInSourcePackage + "ms");  //$NON-NLS-1$ //$NON-NLS-2$
@@ -192,9 +183,14 @@
 	}
 	return super.exists();
 }
+public String findRecommendedLineSeparator() throws JavaModelException {
+	IBuffer buffer = getBuffer();
+	String source = buffer == null ? null : buffer.getContents();
+	return Util.getLineSeparator(source, getJavaProject());
+}
 protected void generateInfos(Object info, HashMap newElements, IProgressMonitor monitor) throws JavaModelException {
 
-	if (JavaModelManager.VERBOSE){
+	if (JavaModelCache.VERBOSE){
 		String element;
 		switch (getElementType()) {
 			case JAVA_PROJECT:
@@ -240,8 +236,8 @@
 	// remove out of sync buffer for this element
 	JavaModelManager.getJavaModelManager().getElementsOutOfSynchWithBuffers().remove(this);
 
-	if (JavaModelManager.VERBOSE) {
-		System.out.println(JavaModelManager.getJavaModelManager().cache.toStringFillingRation("-> ")); //$NON-NLS-1$
+	if (JavaModelCache.VERBOSE) {
+		System.out.println(JavaModelManager.getJavaModelManager().cacheToString("-> ")); //$NON-NLS-1$
 	}
 }
 /**
@@ -262,6 +258,9 @@
 			// try to (re)open a buffer
 			buffer = openBuffer(null, info);
 		}
+		if (buffer instanceof NullBuffer) {
+			return null;
+		}
 		return buffer;
 	} else {
 		return null;
@@ -394,34 +393,8 @@
  * @see IOpenable
  */
 public void makeConsistent(IProgressMonitor monitor) throws JavaModelException {
-	if (isConsistent()) return;
-	
-	// 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();
-	boolean hadTemporaryCache = manager.hasTemporaryCache();
-	try {
-		HashMap newElements = manager.getTemporaryCache();
-		openWhenClosed(newElements, monitor);
-		if (newElements.get(this) == null) {
-			// close any buffer that was opened for the new elements
-			Iterator iterator = newElements.keySet().iterator();
-			while (iterator.hasNext()) {
-				IJavaElement element = (IJavaElement)iterator.next();
-				if (element instanceof Openable) {
-					((Openable)element).closeBuffer();
-				}
-			}
-			throw newNotPresentException();
-		}
-		if (!hadTemporaryCache) {
-			manager.putInfos(this, newElements);
-		}
-	} finally {
-		if (!hadTemporaryCache) {
-			manager.resetTemporaryCache();
-		}
-	}
+	// only compilation units can be inconsistent
+	// other openables cannot be inconsistent so default is to do nothing
 }
 /**
  * @see IOpenable
@@ -493,12 +466,7 @@
  * Find enclosing package fragment root if any
  */
 public PackageFragmentRoot getPackageFragmentRoot() {
-	IJavaElement current = this;
-	do {
-		if (current instanceof PackageFragmentRoot) return (PackageFragmentRoot)current;
-		current = current.getParent();
-	} while(current != null);
-	return null;
+	return (PackageFragmentRoot) getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
 }
 
 }
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 ded5721..0b35f5c 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 4e91f55..80c20f8 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,7 +10,6 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
-import java.text.NumberFormat;
 import java.util.Enumeration;
 import java.util.Iterator;
 
@@ -162,15 +161,13 @@
 	protected boolean makeSpace(int space) {
 	
 		int limit = fSpaceLimit;
-		if (fOverflow == 0) {
+		if (fOverflow == 0 && fCurrentSpace + space <= limit) {
 			/* if space is already available */
-			if (fCurrentSpace + space <= limit) {
-				return true;
-			}
+			return true;
 		}
 	
 		/* Free up space by removing oldest entries */
-		int spaceNeeded = (int)((1 - fLoadFactor) * fSpaceLimit);
+		int spaceNeeded = (int)((1 - fLoadFactor) * limit);
 		spaceNeeded = (spaceNeeded > space) ? spaceNeeded : space;
 		LRUCacheEntry entry = fEntryQueueTail;
 	
@@ -201,20 +198,6 @@
 	 * Returns a new instance of the reciever.
 	 */
 	protected abstract LRUCache newInstance(int size, int overflow);
-	/**
-	 * Answers the value in the cache at the given key.
-	 * If the value is not in the cache, returns null
-	 *
-	 * This function does not modify timestamps.
-	 */
-	public Object peek(Object key) {
-		
-		LRUCacheEntry entry = (LRUCacheEntry) fEntryTable.get(key);
-		if (entry == null) {
-			return null;
-		}
-		return entry._fValue;
-	}
 /**
  * For testing purposes only
  */
@@ -259,8 +242,8 @@
 		}
 	}
 
-	for (Iterator iter = h.keySet().iterator(); iter.hasNext();){
-		System.out.println(h.get(iter.next()));
+	for (Iterator iter = h.values().iterator(); iter.hasNext();){
+		System.out.println(iter.next());
 	}
 }
 	/**
@@ -290,7 +273,6 @@
 		if (external) {
 			fEntryTable.remove(entry._fKey);			
 			fCurrentSpace -= entry._fSpace;
-			privateNotifyDeletionFromCache(entry);
 		} else {
 			if (!close(entry)) return;
 			// buffer close will recursively call #privateRemoveEntry with external==true
@@ -301,7 +283,6 @@
 				// basic removal
 				fEntryTable.remove(entry._fKey);			
 				fCurrentSpace -= entry._fSpace;
-				privateNotifyDeletionFromCache(entry);
 			}
 		}
 	}
@@ -415,8 +396,8 @@
  */
 public String toString() {
 	return 
-		"OverflowingLRUCache " + NumberFormat.getInstance().format(this.fillingRatio()) + "% full\n" + //$NON-NLS-1$ //$NON-NLS-2$
-		this.toStringContents();
+		toStringFillingRation("OverflowingLRUCache ") + //$NON-NLS-1$
+		toStringContents();
 }
 /**
  * Updates the timestamp for the given entry, ensuring that the queue is 
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 f2065fa..f374c43 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,8 +10,9 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
-import java.util.*;
+import java.net.URL;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.Map;
 
 import org.eclipse.core.resources.IContainer;
@@ -20,15 +21,22 @@
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.OperationCanceledException;
 import org.eclipse.core.runtime.Path;
-import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.IClassFile;
 import org.eclipse.jdt.core.ICompilationUnit;
 import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IJavaModelStatusConstants;
+import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.IPackageFragment;
 import org.eclipse.jdt.core.IPackageFragmentRoot;
+import org.eclipse.jdt.core.IParent;
+import org.eclipse.jdt.core.ISourceManipulation;
+import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.WorkingCopyOwner;
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
+import org.eclipse.jdt.internal.core.JavaModelManager.PerProjectInfo;
 import org.eclipse.jdt.internal.core.util.MementoTokenizer;
 import org.eclipse.jdt.internal.core.util.Messages;
 import org.eclipse.jdt.internal.core.util.Util;
@@ -59,8 +67,12 @@
 
 	// check whether this pkg can be opened
 	if (!underlyingResource.isAccessible()) throw newNotPresentException();
-
+	
+	// check that it is not excluded (https://bugs.eclipse.org/bugs/show_bug.cgi?id=138577)
 	int kind = getKind();
+	if (kind == IPackageFragmentRoot.K_SOURCE && Util.isExcluded(this)) 
+		throw newNotPresentException();
+
 
 	// add compilation units/class files from resources
 	HashSet vChildren = new HashSet();
@@ -69,17 +81,23 @@
 		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, inclusionPatterns, exclusionPatterns)) {
-				IJavaElement childElement;
-				if (kind == IPackageFragmentRoot.K_SOURCE && Util.isValidCompilationUnitName(child.getName())) {
-					childElement = new CompilationUnit(this, child.getName(), DefaultWorkingCopyOwner.PRIMARY);
-					vChildren.add(childElement);
-				} else if (kind == IPackageFragmentRoot.K_BINARY && Util.isValidClassFileName(child.getName())) {
-					childElement = getClassFile(child.getName());
-					vChildren.add(childElement);
+		int length = members.length;
+		if (length > 0) {
+			IJavaProject project = getJavaProject();
+			String sourceLevel = project.getOption(JavaCore.COMPILER_SOURCE, true);
+			String complianceLevel = project.getOption(JavaCore.COMPILER_COMPLIANCE, true);
+			for (int i = 0; i < length; i++) {
+				IResource child = members[i];
+				if (child.getType() != IResource.FOLDER
+						&& !Util.isExcluded(child, inclusionPatterns, exclusionPatterns)) {
+					IJavaElement childElement;
+					if (kind == IPackageFragmentRoot.K_SOURCE && Util.isValidCompilationUnitName(child.getName(), sourceLevel, complianceLevel)) {
+						childElement = new CompilationUnit(this, child.getName(), DefaultWorkingCopyOwner.PRIMARY);
+						vChildren.add(childElement);
+					} else if (kind == IPackageFragmentRoot.K_BINARY && Util.isValidClassFileName(child.getName(), sourceLevel, complianceLevel)) {
+						childElement = getClassFile(child.getName());
+						vChildren.add(childElement);
+					}
 				}
 			}
 		}
@@ -156,6 +174,11 @@
 	return Util.equalArraysOrNull(this.names, other.names) &&
 			this.parent.equals(other.parent);
 }
+public boolean exists() {
+	// super.exist() only checks for the parent and the resource existence
+	// so also ensure that the package is not exceluded (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=138577)
+	return super.exists() && !Util.isExcluded(this); 
+}
 /**
  * @see IPackageFragment#getClassFile(String)
  * @exception IllegalArgumentException if the name does not end with ".class"
@@ -164,7 +187,12 @@
 	if (!org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(classFileName)) {
 		throw new IllegalArgumentException(Messages.element_invalidClassFileName); 
 	}
-	return new ClassFile(this, classFileName);
+	// don't hold on the .class file extension to save memory
+	// also make sure to not use substring as the resulting String may hold on the underlying char[] which might be much bigger than necessary
+	int length = classFileName.length() - 6;
+	char[] nameWithoutExtension = new char[length];
+	classFileName.getChars(0, length, nameWithoutExtension, 0);
+	return new ClassFile(this, new String(nameWithoutExtension));
 }
 /**
  * Returns a the collection of class files in this - a folder package fragment which has a root
@@ -430,4 +458,37 @@
 		}
 	}
 }
+/*
+ * @see IJavaElement#getAttachedJavadoc(IProgressMonitor)
+ */
+public String getAttachedJavadoc(IProgressMonitor monitor) throws JavaModelException {
+	PerProjectInfo projectInfo = JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(this.getJavaProject().getProject());
+	String cachedJavadoc = null;
+	synchronized (projectInfo.javadocCache) {
+		cachedJavadoc = (String) projectInfo.javadocCache.get(this);
+	}
+	if (cachedJavadoc != null) {
+		return cachedJavadoc;
+	}
+	URL baseLocation= getJavadocBaseLocation();
+	if (baseLocation == null) {
+		return null;
+	}
+	StringBuffer pathBuffer = new StringBuffer(baseLocation.toExternalForm());
+
+	if (!(pathBuffer.charAt(pathBuffer.length() - 1) == '/')) {
+		pathBuffer.append('/');
+	}
+	String packPath= this.getElementName().replace('.', '/');
+	pathBuffer.append(packPath).append('/').append(JavadocConstants.PACKAGE_FILE_NAME);
+	
+	if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
+	final String contents = getURLContents(String.valueOf(pathBuffer));
+	if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
+	if (contents == null) throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.CANNOT_RETRIEVE_ATTACHED_JAVADOC, this));
+	synchronized (projectInfo.javadocCache) {
+		projectInfo.javadocCache.put(this, contents);
+	}
+	return contents;
+}
 }
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 14704a4..f256bff 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 0896050..ab2825c 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -15,13 +15,7 @@
 import java.util.Map;
 
 import org.eclipse.core.resources.*;
-import org.eclipse.core.resources.IContainer;
-import org.eclipse.core.resources.IFolder;
-import org.eclipse.core.resources.IResource;
 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.*;
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.core.util.MementoTokenizer;
@@ -41,11 +35,7 @@
 	/*
 	 * No source attachment property
 	 */
-	protected final static String NO_SOURCE_ATTACHMENT = ""; //$NON-NLS-1$
-	/*
-	 * No source mapper singleton
-	 */
-	protected final static SourceMapper NO_SOURCE_MAPPER = new SourceMapper();
+	public final static String NO_SOURCE_ATTACHMENT = ""; //$NON-NLS-1$
 
 	/**
 	 * The resource associated with this root.
@@ -113,9 +103,6 @@
 			// check if source path is valid
 			Object target = JavaModel.getTarget(workspace.getRoot(), sourcePath, false);
 			if (target == null) {
-				if (monitor != null) {
-					monitor.done();
-				}
 				throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, sourcePath));
 			}
 			SourceMapper mapper = createSourceMapper(sourcePath, rootPath);
@@ -126,10 +113,11 @@
 			setSourceMapper(mapper);
 		}
 		if (sourcePath == null) {
-			setSourceAttachmentProperty(null); //remove the property
+			Util.setSourceAttachmentProperty(getPath(), null); //remove the property
 		} else {
 			//set the property to the path of the mapped source
-			setSourceAttachmentProperty(
+			Util.setSourceAttachmentProperty(
+				getPath(),
 				sourcePath.toString() 
 				+ (rootPath == null ? "" : (ATTACHMENT_PROPERTY_DELIMITER + rootPath.toString()))); //$NON-NLS-1$
 		}
@@ -151,7 +139,7 @@
 			}
 		}
 	} catch (JavaModelException e) {
-		setSourceAttachmentProperty(null); // loose info - will be recomputed
+		Util.setSourceAttachmentProperty(getPath(), null); // loose info - will be recomputed
 		throw e;
 	} finally {
 		if (monitor != null) {
@@ -211,7 +199,7 @@
 			IContainer rootFolder = (IContainer) underlyingResource;
 			char[][] inclusionPatterns = fullInclusionPatternChars();
 			char[][] exclusionPatterns = fullExclusionPatternChars();
-			computeFolderChildren(rootFolder, !Util.isExcluded(rootFolder, inclusionPatterns, exclusionPatterns), CharOperation.NO_STRINGS, vChildren, inclusionPatterns, exclusionPatterns); //$NON-NLS-1$
+			computeFolderChildren(rootFolder, !Util.isExcluded(rootFolder, inclusionPatterns, exclusionPatterns), CharOperation.NO_STRINGS, vChildren, inclusionPatterns, exclusionPatterns);
 			IJavaElement[] children = new IJavaElement[vChildren.size()];
 			vChildren.toArray(children);
 			info.setChildren(children);
@@ -241,35 +229,39 @@
 		JavaModelManager manager = JavaModelManager.getJavaModelManager();
 		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();
+		int length = members.length;
+		if (length >0) {
+			String sourceLevel = javaProject.getOption(JavaCore.COMPILER_SOURCE, true);
+			String complianceLevel = javaProject.getOption(JavaCore.COMPILER_COMPLIANCE, true);
+			for (int i = 0; i < length; i++) {
+				IResource member = members[i];
+				String memberName = member.getName();
 			
-			switch(member.getType()) {
+				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[] newNames = Util.arrayConcat(pkgName, manager.intern(memberName));
-								computeFolderChildren((IFolder) member, isMemberIncluded, newNames, vChildren, inclusionPatterns, 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)
+			    	case IResource.FOLDER:
+			    		// recurse into sub folders even even parent not included as a sub folder could be included
+			    		// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=65637)
+			    		if (Util.isValidFolderNameForPackage(memberName, sourceLevel, complianceLevel)) {
+			    			// eliminate binary output only if nested inside direct subfolders
+			    			if (javaProject.contains(member)) {
+			    				String[] newNames = Util.arrayConcat(pkgName, manager.intern(memberName));
+			    				boolean isMemberIncluded = !Util.isExcluded(member, inclusionPatterns, exclusionPatterns);
+			    				computeFolderChildren((IFolder) member, isMemberIncluded, newNames, vChildren, inclusionPatterns, 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, sourceLevel, complianceLevel)
 								&& !Util.isExcluded(member, inclusionPatterns, exclusionPatterns)) {
-						hasIncluded = true;
-					    IPackageFragment pkg = getPackageFragment(pkgName);
-					    vChildren.add(pkg); 
-					}
-			        break;
+			    			hasIncluded = true;
+			    			IPackageFragment pkg = getPackageFragment(pkgName);
+			    			vChildren.add(pkg); 
+			    		}
+			    		break;
+				}
 			}
 		}
 	} catch(IllegalArgumentException e){
@@ -319,12 +311,9 @@
  * 		not exist.
  */
 protected int determineKind(IResource underlyingResource) throws JavaModelException {
-	IClasspathEntry[] entries= ((JavaProject)getJavaProject()).getResolvedClasspath(true);
-	for (int i= 0; i < entries.length; i++) {
-		IClasspathEntry entry= entries[i];
-		if (entry.getPath().equals(underlyingResource.getFullPath())) {
-			return entry.getContentKind();
-		}
+	IClasspathEntry entry = ((JavaProject)getJavaProject()).getClasspathEntryFor(underlyingResource.getFullPath());
+	if (entry != null) {
+		return entry.getContentKind();
 	}
 	return IPackageFragmentRoot.K_SOURCE;
 }
@@ -341,7 +330,7 @@
 	if (!(o instanceof PackageFragmentRoot))
 		return false;
 	PackageFragmentRoot other = (PackageFragmentRoot) o;
-	return this.resource.equals(other.resource) && 
+	return getResource().equals(other.getResource()) && 
 			this.parent.equals(other.parent);
 }
 
@@ -352,7 +341,7 @@
 	return super.exists() && validateOnClasspath().isOK();
 }
 
-public IClasspathEntry findSourceAttachmentRecommendation() {
+private IClasspathEntry findSourceAttachmentRecommendation() {
 	try {
 		IPath rootPath = this.getPath();
 		IClasspathEntry entry;
@@ -465,8 +454,9 @@
 	}
 }		
 public String getElementName() {
-	if (this.resource instanceof IFolder)
-		return ((IFolder) this.resource).getName();
+	IResource res = getResource();
+	if (res instanceof IFolder)
+		return ((IFolder) res).getName();
 	return ""; //$NON-NLS-1$
 }
 /**
@@ -589,10 +579,13 @@
 
 	IClasspathEntry rawEntry = null;
 	JavaProject project = (JavaProject)this.getJavaProject();
-	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());
+	project.getResolvedClasspath(); // force the reverse rawEntry cache to be populated
+	Map rootPathToRawEntries = project.getPerProjectInfo().rootPathToRawEntries;
+	if (rootPathToRawEntries != null) {
+		rawEntry = (IClasspathEntry) rootPathToRawEntries.get(this.getPath());
+	}
+	if (rawEntry == null) {
+		throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_NOT_ON_CLASSPATH, this));
 	}
 	return rawEntry;
 }
@@ -610,69 +603,33 @@
 public IPath getSourceAttachmentPath() throws JavaModelException {
 	if (getKind() != K_BINARY) return null;
 	
-	String serverPathString= getSourceAttachmentProperty();
-	if (serverPathString == null) {
-		return null;
-	}
-	int index= serverPathString.lastIndexOf(ATTACHMENT_PROPERTY_DELIMITER);
-	if (index < 0) {
-		// no root path specified
-		return new Path(serverPathString);
-	} else {
-		String serverSourcePathString= serverPathString.substring(0, index);
-		return new Path(serverSourcePathString);
-	}
-}
-
-/**
- * Returns the server property for this package fragment root's
- * source attachement.
- */
-protected String getSourceAttachmentProperty() throws JavaModelException {
-	String propertyString = null;
-	QualifiedName qName= getSourceAttachmentPropertyName();
-	try {
-		propertyString = ResourcesPlugin.getWorkspace().getRoot().getPersistentProperty(qName);
-		
-		// if no existing source attachment information, then lookup a recommendation from classpath entries
-		if (propertyString == null) {
-			IClasspathEntry recommendation = findSourceAttachmentRecommendation();
-			if (recommendation != null) {
-				IPath rootPath = recommendation.getSourceAttachmentRootPath();
-				propertyString = 
-					recommendation.getSourceAttachmentPath().toString() 
-						+ ((rootPath == null) 
-							? "" : //$NON-NLS-1$
-							(ATTACHMENT_PROPERTY_DELIMITER + rootPath.toString())); 
-				setSourceAttachmentProperty(propertyString);
-			} else {
-				// mark as being already looked up
-				setSourceAttachmentProperty(NO_SOURCE_ATTACHMENT);
-			}
-		} else if (NO_SOURCE_ATTACHMENT.equals(propertyString)) {
-			// already looked up and no source attachment found
-			return null;
+	// 1) look source attachment property (set iff attachSource(...) was called
+	IPath path = getPath();
+	String serverPathString= Util.getSourceAttachmentProperty(path);
+	if (serverPathString != null) {
+		int index= serverPathString.lastIndexOf(ATTACHMENT_PROPERTY_DELIMITER);
+		if (index < 0) {
+			// no root path specified
+			return new Path(serverPathString);
+		} else {
+			String serverSourcePathString= serverPathString.substring(0, index);
+			return new Path(serverSourcePathString);
 		}
-		return propertyString;
-	} catch (CoreException ce) {
-		throw new JavaModelException(ce);
 	}
-}
-	
-/**
- * Returns the qualified name for the source attachment property
- * of this root.
- */
-protected QualifiedName getSourceAttachmentPropertyName() {
-	return new QualifiedName(JavaCore.PLUGIN_ID, "sourceattachment: " + this.getPath().toOSString()); //$NON-NLS-1$
-}
 
-public void setSourceAttachmentProperty(String property) {
-	try {
-		ResourcesPlugin.getWorkspace().getRoot().setPersistentProperty(this.getSourceAttachmentPropertyName(), property);
-	} catch (CoreException ce) {
-		// ignore
+	// 2) look at classpath entry
+	IClasspathEntry entry = ((JavaProject) getParent()).getClasspathEntryFor(path);
+	IPath sourceAttachmentPath;
+	if (entry != null && (sourceAttachmentPath = entry.getSourceAttachmentPath()) != null)
+		return sourceAttachmentPath;
+	
+	// 3) look for a recommendation
+	entry = findSourceAttachmentRecommendation();
+	if (entry != null && (sourceAttachmentPath = entry.getSourceAttachmentPath()) != null) {
+		return sourceAttachmentPath;
 	}
+	
+	return null;	
 }
 
 /**
@@ -691,17 +648,31 @@
 public IPath getSourceAttachmentRootPath() throws JavaModelException {
 	if (getKind() != K_BINARY) return null;
 	
-	String serverPathString= getSourceAttachmentProperty();
-	if (serverPathString == null) {
-		return null;
+	// 1) look source attachment property (set iff attachSource(...) was called
+	IPath path = getPath();
+	String serverPathString= Util.getSourceAttachmentProperty(path);
+	if (serverPathString != null) {
+		int index = serverPathString.lastIndexOf(ATTACHMENT_PROPERTY_DELIMITER);
+		if (index == -1) return null;
+		String serverRootPathString= IPackageFragmentRoot.DEFAULT_PACKAGEROOT_PATH;
+		if (index != serverPathString.length() - 1) {
+			serverRootPathString= serverPathString.substring(index + 1);
+		}
+		return new Path(serverRootPathString);
 	}
-	int index = serverPathString.lastIndexOf(ATTACHMENT_PROPERTY_DELIMITER);
-	if (index == -1) return null;
-	String serverRootPathString= IPackageFragmentRoot.DEFAULT_PACKAGEROOT_PATH;
-	if (index != serverPathString.length() - 1) {
-		serverRootPathString= serverPathString.substring(index + 1);
-	}
-	return new Path(serverRootPathString);
+
+	// 2) look at classpath entry
+	IClasspathEntry entry = ((JavaProject) getParent()).getClasspathEntryFor(path);
+	IPath sourceAttachmentRootPath;
+	if (entry != null && (sourceAttachmentRootPath = entry.getSourceAttachmentRootPath()) != null)
+		return sourceAttachmentRootPath;
+	
+	// 3) look for a recomendation
+	entry = findSourceAttachmentRecommendation();
+	if (entry != null && (sourceAttachmentRootPath = entry.getSourceAttachmentRootPath()) != null)
+		return sourceAttachmentRootPath;
+	
+	return null;	
 }
 
 /**
@@ -715,28 +686,12 @@
 		if (mapper == null) {
 			// first call to this method
 			IPath sourcePath= getSourceAttachmentPath();
-			if (sourcePath != null) {
-				IPath rootPath= getSourceAttachmentRootPath();
-				mapper = this.createSourceMapper(sourcePath, rootPath);
-				if (rootPath == null && mapper.rootPath != null) {
-					// as a side effect of calling the SourceMapper constructor, the root path was computed
-					rootPath = new Path(mapper.rootPath);
-					
-					//set the property to the path of the mapped source
-					this.setSourceAttachmentProperty(
-						sourcePath.toString() 
-						+ ATTACHMENT_PROPERTY_DELIMITER 
-						+ rootPath.toString());
-				}
-				rootInfo.setSourceMapper(mapper);
-			} else {
-				// remember that no source is attached
-				rootInfo.setSourceMapper(NO_SOURCE_MAPPER);
-				mapper = null;
-			}
-		} else if (mapper == NO_SOURCE_MAPPER) {
-			// a previous call to this method found out that no source was attached
-			mapper = null;
+			IPath rootPath= getSourceAttachmentRootPath();
+			if (sourcePath == null)
+				mapper = createSourceMapper(getPath(), rootPath); // attach root to itself
+			else
+				mapper = createSourceMapper(sourcePath, rootPath);
+			rootInfo.setSourceMapper(mapper);
 		}
 	} catch (JavaModelException e) {
 		// no source can be attached
@@ -762,7 +717,7 @@
 }
 
 public int hashCode() {
-	return this.resource.hashCode();
+	return getResource().hashCode();
 }
 
 /**
@@ -788,12 +743,9 @@
 	try {
 		// check package fragment root on classpath of its project
 		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)) {
-				return Status.OK_STATUS;
-			}
+		IClasspathEntry entry = project.getClasspathEntryFor(path);	
+		if (entry != null) {
+			return Status.OK_STATUS;
 		}
 	} catch(JavaModelException e){
 		// could not read classpath, then assume it is outside
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 caa9645..22cf527 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -16,9 +16,6 @@
 import org.eclipse.core.runtime.IPath;
 
 import org.eclipse.jdt.core.*;
-import org.eclipse.jdt.core.IPackageFragmentRoot;
-import org.eclipse.jdt.core.IJavaProject;
-import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.internal.core.util.Util;
 
 /**
@@ -60,39 +57,43 @@
 	Object[] nonJavaResources = new IResource[5];
 	int nonJavaResourcesCounter = 0;
 	try {
-		IClasspathEntry[] classpath = project.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
+		IClasspathEntry[] classpath = project.getResolvedClasspath();
 		IResource[] members = folder.members();
-		nextResource: for (int i = 0, max = members.length; i < max; i++) {
-			IResource member = members[i];
-			switch (member.getType()) {
-				case IResource.FILE :
-					String fileName = member.getName();
+		int length = members.length;
+		if (length > 0) {
+			String sourceLevel = project.getOption(JavaCore.COMPILER_SOURCE, true);
+			String complianceLevel = project.getOption(JavaCore.COMPILER_COMPLIANCE, true);
+			nextResource: for (int i = 0; i < length; i++) {
+				IResource member = members[i];
+				switch (member.getType()) {
+					case IResource.FILE :
+						String fileName = member.getName();
 					
-					// ignore .java files that are not excluded
-					if (Util.isValidCompilationUnitName(fileName) && !Util.isExcluded(member, inclusionPatterns, exclusionPatterns)) 
-						continue nextResource;
-					// ignore .class files
-					if (Util.isValidClassFileName(fileName)) 
-						continue nextResource;
-					// ignore .zip or .jar file on classpath
-					if (org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(fileName) && isClasspathEntry(member.getFullPath(), classpath)) 
-						continue nextResource;
-					break;
+						// ignore .java files that are not excluded
+						if (Util.isValidCompilationUnitName(fileName, sourceLevel, complianceLevel) && !Util.isExcluded(member, inclusionPatterns, exclusionPatterns)) 
+							continue nextResource;
+						// ignore .class files
+						if (Util.isValidClassFileName(fileName, sourceLevel, complianceLevel)) 
+							continue nextResource;
+						// ignore .zip or .jar file on classpath
+						if (org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(fileName) && isClasspathEntry(member.getFullPath(), classpath)) 
+							continue nextResource;
+						break;
 
-				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, inclusionPatterns, exclusionPatterns) 
-								|| isClasspathEntry(member.getFullPath(), classpath)))
-						continue nextResource;
-					break;
-			}
-			if (nonJavaResources.length == nonJavaResourcesCounter) {
-				// resize
-				System.arraycopy(nonJavaResources, 0, (nonJavaResources = new IResource[nonJavaResourcesCounter * 2]), 0, nonJavaResourcesCounter);
-			}
-			nonJavaResources[nonJavaResourcesCounter++] = member;
-
+					case IResource.FOLDER :
+						// ignore valid packages or excluded folders that correspond to a nested pkg fragment root
+						if (Util.isValidFolderNameForPackage(member.getName(), sourceLevel, complianceLevel)
+								&& (!Util.isExcluded(member, inclusionPatterns, exclusionPatterns) 
+										|| isClasspathEntry(member.getFullPath(), classpath)))
+							continue nextResource;
+						break;
+				}
+				if (nonJavaResources.length == nonJavaResourcesCounter) {
+					// resize
+					System.arraycopy(nonJavaResources, 0, (nonJavaResources = new IResource[nonJavaResourcesCounter * 2]), 0, nonJavaResourcesCounter);
+				}
+				nonJavaResources[nonJavaResourcesCounter++] = member;
+			}	
 		}
 		if (nonJavaResources.length != nonJavaResourcesCounter) {
 			System.arraycopy(nonJavaResources, 0, (nonJavaResources = new IResource[nonJavaResourcesCounter]), 0, nonJavaResourcesCounter);
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ProjectReferenceChange.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ProjectReferenceChange.java
new file mode 100755
index 0000000..e0ff9c4
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ProjectReferenceChange.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core;
+
+import java.util.HashSet;
+import java.util.Iterator;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IProjectDescription;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.core.util.Util;
+
+public class ProjectReferenceChange {
+	
+	private JavaProject project;
+	private IClasspathEntry[] oldResolvedClasspath;
+	
+	public ProjectReferenceChange(JavaProject project, IClasspathEntry[] oldResolvedClasspath) {
+		this.project = project;
+		this.oldResolvedClasspath = oldResolvedClasspath;
+	}
+
+	/*
+	 * Update projects references so that the build order is consistent with the classpath
+	 */
+	public void updateProjectReferencesIfNecessary() throws JavaModelException {
+		
+		String[] oldRequired = this.oldResolvedClasspath == null ? CharOperation.NO_STRINGS : this.project.projectPrerequisites(this.oldResolvedClasspath);
+		IClasspathEntry[] newResolvedClasspath = this.project.getResolvedClasspath();
+		String[] newRequired = this.project.projectPrerequisites(newResolvedClasspath);
+		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){
+			if (!ExternalJavaProject.EXTERNAL_PROJECT_NAME.equals(this.project.getElementName()))
+				throw new JavaModelException(e);
+		}
+	}
+	public String toString() {
+		return "ProjectRefenceChange: " + this.project.getElementName(); //$NON-NLS-1$
+	}
+}
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 3cec2ff..82756ac 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,104 +10,255 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
+import java.util.HashMap;
+import java.util.Iterator;
 import java.util.Map;
 
+import org.eclipse.core.runtime.ISafeRunnable;
 import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.SafeRunner;
 import org.eclipse.jdt.core.*;
-import org.eclipse.jdt.core.IJavaElement;
-import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.compiler.CategorizedProblem;
+import org.eclipse.jdt.core.compiler.CompilationParticipant;
+import org.eclipse.jdt.core.compiler.ReconcileContext;
 import org.eclipse.jdt.core.dom.AST;
 import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
 import org.eclipse.jdt.internal.core.util.Messages;
+import org.eclipse.jdt.internal.core.util.Util;
 
 /**
  * Reconcile a working copy and signal the changes through a delta.
+ * <p>
+ * High level summmary of what a reconcile does:
+ * <ul>
+ * <li>populates the model with the new working copy contents</li>
+ * <li>fires a fine grained delta (flag F_FINE_GRAINED) describing the difference between the previous content
+ *      and the new content (which method was added/removed, which field was changed, etc.)</li>
+ * <li>computes problems and reports them to the IProblemRequestor (begingReporting(), n x acceptProblem(...), endReporting()) iff
+ *     	(working copy is not consistent with its buffer || forceProblemDetection is set)
+ * 		&& problem requestor is active
+ * </li>
+ * <li>produces a DOM AST (either JLS_2, JLS_3 or NO_AST) that is resolved if flag is set</li>
+ * <li>notifies compilation participants of the reconcile allowing them to participate in this operation and report problems</li>
+ * </ul>
  */
 public class ReconcileWorkingCopyOperation extends JavaModelOperation {
 	public static boolean PERF = false;
-	
-	boolean createAST;
-	int astLevel;
-	boolean forceProblemDetection;
+
+	public int astLevel;
+	public boolean resolveBindings;
+	public HashMap problems;
+	public int reconcileFlags;
 	WorkingCopyOwner workingCopyOwner;
-	org.eclipse.jdt.core.dom.CompilationUnit ast;
-	
-	public ReconcileWorkingCopyOperation(IJavaElement workingCopy, boolean creatAST, int astLevel, boolean forceProblemDetection, WorkingCopyOwner workingCopyOwner) {
+	public org.eclipse.jdt.core.dom.CompilationUnit ast;
+	public JavaElementDeltaBuilder deltaBuilder;
+	public boolean requestorIsActive;
+
+	public ReconcileWorkingCopyOperation(IJavaElement workingCopy, int astLevel, int reconcileFlags, WorkingCopyOwner workingCopyOwner) {
 		super(new IJavaElement[] {workingCopy});
-		this.createAST = creatAST;
 		this.astLevel = astLevel;
-		this.forceProblemDetection = forceProblemDetection;
+		this.reconcileFlags = reconcileFlags;
 		this.workingCopyOwner = workingCopyOwner;
 	}
+
 	/**
 	 * @exception JavaModelException if setting the source
 	 * 	of the original compilation unit fails
 	 */
 	protected void executeOperation() throws JavaModelException {
-		if (this.progressMonitor != null){
-			if (this.progressMonitor.isCanceled()) 
-				throw new OperationCanceledException();
-			this.progressMonitor.beginTask(Messages.element_reconciling, 2); 
-		}
-	
-		CompilationUnit workingCopy = getWorkingCopy();
-		boolean wasConsistent = workingCopy.isConsistent();
+		checkCanceled();
 		try {
-			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
-				this.ast = workingCopy.makeConsistent(this.createAST, this.astLevel, this.progressMonitor);
-				deltaBuilder.buildDeltas();
+			beginTask(Messages.element_reconciling, 2);
 
-				if (progressMonitor != null) progressMonitor.worked(2);
-			
-				// register the deltas
-				if (deltaBuilder.delta != null) {
-					addReconcileDelta(workingCopy, deltaBuilder.delta);
+			CompilationUnit workingCopy = getWorkingCopy();
+			boolean wasConsistent = workingCopy.isConsistent();
+
+			// check is problem requestor is active
+			IProblemRequestor problemRequestor = workingCopy.getPerWorkingCopyInfo();
+			if (problemRequestor != null) 
+				problemRequestor =  ((JavaModelManager.PerWorkingCopyInfo)problemRequestor).getProblemRequestor();
+			boolean defaultRequestorIsActive = problemRequestor != null && problemRequestor.isActive();
+			IProblemRequestor ownerProblemRequestor = this.workingCopyOwner.getProblemRequestor(workingCopy);
+			boolean ownerRequestorIsActive = ownerProblemRequestor != null && ownerProblemRequestor != problemRequestor && ownerProblemRequestor.isActive();
+			this.requestorIsActive = defaultRequestorIsActive || ownerRequestorIsActive;
+
+			// create the delta builder (this remembers the current content of the cu)
+			this.deltaBuilder = new JavaElementDeltaBuilder(workingCopy);
+
+			// make working copy consistent if needed and compute AST if needed
+			makeConsistent(workingCopy);
+
+			// notify reconcile participants only if working copy was not consistent or if forcing problem detection
+			// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=177319)
+			if (!wasConsistent || ((this.reconcileFlags & ICompilationUnit.FORCE_PROBLEM_DETECTION) != 0)) {
+				notifyParticipants(workingCopy);
+
+				// recreate ast if one participant reset it
+				if (this.ast == null)
+					makeConsistent(workingCopy);
+			}
+
+			// report problems
+			if (this.problems != null && (((this.reconcileFlags & ICompilationUnit.FORCE_PROBLEM_DETECTION) != 0) || !wasConsistent)) {
+				if (defaultRequestorIsActive) {
+					reportProblems(workingCopy, problemRequestor);
 				}
-			} 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, !this.createAST/*reset env if not creating AST*/, 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*/, workingCopy, this.progressMonitor);
-								if (progressMonitor != null) progressMonitor.worked(1);
-							}
-					    } finally {
-					        if (unit != null) {
-					            unit.cleanUp();
-					        }
-					    }
+				if (ownerRequestorIsActive) {
+					reportProblems(workingCopy, ownerProblemRequestor);
+				}
+			}
+
+			// report delta
+			JavaElementDelta delta = this.deltaBuilder.delta;
+			if (delta != null) {
+				addReconcileDelta(workingCopy, delta);
+			}
+		} finally {
+			done();
+		}
+	}
+
+	/**
+	 * Report working copy problems to a given requestor.
+	 *
+	 * @param workingCopy
+	 * @param problemRequestor
+	 */
+	private void reportProblems(CompilationUnit workingCopy, IProblemRequestor problemRequestor) {
+		try {
+			problemRequestor.beginReporting();
+			for (Iterator iteraror = this.problems.values().iterator(); iteraror.hasNext();) {
+				CategorizedProblem[] categorizedProblems = (CategorizedProblem[]) iteraror.next();
+				if (categorizedProblems == null) continue;
+				for (int i = 0, length = categorizedProblems.length; i < length; i++) {
+					CategorizedProblem problem = categorizedProblems[i];
+					if (JavaModelManager.VERBOSE){
+						System.out.println("PROBLEM FOUND while reconciling : " + problem.getMessage());//$NON-NLS-1$
 					}
+					if (this.progressMonitor != null && this.progressMonitor.isCanceled()) break;
+					problemRequestor.acceptProblem(problem);
 				}
 			}
 		} finally {
-			if (progressMonitor != null) progressMonitor.done();
+			problemRequestor.endReporting();
 		}
 	}
+
 	/**
 	 * Returns the working copy this operation is working on.
 	 */
 	protected CompilationUnit getWorkingCopy() {
 		return (CompilationUnit)getElementToProcess();
 	}
-	/**
-	 * @see JavaModelOperation#isReadOnly
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.jdt.internal.core.JavaModelOperation#isReadOnly()
 	 */
 	public boolean isReadOnly() {
 		return true;
 	}
+
+	/*
+	 * Makes the given working copy consistent, computes the delta and computes an AST if needed.
+	 * Returns the AST.
+	 */
+	public org.eclipse.jdt.core.dom.CompilationUnit makeConsistent(CompilationUnit workingCopy) throws JavaModelException {
+		if (!workingCopy.isConsistent()) {
+			// make working copy consistent
+			if (this.problems == null) this.problems = new HashMap();
+			this.resolveBindings = this.requestorIsActive;
+			this.ast = workingCopy.makeConsistent(this.astLevel, this.resolveBindings, reconcileFlags, this.problems, this.progressMonitor);
+			this.deltaBuilder.buildDeltas();
+			if (this.ast != null && this.deltaBuilder.delta != null)
+				this.deltaBuilder.delta.changedAST(this.ast);
+			return this.ast;
+		}
+		if (this.ast != null) 
+			return this.ast; // no need to recompute AST if known already
+		
+		CompilationUnitDeclaration unit = null;
+		char[] contents = null;
+		try {
+			// find problems if needed
+			if (JavaProject.hasJavaNature(workingCopy.getJavaProject().getProject()) 
+					&& (this.reconcileFlags & ICompilationUnit.FORCE_PROBLEM_DETECTION) != 0) {
+				this.resolveBindings = this.requestorIsActive;
+				if (this.problems == null)
+					this.problems = new HashMap();
+				contents = workingCopy.getContents();
+				unit =
+					CompilationUnitProblemFinder.process(
+						workingCopy,
+						contents,
+						this.workingCopyOwner,
+						this.problems,
+						this.astLevel != ICompilationUnit.NO_AST/*creating AST if level is not NO_AST */,
+						reconcileFlags,
+						this.progressMonitor);
+				if (this.progressMonitor != null) this.progressMonitor.worked(1);
+			}
+			
+			// create AST if needed
+			if (this.astLevel != ICompilationUnit.NO_AST 
+					&& unit !=null/*unit is null if working copy is consistent && (problem detection not forced || non-Java project) -> don't create AST as per API*/) {
+				Map options = workingCopy.getJavaProject().getOptions(true);
+				// convert AST
+				this.ast =
+					AST.convertCompilationUnit(
+						this.astLevel,
+						unit,
+						contents,
+						options,
+						this.resolveBindings,
+						workingCopy,
+						reconcileFlags,
+						this.progressMonitor);
+				if (this.ast != null) {
+					this.deltaBuilder.delta = new JavaElementDelta(workingCopy);
+					this.deltaBuilder.delta.changedAST(this.ast);
+				}
+				if (this.progressMonitor != null) this.progressMonitor.worked(1);
+			}
+	    } catch (JavaModelException e) {
+	    	if (JavaProject.hasJavaNature(workingCopy.getJavaProject().getProject()))
+	    		throw e;
+	    	// else JavaProject has lost its nature (or most likely was closed/deleted) while reconciling -> ignore
+	    	// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=100919)
+	    } finally {
+	        if (unit != null) {
+	            unit.cleanUp();
+	        }
+	    }
+		return this.ast;
+	}
+	
+	private void notifyParticipants(final CompilationUnit workingCopy) {
+		IJavaProject javaProject = getWorkingCopy().getJavaProject();
+		CompilationParticipant[] participants = JavaModelManager.getJavaModelManager().compilationParticipants.getCompilationParticipants(javaProject);
+		if (participants == null) return;
+
+		final ReconcileContext context = new ReconcileContext(this, workingCopy);
+		for (int i = 0, length = participants.length; i < length; i++) {
+			final CompilationParticipant participant = participants[i];
+			SafeRunner.run(new ISafeRunnable() {
+				public void handleException(Throwable exception) {
+					if (exception instanceof Error) {
+						throw (Error) exception; // errors are not supposed to be caught
+					} else if (exception instanceof OperationCanceledException)
+						throw (OperationCanceledException) exception;
+					else if (exception instanceof UnsupportedOperationException) {
+						// might want to disable participant as it tried to modify the buffer of the working copy being reconciled
+						Util.log(exception, "Reconcile participant attempted to modify the buffer of the working copy being reconciled"); //$NON-NLS-1$
+					} else
+						Util.log(exception, "Exception occurred in reconcile participant"); //$NON-NLS-1$
+				}
+				public void run() throws Exception {
+					participant.reconcile(context);
+				}
+			});
+		}
+	}
+
 	protected IJavaModelStatus verify() {
 		IJavaModelStatus status = super.verify();
 		if (!status.isOK()) {
@@ -120,5 +271,4 @@
 		return status;
 	}
 
-
 }
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 4bb5ece..b35d79b 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -16,7 +16,6 @@
 import org.eclipse.jdt.core.IParent;
 import org.eclipse.jdt.core.IRegion;
 
-
 /**
  * @see IRegion
  */
@@ -110,7 +109,7 @@
  *
  * <p>Children are all children, not just direct children.
  */
-private void removeAllChildren(IJavaElement element) {
+protected void removeAllChildren(IJavaElement element) {
 	if (element instanceof IParent) {
 		ArrayList newRootElements = new ArrayList();
 		for (int i = 0, size = fRootElements.size(); i < size; i++) {
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 352fe23..5bf4076 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -65,8 +65,6 @@
  * @see MultiOperation
  */
 protected void verify(IJavaElement element) throws JavaModelException {
-	int elementType = element.getElementType();
-	
 	if (element == null || !element.exists())
 		error(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, element);
 		
@@ -76,6 +74,7 @@
 	if (!(element instanceof ISourceReference))
 		error(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, element);
 		
+	int elementType = element.getElementType();
 	if (elementType < IJavaElement.TYPE || elementType == IJavaElement.INITIALIZER)
 		error(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, element);
 		
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 1879091..d48ff1a 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedBinaryField.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedBinaryField.java
index 3e24250..81c0793 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedBinaryField.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedBinaryField.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004, 2005 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -51,4 +51,10 @@
 			buffer.append("}"); //$NON-NLS-1$
 		}
 	}
+
+	public JavaElement unresolved() {
+		SourceRefElement handle = new BinaryField(this.parent, this.name);
+		handle.occurrenceCount = this.occurrenceCount;
+		return handle;
+	}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedBinaryMethod.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedBinaryMethod.java
index 5c68ee4..aff1171 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedBinaryMethod.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedBinaryMethod.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004, 2005 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -37,6 +37,7 @@
 	public boolean isResolved() {
 		return true;
 	}
+	
 	/**
 	 * @private Debugging purposes
 	 */
@@ -48,4 +49,10 @@
 			buffer.append("}"); //$NON-NLS-1$
 		}
 	}
+	
+	public JavaElement unresolved() {
+		SourceRefElement handle = new BinaryMethod(this.parent, this.name, this.parameterTypes);
+		handle.occurrenceCount = this.occurrenceCount;
+		return handle;
+	}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedBinaryType.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedBinaryType.java
index 90b3553..b1cc4ad 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedBinaryType.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedBinaryType.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004, 2005 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -57,4 +57,10 @@
 			buffer.append("}"); //$NON-NLS-1$
 		}
 	}
+	
+	public JavaElement unresolved() {
+		SourceRefElement handle = new BinaryType(this.parent, this.name);
+		handle.occurrenceCount = this.occurrenceCount;
+		return handle;
+	}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedSourceField.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedSourceField.java
index ec7e24d..d710f04 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedSourceField.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedSourceField.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004, 2005 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -51,4 +51,10 @@
 			buffer.append("}"); //$NON-NLS-1$
 		}
 	}
+	
+	public JavaElement unresolved() {
+		SourceRefElement handle = new SourceField(this.parent, this.name);
+		handle.occurrenceCount = this.occurrenceCount;
+		return handle;
+	}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedSourceMethod.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedSourceMethod.java
index 3ba8dba..1b67651 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedSourceMethod.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedSourceMethod.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004, 2005 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -38,6 +38,7 @@
 	public boolean isResolved() {
 		return true;
 	}
+	
 	/**
 	 * @private Debugging purposes
 	 */
@@ -49,4 +50,10 @@
 			buffer.append("}"); //$NON-NLS-1$
 		}
 	}
+
+	public JavaElement unresolved() {
+		SourceRefElement handle = new SourceMethod(this.parent, this.name, this.parameterTypes);
+		handle.occurrenceCount = this.occurrenceCount;
+		return handle;
+	}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedSourceType.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedSourceType.java
index b61905c..59c4e6d 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedSourceType.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedSourceType.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004, 2005 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -57,4 +57,10 @@
 			buffer.append("}"); //$NON-NLS-1$
 		}
 	}
+	
+	public JavaElement unresolved() {
+		SourceRefElement handle = new SourceType(this.parent, this.name);
+		handle.occurrenceCount = this.occurrenceCount;
+		return handle;
+	}
 }
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 4da06fa..45acefc 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -13,17 +13,10 @@
 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.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.internal.codeassist.ISearchRequestor;
 import org.eclipse.jdt.internal.compiler.env.AccessRestriction;
-import org.eclipse.jdt.internal.compiler.env.AccessRuleSet;
 import org.eclipse.jdt.internal.compiler.env.IBinaryType;
 import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
 import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
@@ -74,6 +67,24 @@
 		this(project, owner == null ? null : JavaModelManager.getJavaModelManager().getWorkingCopies(owner, true/*add primary WCs*/));
 	}
 
+	private static int convertSearchFilterToModelFilter(int searchFilter) {
+		switch (searchFilter) {
+			case IJavaSearchConstants.CLASS:
+				return NameLookup.ACCEPT_CLASSES;
+			case IJavaSearchConstants.INTERFACE:
+				return NameLookup.ACCEPT_INTERFACES;
+			case IJavaSearchConstants.ENUM:
+				return NameLookup.ACCEPT_ENUMS;
+			case IJavaSearchConstants.ANNOTATION_TYPE:
+				return NameLookup.ACCEPT_ANNOTATIONS;
+			case IJavaSearchConstants.CLASS_AND_ENUM:
+				return NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_ENUMS;
+			case IJavaSearchConstants.CLASS_AND_INTERFACE:
+				return NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES;
+			default:
+				return NameLookup.ACCEPT_ALL;
+		}
+	}
 	/**
 	 * Returns the given type in the the given package if it exists,
 	 * otherwise <code>null</code>.
@@ -81,43 +92,25 @@
 	protected NameEnvironmentAnswer find(String typeName, String packageName) {
 		if (packageName == null)
 			packageName = IPackageFragment.DEFAULT_PACKAGE_NAME;
-		IType type =
+		NameLookup.Answer answer =
 			this.nameLookup.findType(
 				typeName,
 				packageName,
-				false,
-				NameLookup.ACCEPT_ALL);
-		if (type != null) {
-			boolean isBinary = type instanceof BinaryType;
-			
-			// determine associated access restriction
-			AccessRestriction accessRestriction = null;
-			
-			if (this.checkAccessRestrictions && (isBinary || !type.getJavaProject().equals(this.project))) {
-				PackageFragmentRoot root = (PackageFragmentRoot)type.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
-				ClasspathEntry entry = (ClasspathEntry) this.nameLookup.rootToResolvedEntries.get(root);
-				if (entry != null) { // reverse map always contains resolved CP entry
-					AccessRuleSet accessRuleSet = entry.getAccessRuleSet();
-					if (accessRuleSet != null) {
-						// TODO (philippe) improve char[] <-> String conversions to avoid performing them on the fly
-						char[][] packageChars = CharOperation.splitOn('.', packageName.toCharArray());
-						char[] classFileChars = type.getElementName().toCharArray();
-						accessRestriction = accessRuleSet.getViolatedRestriction(CharOperation.concatWith(packageChars, classFileChars, '/'));
-					}
-				}
-			}
-			
+				false/*exact match*/,
+				NameLookup.ACCEPT_ALL,
+				this.checkAccessRestrictions);
+		if (answer != null) {
 			// construct name env answer
-			if (isBinary) { // BinaryType
+			if (answer.type instanceof BinaryType) { // BinaryType
 				try {
-					return new NameEnvironmentAnswer((IBinaryType) ((BinaryType) type).getElementInfo(), accessRestriction);
+					return new NameEnvironmentAnswer((IBinaryType) ((BinaryType) answer.type).getElementInfo(), answer.restriction);
 				} catch (JavaModelException npe) {
 					return null;
 				}
 			} else { //SourceType
 				try {
 					// retrieve the requested type
-					SourceTypeElementInfo sourceType = (SourceTypeElementInfo)((SourceType)type).getElementInfo();
+					SourceTypeElementInfo sourceType = (SourceTypeElementInfo)((SourceType) answer.type).getElementInfo();
 					ISourceType topLevelType = sourceType;
 					while (topLevelType.getEnclosingType() != null) {
 						topLevelType = topLevelType.getEnclosingType();
@@ -135,7 +128,7 @@
 						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, accessRestriction);
+					return new NameEnvironmentAnswer(sourceTypes, answer.restriction);
 				} catch (JavaModelException npe) {
 					return null;
 				}
@@ -159,6 +152,107 @@
 	}
 
 	/**
+	 * Find the top-level types that are defined
+	 * in the current environment and whose simple name matches the given name.
+	 *
+	 * The types found are passed to one of the following methods (if additional
+	 * information is known about the types):
+	 *    ISearchRequestor.acceptType(char[][] packageName, char[] typeName)
+	 *    ISearchRequestor.acceptClass(char[][] packageName, char[] typeName, int modifiers)
+	 *    ISearchRequestor.acceptInterface(char[][] packageName, char[] typeName, int modifiers)
+	 *
+	 * This method can not be used to find member types... member
+	 * types are found relative to their enclosing type.
+	 */
+	public void findExactTypes(char[] name, final boolean findMembers, int searchFor, final ISearchRequestor storage) {
+
+		try {
+			final String excludePath;
+			if (this.unitToSkip != null) {
+				if (!(this.unitToSkip instanceof IJavaElement)) {
+					// revert to model investigation
+					findExactTypes(
+						new String(name),
+						storage,
+						convertSearchFilterToModelFilter(searchFor));
+					return;
+				}
+				excludePath = ((IJavaElement) this.unitToSkip).getPath().toString();
+			} else {
+				excludePath = null;
+			}
+
+			IProgressMonitor progressMonitor = new IProgressMonitor() {
+				boolean isCanceled = false;
+				public void beginTask(String n, int totalWork) {
+					// implements interface method
+				}
+				public void done() {
+					// implements interface method
+				}
+				public void internalWorked(double work) {
+					// implements interface method
+				}
+				public boolean isCanceled() {
+					return isCanceled;
+				}
+				public void setCanceled(boolean value) {
+					isCanceled = value;
+				}
+				public void setTaskName(String n) {
+					// implements interface method
+				}
+				public void subTask(String n) {
+					// implements interface method
+				}
+				public void worked(int work) {
+					// implements interface method
+				}
+			};
+			IRestrictedAccessTypeRequestor typeRequestor = new IRestrictedAccessTypeRequestor() {
+				public void acceptType(int modifiers, char[] packageName, char[] simpleTypeName, char[][] enclosingTypeNames, String path, AccessRestriction access) {
+					if (excludePath != null && excludePath.equals(path))
+						return;
+					if (!findMembers && enclosingTypeNames != null && enclosingTypeNames.length > 0)
+						return; // accept only top level types
+					storage.acceptType(packageName, simpleTypeName, enclosingTypeNames, modifiers, access);
+				}
+			};
+			try {
+				new BasicSearchEngine(this.workingCopies).searchAllTypeNames(
+					null,
+					SearchPattern.R_EXACT_MATCH,
+					name,
+					SearchPattern.R_EXACT_MATCH,
+					searchFor,
+					this.searchScope,
+					typeRequestor,
+					CANCEL_IF_NOT_READY_TO_SEARCH,
+					progressMonitor);
+			} catch (OperationCanceledException e) {
+				findExactTypes(
+					new String(name),
+					storage,
+					convertSearchFilterToModelFilter(searchFor));
+			}
+		} catch (JavaModelException e) {
+			findExactTypes(
+				new String(name),
+				storage,
+				convertSearchFilterToModelFilter(searchFor));
+		}
+	}
+	
+	/**
+	 * Returns all types whose simple name matches with the given <code>name</code>.
+	 */
+	private void findExactTypes(String name, ISearchRequestor storage, int type) {
+		SearchableEnvironmentRequestor requestor =
+			new SearchableEnvironmentRequestor(storage, this.unitToSkip, this.project, this.nameLookup);
+		this.nameLookup.seekTypes(name, null, false, type, requestor);
+	}
+	
+	/**
 	 * @see org.eclipse.jdt.internal.compiler.env.INameEnvironment#findType(char[][])
 	 */
 	public NameEnvironmentAnswer findType(char[][] compoundTypeName) {
@@ -191,7 +285,7 @@
 	}
 
 	/**
-	 * Find the top-level types (classes and interfaces) that are defined
+	 * Find the top-level types that are defined
 	 * in the current environment and whose name starts with the
 	 * given prefix. The prefix is a qualified name separated by periods
 	 * or a simple name (ex. java.util.V or V).
@@ -205,7 +299,7 @@
 	 * This method can not be used to find member types... member
 	 * types are found relative to their enclosing type.
 	 */
-	public void findTypes(char[] prefix, final boolean findMembers, final ISearchRequestor storage) {
+	public void findTypes(char[] prefix, final boolean findMembers, boolean camelCaseMatch, int searchFor, final ISearchRequestor storage) {
 
 		/*
 			if (true){
@@ -221,7 +315,7 @@
 					findTypes(
 						new String(prefix),
 						storage,
-						NameLookup.ACCEPT_ALL);
+						convertSearchFilterToModelFilter(searchFor));
 					return;
 				}
 				excludePath = ((IJavaElement) this.unitToSkip).getPath().toString();
@@ -232,12 +326,20 @@
 			char[] qualification, simpleName;
 			if (lastDotIndex < 0) {
 				qualification = null;
-				simpleName = CharOperation.toLowerCase(prefix);
+				if (camelCaseMatch) {
+					simpleName = prefix;
+				} else {
+					simpleName = CharOperation.toLowerCase(prefix);
+				}
 			} else {
 				qualification = CharOperation.subarray(prefix, 0, lastDotIndex);
-				simpleName =
-					CharOperation.toLowerCase(
-						CharOperation.subarray(prefix, lastDotIndex + 1, prefix.length));
+				if (camelCaseMatch) {
+					simpleName = CharOperation.subarray(prefix, lastDotIndex + 1, prefix.length);
+				} else {
+					simpleName =
+						CharOperation.toLowerCase(
+							CharOperation.subarray(prefix, lastDotIndex + 1, prefix.length));
+				}
 			}
 
 			IProgressMonitor progressMonitor = new IProgressMonitor() {
@@ -277,11 +379,14 @@
 				}
 			};
 			try {
+				int matchRule = SearchPattern.R_PREFIX_MATCH;
+				if (camelCaseMatch) matchRule |= SearchPattern.R_CAMELCASE_MATCH;
 				new BasicSearchEngine(this.workingCopies).searchAllTypeNames(
 					qualification,
+					SearchPattern.R_EXACT_MATCH,
 					simpleName,
-					SearchPattern.R_PREFIX_MATCH, // not case sensitive
-					IJavaSearchConstants.TYPE,
+					matchRule, // not case sensitive
+					searchFor,
 					this.searchScope,
 					typeRequestor,
 					CANCEL_IF_NOT_READY_TO_SEARCH,
@@ -290,13 +395,13 @@
 				findTypes(
 					new String(prefix),
 					storage,
-					NameLookup.ACCEPT_ALL);
+					convertSearchFilterToModelFilter(searchFor));
 			}
 		} catch (JavaModelException e) {
 			findTypes(
 				new String(prefix),
 				storage,
-				NameLookup.ACCEPT_ALL);
+				convertSearchFilterToModelFilter(searchFor));
 		}
 	}
 
@@ -307,6 +412,7 @@
 	 * the <code>prefix</code> are returned.
 	 */
 	private void findTypes(String prefix, ISearchRequestor storage, int type) {
+		//TODO (david) should add camel case support
 		SearchableEnvironmentRequestor requestor =
 			new SearchableEnvironmentRequestor(storage, this.unitToSkip, this.project, this.nameLookup);
 		int index = prefix.lastIndexOf('.');
@@ -330,22 +436,17 @@
 	 * @see org.eclipse.jdt.internal.compiler.env.INameEnvironment#isPackage(char[][], char[])
 	 */
 	public boolean isPackage(char[][] parentPackageName, char[] subPackageName) {
-		if (subPackageName == null || CharOperation.contains('.', subPackageName))
-			return false;
-		if (parentPackageName == null || parentPackageName.length == 0)
-			return isTopLevelPackage(subPackageName);
-		for (int i = 0, length = parentPackageName.length; i < length; i++)
-			if (parentPackageName[i] == null || CharOperation.contains('.', parentPackageName[i]))
-				return false;
-
-		String packageName = new String(CharOperation.concatWith(parentPackageName, subPackageName, '.'));
-		return this.nameLookup.findPackageFragments(packageName, false) != null;
-	}
-
-	public boolean isTopLevelPackage(char[] packageName) {
-		return packageName != null &&
-			!CharOperation.contains('.', packageName) &&
-			this.nameLookup.findPackageFragments(new String(packageName), false) != null;
+		String[] pkgName;
+		if (parentPackageName == null)
+			pkgName = new String[] {new String(subPackageName)};
+		else {
+			int length = parentPackageName.length;
+			pkgName = new String[length+1];
+			for (int i = 0; i < length; i++)
+				pkgName[i] = new String(parentPackageName[i]);
+			pkgName[length] = new String(subPackageName);
+		}
+		return this.nameLookup.isPackage(pkgName);
 	}
 
 	/**
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 bc53cd2..d7b741c 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -24,11 +24,10 @@
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.Signature;
 import org.eclipse.jdt.core.compiler.*;
-import org.eclipse.jdt.core.compiler.IProblem;
 import org.eclipse.jdt.internal.codeassist.ISelectionRequestor;
 import org.eclipse.jdt.internal.codeassist.SelectionEngine;
 import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
-import org.eclipse.jdt.internal.compiler.env.IConstants;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
 import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
 import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding;
 import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
@@ -36,6 +35,8 @@
 import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
 import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
 import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
+import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
 import org.eclipse.jdt.internal.core.util.HandleFactory;
 import org.eclipse.jdt.internal.core.util.Util;
 
@@ -59,7 +60,7 @@
 	 */
 	protected IJavaElement[] elements = JavaElement.NO_ELEMENTS;
 	protected int elementIndex = -1;
-	
+
 	protected HandleFactory handleFactory = new HandleFactory();
 
 /**
@@ -73,26 +74,91 @@
 	this.nameLookup = nameLookup;
 	this.openable = openable;
 }
+private void acceptBinaryMethod(
+		IType type,
+		IMethod method,
+		char[] uniqueKey,
+		boolean isConstructor) {
+	try {
+		if(!isConstructor || ((JavaElement)method).getSourceMapper() == null) {
+			if (uniqueKey != null) {
+				ResolvedBinaryMethod resolvedMethod = new ResolvedBinaryMethod(
+						(JavaElement)method.getParent(),
+						method.getElementName(),
+						method.getParameterTypes(),
+						new String(uniqueKey));
+				resolvedMethod.occurrenceCount = method.getOccurrenceCount();
+				method = resolvedMethod;
+			}
+
+			addElement(method);
+			if(SelectionEngine.DEBUG){
+				System.out.print("SELECTION - accept method("); //$NON-NLS-1$
+				System.out.print(method.toString());
+				System.out.println(")"); //$NON-NLS-1$
+			}
+		} else {
+			ISourceRange range = method.getSourceRange();
+			if (range.getOffset() != -1 && range.getLength() != 0 ) {
+				if (uniqueKey != null) {
+					ResolvedBinaryMethod resolvedMethod = new ResolvedBinaryMethod(
+							(JavaElement)method.getParent(),
+							method.getElementName(),
+							method.getParameterTypes(),
+							new String(uniqueKey));
+					resolvedMethod.occurrenceCount = method.getOccurrenceCount();
+					method = resolvedMethod;
+				}
+				addElement(method);
+				if(SelectionEngine.DEBUG){
+					System.out.print("SELECTION - accept method("); //$NON-NLS-1$
+					System.out.print(method.toString());
+					System.out.println(")"); //$NON-NLS-1$
+				}
+			} else {
+				// no range was actually found, but a method was originally given -> default constructor
+				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$
+				}
+			}
+		}
+	} catch (JavaModelException e) {
+		// an exception occurs, return nothing
+	}
+}
 /**
  * Resolve the binary method
  *
  * fix for 1FWFT6Q
  */
-protected void acceptBinaryMethod(IType type, char[] selector, char[][] parameterPackageNames, char[][] parameterTypeNames, String[] parameterSignatures, char[] uniqueKey) {
+protected void acceptBinaryMethod(
+		IType type,
+		char[] selector,
+		char[][] parameterPackageNames,
+		char[][] parameterTypeNames,
+		String[] parameterSignatures,
+		char[][] typeParameterNames,
+		char[][][] typeParameterBoundNames,
+		char[] uniqueKey,
+		boolean isConstructor) {
 	IMethod method= type.getMethod(new String(selector), parameterSignatures);
+
 	if (method.exists()) {
-		if (uniqueKey != null)
-			method = new ResolvedBinaryMethod(
-					(JavaElement)method.getParent(),
-					method.getElementName(),
-					method.getParameterTypes(),
-					new String(uniqueKey));
-		addElement(method);
-		if(SelectionEngine.DEBUG){
-			System.out.print("SELECTION - accept method("); //$NON-NLS-1$
-			System.out.print(method.toString());
-			System.out.println(")"); //$NON-NLS-1$
+		if (typeParameterNames != null && typeParameterNames.length != 0) {
+			IMethod[] methods = type.findMethods(method);
+			if (methods.length > 1) {
+				for (int i = 0; i < methods.length; i++) {
+					if (areTypeParametersCompatible(methods[i], typeParameterNames, typeParameterBoundNames)) {
+						acceptBinaryMethod(type, method, uniqueKey, isConstructor);
+					}
+				}
+				return;
+			}
 		}
+		acceptBinaryMethod(type, method, uniqueKey, isConstructor);
 	}
 }
 /**
@@ -100,16 +166,16 @@
  */
 public void acceptType(char[] packageName, char[] typeName, int modifiers, boolean isDeclaration, char[] uniqueKey, int start, int end) {
 	int acceptFlags = 0;
-	int kind = modifiers & (IConstants.AccInterface+IConstants.AccEnum+IConstants.AccAnnotation);
+	int kind = modifiers & (ClassFileConstants.AccInterface|ClassFileConstants.AccEnum|ClassFileConstants.AccAnnotation);
 	switch (kind) {
-		case IConstants.AccAnnotation:
-		case IConstants.AccAnnotation+IConstants.AccInterface:
+		case ClassFileConstants.AccAnnotation:
+		case ClassFileConstants.AccAnnotation|ClassFileConstants.AccInterface:
 			acceptFlags = NameLookup.ACCEPT_ANNOTATIONS;
 			break;
-		case IConstants.AccEnum:
+		case ClassFileConstants.AccEnum:
 			acceptFlags = NameLookup.ACCEPT_ENUMS;
 			break;
-		case IConstants.AccInterface:
+		case ClassFileConstants.AccInterface:
 			acceptFlags = NameLookup.ACCEPT_INTERFACES;
 			break;
 		default:
@@ -124,13 +190,17 @@
 		if(type != null ) {
 			String key = uniqueKey == null ? type.getKey() : new String(uniqueKey);
 			if(type.isBinary()) {
-				type = new ResolvedBinaryType((JavaElement)type.getParent(), type.getElementName(), key);
+				ResolvedBinaryType resolvedType = new ResolvedBinaryType((JavaElement)type.getParent(), type.getElementName(), key);
+				resolvedType.occurrenceCount = type.getOccurrenceCount();
+				type = resolvedType;
 			} else {
-				type = new ResolvedSourceType((JavaElement)type.getParent(), type.getElementName(), key);
+				ResolvedSourceType resolvedType = new ResolvedSourceType((JavaElement)type.getParent(), type.getElementName(), key);
+				resolvedType.occurrenceCount = type.getOccurrenceCount();
+				type = resolvedType;
 			}
 		}
 	}
-	
+
 	if (type != null) {
 		addElement(type);
 		if(SelectionEngine.DEBUG){
@@ -138,12 +208,12 @@
 			System.out.print(type.toString());
 			System.out.println(")"); //$NON-NLS-1$
 		}
-	} 
+	}
 }
 /**
  * @see ISelectionRequestor#acceptError
  */
-public void acceptError(IProblem error) {
+public void acceptError(CategorizedProblem error) {
 	// do nothing
 }
 /**
@@ -173,7 +243,7 @@
 					}
 				}
 			} catch (JavaModelException e) {
-				return; 
+				return;
 			}
 		}
 	} else {
@@ -183,15 +253,19 @@
 			if (field.exists()) {
 				if (uniqueKey != null) {
 					if(field.isBinary()) {
-						field = new ResolvedBinaryField(
+						ResolvedBinaryField resolvedField = new ResolvedBinaryField(
 								(JavaElement)field.getParent(),
 								field.getElementName(),
 								new String(uniqueKey));
+						resolvedField.occurrenceCount = field.getOccurrenceCount();
+						field = resolvedField;
 					} else {
-						field = new ResolvedSourceField(
+						ResolvedSourceField resolvedField = new ResolvedSourceField(
 								(JavaElement)field.getParent(),
 								field.getElementName(),
 								new String(uniqueKey));
+						resolvedField.occurrenceCount = field.getOccurrenceCount();
+						field = resolvedField;
 					}
 				}
 				addElement(field);
@@ -207,7 +281,7 @@
 public void acceptLocalField(FieldBinding fieldBinding) {
 	IJavaElement res;
 	if(fieldBinding.declaringClass instanceof ParameterizedTypeBinding) {
-		LocalTypeBinding localTypeBinding = (LocalTypeBinding)((ParameterizedTypeBinding)fieldBinding.declaringClass).type;
+		LocalTypeBinding localTypeBinding = (LocalTypeBinding)((ParameterizedTypeBinding)fieldBinding.declaringClass).genericType();
 		res = findLocalElement(localTypeBinding.sourceStart());
 	} else {
 		SourceTypeBinding typeBinding = (SourceTypeBinding)fieldBinding.declaringClass;
@@ -219,15 +293,19 @@
 		if (field.exists()) {
 			char[] uniqueKey = fieldBinding.computeUniqueKey();
 			if(field.isBinary()) {
-				field = new ResolvedBinaryField(
+				ResolvedBinaryField resolvedField = new ResolvedBinaryField(
 						(JavaElement)field.getParent(),
 						field.getElementName(),
 						new String(uniqueKey));
+				resolvedField.occurrenceCount = field.getOccurrenceCount();
+				field = resolvedField;
 			} else {
-				field = new ResolvedSourceField(
+				ResolvedSourceField resolvedField = new ResolvedSourceField(
 						(JavaElement)field.getParent(),
 						field.getElementName(),
 						new String(uniqueKey));
+				resolvedField.occurrenceCount = field.getOccurrenceCount();
+				field = resolvedField;
 			}
 			addElement(field);
 			if(SelectionEngine.DEBUG){
@@ -240,41 +318,56 @@
 }
 public void acceptLocalMethod(MethodBinding methodBinding) {
 	IJavaElement res = findLocalElement(methodBinding.sourceStart());
-	if(res != null && res.getElementType() == IJavaElement.METHOD) {
-		IMethod method = (IMethod) res;
-		
-		char[] uniqueKey = methodBinding.computeUniqueKey();
-		if(method.isBinary()) {
-			res = new ResolvedBinaryMethod(
-					(JavaElement)res.getParent(),
-					method.getElementName(),
-					method.getParameterTypes(), 
-					new String(uniqueKey));
-		} else {
-			res = new ResolvedSourceMethod(
-					(JavaElement)res.getParent(),
-					method.getElementName(),
-					method.getParameterTypes(), 
-					new String(uniqueKey));
-		}
-		addElement(res);
-		if(SelectionEngine.DEBUG){
-			System.out.print("SELECTION - accept method("); //$NON-NLS-1$
-			System.out.print(res.toString());
-			System.out.println(")"); //$NON-NLS-1$
+	if(res != null) {
+		if(res.getElementType() == IJavaElement.METHOD) {
+			IMethod method = (IMethod) res;
+
+			char[] uniqueKey = methodBinding.computeUniqueKey();
+			if(method.isBinary()) {
+				ResolvedBinaryMethod resolvedRes = new ResolvedBinaryMethod(
+						(JavaElement)res.getParent(),
+						method.getElementName(),
+						method.getParameterTypes(),
+						new String(uniqueKey));
+				resolvedRes.occurrenceCount = method.getOccurrenceCount();
+				res = resolvedRes;
+			} else {
+				ResolvedSourceMethod resolvedRes = new ResolvedSourceMethod(
+						(JavaElement)res.getParent(),
+						method.getElementName(),
+						method.getParameterTypes(),
+						new String(uniqueKey));
+				resolvedRes.occurrenceCount = method.getOccurrenceCount();
+				res = resolvedRes;
+			}
+			addElement(res);
+			if(SelectionEngine.DEBUG){
+				System.out.print("SELECTION - accept method("); //$NON-NLS-1$
+				System.out.print(res.toString());
+				System.out.println(")"); //$NON-NLS-1$
+			}
+		} else if(methodBinding.selector == TypeConstants.INIT && res.getElementType() == IJavaElement.TYPE) {
+			// it's a default constructor
+			res = ((JavaElement)res).resolved(methodBinding.declaringClass);
+			addElement(res);
+			if(SelectionEngine.DEBUG){
+				System.out.print("SELECTION - accept type("); //$NON-NLS-1$
+				System.out.print(res.toString());
+				System.out.println(")"); //$NON-NLS-1$
+			}
 		}
 	}
 }
 public void acceptLocalType(TypeBinding typeBinding) {
 	IJavaElement res =  null;
 	if(typeBinding instanceof ParameterizedTypeBinding) {
-		LocalTypeBinding localTypeBinding = (LocalTypeBinding)((ParameterizedTypeBinding)typeBinding).type;
+		LocalTypeBinding localTypeBinding = (LocalTypeBinding)((ParameterizedTypeBinding)typeBinding).genericType();
 		res = findLocalElement(localTypeBinding.sourceStart());
 	} else if(typeBinding instanceof SourceTypeBinding) {
 		res = findLocalElement(((SourceTypeBinding)typeBinding).sourceStart());
 	}
 	if(res != null && res.getElementType() == IJavaElement.TYPE) {
-		res = new ResolvedSourceType((JavaElement)res.getParent(), res.getElementName(), new String(typeBinding.computeUniqueKey()));
+		res = ((JavaElement)res).resolved(typeBinding);
 		addElement(res);
 		if(SelectionEngine.DEBUG){
 			System.out.print("SELECTION - accept type("); //$NON-NLS-1$
@@ -283,14 +376,53 @@
 		}
 	}
 }
+public void acceptLocalTypeParameter(TypeVariableBinding typeVariableBinding) {
+	IJavaElement res;
+	if(typeVariableBinding.declaringElement instanceof ParameterizedTypeBinding) {
+		LocalTypeBinding localTypeBinding = (LocalTypeBinding)((ParameterizedTypeBinding)typeVariableBinding.declaringElement).genericType();
+		res = findLocalElement(localTypeBinding.sourceStart());
+	} else {
+		SourceTypeBinding typeBinding = (SourceTypeBinding)typeVariableBinding.declaringElement;
+		res = findLocalElement(typeBinding.sourceStart());
+	}
+	if (res != null && res.getElementType() == IJavaElement.TYPE) {
+		IType type = (IType) res;
+		ITypeParameter typeParameter = type.getTypeParameter(new String(typeVariableBinding.sourceName));
+		if (typeParameter.exists()) {
+			addElement(typeParameter);
+			if(SelectionEngine.DEBUG){
+				System.out.print("SELECTION - accept type parameter("); //$NON-NLS-1$
+				System.out.print(typeParameter.toString());
+				System.out.println(")"); //$NON-NLS-1$
+			}
+		}
+	}
+}
+public void acceptLocalMethodTypeParameter(TypeVariableBinding typeVariableBinding) {
+	MethodBinding methodBinding = (MethodBinding)typeVariableBinding.declaringElement;
+	IJavaElement res = findLocalElement(methodBinding.sourceStart());
+	if(res != null && res.getElementType() == IJavaElement.METHOD) {
+		IMethod method = (IMethod) res;
+
+		ITypeParameter typeParameter = method.getTypeParameter(new String(typeVariableBinding.sourceName));
+		if (typeParameter.exists()) {
+			addElement(typeParameter);
+			if(SelectionEngine.DEBUG){
+				System.out.print("SELECTION - accept type parameter("); //$NON-NLS-1$
+				System.out.print(typeParameter.toString());
+				System.out.println(")"); //$NON-NLS-1$
+			}
+		}
+	}
+}
 public void acceptLocalVariable(LocalVariableBinding binding) {
 	LocalDeclaration local = binding.declaration;
 	IJavaElement parent = findLocalElement(local.sourceStart); // findLocalElement() cannot find local variable
 	IJavaElement localVar = null;
 	if(parent != null) {
 		localVar = new LocalVariable(
-				(JavaElement)parent, 
-				new String(local.name), 
+				(JavaElement)parent,
+				new String(local.name),
 				local.declarationSourceStart,
 				local.declarationSourceEnd,
 				local.sourceStart,
@@ -309,17 +441,31 @@
 /**
  * Resolve the method
  */
-public void acceptMethod(char[] declaringTypePackageName, char[] declaringTypeName, String enclosingDeclaringTypeSignature, char[] selector, char[][] parameterPackageNames, char[][] parameterTypeNames, String[] parameterSignatures, boolean isConstructor, boolean isDeclaration, char[] uniqueKey, int start, int end) {
+public void acceptMethod(
+		char[] declaringTypePackageName,
+		char[] declaringTypeName,
+		String enclosingDeclaringTypeSignature,
+		char[] selector,
+		char[][] parameterPackageNames,
+		char[][] parameterTypeNames,
+		String[] parameterSignatures,
+		char[][] typeParameterNames,
+		char[][][] typeParameterBoundNames,
+		boolean isConstructor,
+		boolean isDeclaration,
+		char[] uniqueKey,
+		int start,
+		int end) {
 	IJavaElement[] previousElement = this.elements;
 	int previousElementIndex = this.elementIndex;
 	this.elements = JavaElement.NO_ELEMENTS;
 	this.elementIndex = -1;
-	
+
 	if(isDeclaration) {
 		IType type = resolveTypeByLocation(declaringTypePackageName, declaringTypeName,
 				NameLookup.ACCEPT_ALL,
 				start, end);
-		
+
 		if(type != null) {
 			this.acceptMethodDeclaration(type, selector, start, end);
 		}
@@ -329,35 +475,35 @@
 		// 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);
 					System.arraycopy(parameterSignatures, 0, parameterSignatures = new String[length+1], 1, length);
-					
+
 					parameterPackageNames[0] = declaringDeclaringType.getPackageFragment().getElementName().toCharArray();
 					parameterTypeNames[0] = declaringDeclaringType.getTypeQualifiedName().toCharArray();
-					parameterSignatures[0] = enclosingDeclaringTypeSignature;
+					parameterSignatures[0] = Signature.getTypeErasure(enclosingDeclaringTypeSignature);
 				}
-				
-				acceptBinaryMethod(type, selector, parameterPackageNames, parameterTypeNames, parameterSignatures, uniqueKey);
+
+				acceptBinaryMethod(type, selector, parameterPackageNames, parameterTypeNames, parameterSignatures, typeParameterNames, typeParameterBoundNames, uniqueKey, isConstructor);
 			} else {
-				acceptSourceMethod(type, selector, parameterPackageNames, parameterTypeNames, uniqueKey);
+				acceptSourceMethod(type, selector, parameterPackageNames, parameterTypeNames, parameterSignatures, typeParameterNames, typeParameterBoundNames, uniqueKey);
 			}
 		}
 	}
-	
+
 	if(previousElementIndex > -1) {
 		int elementsLength = this.elementIndex + previousElementIndex + 2;
 		if(elementsLength > this.elements.length) {
@@ -388,7 +534,16 @@
  *
  * fix for 1FWFT6Q
  */
-protected void acceptSourceMethod(IType type, char[] selector, char[][] parameterPackageNames, char[][] parameterTypeNames, char[] uniqueKey) {
+protected void acceptSourceMethod(
+		IType type,
+		char[] selector,
+		char[][] parameterPackageNames,
+		char[][] parameterTypeNames,
+		String[] parameterSignatures,
+		char[][] typeParameterNames,
+		char[][][] typeParameterBoundNames,
+		char[] uniqueKey) {
+
 	String name = new String(selector);
 	IMethod[] methods = null;
 	try {
@@ -397,17 +552,20 @@
 			if (methods[i].getElementName().equals(name)
 					&& methods[i].getParameterTypes().length == parameterTypeNames.length) {
 				IMethod method = methods[i];
-				if (uniqueKey != null)
-					method = new ResolvedSourceMethod(
+				if (uniqueKey != null) {
+					ResolvedSourceMethod resolvedMethod = new ResolvedSourceMethod(
 						(JavaElement)method.getParent(),
 						method.getElementName(),
 						method.getParameterTypes(),
 						new String(uniqueKey));
+					resolvedMethod.occurrenceCount = method.getOccurrenceCount();
+					method = resolvedMethod;
+				}
 				addElement(method);
 			}
 		}
 	} catch (JavaModelException e) {
-		return; 
+		return;
 	}
 
 	// if no matches, nothing to report
@@ -449,6 +607,11 @@
 				break;
 			}
 		}
+
+		if (match && !areTypeParametersCompatible(method, typeParameterNames, typeParameterBoundNames)) {
+			match = false;
+		}
+
 		if (match) {
 			addElement(method);
 			if(SelectionEngine.DEBUG){
@@ -458,7 +621,7 @@
 			}
 		}
 	}
-	
+
 }
 protected void acceptMethodDeclaration(IType type, char[] selector, int start, int end) {
 	String name = new String(selector);
@@ -480,7 +643,7 @@
 			}
 		}
 	} catch (JavaModelException e) {
-		return; 
+		return;
 	}
 
 	// no match was actually found
@@ -502,7 +665,7 @@
 		type = resolveType(declaringTypePackageName, declaringTypeName,
 				NameLookup.ACCEPT_ALL);
 	}
-			
+
 	if(type != null) {
 		ITypeParameter typeParameter = type.getTypeParameter(new String(typeParameterName));
 		if(typeParameter == null) {
@@ -526,13 +689,13 @@
 	IType type = resolveTypeByLocation(declaringTypePackageName, declaringTypeName,
 			NameLookup.ACCEPT_ALL,
 			selectorStart, selectorEnd);
-	
+
 	if(type != null) {
 		IMethod method = null;
-		
+
 		String name = new String(selector);
 		IMethod[] methods = null;
-		
+
 		try {
 			methods = type.getMethods();
 			done : for (int i = 0; i < methods.length; i++) {
@@ -585,7 +748,45 @@
 	}
 	this.elements[++this.elementIndex] = element;
 }
+private boolean areTypeParametersCompatible(IMethod method, char[][] typeParameterNames, char[][][] typeParameterBoundNames) {
+	try {
+		ITypeParameter[] typeParameters = method.getTypeParameters();
+		int length1 = typeParameters == null ? 0 : typeParameters.length;
+		int length2 = typeParameterNames == null ? 0 : typeParameterNames.length;
+		if (length1 != length2) {
+			return false;
+		} else {
+			for (int j = 0; j < length1; j++) {
+				ITypeParameter typeParameter = typeParameters[j];
+				String typeParameterName = typeParameter.getElementName();
+				if (!typeParameterName.equals(new String(typeParameterNames[j]))) {
+					return false;
+				}
 
+				String[] bounds = typeParameter.getBounds();
+				int boundCount = typeParameterBoundNames[j] == null ? 0 : typeParameterBoundNames[j].length;
+
+				if (bounds.length != boundCount) {
+					return false;
+				} else {
+					for (int k = 0; k < boundCount; k++) {
+						String simpleName = Signature.getSimpleName(bounds[k]);
+						int index = simpleName.indexOf('<');
+						if (index != -1) {
+							simpleName = simpleName.substring(0, index);
+						}
+						if (!simpleName.equals(new String(typeParameterBoundNames[j][k]))) {
+							return false;
+						}
+					}
+				}
+			}
+		}
+	} catch (JavaModelException e) {
+		return false;
+	}
+	return true;
+}
 /*
  * findLocalElement() cannot find local variable
  */
@@ -624,13 +825,13 @@
 protected IType resolveType(char[] packageName, char[] typeName, int acceptFlags) {
 
 	IType type= null;
-	
+
 	if (this.openable instanceof CompilationUnit && ((CompilationUnit)this.openable).isWorkingCopy()) {
 		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) {
 					type = wc.getType(new String(compoundName[0]));
@@ -638,24 +839,24 @@
 						type = type.getType(new String(compoundName[i]));
 					}
 				}
-				
+
 				if(type != null && !type.exists()) {
 					type = null;
 				}
 			}
 		}catch (JavaModelException e) {
-			type = null;
+			// type is null
 		}
 	}
 
 	if(type == null) {
 		IPackageFragment[] pkgs = this.nameLookup.findPackageFragments(
-			(packageName == null || packageName.length == 0) ? IPackageFragment.DEFAULT_PACKAGE_NAME : new String(packageName), 
+			(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;	
+			type= this.nameLookup.findType(new String(typeName), pkgs[i], false, acceptFlags, true/*consider secondary types*/);
+			if (type != null) break;
 		}
 		if (type == null) {
 			String pName= IPackageFragment.DEFAULT_PACKAGE_NAME;
@@ -687,17 +888,17 @@
 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;
@@ -718,24 +919,24 @@
 						i++;
 					}
 				}
-				
+
 				if(type != null && !type.exists()) {
 					type = null;
 				}
 			}
 		}catch (JavaModelException e) {
-			type = null;
+			// type is null
 		}
 	}
 
 	if(type == null) {
 		IPackageFragment[] pkgs = this.nameLookup.findPackageFragments(
-			(packageName == null || packageName.length == 0) ? IPackageFragment.DEFAULT_PACKAGE_NAME : new String(packageName), 
+			(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;	
+			type= this.nameLookup.findType(new String(typeName), pkgs[i], false, acceptFlags, true/*consider secondary types*/);
+			if (type != null) break;
 		}
 		if (type == null) {
 			String pName= IPackageFragment.DEFAULT_PACKAGE_NAME;
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 704a8f1..d21117a 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,830 +10,79 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
-import java.util.*;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Iterator;
-
-import org.eclipse.core.resources.IFolder;
-import org.eclipse.core.resources.IResource;
-import org.eclipse.core.resources.IWorkspace;
-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.IClasspathEntry;
 import org.eclipse.jdt.core.IJavaElement;
-import org.eclipse.jdt.core.IJavaElementDelta;
-import org.eclipse.jdt.core.IJavaModel;
 import org.eclipse.jdt.core.IJavaModelStatus;
 import org.eclipse.jdt.core.IJavaProject;
-import org.eclipse.jdt.core.IPackageFragment;
-import org.eclipse.jdt.core.IPackageFragmentRoot;
 import org.eclipse.jdt.core.JavaModelException;
 
-import org.eclipse.jdt.internal.compiler.env.AccessRuleSet;
-import org.eclipse.jdt.internal.compiler.util.ObjectVector;
-import org.eclipse.jdt.internal.core.search.indexing.IndexManager;
-import org.eclipse.jdt.internal.core.util.Messages;
-import org.eclipse.jdt.internal.core.util.Util;
-
 /**
  * This operation sets an <code>IJavaProject</code>'s classpath.
  *
  * @see IJavaProject
  */
-public class SetClasspathOperation extends JavaModelOperation {
+public class SetClasspathOperation extends ChangeClasspathOperation {
 
-	IClasspathEntry[] oldResolvedPath, newResolvedPath;
-	IClasspathEntry[] newRawPath;
-	boolean canChangeResources;
-	boolean classpathWasSaved;
-	boolean needCycleCheck;
-	boolean needValidation;
-	boolean needSave;
+	IClasspathEntry[] newRawClasspath;
 	IPath newOutputLocation;
 	JavaProject project;
-	boolean identicalRoots;
-	
-	/*
-	 * Used to indicate that the classpath entries remain the same.
-	 */
-	public static final IClasspathEntry[] DO_NOT_SET_ENTRIES = new IClasspathEntry[0];
-	
-	public static final IClasspathEntry[] DO_NOT_UPDATE_PROJECT_REFS = new IClasspathEntry[0];
-	
-	/*
-	 * Used to indicate that the output location remains the same.
-	 */
-	public static final IPath DO_NOT_SET_OUTPUT = new Path("Reuse Existing Output Location");  //$NON-NLS-1$
-	
+			
 	/**
-	 * When executed, this operation sets the classpath of the given project.
+	 * When executed, this operation sets the raw classpath and output location of the given project.
 	 */
 	public SetClasspathOperation(
 		JavaProject project,
-		IClasspathEntry[] oldResolvedPath,
-		IClasspathEntry[] newRawPath,
+		IClasspathEntry[] newRawClasspath,
 		IPath newOutputLocation,
-		boolean canChangeResource,
-		boolean needValidation,
-		boolean needSave) {
+		boolean canChangeResource) {
 
-		super(new IJavaElement[] { project });
-		this.oldResolvedPath = oldResolvedPath;
-		this.newRawPath = newRawPath;
-		this.newOutputLocation = newOutputLocation;
-		this.canChangeResources = canChangeResource;
-		this.needValidation = needValidation;
-		this.needSave = needSave;
+		super(new IJavaElement[] { project }, canChangeResource);
 		this.project = project;
-	}
-
-	/**
-	 * Adds deltas for the given roots, with the specified change flag,
-	 * and closes the root. Helper method for #setClasspath
-	 */
-	protected void addClasspathDeltas(
-		IPackageFragmentRoot[] roots,
-		int flag,
-		JavaElementDelta delta) {
-
-		for (int i = 0; i < roots.length; i++) {
-			IPackageFragmentRoot root = roots[i];
-			delta.changed(root, flag);
-			if ((flag & IJavaElementDelta.F_REMOVED_FROM_CLASSPATH) != 0 
-					|| (flag & IJavaElementDelta.F_SOURCEATTACHED) != 0
-					|| (flag & IJavaElementDelta.F_SOURCEDETACHED) != 0){
-				try {
-					root.close();
-				} catch (JavaModelException e) {
-					// ignore
-				}
-				// force detach source on jar package fragment roots (source will be lazily computed when needed)
-				((PackageFragmentRoot) root).setSourceAttachmentProperty(null);// loose info - will be recomputed
-			}
-		}
-	}
-
-	protected boolean canModifyRoots() {
-		// setting classpath can modify roots
-		return true;
-	}
-
-	/**
-	 * Returns the index of the item in the list if the given list contains the specified entry. If the list does
-	 * not contain the entry, -1 is returned.
-	 * A helper method for #setClasspath
-	 */
-	protected int classpathContains(
-		IClasspathEntry[] list,
-		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()
-				&& other.getEntryKind() == entry.getEntryKind()
-				&& other.isExported() == entry.isExported()
-				&& other.getPath().equals(entry.getPath())) {
-					// check custom outputs
-					IPath entryOutput = entry.getOutputLocation();
-					IPath otherOutput = other.getOutputLocation();
-					if (entryOutput == null) {
-						if (otherOutput != null)
-							continue;
-					} else {
-						if (!entryOutput.equals(otherOutput))
-							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 == null || otherExcludes.length != excludeLength)
-							continue;
-						for (int j = 0; j < excludeLength; j++) {
-							// compare toStrings instead of IPaths 
-							// since IPath.equals is specified to ignore trailing separators
-							if (!exclusionPatterns[j].toString().equals(otherExcludes[j].toString()))
-								continue nextEntry;
-						}
-					}
-					return i;
-			}
-		}
-		return -1;
-	}
-
-	/**
-	 * Recursively adds all subfolders of <code>folder</code> to the given collection.
-	 */
-	protected void collectAllSubfolders(IFolder folder, ArrayList collection) throws JavaModelException {
-		try {
-			IResource[] members= folder.members();
-			for (int i = 0, max = members.length; i < max; i++) {
-				IResource r= members[i];
-				if (r.getType() == IResource.FOLDER) {
-					collection.add(r);
-					collectAllSubfolders((IFolder)r, collection);
-				}
-			}	
-		} catch (CoreException e) {
-			throw new JavaModelException(e);
-		}
-	}
-
-	/**
-	 * Returns a collection of package fragments that have been added/removed
-	 * as the result of changing the output location to/from the given
-	 * location. The collection is empty if no package fragments are
-	 * affected.
-	 */
-	protected ArrayList determineAffectedPackageFragments(IPath location) throws JavaModelException {
-		ArrayList fragments = new ArrayList();
-	
-		// see if this will cause any package fragments to be affected
-		IWorkspace workspace = ResourcesPlugin.getWorkspace();
-		IResource resource = null;
-		if (location != null) {
-			resource = workspace.getRoot().findMember(location);
-		}
-		if (resource != null && resource.getType() == IResource.FOLDER) {
-			IFolder folder = (IFolder) resource;
-			// only changes if it actually existed
-			IClasspathEntry[] classpath = project.getExpandedClasspath(true);
-			for (int i = 0; i < classpath.length; i++) {
-				IClasspathEntry entry = classpath[i];
-				IPath path = classpath[i].getPath();
-				if (entry.getEntryKind() != IClasspathEntry.CPE_PROJECT && path.isPrefixOf(location) && !path.equals(location)) {
-					IPackageFragmentRoot[] roots = project.computePackageFragmentRoots(classpath[i]);
-					PackageFragmentRoot root = (PackageFragmentRoot) roots[0];
-					// now the output location becomes a package fragment - along with any subfolders
-					ArrayList folders = new ArrayList();
-					folders.add(folder);
-					collectAllSubfolders(folder, folders);
-					Iterator elements = folders.iterator();
-					int segments = path.segmentCount();
-					while (elements.hasNext()) {
-						IFolder f = (IFolder) elements.next();
-						IPath relativePath = f.getFullPath().removeFirstSegments(segments);
-						String[] pkgName = relativePath.segments();
-						IPackageFragment pkg = root.getPackageFragment(pkgName);
-						fragments.add(pkg);
-					}
-				}
-			}
-		}
-		return fragments;
+		this.newRawClasspath = newRawClasspath;
+		this.newOutputLocation = newOutputLocation;
 	}
 
 	/**
 	 * Sets the classpath of the pre-specified project.
 	 */
 	protected void executeOperation() throws JavaModelException {
-		// project reference updated - may throw an exception if unable to write .project file
-		updateProjectReferencesIfNecessary();
-
-		// classpath file updated - may throw an exception if unable to write .classpath file
-		saveClasspathIfNecessary();
-		
-		// perform classpath and output location updates, if exception occurs in classpath update,
-		// make sure the output location is updated before surfacing the exception (in case the output
-		// location update also throws an exception, give priority to the classpath update one).
-		JavaModelException originalException = null;
-
+		checkCanceled();
 		try {
-			if (this.newRawPath == DO_NOT_UPDATE_PROJECT_REFS) this.newRawPath = project.getRawClasspath();
-			if (this.newRawPath != DO_NOT_SET_ENTRIES){
-				updateClasspath();
-				project.updatePackageFragmentRoots();
-				JavaModelManager.getJavaModelManager().getDeltaProcessor().addForRefresh(project);
-			}
-
-		} catch(JavaModelException e){
-			originalException = e;
-			throw e;
-
-		} finally { // if traversed by an exception we still need to update the output location when necessary
-
-			try {
-				if (this.newOutputLocation != DO_NOT_SET_OUTPUT) updateOutputLocation();
-
-			} catch(JavaModelException e){
-				if (originalException != null) throw originalException; 
-				throw e;
-			} finally {
-				// ensures the project is getting rebuilt if only variable is modified
-				if (!this.identicalRoots && this.canChangeResources) {
-					try {
-						this.project.getProject().touch(this.progressMonitor);
-					} catch (CoreException e) {
-						if (JavaModelManager.CP_RESOLVE_VERBOSE){
-							Util.verbose("CPContainer INIT - FAILED to touch project: "+ this.project.getElementName(), System.err); //$NON-NLS-1$
-							e.printStackTrace();
-						}
-					}
-				}				
-			}
-		}
-		done();
-	}
-
-	/**
-	 * Generates the delta of removed/added/reordered roots.
-	 * Use three deltas in case the same root is removed/added/reordered (for
-	 * instance, if it is changed from K_SOURCE to K_BINARY or vice versa)
-	 */
-	protected void generateClasspathChangeDeltas() {
-
-		JavaModelManager manager = JavaModelManager.getJavaModelManager();
-		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;
+			// set raw classpath and null out resolved info
+			this.project.getPerProjectInfo().setClasspath(this.newRawClasspath, this.newOutputLocation, JavaModelStatus.VERIFIED_OK/*format is ok*/, null, null, null, null);
 			
-		final IndexManager indexManager = manager.getIndexManager();
-		Map oldRoots = null;
-		IPackageFragmentRoot[] roots = null;
-		if (project.isOpen()) {
-			try {
-				roots = project.getPackageFragmentRoots();
-			} catch (JavaModelException e) {
-				// ignore
-			}
-		} else {
-			Map allRemovedRoots ;
-			if ((allRemovedRoots = manager.getDeltaProcessor().removedRoots) != null) {
-		 		roots = (IPackageFragmentRoot[]) allRemovedRoots.get(project);
-			}
-		}
-		if (roots != null) {
-			oldRoots = new HashMap();
-			for (int i = 0; i < roots.length; i++) {
-				IPackageFragmentRoot root = roots[i];
-				oldRoots.put(root.getPath(), root);
-			}
-		}
-		for (int i = 0; i < oldLength; i++) {
+			// if needed, generate delta, update project ref, create markers, ...
+			classpathChanged(this.project);
 			
-			int index = classpathContains(newResolvedPath, oldResolvedPath[i]);
-			if (index == -1) {
-				// do not notify remote project changes
-				if (oldResolvedPath[i].getEntryKind() == IClasspathEntry.CPE_PROJECT){
-					needToUpdateDependents = true;
-					this.needCycleCheck = true;
-					continue; 
-				}
-
-				IPackageFragmentRoot[] pkgFragmentRoots = null;
-				if (oldRoots != null) {
-					IPackageFragmentRoot oldRoot = (IPackageFragmentRoot)  oldRoots.get(oldResolvedPath[i].getPath());
-					if (oldRoot != null) { // use old root if any (could be none if entry wasn't bound)
-						pkgFragmentRoots = new IPackageFragmentRoot[] { oldRoot };
-					}
-				}
-				if (pkgFragmentRoots == null) {
-					try {
-						ObjectVector accumulatedRoots = new ObjectVector();
-						HashSet rootIDs = new HashSet(5);
-						rootIDs.add(project.rootID());
-						project.computePackageFragmentRoots(
-							oldResolvedPath[i], 
-							accumulatedRoots, 
-							rootIDs,
-							null, // inside original project
-							false, // don't check existency
-							false, // don't retrieve exported roots
-							null); /*no reverse map*/
-						pkgFragmentRoots = new IPackageFragmentRoot[accumulatedRoots.size()];
-						accumulatedRoots.copyInto(pkgFragmentRoots);
-					} catch (JavaModelException e) {
-						pkgFragmentRoots =  new IPackageFragmentRoot[] {};
-					}
-				}
-				addClasspathDeltas(pkgFragmentRoots, IJavaElementDelta.F_REMOVED_FROM_CLASSPATH, delta);
-				
-				int changeKind = oldResolvedPath[i].getEntryKind();
-				needToUpdateDependents |= (changeKind == IClasspathEntry.CPE_SOURCE) || oldResolvedPath[i].isExported();
-
-				// Remove the .java files from the index for a source folder
-				// For a lib folder or a .jar file, remove the corresponding index if not shared.
-				if (indexManager != null) {
-					IClasspathEntry oldEntry = oldResolvedPath[i];
-					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, inclusionPatterns, exclusionPatterns);
-								}
-							}, 
-							REMOVEALL_APPEND);
-							break;
-						case IClasspathEntry.CPE_LIBRARY:
-							final DeltaProcessingState deltaState = manager.deltaState;
-							postAction(new IPostAction() {
-								public String getID() {
-									return path.toString();
-								}
-								public void run() /* throws JavaModelException */ {
-									if (deltaState.otherRoots.get(path) == null) { // if root was not shared
-										indexManager.discardJobs(path.toString());
-										indexManager.removeIndex(path);
-										// TODO (kent) we could just remove the in-memory index and have the indexing check for timestamps
-									}
-								}
-							}, 
-							REMOVEALL_APPEND);
-							break;
-					}		
-				}
-				hasDelta = true;
-
-			} else {
-				// do not notify remote project changes
-				if (oldResolvedPath[i].getEntryKind() == IClasspathEntry.CPE_PROJECT){
-					// Need to updated dependents in case old and/or new entries are exported and have an access restriction
-					ClasspathEntry oldEntry = (ClasspathEntry) oldResolvedPath[i];
-					ClasspathEntry newEntry = (ClasspathEntry) newResolvedPath[index];
-					if (oldEntry.isExported || newEntry.isExported) { // then we need to verify if there's access restriction
-						AccessRuleSet oldRuleSet = oldEntry.getAccessRuleSet();
-						AccessRuleSet newRuleSet = newEntry.getAccessRuleSet();
-						if (index != i) { // entry has been moved
-							needToUpdateDependents |= (oldRuleSet != null || newRuleSet != null); // there's an access restriction, this may change combination
-						} else if (oldRuleSet == null) {
-							needToUpdateDependents |= newRuleSet != null; // access restriction was added
-						} else {
-							needToUpdateDependents |= !oldRuleSet.equals(newRuleSet); // access restriction has changed or has been removed
-						}
-					}
-					this.needCycleCheck |= (oldEntry.isExported() != newEntry.isExported());
-					continue; 
-				}				
-				needToUpdateDependents |= (oldResolvedPath[i].isExported() != newResolvedPath[index].isExported());
-				if (index != i) { //reordering of the classpath
-						addClasspathDeltas(
-							project.computePackageFragmentRoots(oldResolvedPath[i]),
-							IJavaElementDelta.F_REORDER,
-							delta);
-						int changeKind = oldResolvedPath[i].getEntryKind();
-						needToUpdateDependents |= (changeKind == IClasspathEntry.CPE_SOURCE);
-		
-						hasDelta = true;
-				}
-				
-				// check source attachment
-				IPath newSourcePath = newResolvedPath[index].getSourceAttachmentPath();
-				int sourceAttachmentFlags = 
-					this.getSourceAttachmentDeltaFlag(
-						oldResolvedPath[i].getSourceAttachmentPath(),
-						newSourcePath);
-				IPath oldRootPath = oldResolvedPath[i].getSourceAttachmentRootPath();
-				IPath newRootPath = newResolvedPath[index].getSourceAttachmentRootPath();
-				int sourceAttachmentRootFlags = getSourceAttachmentDeltaFlag(oldRootPath, newRootPath);
-				int flags = sourceAttachmentFlags | sourceAttachmentRootFlags;
-				if (flags != 0) {
-					addClasspathDeltas(project.computePackageFragmentRoots(oldResolvedPath[i]), flags, delta);
-					hasDelta = true;
-				} else {
-					if (oldRootPath == null && newRootPath == null) {
-						// if source path is specified and no root path, it needs to be recomputed dynamically
-						// force detach source on jar package fragment roots (source will be lazily computed when needed)
-						IPackageFragmentRoot[] computedRoots = project.computePackageFragmentRoots(oldResolvedPath[i]);
-						for (int j = 0; j < computedRoots.length; j++) {
-							IPackageFragmentRoot root = computedRoots[j];
-							// force detach source on jar package fragment roots (source will be lazily computed when needed)
-							try {
-								root.close();
-							} catch (JavaModelException e) {
-								// ignore
-							}
-							((PackageFragmentRoot) root).setSourceAttachmentProperty(null);// loose info - will be recomputed
-						}
-					}
-				}
-			}
-		}
-
-		for (int i = 0; i < newLength; i++) {
-
-			int index = classpathContains(oldResolvedPath, newResolvedPath[i]);
-			if (index == -1) {
-				// do not notify remote project changes
-				if (newResolvedPath[i].getEntryKind() == IClasspathEntry.CPE_PROJECT){
-					needToUpdateDependents = true;
-					this.needCycleCheck = true;
-					continue; 
-				}
-				addClasspathDeltas(
-					project.computePackageFragmentRoots(newResolvedPath[i]),
-					IJavaElementDelta.F_ADDED_TO_CLASSPATH,
-					delta);
-				int changeKind = newResolvedPath[i].getEntryKind();
-				
-				// Request indexing
-				if (indexManager != null) {
-					switch (changeKind) {
-						case IClasspathEntry.CPE_LIBRARY:
-							boolean pathHasChanged = true;
-							final IPath newPath = newResolvedPath[i].getPath();
-							for (int j = 0; j < oldLength; j++) {
-								IClasspathEntry oldEntry = oldResolvedPath[j];
-								if (oldEntry.getPath().equals(newPath)) {
-									pathHasChanged = false;
-									break;
-								}
-							}
-							if (pathHasChanged) {
-								postAction(new IPostAction() {
-									public String getID() {
-										return newPath.toString();
-									}
-									public void run() /* throws JavaModelException */ {
-										indexManager.indexLibrary(newPath, project.getProject());
-									}
-								}, 
-								REMOVEALL_APPEND);
-							}
-							break;
-						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, inclusionPatterns, exclusionPatterns);
-								}
-							}, 
-							APPEND); // append so that a removeSourceFolder action is not removed
-							break;
-					}
-				}
-				
-				needToUpdateDependents |= (changeKind == IClasspathEntry.CPE_SOURCE) || newResolvedPath[i].isExported();
-				hasDelta = true;
-
-			} // classpath reordering has already been generated in previous loop
-		}
-
-		if (hasDelta) {
-			this.addDelta(delta);
-		} else {
-			this.identicalRoots = true;
-		}
-		if (needToUpdateDependents){
-			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
-	 * or 0 if there is no difference.
-	 */
-	private int getSourceAttachmentDeltaFlag(IPath oldPath, IPath newPath) {
-		if (oldPath == null) {
-			if (newPath != null) {
-				return IJavaElementDelta.F_SOURCEATTACHED;
-			} else {
-				return 0;
-			}
-		} else if (newPath == null) {
-			return IJavaElementDelta.F_SOURCEDETACHED;
-		} else if (!oldPath.equals(newPath)) {
-			return IJavaElementDelta.F_SOURCEATTACHED | IJavaElementDelta.F_SOURCEDETACHED;
-		} else {
-			return 0;
+			// write .classpath file
+			if (this.canChangeResources && this.project.saveClasspath(this.newRawClasspath, this.newOutputLocation))
+				setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE);
+		} finally {		
+			done();
 		}
 	}
 
-	/**
-	 * Returns <code>true</code> if this operation performs no resource modifications,
-	 * otherwise <code>false</code>. Subclasses must override.
-	 */
-	public boolean isReadOnly() {
-		return !this.canChangeResources;
-	}
-
-	protected void saveClasspathIfNecessary() throws JavaModelException {
-		
-		if (!this.canChangeResources || !this.needSave) return;
-				
-		IClasspathEntry[] classpathForSave;
-		if (this.newRawPath == DO_NOT_SET_ENTRIES || this.newRawPath == DO_NOT_UPDATE_PROJECT_REFS){
-			classpathForSave = project.getRawClasspath();
-		} else {
-			classpathForSave = this.newRawPath;
-		}
-		IPath outputLocationForSave;
-		if (this.newOutputLocation == DO_NOT_SET_OUTPUT){
-			outputLocationForSave = project.getOutputLocation();
-		} else {
-			outputLocationForSave = this.newOutputLocation;
-		}
-		// 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); 
-		}
-	}
-	
 	public String toString(){
 		StringBuffer buffer = new StringBuffer(20);
 		buffer.append("SetClasspathOperation\n"); //$NON-NLS-1$
 		buffer.append(" - classpath : "); //$NON-NLS-1$
-		if (this.newRawPath == DO_NOT_SET_ENTRIES){
-			buffer.append("<Reuse Existing Classpath Entries>"); //$NON-NLS-1$
-		} else {
-			buffer.append("{"); //$NON-NLS-1$
-			for (int i = 0; i < this.newRawPath.length; i++) {
-				if (i > 0) buffer.append(","); //$NON-NLS-1$
-				IClasspathEntry element = this.newRawPath[i];
-				buffer.append(" ").append(element.toString()); //$NON-NLS-1$
-			}
+		buffer.append("{"); //$NON-NLS-1$
+		for (int i = 0; i < this.newRawClasspath.length; i++) {
+			if (i > 0) buffer.append(","); //$NON-NLS-1$
+			IClasspathEntry element = this.newRawClasspath[i];
+			buffer.append(" ").append(element.toString()); //$NON-NLS-1$
 		}
 		buffer.append("\n - output location : ");  //$NON-NLS-1$
-		if (this.newOutputLocation == DO_NOT_SET_OUTPUT){
-			buffer.append("<Reuse Existing Output Location>"); //$NON-NLS-1$
-		} else {
-			buffer.append(this.newOutputLocation.toString()); //$NON-NLS-1$
-		}
+		buffer.append(this.newOutputLocation.toString());
 		return buffer.toString();
 	}
 
-	private void updateClasspath() throws JavaModelException {
-
-		beginTask(Messages.bind(Messages.classpath_settingProgress, project.getElementName()), 2); 
-
-		// SIDE-EFFECT: from thereon, the classpath got modified
-		project.getPerProjectInfo().updateClasspathInformation(this.newRawPath);
-
-		// resolve new path (asking for marker creation if problems)
-		if (this.newResolvedPath == null) {
-			this.newResolvedPath = project.getResolvedClasspath(true, this.canChangeResources, false/*don't returnResolutionInProgress*/);
-		}
-		
-		if (this.oldResolvedPath != null) {
-			generateClasspathChangeDeltas();
-		} else {
-			this.needCycleCheck = true;
-			updateAffectedProjects(project.getProject().getFullPath());
-		}
-		
-		updateCycleMarkersIfNecessary();
-	}
-
-	/**
-	 * Update projects which are affected by this classpath change:
-	 * those which refers to the current project as source (indirectly)
-	 */
-	protected void updateAffectedProjects(IPath prerequisiteProjectPath) {
-
-		// remove all update classpath post actions for this project
-		final String updateClasspath = "UpdateClassPath:"; //$NON-NLS-1$
-		removeAllPostAction(updateClasspath + prerequisiteProjectPath.toString());
-		
-		try {
-			IJavaModel model = JavaModelManager.getJavaModelManager().getJavaModel();
-			IJavaProject initialProject = this.project;
-			IJavaProject[] projects = model.getJavaProjects();
-			for (int i = 0, projectCount = projects.length; i < projectCount; i++) {
-				try {
-					final JavaProject affectedProject = (JavaProject) projects[i];
-					if (affectedProject.equals(initialProject)) continue; // skip itself
-					if (!affectedProject.isOpen()) continue; // skip project as its namelookup caches do not exist
-					
-					// consider ALL dependents (even indirect ones), since they may need to
-					// flush their respective namelookup caches (all pkg fragment roots).
-
-					IClasspathEntry[] classpath = affectedProject.getExpandedClasspath(true);
-					for (int j = 0, entryCount = classpath.length; j < entryCount; j++) {
-						IClasspathEntry entry = classpath[j];
-						if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT
-							&& entry.getPath().equals(prerequisiteProjectPath)) {
-								
-							postAction(new IPostAction() {
-									public String getID() {
-										return updateClasspath + affectedProject.getPath().toString();
-									}
-									public void run() throws JavaModelException {
-										affectedProject.setRawClasspath(
-											DO_NOT_UPDATE_PROJECT_REFS, 
-											SetClasspathOperation.DO_NOT_SET_OUTPUT, 
-											SetClasspathOperation.this.progressMonitor, 
-											SetClasspathOperation.this.canChangeResources,  
-											affectedProject.getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/), 
-											false, // updating only - no validation
-											false); // updating only - no need to save
-									}
-								},
-								REMOVEALL_APPEND);
-							break;
-						}
-					}
-				} catch (JavaModelException e) {
-					// ignore
-				}
-			}
-		} catch (JavaModelException e) {
-			// ignore
-		}
-		
-	}
-
-	/**
-	 * Update cycle markers
-	 */
-	protected void updateCycleMarkersIfNecessary() {
-
-		if (!this.needCycleCheck) return;
-		if (!this.canChangeResources) return;
-		 
-		if (!project.hasCycleMarker() && !project.hasClasspathCycle(newResolvedPath)){
-			return;
-		}
-	
-		postAction(
-			new IPostAction() {
-				public String getID() {
-					return "updateCycleMarkers";  //$NON-NLS-1$
-				}
-				public void run() throws JavaModelException {
-					JavaProject.updateAllCycleMarkers(null);
-				}
-			},
-			REMOVEALL_APPEND);
-	}
-
-	/**
-	 * Sets the output location of the pre-specified project.
-	 *
-	 * <p>This can cause changes in package fragments, in case either  the
-	 * old or new output location folder are considered as a package fragment.
-	 */
-	protected void updateOutputLocation() throws JavaModelException {
-		
-		beginTask(Messages.bind(Messages.classpath_settingOutputLocationProgress, project.getElementName()), 2); 
-		
-		IPath oldLocation= project.getOutputLocation();
-	
-		// see if this will cause any package fragments to be added
-		boolean deltaToFire= false;
-		JavaElementDelta delta = newJavaElementDelta();
-		ArrayList added= determineAffectedPackageFragments(oldLocation);
-		Iterator iter = added.iterator();
-		while (iter.hasNext()){
-			IPackageFragment frag= (IPackageFragment)iter.next();
-			((IPackageFragmentRoot)frag.getParent()).close();
-			if (!Util.isExcluded(frag)) {
-				delta.added(frag);
-				deltaToFire = true;
-			}
-		}
-	
-		// see if this will cause any package fragments to be removed
-		ArrayList removed= determineAffectedPackageFragments(this.newOutputLocation);
-		iter = removed.iterator();
-		while (iter.hasNext()){
-			IPackageFragment frag= (IPackageFragment)iter.next();
-			((IPackageFragmentRoot)frag.getParent()).close(); 
-			if (!Util.isExcluded(frag)) {
-				delta.removed(frag);
-				deltaToFire = true;
-			}
-		}
-
-		JavaModelManager.PerProjectInfo perProjectInfo = project.getPerProjectInfo();
-		synchronized (perProjectInfo) {
-			perProjectInfo.outputLocation = this.newOutputLocation;
-		}
-				
-		if (deltaToFire) {
-			addDelta(delta);	
-		}
-		worked(1);
-	}
-	
-	/**
-	 * Update projects references so that the build order is consistent with the classpath
-	 */
-	protected void updateProjectReferencesIfNecessary() throws JavaModelException {
-		
-		if (this.newRawPath == DO_NOT_SET_ENTRIES || this.newRawPath == DO_NOT_UPDATE_PROJECT_REFS) return;
-		// 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() {
-
 		IJavaModelStatus status = super.verify();
-		if (!status.isOK()) {
+		if (!status.isOK())
 			return status;
-		}
-
-		if (needValidation) {
-			// retrieve classpath 
-			IClasspathEntry[] entries = this.newRawPath;
-			if (entries == DO_NOT_SET_ENTRIES){
-				try {
-					entries = project.getRawClasspath();			
-				} catch (JavaModelException e) {
-					return e.getJavaModelStatus();
-				}
-			}		
-			// retrieve output location
-			IPath outputLocation = this.newOutputLocation;
-			if (outputLocation == DO_NOT_SET_OUTPUT){
-				try {
-					outputLocation = project.getOutputLocation();
-				} catch (JavaModelException e) {
-					return e.getJavaModelStatus();
-				}
-			}
-					
-			// perform validation
-			return ClasspathEntry.validateClasspath(
-				project,
-				entries,
-				outputLocation);
-		}
-		
-		return JavaModelStatus.VERIFIED_OK;
+		return ClasspathEntry.validateClasspath(	this.project, this.newRawClasspath, this.newOutputLocation);
 	}
+
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SetContainerOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SetContainerOperation.java
new file mode 100755
index 0000000..22a0347
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SetContainerOperation.java
@@ -0,0 +1,205 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core;
+
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.jdt.core.IClasspathContainer;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.internal.core.util.Util;
+
+public class SetContainerOperation extends ChangeClasspathOperation {
+	
+	IPath containerPath;
+	IJavaProject[] affectedProjects;
+	IClasspathContainer[] respectiveContainers;
+	
+	/*
+	 * Creates a new SetContainerOperation.
+	 */
+	public SetContainerOperation(IPath containerPath, IJavaProject[] affectedProjects, IClasspathContainer[] respectiveContainers) {
+		super(new IJavaElement[] {JavaModelManager.getJavaModelManager().getJavaModel()}, !ResourcesPlugin.getWorkspace().isTreeLocked());
+		this.containerPath = containerPath;
+		this.affectedProjects = affectedProjects;
+		this.respectiveContainers = respectiveContainers;
+	}
+
+	protected void executeOperation() throws JavaModelException {
+		checkCanceled();
+		try {
+			beginTask("", 1); //$NON-NLS-1$
+			if (JavaModelManager.CP_RESOLVE_VERBOSE)
+				verbose_set_container();
+			if (JavaModelManager.CP_RESOLVE_VERBOSE_ADVANCED)
+				verbose_set_container_invocation_trace();
+			
+			JavaModelManager manager = JavaModelManager.getJavaModelManager();
+			if (manager.containerPutIfInitializingWithSameEntries(this.containerPath, this.affectedProjects, this.respectiveContainers))
+				return;
+	
+			final int projectLength = this.affectedProjects.length;	
+			final IJavaProject[] modifiedProjects;
+			System.arraycopy(this.affectedProjects, 0, modifiedProjects = new IJavaProject[projectLength], 0, projectLength);
+			final IClasspathEntry[][] oldResolvedPaths = new IClasspathEntry[projectLength][];
+				
+			// filter out unmodified project containers
+			int remaining = 0;
+			for (int i = 0; i < projectLength; i++){
+				if (isCanceled()) 
+					return;
+				JavaProject affectedProject = (JavaProject) this.affectedProjects[i];
+				IClasspathContainer newContainer = this.respectiveContainers[i];
+				if (newContainer == null) newContainer = JavaModelManager.CONTAINER_INITIALIZATION_IN_PROGRESS; // 30920 - prevent infinite loop
+				boolean found = false;
+				if (JavaProject.hasJavaNature(affectedProject.getProject())){
+					IClasspathEntry[] rawClasspath = affectedProject.getRawClasspath();
+					for (int j = 0, cpLength = rawClasspath.length; j <cpLength; j++) {
+						IClasspathEntry entry = rawClasspath[j];
+						if (entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER && entry.getPath().equals(this.containerPath)){
+							found = true;
+							break;
+						}
+					}
+				}
+				if (!found) {
+					modifiedProjects[i] = null; // filter out this project - does not reference the container path, or isnt't yet Java project
+					manager.containerPut(affectedProject, this.containerPath, newContainer);
+					continue;
+				}
+				IClasspathContainer oldContainer = manager.containerGet(affectedProject, this.containerPath);
+				if (oldContainer == JavaModelManager.CONTAINER_INITIALIZATION_IN_PROGRESS) {
+					oldContainer = null;
+				}
+				if ((oldContainer != null && oldContainer.equals(this.respectiveContainers[i]))
+						|| (oldContainer == this.respectiveContainers[i])/*handle case where old and new containers are null (see bug 149043*/) {
+					modifiedProjects[i] = null; // filter out this project - container did not change
+					continue;
+				}
+				remaining++; 
+				oldResolvedPaths[i] = affectedProject.getResolvedClasspath();
+				manager.containerPut(affectedProject, this.containerPath, newContainer);
+			}
+			
+			if (remaining == 0) return;
+			
+			// trigger model refresh
+			try {
+				for(int i = 0; i < projectLength; i++){
+					if (isCanceled()) 
+						return;
+					
+					JavaProject affectedProject = (JavaProject)modifiedProjects[i];
+					if (affectedProject == null) continue; // was filtered out
+					if (JavaModelManager.CP_RESOLVE_VERBOSE_ADVANCED)
+						verbose_update_project(affectedProject);
+		
+					// force resolved classpath to be recomputed
+					affectedProject.getPerProjectInfo().resetResolvedClasspath();
+					
+					// if needed, generate delta, update project ref, create markers, ...
+					classpathChanged(affectedProject);
+					
+					if (this.canChangeResources) {
+						// touch project to force a build if needed
+						try {
+							affectedProject.getProject().touch(this.progressMonitor);
+						} catch (CoreException e) {
+							// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=148970
+							if (!ExternalJavaProject.EXTERNAL_PROJECT_NAME.equals(affectedProject.getElementName()))
+								throw e;
+						}
+					}
+				}
+			} catch(CoreException e) {
+				if (JavaModelManager.CP_RESOLVE_VERBOSE)
+					verbose_failure(e);
+				if (e instanceof JavaModelException) {
+					throw (JavaModelException)e;
+				} else {
+					throw new JavaModelException(e);
+				}
+			} finally {
+				for (int i = 0; i < projectLength; i++) {
+					if (this.respectiveContainers[i] == null) {
+						manager.containerPut(this.affectedProjects[i], this.containerPath, null); // reset init in progress marker
+					}
+				}
+			}
+		} finally {		
+			done();
+		}
+	}
+
+	private void verbose_failure(CoreException e) {
+		Util.verbose(
+			"CPContainer SET  - FAILED DUE TO EXCEPTION\n" + //$NON-NLS-1$
+			"	container path: " + this.containerPath, //$NON-NLS-1$
+			System.err);
+		e.printStackTrace();
+	}
+
+	private void verbose_update_project(JavaProject affectedProject) {
+		Util.verbose(
+			"CPContainer SET  - updating affected project due to setting container\n" + //$NON-NLS-1$
+			"	project: " + affectedProject.getElementName() + '\n' + //$NON-NLS-1$
+			"	container path: " + this.containerPath); //$NON-NLS-1$
+	}
+
+	private void verbose_set_container() {
+		Util.verbose(
+			"CPContainer SET  - setting container\n" + //$NON-NLS-1$
+			"	container path: " + this.containerPath + '\n' + //$NON-NLS-1$
+			"	projects: {" +//$NON-NLS-1$
+			org.eclipse.jdt.internal.compiler.util.Util.toString(
+				this.affectedProjects, 
+				new org.eclipse.jdt.internal.compiler.util.Util.Displayable(){ 
+					public String displayString(Object o) { return ((IJavaProject) o).getElementName(); }
+				}) +
+			"}\n	values: {\n"  +//$NON-NLS-1$
+			org.eclipse.jdt.internal.compiler.util.Util.toString(
+				this.respectiveContainers, 
+				new org.eclipse.jdt.internal.compiler.util.Util.Displayable(){ 
+					public String displayString(Object o) { 
+						StringBuffer buffer = new StringBuffer("		"); //$NON-NLS-1$
+						if (o == null) {
+							buffer.append("<null>"); //$NON-NLS-1$
+							return buffer.toString();
+						}
+						IClasspathContainer container = (IClasspathContainer) o;
+						buffer.append(container.getDescription());
+						buffer.append(" {\n"); //$NON-NLS-1$
+						IClasspathEntry[] entries = container.getClasspathEntries();
+						if (entries != null){
+							for (int i = 0; i < entries.length; i++){
+								buffer.append(" 			"); //$NON-NLS-1$
+								buffer.append(entries[i]); 
+								buffer.append('\n'); 
+							}
+						}
+						buffer.append(" 		}"); //$NON-NLS-1$
+						return buffer.toString();
+					}
+				}) +
+			"\n	}");//$NON-NLS-1$
+	}
+	
+	private void verbose_set_container_invocation_trace() {
+		Util.verbose(
+			"CPContainer SET  - setting container\n" + //$NON-NLS-1$
+			"	invocation stack trace:"); //$NON-NLS-1$
+			new Exception("<Fake exception>").printStackTrace(System.out); //$NON-NLS-1$
+	}
+	
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SetVariablesOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SetVariablesOperation.java
new file mode 100755
index 0000000..def49a6
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SetVariablesOperation.java
@@ -0,0 +1,193 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core;
+
+import java.util.HashMap;
+import java.util.Iterator;
+
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.IJavaElement;
+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;
+
+public class SetVariablesOperation extends ChangeClasspathOperation {
+	
+	String[] variableNames;
+	IPath[] variablePaths;
+	boolean updatePreferences;
+		
+	/*
+	 * Creates a new SetVariablesOperation for the given variable values (null path meaning removal), allowing to change multiple variable values at once.
+	 */
+	public SetVariablesOperation(String[] variableNames, IPath[] variablePaths, boolean updatePreferences) {
+		super(new IJavaElement[] {JavaModelManager.getJavaModelManager().getJavaModel()}, !ResourcesPlugin.getWorkspace().isTreeLocked());
+		this.variableNames = variableNames;
+		this.variablePaths = variablePaths;
+		this.updatePreferences = updatePreferences;
+	}
+
+	protected void executeOperation() throws JavaModelException {
+		checkCanceled();
+		try {
+			beginTask("", 1); //$NON-NLS-1$
+			if (JavaModelManager.CP_RESOLVE_VERBOSE)
+				verbose_set_variables();
+			
+			JavaModelManager manager = JavaModelManager.getJavaModelManager();
+			if (manager.variablePutIfInitializingWithSameValue(this.variableNames, this.variablePaths))
+				return;
+	
+			int varLength = this.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 = this.variableNames[i];
+				IPath oldPath = manager.variableGet(variableName); // if reentering will provide previous session value 
+				if (oldPath == JavaModelManager.VARIABLE_INITIALIZATION_IN_PROGRESS) {
+					oldPath = null;  //33695 - cannot filter out restored variable, must update affected project to reset cached CP
+				}
+				if (oldPath != null && oldPath.equals(this.variablePaths[i])){
+					this.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 (this.variableNames[i] != null){
+						changedVariableNames[index] = this.variableNames[i];
+						changedVariablePaths[index] = this.variablePaths[i];
+						index++;
+					}
+				}
+				this.variableNames = changedVariableNames;
+				this.variablePaths = changedVariablePaths;
+				varLength = changedLength;
+			}
+			
+			if (isCanceled()) 
+				return;
+	
+			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 = this.variableNames[k];						
+						if (entry.getEntryKind() ==  IClasspathEntry.CPE_VARIABLE){
+	
+							if (variableName.equals(entry.getPath().segment(0))){
+								affectedProjectClasspaths.put(project, project.getResolvedClasspath());
+								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());
+								continue nextProject;
+							}
+						}												
+					}
+				}
+			}
+
+			// update variables
+			for (int i = 0; i < varLength; i++){
+				manager.variablePut(this.variableNames[i], this.variablePaths[i]);
+				if (this.updatePreferences)
+					manager.variablePreferencesPut(this.variableNames[i], this.variablePaths[i]);
+			}
+					
+			// update affected project classpaths
+			if (!affectedProjectClasspaths.isEmpty()) {
+				String[] dbgVariableNames = this.variableNames;
+				try {
+					// propagate classpath change
+					Iterator projectsToUpdate = affectedProjectClasspaths.keySet().iterator();
+					while (projectsToUpdate.hasNext()) {
+	
+						if (this.progressMonitor != null && this.progressMonitor.isCanceled()) return;
+	
+						JavaProject affectedProject = (JavaProject) projectsToUpdate.next();
+	
+						// force resolved classpath to be recomputed
+						if (JavaModelManager.CP_RESOLVE_VERBOSE_ADVANCED)
+							verbose_update_project(dbgVariableNames, affectedProject);
+						affectedProject.getPerProjectInfo().resetResolvedClasspath();
+						
+						// if needed, generate delta, update project ref, create markers, ...
+						classpathChanged(affectedProject);
+
+						if (this.canChangeResources) {
+							// touch project to force a build if needed
+							affectedProject.getProject().touch(this.progressMonitor);
+						}
+					}
+				} catch (CoreException e) {
+					if (JavaModelManager.CP_RESOLVE_VERBOSE){
+						verbose_failure(dbgVariableNames); 
+						e.printStackTrace();
+					}
+					if (e instanceof JavaModelException) {
+						throw (JavaModelException)e;
+					} else {
+						throw new JavaModelException(e);
+					}
+				}
+			}
+		} finally {		
+			done();
+		}
+	}
+
+	private void verbose_failure(String[] dbgVariableNames) {
+		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);
+	}
+
+	private void verbose_update_project(String[] dbgVariableNames,
+			JavaProject affectedProject) {
+		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$
+	}
+
+	private void verbose_set_variables() {
+		Util.verbose(
+			"CPVariable SET  - setting variables\n" + //$NON-NLS-1$
+			"	variables: " + org.eclipse.jdt.internal.compiler.util.Util.toString(this.variableNames) + '\n' +//$NON-NLS-1$
+			"	values: " + org.eclipse.jdt.internal.compiler.util.Util.toString(this.variablePaths)); //$NON-NLS-1$
+	}
+
+}
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 4491164..53650d7 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 37d0f11..1b2c828 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 53e7c13..48b915a 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -7,6 +7,7 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ *     Alex Blewitt - alex_blewitt@yahoo.com https://bugs.eclipse.org/bugs/show_bug.cgi?id=171066
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
@@ -23,7 +24,6 @@
 import org.eclipse.jdt.core.IJavaModelStatusConstants;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.core.dom.AST;
 import org.eclipse.jdt.core.dom.ASTNode;
 import org.eclipse.jdt.core.dom.ASTParser;
 import org.eclipse.jdt.core.dom.ASTVisitor;
@@ -43,6 +43,7 @@
 import org.eclipse.jface.text.Document;
 import org.eclipse.text.edits.RangeMarker;
 import org.eclipse.text.edits.TextEdit;
+import org.eclipse.text.edits.TextEditGroup;
 
 /**
  * This operation is used to sort elements in a compilation unit according to
@@ -51,11 +52,12 @@
  * @since 2.1
  */
 public class SortElementsOperation extends JavaModelOperation {
-	
+	public static final String CONTAINS_MALFORMED_NODES = "malformed"; //$NON-NLS-1$
+
 	Comparator comparator;
 	int[] positions;
     int apiLevel;
-	
+    
 	/**
 	 * Constructor for SortElementsOperation.
      * 
@@ -79,6 +81,16 @@
 		return this.elementsToProcess.length;
 	}
 	
+	boolean checkMalformedNodes(ASTNode node) {
+		Object property = node.getProperty(CONTAINS_MALFORMED_NODES);
+		if (property == null) return false;
+		return ((Boolean) property).booleanValue();
+	}
+
+	protected boolean isMalformed(ASTNode node) {
+		return (node.getFlags() & ASTNode.MALFORMED) != 0;
+	}
+
 	/**
 	 * @see org.eclipse.jdt.internal.core.JavaModelOperation#executeOperation()
 	 */
@@ -101,6 +113,35 @@
 			done();
 		}
 	}
+	
+	/**
+	 * Calculates the required text edits to sort the <code>unit</code>
+	 * @param group 
+	 * @return the edit or null if no sorting is required
+	 */
+	public TextEdit calculateEdit(org.eclipse.jdt.core.dom.CompilationUnit unit, TextEditGroup group) throws JavaModelException {
+		if (this.elementsToProcess.length != 1)
+			throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.NO_ELEMENTS_TO_PROCESS));
+		
+		if (!(this.elementsToProcess[0] instanceof ICompilationUnit))
+			throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, this.elementsToProcess[0]));
+		
+		try {
+			beginTask(Messages.operation_sortelements, getMainAmountOfWork());
+			
+			ICompilationUnit cu= (ICompilationUnit)this.elementsToProcess[0];
+			String content= cu.getBuffer().getContents();
+			ASTRewrite rewrite= sortCompilationUnit(unit, group);
+			if (rewrite == null) {
+				return null;
+			}
+			
+			Document document= new Document(content);
+			return rewrite.rewriteAST(document, null);
+		} finally {
+			done();
+		}
+	}
 
 	/**
 	 * Method processElement.
@@ -108,172 +149,32 @@
 	 * @param source
 	 */
 	private String processElement(ICompilationUnit unit, char[] source) {
+		Document document = new Document(new String(source));
 		CompilerOptions options = new CompilerOptions(unit.getJavaProject().getOptions(true));
 		ASTParser parser = ASTParser.newParser(this.apiLevel);
 		parser.setCompilerOptions(options.getMap());
 		parser.setSource(source);
 		parser.setKind(ASTParser.K_COMPILATION_UNIT);
 		parser.setResolveBindings(false);
-		org.eclipse.jdt.core.dom.CompilationUnit domUnit = (org.eclipse.jdt.core.dom.CompilationUnit) parser.createAST(null);
-		domUnit.accept(new ASTVisitor() {
-			public boolean visit(org.eclipse.jdt.core.dom.CompilationUnit compilationUnit) {
-				List types = compilationUnit.types();
-				for (Iterator iter = types.iterator(); iter.hasNext();) {
-					AbstractTypeDeclaration typeDeclaration = (AbstractTypeDeclaration) iter.next();
-					typeDeclaration.setProperty(CompilationUnitSorter.RELATIVE_ORDER, new Integer(typeDeclaration.getStartPosition()));
-				}
-				return true;
-			}
-			public boolean visit(AnnotationTypeDeclaration annotationTypeDeclaration) {
-				List bodyDeclarations = annotationTypeDeclaration.bodyDeclarations();
-				for (Iterator iter = bodyDeclarations.iterator(); iter.hasNext();) {
-					BodyDeclaration bodyDeclaration = (BodyDeclaration) iter.next();
-					bodyDeclaration.setProperty(CompilationUnitSorter.RELATIVE_ORDER, new Integer(bodyDeclaration.getStartPosition()));
-				}
-				return true;
-			}
-
-			public boolean visit(AnonymousClassDeclaration anonymousClassDeclaration) {
-				List bodyDeclarations = anonymousClassDeclaration.bodyDeclarations();
-				for (Iterator iter = bodyDeclarations.iterator(); iter.hasNext();) {
-					BodyDeclaration bodyDeclaration = (BodyDeclaration) iter.next();
-					bodyDeclaration.setProperty(CompilationUnitSorter.RELATIVE_ORDER, new Integer(bodyDeclaration.getStartPosition()));
-				}
-				return true;
-			}
-			
-			public boolean visit(TypeDeclaration typeDeclaration) {
-				List bodyDeclarations = typeDeclaration.bodyDeclarations();
-				for (Iterator iter = bodyDeclarations.iterator(); iter.hasNext();) {
-					BodyDeclaration bodyDeclaration = (BodyDeclaration) iter.next();
-					bodyDeclaration.setProperty(CompilationUnitSorter.RELATIVE_ORDER, new Integer(bodyDeclaration.getStartPosition()));
-				}
-				return true;
-			}
-
-			public boolean visit(EnumDeclaration enumDeclaration) {
-				List bodyDeclarations = enumDeclaration.bodyDeclarations();
-				for (Iterator iter = bodyDeclarations.iterator(); iter.hasNext();) {
-					BodyDeclaration bodyDeclaration = (BodyDeclaration) iter.next();
-					bodyDeclaration.setProperty(CompilationUnitSorter.RELATIVE_ORDER, new Integer(bodyDeclaration.getStartPosition()));
-				}
-				List enumConstants = enumDeclaration.enumConstants();
-				for (Iterator iter = enumConstants.iterator(); iter.hasNext();) {
-					EnumConstantDeclaration enumConstantDeclaration = (EnumConstantDeclaration) iter.next();
-					enumConstantDeclaration.setProperty(CompilationUnitSorter.RELATIVE_ORDER, new Integer(enumConstantDeclaration.getStartPosition()));
-				}				
-				return true;
-			}
-		});
-		final AST localAst = domUnit.getAST();
-		final ASTRewrite rewriter = ASTRewrite.create(localAst);
-		RangeMarker[] markers = null;
+		org.eclipse.jdt.core.dom.CompilationUnit ast = (org.eclipse.jdt.core.dom.CompilationUnit) parser.createAST(null);
+        
+		ASTRewrite rewriter= sortCompilationUnit(ast, null);
+		if (rewriter == null)
+			return document.get();
 		
-		final boolean needPositionsMapping = this.positions != null;
-		if (needPositionsMapping) {
-			markers = new RangeMarker[this.positions.length];
-			for (int i= 0; i < this.positions.length; i++) {
-				markers[i]= new RangeMarker(this.positions[i], 0);
-			}
-		}
-		String generatedSource = new String(source);
-		Document document = new Document(generatedSource);
-		domUnit.accept(new ASTVisitor() {
-			public boolean visit(org.eclipse.jdt.core.dom.CompilationUnit compilationUnit) {
-				ListRewrite listRewrite = rewriter.getListRewrite(compilationUnit, org.eclipse.jdt.core.dom.CompilationUnit.TYPES_PROPERTY);
-				List types = compilationUnit.types();
-				final int length = types.size();
-				if (length > 1) {
-					final List myCopy = new ArrayList();
-					myCopy.addAll(types);
-					Collections.sort(myCopy, SortElementsOperation.this.comparator);
-					for (int i = 0; i < length; i++) {
-						listRewrite.replace((ASTNode) types.get(i), rewriter.createMoveTarget((ASTNode) myCopy.get(i)), null);
-					}
-				}
-				return true;
-			}
-			public boolean visit(AnnotationTypeDeclaration annotationTypeDeclaration) {
-				ListRewrite listRewrite = rewriter.getListRewrite(annotationTypeDeclaration, AnnotationTypeDeclaration.BODY_DECLARATIONS_PROPERTY);
-				List bodyDeclarations = annotationTypeDeclaration.bodyDeclarations();
-				final int length = bodyDeclarations.size();
-				if (length > 1) {
-					final List myCopy = new ArrayList();
-					myCopy.addAll(bodyDeclarations);
-					Collections.sort(myCopy, SortElementsOperation.this.comparator);
-					for (int i = 0; i < length; i++) {
-						listRewrite.replace((ASTNode) bodyDeclarations.get(i), rewriter.createMoveTarget((ASTNode) myCopy.get(i)), null);
-					}
-				}
-				return true;
-			}
-
-			public boolean visit(AnonymousClassDeclaration anonymousClassDeclaration) {
-				ListRewrite listRewrite = rewriter.getListRewrite(anonymousClassDeclaration, AnonymousClassDeclaration.BODY_DECLARATIONS_PROPERTY);
-				List bodyDeclarations = anonymousClassDeclaration.bodyDeclarations();
-				final int length = bodyDeclarations.size();
-				if (length > 1) {
-					final List myCopy = new ArrayList();
-					myCopy.addAll(bodyDeclarations);
-					Collections.sort(myCopy, SortElementsOperation.this.comparator);
-					for (int i = 0; i < length; i++) {
-						listRewrite.replace((ASTNode) bodyDeclarations.get(i), rewriter.createMoveTarget((ASTNode) myCopy.get(i)), null);
-					}
-				}
-				return true;
-			}
-			
-			public boolean visit(TypeDeclaration typeDeclaration) {
-				ListRewrite listRewrite = rewriter.getListRewrite(typeDeclaration, TypeDeclaration.BODY_DECLARATIONS_PROPERTY);
-				List bodyDeclarations = typeDeclaration.bodyDeclarations();
-				final int length = bodyDeclarations.size();
-				if (length > 1) {
-					final List myCopy = new ArrayList();
-					myCopy.addAll(bodyDeclarations);
-					Collections.sort(myCopy, SortElementsOperation.this.comparator);
-					for (int i = 0; i < length; i++) {
-						listRewrite.replace((ASTNode) bodyDeclarations.get(i), rewriter.createMoveTarget((ASTNode) myCopy.get(i)), null);
-					}
-				}
-				return true;
-			}
-
-			public boolean visit(EnumDeclaration enumDeclaration) {
-				ListRewrite listRewrite = rewriter.getListRewrite(enumDeclaration, EnumDeclaration.BODY_DECLARATIONS_PROPERTY);
-				List bodyDeclarations = enumDeclaration.bodyDeclarations();
-				int length = bodyDeclarations.size();
-				if (length > 1) {
-					final List myCopy = new ArrayList();
-					myCopy.addAll(bodyDeclarations);
-					Collections.sort(myCopy, SortElementsOperation.this.comparator);
-					for (int i = 0; i < length; i++) {
-						listRewrite.replace((ASTNode) bodyDeclarations.get(i), rewriter.createMoveTarget((ASTNode) myCopy.get(i)), null);
-					}
-				}
-				listRewrite = rewriter.getListRewrite(enumDeclaration, EnumDeclaration.ENUM_CONSTANTS_PROPERTY);
-				List enumConstants = enumDeclaration.enumConstants();
-				length = enumConstants.size();
-				if (length > 1) {
-					final List myCopy = new ArrayList();
-					myCopy.addAll(enumConstants);
-					Collections.sort(myCopy, SortElementsOperation.this.comparator);
-					for (int i = 0; i < length; i++) {
-						listRewrite.replace((ASTNode) enumConstants.get(i), rewriter.createMoveTarget((ASTNode) myCopy.get(i)), null);
-					}
-				}
-				return true;
-			}
-		});			
 		TextEdit edits = rewriter.rewriteAST(document, null);
-		if (needPositionsMapping) {
-			for (int i = 0, max = markers.length; i < max; i++) {
+		
+		RangeMarker[] markers = null;
+		if (this.positions != null) {
+			markers = new RangeMarker[this.positions.length];
+			for (int i = 0, max = this.positions.length; i < max; i++) {
+				markers[i]= new RangeMarker(this.positions[i], 0);
 				insert(edits, markers[i]);
 			}
 		}
 		try {
 			edits.apply(document, TextEdit.UPDATE_REGIONS);
-			generatedSource = document.get();
-			if (needPositionsMapping) {
+			if (this.positions != null) {
 				for (int i= 0, max = markers.length; i < max; i++) {
 					this.positions[i]= markers[i].getOffset();
 				}
@@ -281,7 +182,142 @@
 		} catch (BadLocationException e) {
 			// ignore
 		}
-		return generatedSource;
+		return document.get();
+	}
+	
+	
+	private ASTRewrite sortCompilationUnit(org.eclipse.jdt.core.dom.CompilationUnit ast, final TextEditGroup group) {
+		ast.accept(new ASTVisitor() {
+			public boolean visit(org.eclipse.jdt.core.dom.CompilationUnit compilationUnit) {
+				List types = compilationUnit.types();
+				for (Iterator iter = types.iterator(); iter.hasNext();) {
+					AbstractTypeDeclaration typeDeclaration = (AbstractTypeDeclaration) iter.next();
+					typeDeclaration.setProperty(CompilationUnitSorter.RELATIVE_ORDER, new Integer(typeDeclaration.getStartPosition()));
+					compilationUnit.setProperty(CONTAINS_MALFORMED_NODES, Boolean.valueOf(isMalformed(typeDeclaration)));
+				}
+				return true;
+			}
+			public boolean visit(AnnotationTypeDeclaration annotationTypeDeclaration) {
+				List bodyDeclarations = annotationTypeDeclaration.bodyDeclarations();
+				for (Iterator iter = bodyDeclarations.iterator(); iter.hasNext();) {
+					BodyDeclaration bodyDeclaration = (BodyDeclaration) iter.next();
+					bodyDeclaration.setProperty(CompilationUnitSorter.RELATIVE_ORDER, new Integer(bodyDeclaration.getStartPosition()));
+					annotationTypeDeclaration.setProperty(CONTAINS_MALFORMED_NODES, Boolean.valueOf(isMalformed(bodyDeclaration)));
+				}
+				return true;
+			}
+
+			public boolean visit(AnonymousClassDeclaration anonymousClassDeclaration) {
+				List bodyDeclarations = anonymousClassDeclaration.bodyDeclarations();
+				for (Iterator iter = bodyDeclarations.iterator(); iter.hasNext();) {
+					BodyDeclaration bodyDeclaration = (BodyDeclaration) iter.next();
+					bodyDeclaration.setProperty(CompilationUnitSorter.RELATIVE_ORDER, new Integer(bodyDeclaration.getStartPosition()));
+					anonymousClassDeclaration.setProperty(CONTAINS_MALFORMED_NODES, Boolean.valueOf(isMalformed(bodyDeclaration)));
+				}
+				return true;
+			}
+			
+			public boolean visit(TypeDeclaration typeDeclaration) {
+				List bodyDeclarations = typeDeclaration.bodyDeclarations();
+				for (Iterator iter = bodyDeclarations.iterator(); iter.hasNext();) {
+					BodyDeclaration bodyDeclaration = (BodyDeclaration) iter.next();
+					bodyDeclaration.setProperty(CompilationUnitSorter.RELATIVE_ORDER, new Integer(bodyDeclaration.getStartPosition()));
+					typeDeclaration.setProperty(CONTAINS_MALFORMED_NODES, Boolean.valueOf(isMalformed(bodyDeclaration)));
+				}
+				return true;
+			}
+
+			public boolean visit(EnumDeclaration enumDeclaration) {
+				List bodyDeclarations = enumDeclaration.bodyDeclarations();
+				for (Iterator iter = bodyDeclarations.iterator(); iter.hasNext();) {
+					BodyDeclaration bodyDeclaration = (BodyDeclaration) iter.next();
+					bodyDeclaration.setProperty(CompilationUnitSorter.RELATIVE_ORDER, new Integer(bodyDeclaration.getStartPosition()));
+					enumDeclaration.setProperty(CONTAINS_MALFORMED_NODES, Boolean.valueOf(isMalformed(bodyDeclaration)));
+				}
+				List enumConstants = enumDeclaration.enumConstants();
+				for (Iterator iter = enumConstants.iterator(); iter.hasNext();) {
+					EnumConstantDeclaration enumConstantDeclaration = (EnumConstantDeclaration) iter.next();
+					enumConstantDeclaration.setProperty(CompilationUnitSorter.RELATIVE_ORDER, new Integer(enumConstantDeclaration.getStartPosition()));
+					enumDeclaration.setProperty(CONTAINS_MALFORMED_NODES, Boolean.valueOf(isMalformed(enumConstantDeclaration)));
+				}				
+				return true;
+			}
+		});
+		
+		final ASTRewrite rewriter= ASTRewrite.create(ast.getAST()); 
+		final boolean[] hasChanges= new boolean[] {false}; 
+		
+		ast.accept(new ASTVisitor() {
+		
+			private void sortElements(List elements, ListRewrite listRewrite) {
+				if (elements.size() == 0)
+					return;
+				
+				final List myCopy = new ArrayList();
+				myCopy.addAll(elements);
+				Collections.sort(myCopy, SortElementsOperation.this.comparator);
+				
+				for (int i = 0; i < elements.size(); i++) {
+					ASTNode oldNode= (ASTNode) elements.get(i);
+					ASTNode newNode= (ASTNode) myCopy.get(i);
+					if (oldNode != newNode) {
+						listRewrite.replace(oldNode, rewriter.createMoveTarget(newNode), group);
+						hasChanges[0]= true;
+					}
+				}
+			}
+
+			public boolean visit(org.eclipse.jdt.core.dom.CompilationUnit compilationUnit) {
+				if (checkMalformedNodes(compilationUnit)) {
+					return true; // abort sorting of current element
+				}
+				
+				sortElements(compilationUnit.types(), rewriter.getListRewrite(compilationUnit, org.eclipse.jdt.core.dom.CompilationUnit.TYPES_PROPERTY));
+				return true;
+			}
+
+			public boolean visit(AnnotationTypeDeclaration annotationTypeDeclaration) {
+				if (checkMalformedNodes(annotationTypeDeclaration)) {
+					return true; // abort sorting of current element
+				}
+				
+				sortElements(annotationTypeDeclaration.bodyDeclarations(), rewriter.getListRewrite(annotationTypeDeclaration, AnnotationTypeDeclaration.BODY_DECLARATIONS_PROPERTY));
+				return true;
+			}
+
+			public boolean visit(AnonymousClassDeclaration anonymousClassDeclaration) {
+				if (checkMalformedNodes(anonymousClassDeclaration)) {
+					return true; // abort sorting of current element
+				}
+				
+				sortElements(anonymousClassDeclaration.bodyDeclarations(), rewriter.getListRewrite(anonymousClassDeclaration, AnonymousClassDeclaration.BODY_DECLARATIONS_PROPERTY));	
+				return true;
+			}
+			
+			public boolean visit(TypeDeclaration typeDeclaration) {
+				if (checkMalformedNodes(typeDeclaration)) {
+					return true; // abort sorting of current element
+				}
+				
+				sortElements(typeDeclaration.bodyDeclarations(), rewriter.getListRewrite(typeDeclaration, TypeDeclaration.BODY_DECLARATIONS_PROPERTY));
+				return true;
+			}
+
+			public boolean visit(EnumDeclaration enumDeclaration) {
+				if (checkMalformedNodes(enumDeclaration)) {
+					return true; // abort sorting of current element
+				}
+				
+				sortElements(enumDeclaration.bodyDeclarations(), rewriter.getListRewrite(enumDeclaration, EnumDeclaration.BODY_DECLARATIONS_PROPERTY));
+				sortElements(enumDeclaration.enumConstants(), rewriter.getListRewrite(enumDeclaration, EnumDeclaration.ENUM_CONSTANTS_PROPERTY));
+				return true;
+			}
+		});
+		
+		if (!hasChanges[0])
+			return null;
+		
+		return rewriter;
 	}
 
 	/**
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceAnnotationMethodInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceAnnotationMethodInfo.java
index 46407d6..b868785 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceAnnotationMethodInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceAnnotationMethodInfo.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,8 +10,6 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
-import org.eclipse.jdt.core.compiler.CharOperation;
-
 /*
  * Element info for annotation method from source.
  */
@@ -22,16 +20,11 @@
 	 * These are {-1, -1} if the method is an annotation method with no default value.
 	 * Otherwise these are the start and end (inclusive) of the expression representing the default value.
 	 */
-	protected int defaultValueStart;
-	protected int defaultValueEnd;
+ public int defaultValueStart;
+ public int defaultValueEnd;
 
 	public boolean isAnnotationMethod() {
 		return true;
 	}
 	
-	public char[] getDefaultValueSource(char[] cuSource) {
-		if (this.defaultValueStart == -1 && this.defaultValueEnd == -1) 
-			return null;
-		return CharOperation.subarray(cuSource, this.defaultValueStart, this.defaultValueEnd+1);
-	}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceConstructorInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceConstructorInfo.java
index 1fe69f5..922a2d7 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceConstructorInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceConstructorInfo.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 dc936e7..e025213 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -11,10 +11,6 @@
 package org.eclipse.jdt.internal.core;
 
 import org.eclipse.jdt.core.*;
-import org.eclipse.jdt.core.IField;
-import org.eclipse.jdt.core.IType;
-import org.eclipse.jdt.core.JavaModelException;
-import org.eclipse.jdt.core.Signature;
 import org.eclipse.jdt.core.dom.ASTNode;
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
 
@@ -37,8 +33,12 @@
 public ASTNode findNode(org.eclipse.jdt.core.dom.CompilationUnit ast) {
 	// For field declarations, a variable declaration fragment is returned
 	// Return the FieldDeclaration instead
+	// For enum constant declaration, we return the node directly
 	ASTNode node = super.findNode(ast);
 	if (node == null) return null;
+	if (node.getNodeType() == ASTNode.ENUM_CONSTANT_DECLARATION) {
+		return node;
+	}
 	return node.getParent();
 }
 /**
@@ -54,36 +54,41 @@
 			
 	String constantSource = new String(constantSourceChars);
 	String signature = info.getTypeSignature();
-	if (signature.equals(Signature.SIG_INT)) {
-		constant = new Integer(constantSource);
-	} else if (signature.equals(Signature.SIG_SHORT)) {
-		constant = new Short(constantSource);
-	} else if (signature.equals(Signature.SIG_BYTE)) {
-		constant = new Byte(constantSource);
-	} else if (signature.equals(Signature.SIG_BOOLEAN)) {
-		constant = Boolean.valueOf(constantSource);
-	} else if (signature.equals(Signature.SIG_CHAR)) {
-		if (constantSourceChars.length != 3) {
-			return null;
-		}
-		constant = new Character(constantSourceChars[1]);
-	} else if (signature.equals(Signature.SIG_DOUBLE)) {
-		constant = new Double(constantSource);
-	} else if (signature.equals(Signature.SIG_FLOAT)) {
-		constant = new Float(constantSource);
-	} else if (signature.equals(Signature.SIG_LONG)) {
-		if (constantSource.endsWith("L") || constantSource.endsWith("l")) { //$NON-NLS-1$ //$NON-NLS-2$
-			int index = constantSource.lastIndexOf("L");//$NON-NLS-1$
-			if (index != -1) {
-				constant = new Long(constantSource.substring(0, index));
-			} else {
-				constant = new Long(constantSource.substring(0, constantSource.lastIndexOf("l")));//$NON-NLS-1$
+	try {
+		if (signature.equals(Signature.SIG_INT)) {
+			constant = new Integer(constantSource);
+		} else if (signature.equals(Signature.SIG_SHORT)) {
+			constant = new Short(constantSource);
+		} else if (signature.equals(Signature.SIG_BYTE)) {
+			constant = new Byte(constantSource);
+		} else if (signature.equals(Signature.SIG_BOOLEAN)) {
+			constant = Boolean.valueOf(constantSource);
+		} else if (signature.equals(Signature.SIG_CHAR)) {
+			if (constantSourceChars.length != 3) {
+				return null;
 			}
-		} else {
-			constant = new Long(constantSource);
+			constant = new Character(constantSourceChars[1]);
+		} else if (signature.equals(Signature.SIG_DOUBLE)) {
+			constant = new Double(constantSource);
+		} else if (signature.equals(Signature.SIG_FLOAT)) {
+			constant = new Float(constantSource);
+		} else if (signature.equals(Signature.SIG_LONG)) {
+			if (constantSource.endsWith("L") || constantSource.endsWith("l")) { //$NON-NLS-1$ //$NON-NLS-2$
+				int index = constantSource.lastIndexOf("L");//$NON-NLS-1$
+				if (index != -1) {
+					constant = new Long(constantSource.substring(0, index));
+				} else {
+					constant = new Long(constantSource.substring(0, constantSource.lastIndexOf("l")));//$NON-NLS-1$
+				}
+			} else {
+				constant = new Long(constantSource);
+			}
+		} else if (signature.equals("QString;")) {//$NON-NLS-1$
+			constant = constantSource;
 		}
-	} else if (signature.equals("QString;")) {//$NON-NLS-1$
-		constant = constantSource;
+	} catch (NumberFormatException e) {
+		// not a parsable constant
+		return null;
 	}
 	return constant;
 }
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 d3d5f3d..9247f8c 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 23fdcae..d6ca6f4 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -34,7 +34,11 @@
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Path;
+import org.eclipse.jdt.core.Flags;
+import org.eclipse.jdt.core.IClassFile;
+import org.eclipse.jdt.core.IField;
 import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.IMember;
 import org.eclipse.jdt.core.IMethod;
 import org.eclipse.jdt.core.IPackageFragmentRoot;
@@ -42,10 +46,11 @@
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.ITypeParameter;
 import org.eclipse.jdt.core.JavaConventions;
+import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.Signature;
+import org.eclipse.jdt.core.compiler.CategorizedProblem;
 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;
 import org.eclipse.jdt.internal.compiler.SourceElementParser;
@@ -102,15 +107,10 @@
 	protected String rootPath = ""; //$NON-NLS-1$
 
 	/**
-	 * Used for efficiency
-	 */
-	protected static String[] fgEmptyStringArray = new String[0];
-
-	/**
 	 * Table that maps a binary method to its parameter names.
 	 * Keys are the method handles, entries are <code>char[][]</code>.
 	 */
-	protected HashMap fParameterNames;
+	protected HashMap parameterNames;
 	
 	/**
 	 * Table that maps a binary element to its <code>SourceRange</code>s.
@@ -118,37 +118,42 @@
 	 * is a two element array; the first being source range, the second
 	 * being name range.
 	 */
-	protected HashMap fSourceRanges;
+	protected HashMap sourceRanges;
+	
+	/*
+	 * A map from IJavaElement to String[]
+	 */
+	protected HashMap categories;
 	
 
 	/**
 	 * The unknown source range {-1, 0}
 	 */
-	public static SourceRange fgUnknownRange = new SourceRange(-1, 0);
+	public static final SourceRange UNKNOWN_RANGE = new SourceRange(-1, 0);
 
 	/**
 	 * The position within the source of the start of the
 	 * current member element, or -1 if we are outside a member.
 	 */
-	protected int[] fMemberDeclarationStart;
+	protected int[] memberDeclarationStart;
 	/**
 	 * The <code>SourceRange</code> of the name of the current member element.
 	 */
-	protected SourceRange[] fMemberNameRange;
+	protected SourceRange[] memberNameRange;
 	/**
 	 * The name of the current member element.
 	 */
-	protected String[] fMemberName;
+	protected String[] memberName;
 	
 	/**
 	 * The parameter names for the current member method element.
 	 */
-	protected char[][][] fMethodParameterNames;
+	protected char[][][] methodParameterNames;
 	
 	/**
 	 * The parameter types for the current member method element.
 	 */
-	protected char[][][] fMethodParameterTypes;
+	protected char[][][] methodParameterTypes;
 	
 
 	/**
@@ -168,6 +173,7 @@
 	IType[] types;
 	int[] typeDeclarationStarts;
 	SourceRange[] typeNameRanges;
+	int[] typeModifiers;
 	int typeDepth;
 	
 	/**
@@ -208,8 +214,8 @@
 			this.rootPaths.add(rootPath);
 		}
 		this.sourcePath = sourcePath;
-		this.fSourceRanges = new HashMap();
-		this.fParameterNames = new HashMap();
+		this.sourceRanges = new HashMap();
+		this.parameterNames = new HashMap();
 		this.importsTable = new HashMap();
 		this.importsCounterTable = new HashMap();
 	}
@@ -220,7 +226,7 @@
 	public void acceptImport(
 			int declarationStart,
 			int declarationEnd,
-			char[] name,
+			char[][] tokens,
 			boolean onDemand,
 			int modifiers) {
 		char[][] imports = (char[][]) this.importsTable.get(this.binaryType);
@@ -239,6 +245,7 @@
 				0,
 				importsCounter);
 		}
+		char[] name = CharOperation.concatWith(tokens, '.');
 		if (onDemand) {
 			int nameLength = name.length;
 			System.arraycopy(name, 0, (name = new char[nameLength + 2]), 0, nameLength);
@@ -270,17 +277,24 @@
 	/**
 	 * @see ISourceElementRequestor
 	 */
-	public void acceptProblem(IProblem problem) {
+	public void acceptProblem(CategorizedProblem problem) {
 		//do nothing
 	}
 	
+	private void addCategories(IJavaElement element, char[][] elementCategories) {
+		if (elementCategories == null) return;
+		if (this.categories == null)
+			this.categories = new HashMap();
+		this.categories.put(element, CharOperation.toStrings(elementCategories));
+	}
+
 	/**
 	 * Closes this <code>SourceMapper</code>'s zip file. Once this is done, this
 	 * <code>SourceMapper</code> cannot be used again.
 	 */
 	public void close() {
-		fSourceRanges = null;
-		fParameterNames = null;
+		this.sourceRanges = null;
+		this.parameterNames = null;
 	}
 
 	/**
@@ -291,26 +305,57 @@
 	 */
 	private String[] convertTypeNamesToSigs(char[][] typeNames) {
 		if (typeNames == null)
-			return fgEmptyStringArray;
+			return CharOperation.NO_STRINGS;
 		int n = typeNames.length;
 		if (n == 0)
-			return fgEmptyStringArray;
+			return CharOperation.NO_STRINGS;
 		String[] typeSigs = new String[n];
 		for (int i = 0; i < n; ++i) {
-			String typeSig = Signature.createTypeSignature(typeNames[i], false);
-			int lastIndex = typeSig.lastIndexOf('.');
-			if (lastIndex == -1) {
-				typeSigs[i] = typeSig;
+			char[] typeSig = Signature.createCharArrayTypeSignature(typeNames[i], false);
+			
+			// transforms signatures that contains a qualification into unqualified signatures
+			// e.g. "QX<+QMap.Entry;>;" becomes "QX<+QEntry;>;"
+			StringBuffer simpleTypeSig = null;
+			int start = 0;
+			int dot = -1;
+			int length = typeSig.length;
+			for (int j = 0; j < length; j++) {
+				switch (typeSig[j]) {
+					case Signature.C_UNRESOLVED:
+						if (simpleTypeSig != null)
+							simpleTypeSig.append(typeSig, start, j-start);
+						start = j;
+						break;
+					case Signature.C_DOT:
+						dot = j;
+						break;
+					case Signature.C_GENERIC_START:
+					case Signature.C_NAME_END:
+						if (dot > start) {
+							if (simpleTypeSig == null)
+								simpleTypeSig = new StringBuffer().append(typeSig, 0, start);
+							simpleTypeSig.append(Signature.C_UNRESOLVED);
+							simpleTypeSig.append(typeSig, dot+1, j-dot-1);
+							start = j;
+						}
+						break;
+				}
+			}
+			if (simpleTypeSig == null) {
+				typeSigs[i] = new String(typeSig);
 			} else {
-				int arrayEnd = 0;
-				while(typeSig.charAt(arrayEnd) == Signature.C_ARRAY) arrayEnd++;
-				typeSigs[i] = typeSig.substring(0, arrayEnd) + Signature.C_UNRESOLVED + typeSig.substring(lastIndex + 1, typeSig.length());
+				simpleTypeSig.append(typeSig, start, length-start);
+				typeSigs[i] = simpleTypeSig.toString();
 			}
 		}
 		return typeSigs;
 	}
 	
-	private void computeAllRootPaths(IPackageFragmentRoot root) {
+	private synchronized void computeAllRootPaths(IType type) {
+		if (this.areRootPathsComputed) {
+			return;
+		}
+		IPackageFragmentRoot root = (IPackageFragmentRoot) type.getPackageFragment().getParent();
 		final HashSet tempRoots = new HashSet();
 		long time = 0;
 		if (VERBOSE) {
@@ -322,6 +367,9 @@
 
 		if (root.isArchive()) {
 			JarPackageFragmentRoot jarPackageFragmentRoot = (JarPackageFragmentRoot) root;
+			IJavaProject project = jarPackageFragmentRoot.getJavaProject();
+			String sourceLevel = null;
+			String complianceLevel = null;
 			JavaModelManager manager = JavaModelManager.getJavaModelManager();
 			ZipFile zip = null;
 			try {
@@ -334,7 +382,11 @@
 						if (index != -1 && Util.isClassFileName(entryName)) {
 							String firstLevelPackageName = entryName.substring(0, index);
 							if (!firstLevelPackageNames.contains(firstLevelPackageName)) {
-								IStatus status = JavaConventions.validatePackageName(firstLevelPackageName);
+								if (sourceLevel == null) {
+									sourceLevel = project.getOption(JavaCore.COMPILER_SOURCE, true);
+									complianceLevel = project.getOption(JavaCore.COMPILER_COMPLIANCE, true);
+								}
+								IStatus status = JavaConventions.validatePackageName(firstLevelPackageName, sourceLevel, complianceLevel);
 								if (status.isOK() || status.getSeverity() == IStatus.WARNING) {
 									firstLevelPackageNames.add(firstLevelPackageName);
 								}
@@ -396,7 +448,7 @@
 						IPath path = new Path(entryName);
 						int segmentCount = path.segmentCount();
 						if (segmentCount > 1) {
-							loop: for (int i = 0, max = path.segmentCount() - 1; i < max; i++) {
+							for (int i = 0, max = path.segmentCount() - 1; i < max; i++) {
 								if (firstLevelPackageNames.contains(path.segment(i))) {
 									tempRoots.add(path.uptoSegment(i));
 									// don't break here as this path could contain other first level package names (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=74014)
@@ -556,35 +608,41 @@
 				0,
 				this.typeDepth);
 			System.arraycopy(
-				this.fMemberName,
+				this.memberName,
 				0,
-				this.fMemberName = new String[this.typeDepth * 2],
+				this.memberName = new String[this.typeDepth * 2],
 				0,
 				this.typeDepth);
 			System.arraycopy(
-				this.fMemberDeclarationStart,
+				this.memberDeclarationStart,
 				0,
-				this.fMemberDeclarationStart = new int[this.typeDepth * 2],
+				this.memberDeclarationStart = new int[this.typeDepth * 2],
 				0,
 				this.typeDepth);							
 			System.arraycopy(
-				this.fMemberNameRange,
+				this.memberNameRange,
 				0,
-				this.fMemberNameRange = new SourceRange[this.typeDepth * 2],
+				this.memberNameRange = new SourceRange[this.typeDepth * 2],
 				0,
 				this.typeDepth);
 			System.arraycopy(
-				this.fMethodParameterTypes,
+				this.methodParameterTypes,
 				0,
-				this.fMethodParameterTypes = new char[this.typeDepth * 2][][],
+				this.methodParameterTypes = new char[this.typeDepth * 2][][],
 				0,
 				this.typeDepth);
 			System.arraycopy(
-				this.fMethodParameterNames,
+				this.methodParameterNames,
 				0,
-				this.fMethodParameterNames = new char[this.typeDepth * 2][][],
+				this.methodParameterNames = new char[this.typeDepth * 2][][],
 				0,
 				this.typeDepth);					
+			System.arraycopy(
+				this.typeModifiers,
+				0,
+				this.typeModifiers = new int[this.typeDepth * 2],
+				0,
+				this.typeDepth);
 		}
 		if (typeInfo.name.length == 0) {
 			this.anonymousCounter++;
@@ -600,11 +658,13 @@
 			new SourceRange(typeInfo.nameSourceStart, typeInfo.nameSourceEnd - typeInfo.nameSourceStart + 1);
 		this.typeDeclarationStarts[typeDepth] = typeInfo.declarationStart;
 
+		IType currentType = this.types[typeDepth];
+		
+		// type parameters
 		if (typeInfo.typeParameters != null) {
-			final IType currentType = this.types[typeDepth];
 			for (int i = 0, length = typeInfo.typeParameters.length; i < length; i++) {
-				final TypeParameterInfo typeParameterInfo = typeInfo.typeParameters[i];
-				final ITypeParameter typeParameter = currentType.getTypeParameter(new String(typeParameterInfo.name));
+				TypeParameterInfo typeParameterInfo = typeInfo.typeParameters[i];
+				ITypeParameter typeParameter = currentType.getTypeParameter(new String(typeParameterInfo.name));
 				setSourceRange(
 					typeParameter,
 					new SourceRange(
@@ -615,6 +675,12 @@
 						typeParameterInfo.nameSourceEnd - typeParameterInfo.nameSourceStart + 1));
 			}
 		}
+		
+		// type modifiers
+		this.typeModifiers[typeDepth] = typeInfo.modifiers;
+
+		// categories
+		addCategories(currentType, typeInfo.categories);
 	}
 
 	/**
@@ -636,10 +702,16 @@
 	 */
 	public void enterField(FieldInfo fieldInfo) {
 		if (typeDepth >= 0) {
-			fMemberDeclarationStart[typeDepth] = fieldInfo.declarationStart;
-			fMemberNameRange[typeDepth] =
+			this.memberDeclarationStart[typeDepth] = fieldInfo.declarationStart;
+			this.memberNameRange[typeDepth] =
 				new SourceRange(fieldInfo.nameSourceStart, fieldInfo.nameSourceEnd - fieldInfo.nameSourceStart + 1);
-			fMemberName[typeDepth] = new String(fieldInfo.name);
+			String fieldName = new String(fieldInfo.name);
+			this.memberName[typeDepth] = fieldName;
+			
+			// categories
+			IType currentType = this.types[typeDepth];
+			IField field = currentType.getField(fieldName);
+			addCategories(field, fieldInfo.categories);
 		}
 	}
 	
@@ -660,23 +732,46 @@
 	}
 	private void enterAbstractMethod(MethodInfo methodInfo) {
 		if (typeDepth >= 0) {
-			fMemberName[typeDepth] = new String(methodInfo.name);
-			fMemberNameRange[typeDepth] =
+			this.memberName[typeDepth] = new String(methodInfo.name);
+			this.memberNameRange[typeDepth] =
 				new SourceRange(methodInfo.nameSourceStart, methodInfo.nameSourceEnd - methodInfo.nameSourceStart + 1);
-			fMemberDeclarationStart[typeDepth] = methodInfo.declarationStart;
-			fMethodParameterTypes[typeDepth] = methodInfo.parameterTypes;
-			fMethodParameterNames[typeDepth] = methodInfo. parameterNames;
+			this.memberDeclarationStart[typeDepth] = methodInfo.declarationStart;
+			IType currentType = this.types[typeDepth];
+			int currenTypeModifiers = this.typeModifiers[typeDepth];
+			char[][] parameterTypes = methodInfo.parameterTypes;
+			if (parameterTypes != null && methodInfo.isConstructor && currentType.getDeclaringType() != null && !Flags.isStatic(currenTypeModifiers)) {
+				IType declaringType = currentType.getDeclaringType();
+				String declaringTypeName = declaringType.getElementName();
+				if (declaringTypeName.length() == 0) {
+					IClassFile classFile = declaringType.getClassFile();
+					int length = parameterTypes.length;
+					char[][] newParameterTypes = new char[length+1][];
+					declaringTypeName = classFile.getElementName();
+					declaringTypeName = declaringTypeName.substring(0, declaringTypeName.indexOf('.'));
+					newParameterTypes[0] = declaringTypeName.toCharArray();
+					System.arraycopy(parameterTypes, 0, newParameterTypes, 1, length);
+					this.methodParameterTypes[typeDepth] = newParameterTypes;
+				} else {
+					int length = parameterTypes.length;
+					char[][] newParameterTypes = new char[length+1][];
+					newParameterTypes[0] = declaringTypeName.toCharArray();
+					System.arraycopy(parameterTypes, 0, newParameterTypes, 1, length);
+					this.methodParameterTypes[typeDepth] = newParameterTypes;
+				}
+			} else {
+				this.methodParameterTypes[typeDepth] = parameterTypes;
+			}
+			this.methodParameterNames[typeDepth] = methodInfo.parameterNames;
 			
+			IMethod method = currentType.getMethod(
+					this.memberName[typeDepth],
+					convertTypeNamesToSigs(this.methodParameterTypes[typeDepth]));
+			
+			// type parameters
 			if (methodInfo.typeParameters != null) {
-				final IType currentType = this.types[typeDepth];
-				IMethod method = currentType.getMethod(
-						fMemberName[typeDepth],
-						convertTypeNamesToSigs(fMethodParameterTypes[typeDepth]));
-				if (method == null) return;
-				
 				for (int i = 0, length = methodInfo.typeParameters.length; i < length; i++) {
-					final TypeParameterInfo typeParameterInfo = methodInfo.typeParameters[i];
-					final ITypeParameter typeParameter = method.getTypeParameter(new String(typeParameterInfo.name));
+					TypeParameterInfo typeParameterInfo = methodInfo.typeParameters[i];
+					ITypeParameter typeParameter = method.getTypeParameter(new String(typeParameterInfo.name));
 					setSourceRange(
 						typeParameter,
 						new SourceRange(
@@ -687,6 +782,9 @@
 							typeParameterInfo.nameSourceEnd - typeParameterInfo.nameSourceStart + 1));
 				}
 			}	
+			
+			// categories
+			addCategories(method, methodInfo.categories);
 		}
 	}
 	
@@ -727,11 +825,11 @@
 		if (typeDepth >= 0) {
 			IType currentType = this.types[typeDepth];
 			setSourceRange(
-				currentType.getField(fMemberName[typeDepth]),
+				currentType.getField(this.memberName[typeDepth]),
 				new SourceRange(
-					fMemberDeclarationStart[typeDepth],
-					declarationEnd - fMemberDeclarationStart[typeDepth] + 1),
-				fMemberNameRange[typeDepth]);
+					this.memberDeclarationStart[typeDepth],
+					declarationEnd - this.memberDeclarationStart[typeDepth] + 1),
+				this.memberNameRange[typeDepth]);
 		}
 	}
 	
@@ -753,18 +851,18 @@
 			IType currentType = this.types[typeDepth];
 			SourceRange sourceRange =
 				new SourceRange(
-					fMemberDeclarationStart[typeDepth],
-					declarationEnd - fMemberDeclarationStart[typeDepth] + 1);
+					this.memberDeclarationStart[typeDepth],
+					declarationEnd - this.memberDeclarationStart[typeDepth] + 1);
 			IMethod method = currentType.getMethod(
-					fMemberName[typeDepth],
-					convertTypeNamesToSigs(fMethodParameterTypes[typeDepth]));
+					this.memberName[typeDepth],
+					convertTypeNamesToSigs(this.methodParameterTypes[typeDepth]));
 			setSourceRange(
 				method,
 				sourceRange,
-				fMemberNameRange[typeDepth]);
+				this.memberNameRange[typeDepth]);
 			setMethodParameterNames(
 				method,
-				fMethodParameterNames[typeDepth]);
+				this.methodParameterNames[typeDepth]);
 		}
 	}
 	
@@ -773,23 +871,11 @@
 	 * SourceMapper's ZIP file, or returns <code>null</code> if source
 	 * code cannot be found.
 	 */
-	public char[] findSource(IType type) {
+	public char[] findSource(IType type, IBinaryType info) {
 		if (!type.isBinary()) {
 			return null;
 		}
-		BinaryType parent = (BinaryType) type.getDeclaringType();
-		BinaryType declType = (BinaryType) type;
-		while (parent != null) {
-			declType = parent;
-			parent = (BinaryType) declType.getDeclaringType();
-		}
-		IBinaryType info = null;
-		try {
-			info = (IBinaryType) declType.getElementInfo();
-		} catch (JavaModelException e) {
-			return null;
-		}
-		String simpleSourceFileName = declType.sourceFileName(info);
+		String simpleSourceFileName = ((BinaryType) type).getSourceFileName(info);
 		if (simpleSourceFileName == null) {
 			return null;
 		}
@@ -818,13 +904,7 @@
 		}
 
 		if (source == null) {
-			if (!areRootPathsComputed) {
-				computeAllRootPaths((IPackageFragmentRoot) type.getPackageFragment().getParent());
-			}
-			/*
-			 * We should try all existing root paths. If none works, try to recompute it.
-			 * If it still doesn't work, then return null
-			 */
+			computeAllRootPaths(type);
 			if (this.rootPaths != null) {
 				loop: for (Iterator iterator = this.rootPaths.iterator(); iterator.hasNext(); ) {
 					String currentRootPath = (String) iterator.next();
@@ -919,7 +999,7 @@
 			case IJavaElement.METHOD :
 				if (((IMember) element).isBinary()) {
 					IJavaElement[] el = getUnqualifiedMethodHandle((IMethod) element, false);
-					if(el[1] != null && fSourceRanges.get(el[0]) == null) {
+					if(el[1] != null && this.sourceRanges.get(el[0]) == null) {
 						element = getUnqualifiedMethodHandle((IMethod) element, true)[0];
 					} else {
 						element = el[0];
@@ -932,7 +1012,7 @@
 					IMethod method = (IMethod) parent;
 					if (method.isBinary()) {
 						IJavaElement[] el = getUnqualifiedMethodHandle(method, false);
-						if(el[1] != null && fSourceRanges.get(el[0]) == null) {
+						if(el[1] != null && this.sourceRanges.get(el[0]) == null) {
 							method = (IMethod) getUnqualifiedMethodHandle(method, true)[0];
 						} else {
 							method = (IMethod) el[0];
@@ -941,9 +1021,9 @@
 					}
 				}
 		}
-		SourceRange[] ranges = (SourceRange[]) fSourceRanges.get(element);
+		SourceRange[] ranges = (SourceRange[]) this.sourceRanges.get(element);
 		if (ranges == null) {
-			return fgUnknownRange;
+			return UNKNOWN_RANGE;
 		} else {
 			return ranges[1];
 		}
@@ -956,17 +1036,17 @@
 	public char[][] getMethodParameterNames(IMethod method) {
 		if (method.isBinary()) {
 			IJavaElement[] el = getUnqualifiedMethodHandle(method, false);
-			if(el[1] != null && fParameterNames.get(el[0]) == null) {
+			if(el[1] != null && this.parameterNames.get(el[0]) == null) {
 				method = (IMethod) getUnqualifiedMethodHandle(method, true)[0];
 			} else {
 				method = (IMethod) el[0];
 			}
 		}
-		char[][] parameterNames = (char[][]) fParameterNames.get(method);
-		if (parameterNames == null) {
+		char[][] parameters = (char[][]) this.parameterNames.get(method);
+		if (parameters == null) {
 			return null;
 		} else {
-			return parameterNames;
+			return parameters;
 		}
 	}
 	
@@ -979,7 +1059,7 @@
 			case IJavaElement.METHOD :
 				if (((IMember) element).isBinary()) {
 					IJavaElement[] el = getUnqualifiedMethodHandle((IMethod) element, false);
-					if(el[1] != null && fSourceRanges.get(el[0]) == null) {
+					if(el[1] != null && this.sourceRanges.get(el[0]) == null) {
 						element = getUnqualifiedMethodHandle((IMethod) element, true)[0];
 					} else {
 						element = el[0];
@@ -992,7 +1072,7 @@
 					IMethod method = (IMethod) parent;
 					if (method.isBinary()) {
 						IJavaElement[] el = getUnqualifiedMethodHandle(method, false);
-						if(el[1] != null && fSourceRanges.get(el[0]) == null) {
+						if(el[1] != null && this.sourceRanges.get(el[0]) == null) {
 							method = (IMethod) getUnqualifiedMethodHandle(method, true)[0];
 						} else {
 							method = (IMethod) el[0];
@@ -1001,9 +1081,9 @@
 					}
 				}
 		}
-		SourceRange[] ranges = (SourceRange[]) fSourceRanges.get(element);
+		SourceRange[] ranges = (SourceRange[]) this.sourceRanges.get(element);
 		if (ranges == null) {
-			return fgUnknownRange;
+			return UNKNOWN_RANGE;
 		} else {
 			return ranges[0];
 		}
@@ -1022,7 +1102,6 @@
 			for (int i = 0; i <= lastDollar; i++)
 				newClassFileName.append(classFileName.charAt(i));
 			newClassFileName.append(Integer.toString(this.anonymousCounter));
-			newClassFileName.append(SuffixConstants.SUFFIX_class);
 			PackageFragment pkg = (PackageFragment) classFile.getParent();
 			return new BinaryType(new ClassFile(pkg, newClassFileName.toString()), typeName);
 		} else if (this.binaryType.getElementName().equals(typeName))
@@ -1040,48 +1119,10 @@
 		String[] qualifiedParameterTypes = method.getParameterTypes();
 		String[] unqualifiedParameterTypes = new String[qualifiedParameterTypes.length];
 		for (int i = 0; i < qualifiedParameterTypes.length; i++) {
-			StringBuffer unqualifiedName = new StringBuffer();
-			String qualifiedName = qualifiedParameterTypes[i];
-			int count = 0;
-			while (qualifiedName.charAt(count) == Signature.C_ARRAY) {
-				unqualifiedName.append(Signature.C_ARRAY);
-				++count;
-			}
-			char currentChar = qualifiedName.charAt(count);
-			if (currentChar == Signature.C_RESOLVED || currentChar == Signature.C_TYPE_VARIABLE) {
-				unqualifiedName.append(Signature.C_UNRESOLVED);
-				String simpleName = Signature.getSimpleName(qualifiedName.substring(count+1));
-				int lastDollar = simpleName.lastIndexOf('$');
-				hasDollar |= lastDollar != -1;
-				int start = noDollar ? lastDollar + 1 : 0;
-				boolean sigStart = false;
-				for (int j = start, length = simpleName.length(); j < length; j++) {
-					char current = simpleName.charAt(j);
-					switch (current) {
-						case Signature.C_SUPER:
-						case Signature.C_EXTENDS:
-						case Signature.C_GENERIC_START:
-						case Signature.C_NAME_END:
-							unqualifiedName.append(current);
-							sigStart = true;
-							break;
-						default:
-							if (sigStart) {
-								if (current == Signature.C_TYPE_VARIABLE) {
-									unqualifiedName.append(Signature.C_UNRESOLVED);
-								} else {
-									unqualifiedName.append(current);
-								}
-								sigStart = false;
-							} else {
-								unqualifiedName.append(current);
-							}
-					}
-				}
-			} else {
-				unqualifiedName.append(qualifiedName.substring(count, qualifiedName.length()));
-			}
-			unqualifiedParameterTypes[i] = unqualifiedName.toString();
+			StringBuffer unqualifiedTypeSig = new StringBuffer();
+			getUnqualifiedTypeSignature(qualifiedParameterTypes[i], 0/*start*/, qualifiedParameterTypes[i].length(), unqualifiedTypeSig, noDollar);
+			unqualifiedParameterTypes[i] = unqualifiedTypeSig.toString();
+			hasDollar |= unqualifiedParameterTypes[i].lastIndexOf('$') != -1;
 		}
 		
 		IJavaElement[] result = new IJavaElement[2];
@@ -1093,12 +1134,89 @@
 		}
 		return result;
 	}
+
+	private int getUnqualifiedTypeSignature(String qualifiedTypeSig, int start, int length, StringBuffer unqualifiedTypeSig, boolean noDollar) {
+		char firstChar = qualifiedTypeSig.charAt(start);
+		int end = start + 1;
+		boolean sigStart = false;
+		firstPass: for (int i = start; i < length; i++) {
+			char current = qualifiedTypeSig.charAt(i);
+			switch (current) {
+				case Signature.C_ARRAY :
+				case Signature.C_SUPER:
+				case Signature.C_EXTENDS:
+					unqualifiedTypeSig.append(current);
+					start = i + 1;
+					end = start + 1;
+					firstChar = qualifiedTypeSig.charAt(start);
+					break;
+				case Signature.C_RESOLVED :
+				case Signature.C_UNRESOLVED :
+				case Signature.C_TYPE_VARIABLE :
+					if (!sigStart) {
+						start = ++i;
+						sigStart = true;
+					}
+					break;
+				case Signature.C_NAME_END:
+				case Signature.C_GENERIC_START :
+					end = i;
+					break firstPass;
+				case Signature.C_STAR :
+					unqualifiedTypeSig.append(current);
+					start = i + 1;
+					end = start + 1;
+					firstChar = qualifiedTypeSig.charAt(start);
+					break;
+				case Signature.C_GENERIC_END :
+					return i;
+				case Signature.C_DOT:
+					start = ++i;
+					break;
+			}
+		}
+		switch (firstChar) {
+			case Signature.C_RESOLVED :
+			case Signature.C_UNRESOLVED :
+			case Signature.C_TYPE_VARIABLE :
+				unqualifiedTypeSig.append(Signature.C_UNRESOLVED);
+				if (noDollar) {
+					int lastDollar = qualifiedTypeSig.lastIndexOf('$', end);
+					if (lastDollar > start)
+						start = lastDollar + 1;
+				}
+				for (int i = start; i < length; i++) {
+					char current = qualifiedTypeSig.charAt(i);
+					switch (current) {
+						case Signature.C_GENERIC_START:
+							unqualifiedTypeSig.append(current);
+							i++;
+							do {
+								i = getUnqualifiedTypeSignature(qualifiedTypeSig, i, length, unqualifiedTypeSig, noDollar);
+							} while (qualifiedTypeSig.charAt(i) != Signature.C_GENERIC_END);
+							unqualifiedTypeSig.append(Signature.C_GENERIC_END);
+							break;
+						case Signature.C_NAME_END:
+							unqualifiedTypeSig.append(current);
+							return i + 1;
+						default:
+							unqualifiedTypeSig.append(current);
+							break;
+					}
+				}
+				return length;
+			default :
+				// primitive type or wildcard
+				unqualifiedTypeSig.append(qualifiedTypeSig.substring(start, end));
+				return end;
+		}
+	}
 		
 	/**
 	 * Maps the given source code to the given binary type and its children.
 	 */
-	public void mapSource(IType type, char[] contents) {
-		this.mapSource(type, contents, null);
+	public void mapSource(IType type, char[] contents, IBinaryType info) {
+		this.mapSource(type, contents, info, null);
 	}
 	
 	/**
@@ -1109,12 +1227,13 @@
 	public synchronized ISourceRange mapSource(
 		IType type,
 		char[] contents,
+		IBinaryType info,
 		IJavaElement elementToFind) {
 			
 		this.binaryType = (BinaryType) type;
 		
 		// check whether it is already mapped
-		if (this.fSourceRanges.get(type) != null) return (elementToFind != null) ? this.getNameRange(elementToFind) : null;
+		if (this.sourceRanges.get(type) != null) return (elementToFind != null) ? getNameRange(elementToFind) : null;
 		
 		this.importsTable.remove(this.binaryType);
 		this.importsCounterTable.remove(this.binaryType);
@@ -1122,29 +1241,29 @@
 		this.types = new IType[1];
 		this.typeDeclarationStarts = new int[1];
 		this.typeNameRanges = new SourceRange[1];
+		this.typeModifiers = new int[1];
 		this.typeDepth = -1;
-		this.fMemberDeclarationStart = new int[1];
-		this.fMemberName = new String[1];
-		this.fMemberNameRange = new SourceRange[1];
-		this.fMethodParameterTypes = new char[1][][];
-		this.fMethodParameterNames = new char[1][][];
+		this.memberDeclarationStart = new int[1];
+		this.memberName = new String[1];
+		this.memberNameRange = new SourceRange[1];
+		this.methodParameterTypes = new char[1][][];
+		this.methodParameterNames = new char[1][][];
 		this.anonymousCounter = 0;
 		
-		HashMap oldSourceRanges = (HashMap) fSourceRanges.clone();
+		HashMap oldSourceRanges = (HashMap) this.sourceRanges.clone();
 		try {
 			IProblemFactory factory = new DefaultProblemFactory();
 			SourceElementParser parser = null;
-			boolean isAnonymousClass = false;
-			char[] fullName = null;
 			this.anonymousClassName = 0;
-			IBinaryType info = null;
-			try {
-				info = (IBinaryType) this.binaryType.getElementInfo();
-				isAnonymousClass = info.isAnonymous();
-				fullName = info.getName();
-			} catch(JavaModelException e) {
-				// ignore
+			if (info == null) {
+				try {
+					info = (IBinaryType) this.binaryType.getElementInfo();
+				} catch(JavaModelException e) {
+					return null;
+				}
 			}
+			boolean isAnonymousClass = info.isAnonymous();
+			char[] fullName = info.getName();
 			if (isAnonymousClass) {
 				String eltName = this.binaryType.getParent().getElementName();
 				eltName = eltName.substring(eltName.lastIndexOf('$') + 1, eltName.length());
@@ -1170,7 +1289,7 @@
 			}
 		} finally {
 			if (elementToFind != null) {
-				fSourceRanges = oldSourceRanges;
+				this.sourceRanges = oldSourceRanges;
 			}
 			this.binaryType = null;
 			this.searchedElement = null;
@@ -1195,7 +1314,7 @@
 	/** 
 	 * Sets the mapping for this method to its parameter names.
 	 *
-	 * @see #fParameterNames
+	 * @see #parameterNames
 	 */
 	protected void setMethodParameterNames(
 		IMethod method,
@@ -1203,20 +1322,20 @@
 		if (parameterNames == null) {
 			parameterNames = CharOperation.NO_CHAR_CHAR;
 		}
-		fParameterNames.put(method, parameterNames);
+		this.parameterNames.put(method, parameterNames);
 	}
 	
 	/** 
 	 * Sets the mapping for this element to its source ranges for its source range
 	 * and name range.
 	 *
-	 * @see #fSourceRanges
+	 * @see #sourceRanges
 	 */
 	protected void setSourceRange(
 		IJavaElement element,
 		SourceRange sourceRange,
 		SourceRange nameRange) {
-		fSourceRanges.put(element, new SourceRange[] { sourceRange, nameRange });
+		this.sourceRanges.put(element, new SourceRange[] { sourceRange, nameRange });
 	}
 
 	/**
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 e337487..4f60530 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -11,11 +11,6 @@
 package org.eclipse.jdt.internal.core;
 
 import org.eclipse.jdt.core.*;
-import org.eclipse.jdt.core.Flags;
-import org.eclipse.jdt.core.IMethod;
-import org.eclipse.jdt.core.IType;
-import org.eclipse.jdt.core.JavaModelException;
-import org.eclipse.jdt.core.Signature;
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
 import org.eclipse.jdt.internal.core.util.Util;
@@ -35,7 +30,8 @@
 
 protected SourceMethod(JavaElement parent, String name, String[] parameterTypes) {
 	super(parent, name);
-	Assert.isTrue(name.indexOf('.') == -1);
+	// Assertion disabled since bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=179011
+	// Assert.isTrue(name.indexOf('.') == -1);
 	if (parameterTypes == null) {
 		this.parameterTypes= CharOperation.NO_STRINGS;
 	} else {
@@ -170,6 +166,9 @@
 	IJavaElement primaryParent = this.parent.getPrimaryElement(false);
 	return ((IType)primaryParent).getMethod(this.name, this.parameterTypes);
 }
+public String[] getRawParameterNames() throws JavaModelException {
+	return getParameterNames();
+}
 /**
  * @see IMethod
  */
@@ -198,6 +197,10 @@
  * @see IMethod
  */
 public boolean isConstructor() throws JavaModelException {
+	if (!this.getElementName().equals(this.parent.getElementName())) {
+		// faster than reaching the info
+		return false;
+	}
 	SourceMethodElementInfo info = (SourceMethodElementInfo) getElementInfo();
 	return info.isConstructor();
 }
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 5230b2f..f9ba197 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMethodInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMethodInfo.java
index e4c54c2..ce8489c 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMethodInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMethodInfo.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 7332b9c..169e91b 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -23,6 +23,15 @@
 	this.offset = offset;
 	this.length = length;
 }
+/*
+ * @see Object#equals(Object)
+ */
+public boolean equals(Object obj) {
+	if (!(obj instanceof ISourceRange))
+        return false;
+	ISourceRange sourceRange = (ISourceRange) obj;
+    return sourceRange.getOffset() == this.offset && sourceRange.getLength() == this.length;
+}
 /**
  * @see ISourceRange
  */
@@ -35,6 +44,12 @@
 public int getOffset() {
 	return this.offset;
 }
+/*
+ * @see Object#hashCode()
+ */
+public int hashCode() {
+    return this.length ^ this.offset;
+}
 public String toString() {
 	StringBuffer buffer = new StringBuffer();
 	buffer.append("[offset="); //$NON-NLS-1$
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 daff756..26ce57e 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -16,13 +16,6 @@
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.jdt.core.*;
-import org.eclipse.jdt.core.IBuffer;
-import org.eclipse.jdt.core.ICompilationUnit;
-import org.eclipse.jdt.core.IJavaElement;
-import org.eclipse.jdt.core.IOpenable;
-import org.eclipse.jdt.core.ISourceRange;
-import org.eclipse.jdt.core.ISourceReference;
-import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.dom.ASTNode;
 import org.eclipse.jdt.core.dom.CompilationUnit;
 import org.eclipse.jdt.internal.core.util.DOMFinder;
@@ -118,7 +111,7 @@
  * @see IMember
  */
 public ICompilationUnit getCompilationUnit() {
-	return ((JavaElement)getParent()).getCompilationUnit();
+	return (ICompilationUnit) getAncestor(COMPILATION_UNIT);
 }
 /**
  * Elements within compilation units and class files have no
@@ -158,6 +151,12 @@
 	String token = memento.nextToken();
 	return getHandleFromMemento(token, memento, owner);
 }
+/*
+ * @see IMember#getOccurrenceCount()
+ */
+public int getOccurrenceCount() {
+	return this.occurrenceCount;
+}
 /**
  * Return the first instance of IOpenable in the hierarchy of this
  * type (going up the hierarchy from this type);
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 fe09baf..12838c1 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 ff40087..a76d21b 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -12,16 +12,17 @@
 
 import java.io.InputStream;
 import java.util.ArrayList;
+import java.util.HashMap;
 
+import org.eclipse.core.runtime.Assert;
 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.search.SearchEngine;
 import org.eclipse.jdt.internal.codeassist.CompletionEngine;
 import org.eclipse.jdt.internal.codeassist.ISelectionRequestor;
 import org.eclipse.jdt.internal.codeassist.SelectionEngine;
-import org.eclipse.jdt.internal.compiler.env.IGenericType;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
 import org.eclipse.jdt.internal.compiler.env.ISourceType;
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
 import org.eclipse.jdt.internal.core.hierarchy.TypeHierarchy;
@@ -40,7 +41,6 @@
 	
 protected SourceType(JavaElement parent, String name) {
 	super(parent, name);
-	Assert.isTrue(name.indexOf('.') == -1, Messages.bind(Messages.sourcetype_invalidName, name)); 
 }
 protected void closing(Object info) throws JavaModelException {
 	super.closing(info);
@@ -168,6 +168,29 @@
 		return null;
 	}
 }
+public IJavaElement[] getChildrenForCategory(String category) throws JavaModelException {
+	IJavaElement[] children = getChildren();
+	int length = children.length;
+	if (length == 0) return NO_ELEMENTS;
+	SourceTypeElementInfo info = (SourceTypeElementInfo) getElementInfo();
+	HashMap categories = info.getCategories();
+	if (categories == null) return NO_ELEMENTS;
+	IJavaElement[] result = new IJavaElement[length];
+	int index = 0;
+	for (int i = 0; i < length; i++) {
+		IJavaElement child = children[i];
+		String[] elementCategories = (String[]) categories.get(child);
+		if (elementCategories != null) 
+			for (int j = 0, length2 = elementCategories.length; j < length2; j++) {
+				if (elementCategories[j].equals(category))
+					result[index++] = child;
+			}
+	}
+	if (index == 0) return NO_ELEMENTS;
+	if (index < length)
+		System.arraycopy(result, 0, result = new IJavaElement[index], 0, index);
+	return result;
+}
 /**
  * @see IMember
  */
@@ -274,17 +297,13 @@
 			String[] parameters = new String[params.size()];
 			params.toArray(parameters);
 			JavaElement method = (JavaElement)getMethod(selector, parameters);
-			if (token != null) {
-				switch (token.charAt(0)) {
-					case JEM_TYPE:
-					case JEM_TYPE_PARAMETER:
-					case JEM_LOCALVARIABLE:
-						return method.getHandleFromMemento(token, memento, workingCopyOwner);
-					default:
-						return method;
-				}
-			} else {
-				return method;
+			switch (token.charAt(0)) {
+				case JEM_TYPE:
+				case JEM_TYPE_PARAMETER:
+				case JEM_LOCALVARIABLE:
+					return method.getHandleFromMemento(token, memento, workingCopyOwner);
+				default:
+					return method;
 			}
 		case JEM_TYPE:
 			String typeName;
@@ -524,7 +543,7 @@
  */
 public boolean isClass() throws JavaModelException {
 	SourceTypeElementInfo info = (SourceTypeElementInfo) getElementInfo();
-	return info.getKind() == IGenericType.CLASS_DECL;
+	return TypeDeclaration.kind(info.getModifiers()) == TypeDeclaration.CLASS_DECL;
 }
 
 /**
@@ -533,7 +552,7 @@
  */
 public boolean isEnum() throws JavaModelException {
 	SourceTypeElementInfo info = (SourceTypeElementInfo) getElementInfo();
-	return info.getKind() == IGenericType.ENUM_DECL;
+	return TypeDeclaration.kind(info.getModifiers()) == TypeDeclaration.ENUM_DECL;
 }
 
 /**
@@ -541,9 +560,9 @@
  */
 public boolean isInterface() throws JavaModelException {
 	SourceTypeElementInfo info = (SourceTypeElementInfo) getElementInfo();
-	switch (info.getKind()) {
-		case IGenericType.INTERFACE_DECL:
-		case IGenericType.ANNOTATION_TYPE_DECL: // annotation is interface too
+	switch (TypeDeclaration.kind(info.getModifiers())) {
+		case TypeDeclaration.INTERFACE_DECL:
+		case TypeDeclaration.ANNOTATION_TYPE_DECL: // annotation is interface too
 			return true;
 	}
 	return false;
@@ -555,14 +574,21 @@
  */
 public boolean isAnnotation() throws JavaModelException {
 	SourceTypeElementInfo info = (SourceTypeElementInfo) getElementInfo();
-	return info.getKind() == IGenericType.ANNOTATION_TYPE_DECL;
+	return TypeDeclaration.kind(info.getModifiers()) == TypeDeclaration.ANNOTATION_TYPE_DECL;
 }
 
 /**
  * @see IType#isLocal()
  */
 public boolean isLocal() {
-	return this.parent instanceof IMethod || this.parent instanceof IInitializer;
+	switch (this.parent.getElementType()) {
+		case IJavaElement.METHOD:
+		case IJavaElement.INITIALIZER:
+		case IJavaElement.FIELD:
+			return true;
+		default:
+			return false;
+	}
 }
 /**
  * @see IType#isMember()
@@ -791,13 +817,13 @@
 				this.answers[length] = answer;
 			}
 		}
-		public void acceptError(IProblem error) {
+		public void acceptError(CategorizedProblem error) {
 			// ignore
 		}
 		public void acceptField(char[] declaringTypePackageName, char[] declaringTypeName, char[] fieldName, boolean isDeclaration, char[] uniqueKey, int start, int end) {
 			// ignore
 		}
-		public void acceptMethod(char[] declaringTypePackageName, char[] declaringTypeName, String enclosingDeclaringTypeSignature, char[] selector, char[][] parameterPackageNames, char[][] parameterTypeNames, String[] parameterSignatures, boolean isConstructor, boolean isDeclaration, char[] uniqueKey, int start, int end) {
+		public void acceptMethod(char[] declaringTypePackageName, char[] declaringTypeName, String enclosingDeclaringTypeSignature, char[] selector, char[][] parameterPackageNames, char[][] parameterTypeNames, String[] parameterSignatures, char[][] typeParameterNames, char[][][] typeParameterBoundNames, boolean isConstructor, boolean isDeclaration, char[] uniqueKey, int start, int end) {
 			// ignore
 		}
 		public void acceptPackage(char[] packageName){
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 ec9777a..de57e1c 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,13 +10,10 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
+import java.util.HashMap;
+
 import org.eclipse.jdt.core.*;
-import org.eclipse.jdt.core.IJavaElement;
-import org.eclipse.jdt.core.IType;
-import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.internal.compiler.env.IConstants;
-import org.eclipse.jdt.internal.compiler.env.IGenericType;
 import org.eclipse.jdt.internal.compiler.env.ISourceField;
 import org.eclipse.jdt.internal.compiler.env.ISourceImport;
 import org.eclipse.jdt.internal.compiler.env.ISourceMethod;
@@ -57,6 +54,25 @@
 	 * The type parameters of this source type. Empty if none.
 	 */
 	protected ITypeParameter[] typeParameters = TypeParameter.NO_TYPE_PARAMETERS;
+	
+	/*
+	 * A map from an IJavaElement (this type or a child of this type) to a String[] (the categories of this element)
+	 */
+	protected HashMap categories;
+	
+protected void addCategories(IJavaElement element, char[][] elementCategories) {
+	if (elementCategories == null) return;
+	if (this.categories == null)
+		this.categories = new HashMap();
+	this.categories.put(element, CharOperation.toStrings(elementCategories));
+}
+
+/*
+ * Return a map from an IJavaElement (this type or a child of this type) to a String[] (the categories of this element)
+ */
+public HashMap getCategories() {
+	return this.categories;
+}
 
 /**
  * Returns the ISourceType that is the enclosing type for this
@@ -151,18 +167,7 @@
 	}
 	return this.superInterfaceNames;
 }
-/**
- * @see org.eclipse.jdt.internal.compiler.env.IGenericType#getKind()
- */
-public int getKind() {
-	if ((this.flags & IConstants.AccInterface) != 0) {
-		if ((this.flags & IConstants.AccAnnotation) != 0)
-			return IGenericType.ANNOTATION_TYPE_DECL;
-		return IGenericType.INTERFACE_DECL;
-	}
-	if ((this.flags & IConstants.AccEnum) != 0) return IGenericType.ENUM_DECL;
-	return IGenericType.CLASS_DECL;
-}
+
 /**
  * @see ISourceType
  */
@@ -274,6 +279,12 @@
 public boolean isBinaryType() {
 	return false;
 }
+/*
+ * Returns whether the source type is an anonymous type of a member type.
+ */
+public boolean isAnonymousMember() {
+	return false;
+}
 /**
  * Sets the handle for this type info
  */
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/TypeParameter.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/TypeParameter.java
index a3361a6..2fac008 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/TypeParameter.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/TypeParameter.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,6 +10,9 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
+import java.util.HashMap;
+
+import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.IMember;
 import org.eclipse.jdt.core.ITypeParameter;
@@ -32,6 +35,16 @@
 		return super.equals(o);
 	}
 
+	/*
+	 * @see JavaElement#generateInfos
+	 */
+	protected void generateInfos(Object info, HashMap newElements, IProgressMonitor pm) throws JavaModelException {
+		Openable openableParent = (Openable)getOpenableParent();
+		if (JavaModelManager.getJavaModelManager().getInfo(openableParent) == null) {
+			openableParent.generateInfos(openableParent.createElementInfo(), newElements, pm);
+		}
+	}	
+	
 	public String[] getBounds() throws JavaModelException {
 		TypeParameterElementInfo info = (TypeParameterElementInfo) getElementInfo();
 		return CharOperation.toStrings(info.bounds);
@@ -54,6 +67,15 @@
 	}
 	
 	public ISourceRange getNameRange() throws JavaModelException {
+		SourceMapper mapper= getSourceMapper();
+		if (mapper != null) {
+			// ensure the class file's buffer is open so that source ranges are computed
+			ClassFile classFile = (ClassFile)getClassFile();
+			if (classFile != null) {
+				classFile.getBuffer();
+				return mapper.getNameRange(this);
+			}
+		}
 		TypeParameterElementInfo info = (TypeParameterElementInfo) getElementInfo();
 		return new SourceRange(info.nameStart, info.nameEnd - info.nameStart + 1);
 	}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/TypeParameterElementInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/TypeParameterElementInfo.java
index 75b0422..28affc4 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/TypeParameterElementInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/TypeParameterElementInfo.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 a4d86f2..2db65db 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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
index 14c3a78..bf43bf3 100644
--- 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
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -19,6 +19,8 @@
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
+
+import org.eclipse.core.runtime.Assert;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.Path;
 import org.eclipse.jdt.core.IAccessRule;
@@ -96,18 +98,18 @@
 		return hashCode;
 	}
 	
-	/* package */  String serialize() throws IOException {
+	public static String serialize(IClasspathEntry[] entries, boolean isSystemLibrary) throws IOException {
 		ByteArrayOutputStream s = new ByteArrayOutputStream();
 		OutputStreamWriter writer = new OutputStreamWriter(s, "UTF8"); //$NON-NLS-1$
-		XMLWriter xmlWriter = new XMLWriter(writer, null/*use the workspace line delimiter*/);
+		XMLWriter xmlWriter = new XMLWriter(writer, null/*use the workspace line delimiter*/, true/*print XML version*/);
 		
 		HashMap library = new HashMap();
 		library.put(TAG_VERSION, String.valueOf(CURRENT_VERSION));
-		library.put(TAG_SYSTEMLIBRARY, String.valueOf(this.isSystemLibrary));
+		library.put(TAG_SYSTEMLIBRARY, String.valueOf(isSystemLibrary));
 		xmlWriter.printTag(TAG_USERLIBRARY, library, true, true, false);
 		
-		for (int i = 0; i < this.entries.length; ++i) {
-			ClasspathEntry cpEntry = (ClasspathEntry) this.entries[i];
+		for (int i = 0, length = entries.length; i < length; ++i) {
+			ClasspathEntry cpEntry = (ClasspathEntry) entries[i];
 		
 			HashMap archive = new HashMap();
 			archive.put(TAG_PATH, cpEntry.getPath().toString());
@@ -134,16 +136,16 @@
 
 			// write archive end tag if necessary
 			if (hasExtraAttributes || hasRestrictions) {
-				xmlWriter.endTag(TAG_ARCHIVE, true);
+				xmlWriter.endTag(TAG_ARCHIVE, true/*insert tab*/, true/*insert new line*/);
 			}
 		}	
-		xmlWriter.endTag(TAG_USERLIBRARY, true);
+		xmlWriter.endTag(TAG_USERLIBRARY, true/*insert tab*/, true/*insert new line*/);
 		writer.flush();
 		writer.close();
 		return s.toString("UTF8");//$NON-NLS-1$
 	}
 	
-	/* package */ static UserLibrary createFromString(Reader reader) throws IOException {
+	public static UserLibrary createFromString(Reader reader) throws IOException {
 		Element cpElement;
 		try {
 			DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
@@ -156,7 +158,7 @@
 			reader.close();
 		}
 		
-		if (!cpElement.getNodeName().equalsIgnoreCase(TAG_USERLIBRARY)) { //$NON-NLS-1$
+		if (!cpElement.getNodeName().equalsIgnoreCase(TAG_USERLIBRARY)) {
 			throw new IOException(Messages.file_badFormat); 
 		}
 		// String version= cpElement.getAttribute(TAG_VERSION);
@@ -177,8 +179,12 @@
 					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;
-					IClasspathAttribute[] extraAttributes = ClasspathEntry.decodeExtraAttributes(element);
-					IAccessRule[] accessRules = ClasspathEntry.decodeAccessRules(element);
+					NodeList children = element.getElementsByTagName("*"); //$NON-NLS-1$
+					boolean[] foundChildren = new boolean[children.getLength()];
+					NodeList attributeList = ClasspathEntry.getChildAttributes(ClasspathEntry.TAG_ATTRIBUTES, children, foundChildren);
+					IClasspathAttribute[] extraAttributes = ClasspathEntry.decodeExtraAttributes(attributeList);
+					attributeList = ClasspathEntry.getChildAttributes(ClasspathEntry.TAG_ACCESS_RULES, children, foundChildren);
+					IAccessRule[] accessRules = ClasspathEntry.decodeAccessRules(attributeList);
 					IClasspathEntry entry = JavaCore.newLibraryEntry(new Path(path), sourceAttach, sourceAttachRoot, accessRules, extraAttributes, false/*not exported*/);
 					res.add(entry);
 				}
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
index c5e9b89..c02310e 100644
--- 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
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -15,6 +15,7 @@
 import org.eclipse.jdt.core.IClasspathContainer;
 import org.eclipse.jdt.core.IClasspathEntry;
 import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.internal.core.util.Util;
 
 /**
  *
@@ -23,14 +24,10 @@
 	
 	private String name;
 	
-	public UserLibraryClasspathContainer(String libName) {
-		this.name= libName;
+	public UserLibraryClasspathContainer(String name) {
+		this.name = name;
 	}
 	
-	private UserLibrary getUserLibrary() {
-		return UserLibraryManager.getUserLibrary(this.name);
-	}
-
 	/* (non-Javadoc)
 	 * @see org.eclipse.jdt.core.IClasspathContainer#getClasspathEntries()
 	 */
@@ -40,7 +37,6 @@
 			return library.getEntries();
 		}
 		return new IClasspathEntry[0];
-		
 	}
 
 	/* (non-Javadoc)
@@ -67,4 +63,18 @@
 	public IPath getPath() {
 		return new Path(JavaCore.USER_LIBRARY_CONTAINER_ID).append(this.name);
 	}
+	
+	private UserLibrary getUserLibrary() {
+		UserLibrary userLibrary = JavaModelManager.getUserLibraryManager().getUserLibrary(this.name);
+		if (userLibrary == null && JavaModelManager.CP_RESOLVE_VERBOSE) {
+			verbose_no_user_library_found(this.name);
+		}
+		return userLibrary;
+	}
+
+	private void verbose_no_user_library_found(String userLibraryName) {
+		Util.verbose(
+			"UserLibrary INIT - FAILED (no user library found)\n" + //$NON-NLS-1$
+			"	userLibraryName: " + userLibraryName); //$NON-NLS-1$
+	}
 }
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
index a516a38..1b02260 100644
--- 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
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -16,6 +16,7 @@
 import org.eclipse.jdt.core.IClasspathContainer;
 import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.internal.core.util.Util;
 
 /**
  *
@@ -23,46 +24,19 @@
 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)
+	/* (non-Javadoc)
+	 * @see org.eclipse.jdt.core.ClasspathContainerInitializer#getComparisonID(org.eclipse.core.runtime.IPath, org.eclipse.jdt.core.IJavaProject)
 	 */
-	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
-			}
-		}
+	public Object getComparisonID(IPath containerPath, IJavaProject project) {
+		return containerPath;
 	}
-
+	
 	/**
 	 * @see org.eclipse.jdt.core.ClasspathContainerInitializer#getDescription(org.eclipse.core.runtime.IPath, org.eclipse.jdt.core.IJavaProject)
 	 */
@@ -73,10 +47,51 @@
 		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 void initialize(IPath containerPath, IJavaProject project) throws CoreException {
+		if (isUserLibraryContainer(containerPath)) {
+			String userLibName = containerPath.segment(1);
+			UserLibrary userLibrary = JavaModelManager.getUserLibraryManager().getUserLibrary(userLibName);
+			if (userLibrary != null) {
+				UserLibraryClasspathContainer container = new UserLibraryClasspathContainer(userLibName);
+				JavaCore.setClasspathContainer(containerPath, new IJavaProject[] { project }, new IClasspathContainer[] { container }, null);
+			} else if (JavaModelManager.CP_RESOLVE_VERBOSE) {
+				verbose_no_user_library_found(project, userLibName);
+			}
+		} else if (JavaModelManager.CP_RESOLVE_VERBOSE) {
+			verbose_not_a_user_library(project, containerPath);
+		}
+	}
+	
+	private boolean isUserLibraryContainer(IPath path) {
+		return path != null && path.segmentCount() == 2 && JavaCore.USER_LIBRARY_CONTAINER_ID.equals(path.segment(0));
+	}
+	
+	/**
+	 * @see org.eclipse.jdt.core.ClasspathContainerInitializer#requestClasspathContainerUpdate(org.eclipse.core.runtime.IPath, org.eclipse.jdt.core.IJavaProject, org.eclipse.jdt.core.IClasspathContainer)
 	 */
-	public Object getComparisonID(IPath containerPath, IJavaProject project) {
-		return containerPath;
+	public void requestClasspathContainerUpdate(IPath containerPath, IJavaProject project, IClasspathContainer containerSuggestion) throws CoreException {
+		if (isUserLibraryContainer(containerPath)) {
+			String name = containerPath.segment(1);
+			if (containerSuggestion != null) {
+				JavaModelManager.getUserLibraryManager().setUserLibrary(name, containerSuggestion.getClasspathEntries(), containerSuggestion.getKind() == IClasspathContainer.K_SYSTEM);
+			} else {
+				JavaModelManager.getUserLibraryManager().removeUserLibrary(name);
+			}
+			// update of affected projects was done as a consequence of setUserLibrary() or removeUserLibrary()
+		}
+	}
+
+	private void verbose_no_user_library_found(IJavaProject project, String userLibraryName) {
+		Util.verbose(
+			"UserLibrary INIT - FAILED (no user library found)\n" + //$NON-NLS-1$
+			"	project: " + project.getElementName() + '\n' + //$NON-NLS-1$
+			"	userLibraryName: " + userLibraryName); //$NON-NLS-1$
+	}
+	
+	private void verbose_not_a_user_library(IJavaProject project, IPath containerPath) {
+		Util.verbose(
+			"UserLibrary INIT - FAILED (not a user library)\n" + //$NON-NLS-1$
+			"	project: " + project.getElementName() + '\n' + //$NON-NLS-1$
+			"	container path: " + containerPath); //$NON-NLS-1$
 	}
 }
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
index d53df3b..a64ce16 100644
--- 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
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -16,13 +16,9 @@
 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.SubProgressMonitor;
 import org.eclipse.core.runtime.preferences.IEclipsePreferences;
 import org.eclipse.jdt.core.IClasspathContainer;
 import org.eclipse.jdt.core.IClasspathEntry;
@@ -35,226 +31,157 @@
 /**
  *
  */
-public class UserLibraryManager {
+public class UserLibraryManager implements IEclipsePreferences.IPreferenceChangeListener {
 	
 	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 IEclipsePreferences.IPreferenceChangeListener listener= new IEclipsePreferences.IPreferenceChangeListener() {
+	private Map userLibraries;
 
-		public void preferenceChange(IEclipsePreferences.PreferenceChangeEvent event) {
-			String key= event.getKey();
-			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
+	public UserLibraryManager() {
+		initialize();
 	}
 		
-	/**
+	/*
+	 * Gets the library for a given name or <code>null</code> if no such library exists.
+	 */
+	public synchronized UserLibrary getUserLibrary(String libName) {
+		return (UserLibrary) this.userLibraries.get(libName);
+	}
+	
+	/*
 	 * 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();
+	public synchronized String[] getUserLibraryNames() {
+		Set set = this.userLibraries.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$
+	private void initialize() {
+		this.userLibraries = new HashMap();
+		IEclipsePreferences instancePreferences = JavaModelManager.getJavaModelManager().getInstancePreferences();
+		String[] propertyNames;
 		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));
+			propertyNames = instancePreferences.keys();
+		} catch (BackingStoreException e) {
+			Util.log(e, "Exception while initializing user libraries"); //$NON-NLS-1$
+			return;
+		}
+
+		boolean preferencesNeedFlush = false;
+		for (int i = 0, length = propertyNames.length; i < length; i++) {
+			String propertyName = propertyNames[i];
+			if (propertyName.startsWith(CP_USERLIBRARY_PREFERENCES_PREFIX)) {
+				String propertyValue = instancePreferences.get(propertyName, null);
+				if (propertyValue != null) {
+					String libName= propertyName.substring(CP_USERLIBRARY_PREFERENCES_PREFIX.length());
+					StringReader reader = new StringReader(propertyValue);
+					UserLibrary library;
+					try {
+						library = UserLibrary.createFromString(reader);
+					} catch (IOException e) {
+						Util.log(e, "Exception while initializing user library " + libName); //$NON-NLS-1$
+						instancePreferences.remove(propertyName);
+						preferencesNeedFlush = true;
+						continue;
+					}
+					this.userLibraries.put(libName, library);
+				}
 			}
-		} finally {
-			monitor.done();
+		}
+		if (preferencesNeedFlush) {
+			try {
+				instancePreferences.flush();
+			} catch (BackingStoreException e) {
+				Util.log(e, "Exception while flusing instance preferences"); //$NON-NLS-1$
+			}
 		}
 	}
-	
-	/**
-	 * 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
-			IEclipsePreferences instancePreferences = JavaModelManager.getJavaModelManager().getInstancePreferences();
-			instancePreferences.addPreferenceChangeListener(listener);
 
-			// only get variable from preferences not set to their default
+	public void preferenceChange(IEclipsePreferences.PreferenceChangeEvent event) {
+		String key = event.getKey();
+		if (key.startsWith(CP_USERLIBRARY_PREFERENCES_PREFIX)) {
+			String libName = key.substring(CP_USERLIBRARY_PREFERENCES_PREFIX.length());
 			try {
-				String[] propertyNames = instancePreferences.keys();
-				for (int i = 0; i < propertyNames.length; i++) {
-					String propertyName = propertyNames[i];
-					if (propertyName.startsWith(CP_USERLIBRARY_PREFERENCES_PREFIX)) {
-						try {
-							String propertyValue = instancePreferences.get(propertyName, null);
-							if (propertyValue != null)
-								recreatePersistedUserLibraryEntry(propertyName,propertyValue, false, false);
-						} catch (JavaModelException e) {
-							// won't happen: no rebinding
+				// find affected projects
+				IPath containerPath = new Path(JavaCore.USER_LIBRARY_CONTAINER_ID).append(libName);
+				IJavaProject[] allJavaProjects = JavaCore.create(ResourcesPlugin.getWorkspace().getRoot()).getJavaProjects();
+				ArrayList affectedProjects = new ArrayList();
+				for (int i= 0; i < allJavaProjects.length; i++) {
+					IJavaProject javaProject = allJavaProjects[i];
+					IClasspathEntry[] entries= javaProject.getRawClasspath();
+					for (int j= 0; j < entries.length; j++) {
+						IClasspathEntry entry = entries[j];
+						if (entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
+							if (containerPath.equals(entry.getPath())) {
+								affectedProjects.add(javaProject);
+								break;
+							}				
 						}
 					}
 				}
-			} catch (BackingStoreException e) {
-				// nothing to do in this case
+				
+				// decode user library
+				String encodedUserLibrary = (String) event.getNewValue();
+				UserLibrary userLibrary = encodedUserLibrary == null ? null : UserLibrary.createFromString(new StringReader(encodedUserLibrary));
+				
+				// update user libraries map
+				if (userLibrary != null) {
+					this.userLibraries.put(libName, userLibrary);
+				} else {
+					this.userLibraries.remove(libName);
+				}
+				
+				// update affected projects
+				int length = affectedProjects.size();
+				if (length == 0)
+					return;
+				IJavaProject[] projects = new IJavaProject[length];
+				affectedProjects.toArray(projects);
+				IClasspathContainer[] containers = new IClasspathContainer[length];
+				if (userLibrary != null) {
+					UserLibraryClasspathContainer container = new UserLibraryClasspathContainer(libName);
+					for (int i = 0; i < length; i++) {
+						containers[i] = container;
+					}
+				}
+				JavaCore.setClasspathContainer(containerPath, projects, containers, null);
+			} catch (IOException e) {
+				Util.log(e, "Exception while decoding user library '"+ libName +"'."); //$NON-NLS-1$ //$NON-NLS-2$
+			} catch (JavaModelException e) {
+				Util.log(e, "Exception while setting user library '"+ libName +"'."); //$NON-NLS-1$ //$NON-NLS-2$
 			}
 		}
-		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
-			}
-		}
-		
+	public synchronized void removeUserLibrary(String libName)  {
 		IEclipsePreferences instancePreferences = JavaModelManager.getJavaModelManager().getInstancePreferences();
-		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
-			}
-		}
-		instancePreferences.removePreferenceChangeListener(listener);
+		String propertyName = CP_USERLIBRARY_PREFERENCES_PREFIX+libName;
+		instancePreferences.remove(propertyName);
 		try {
-			instancePreferences.put(containerKey, containerString);
-			if (save) {
-				try {
-					instancePreferences.flush();
-				} catch (BackingStoreException e) {
-					// nothing to do in this case
-				}
-			}
-			if (rebind) {
-				rebindClasspathEntries(name, library==null, monitor);
-			}
-			
-		} finally {
-			instancePreferences.addPreferenceChangeListener(listener);
+			instancePreferences.flush();
+		} catch (BackingStoreException e) {
+			Util.log(e, "Exception while removing user library " + libName); //$NON-NLS-1$
 		}
+		// this.userLibraries was updated during the PreferenceChangeEvent (see preferenceChange(...))
 	}
-
-	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;
-					}				
-				}
-			}
+	
+	public synchronized void setUserLibrary(String libName, IClasspathEntry[] entries, boolean isSystemLibrary)  {
+		IEclipsePreferences instancePreferences = JavaModelManager.getJavaModelManager().getInstancePreferences();
+		String propertyName = CP_USERLIBRARY_PREFERENCES_PREFIX+libName;
+		try {
+			String propertyValue = UserLibrary.serialize(entries, isSystemLibrary);
+			instancePreferences.put(propertyName, propertyValue); // sends out a PreferenceChangeEvent (see preferenceChange(...))
+		} catch (IOException e) {
+			Util.log(e, "Exception while serializing user library " + libName); //$NON-NLS-1$
+			return;
 		}
-		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();
-			}
+		try {
+			instancePreferences.flush();
+		} catch (BackingStoreException e) {
+			Util.log(e, "Exception while saving user library " + libName); //$NON-NLS-1$
 		}
+		// this.userLibraries was updated during the PreferenceChangeEvent (see preferenceChange(...))
 	}
-
-
 	
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/VerboseElementCache.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/VerboseElementCache.java
new file mode 100755
index 0000000..374ce2b
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/VerboseElementCache.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core;
+
+import java.text.NumberFormat;
+import java.util.Date;
+
+public class VerboseElementCache extends ElementCache {
+
+	private Object beingAdded;
+	private String name;
+
+	public VerboseElementCache(int size, String name) {
+		super(size);
+		this.name = name;
+	}
+
+	protected boolean makeSpace(int space) {
+		if (this.beingAdded == null) return super.makeSpace(space);
+		String fillingRatio = toStringFillingRation(this.name);
+		boolean result = super.makeSpace(space);
+		String newFillingRatio = toStringFillingRation(this.name);
+		if (!fillingRatio.equals(newFillingRatio)) {
+			System.out.println(Thread.currentThread() + " " + new Date(System.currentTimeMillis()).toString()); //$NON-NLS-1$
+			System.out.println(Thread.currentThread() + " MADE SPACE FOR " + fillingRatio + " (NOW " + NumberFormat.getInstance().format(fillingRatio()) + "% full)"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+			System.out.println(Thread.currentThread() + " WHILE OPENING "+ ((JavaElement) this.beingAdded).toStringWithAncestors());  //$NON-NLS-1$
+			System.out.println();
+		}
+		return result;
+	}
+
+	public Object put(Object key, Object value) {
+		try {
+			if (this.beingAdded == null)
+				this.beingAdded = key;
+			return super.put(key, value);
+		} finally {
+			if (key.equals(this.beingAdded))
+				this.beingAdded = null;
+		}
+	}
+
+}
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 7fad140..cc41dd8 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -9,102 +9,17 @@
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
-import java.io.PrintWriter;
 import java.io.Writer;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.HashMap;
 
 import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.internal.compiler.util.GenericXMLWriter;
 import org.eclipse.jdt.internal.core.util.Util;
 /**
  * @since 3.0
  */
-class XMLWriter extends PrintWriter {
-	/* constants */
-	private static final String XML_VERSION= "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; //$NON-NLS-1$
-	private static void appendEscapedChar(StringBuffer buffer, char c) {
-		String replacement= getReplacement(c);
-		if (replacement != null) {
-			buffer.append('&');
-			buffer.append(replacement);
-			buffer.append(';');
-		} else {
-			buffer.append(c);
-		}
-	}
-	private static String getEscaped(String s) {
-		StringBuffer result= new StringBuffer(s.length() + 10);
-		for (int i= 0; i < s.length(); ++i)
-			appendEscapedChar(result, s.charAt(i));
-		return result.toString();
-	}
-	private static String getReplacement(char c) {
-		// Encode special XML characters into the equivalent character references.
-		// These five are defined by default for all XML documents.
-		switch (c) {
-			case '<' :
-				return "lt"; //$NON-NLS-1$
-			case '>' :
-				return "gt"; //$NON-NLS-1$
-			case '"' :
-				return "quot"; //$NON-NLS-1$
-			case '\'' :
-				return "apos"; //$NON-NLS-1$
-			case '&' :
-				return "amp"; //$NON-NLS-1$
-		}
-		return null;
-	}
-	private int tab;
-	private String lineSeparator;
-	public XMLWriter(Writer writer, IJavaProject project) {
-		super(writer);
-		this.tab= 0;
-		this.lineSeparator = Util.getLineSeparator((String) null, project);
-		print(XML_VERSION);
-		print(this.lineSeparator);
-	}
-	public void endTag(String name, boolean insertTab) {
-		this.tab --;
-		printTag('/' + name, null/*no parameters*/, insertTab, true/*insert new line*/, false/*don't close tag*/);
-	}
-	private void printTabulation() {
-		for (int i= 0; i < tab; i++)
-			super.print('\t');
-	}
-	public void printTag(String name, HashMap parameters, boolean insertTab, boolean insertNewLine, boolean closeTag) {
-		StringBuffer sb= new StringBuffer();
-		sb.append("<"); //$NON-NLS-1$
-		sb.append(name);
-		if (parameters != null) {
-			for (Enumeration en = Collections.enumeration(parameters.keySet()); en.hasMoreElements();) {
-				sb.append(" "); //$NON-NLS-1$
-				String key= (String) en.nextElement();
-				sb.append(key);
-				sb.append("=\""); //$NON-NLS-1$
-				sb.append(getEscaped(String.valueOf(parameters.get(key))));
-				sb.append("\""); //$NON-NLS-1$
-			}
-		}
-		if (closeTag) {
-			sb.append("/>"); //$NON-NLS-1$
-		} else {
-			sb.append(">"); //$NON-NLS-1$
-		}
-		if (insertTab) {
-			printTabulation();
-		}
-		print(sb.toString());
-		if (insertNewLine) {
-			print(this.lineSeparator);
-		}
-		if (parameters != null && !closeTag)
-			this.tab++;
+class XMLWriter extends GenericXMLWriter {
 
-	}
-	public void startTag(String name, boolean insertTab) {
-		printTag(name, null/*no parameters*/, insertTab, true/*insert new line*/, false/*don't close tag*/);
-		this.tab++;
+	public XMLWriter(Writer writer, IJavaProject project, boolean printXmlVersion) {
+		super(writer, Util.getLineSeparator((String) null, project), printXmlVersion);
 	}
 }
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 7d11742..2f314c8 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 b253f44..3a88ee5 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -15,13 +15,15 @@
 
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.compiler.*;
-import org.eclipse.jdt.core.compiler.IProblem;
 import org.eclipse.jdt.internal.compiler.*;
-import org.eclipse.jdt.internal.compiler.ClassFile;
 import org.eclipse.jdt.internal.compiler.Compiler;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.compiler.problem.*;
+import org.eclipse.jdt.internal.compiler.util.SimpleSet;
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
+import org.eclipse.jdt.internal.core.JavaModelManager;
 import org.eclipse.jdt.internal.core.util.Messages;
 import org.eclipse.jdt.internal.core.util.Util;
 
@@ -33,7 +35,7 @@
  * Provides the building and compilation mechanism
  * in common with the batch and incremental builders.
  */
-public abstract class AbstractImageBuilder implements ICompilerRequestor {
+public abstract class AbstractImageBuilder implements ICompilerRequestor, ICompilationUnitLocator {
 
 protected JavaBuilder javaBuilder;
 protected State newState;
@@ -50,15 +52,20 @@
 
 private boolean inCompiler;
 
-public static int MAX_AT_ONCE = 1000;
+protected boolean keepStoringProblemMarkers;
+protected SimpleSet filesWithAnnotations = null;
+
+public static int MAX_AT_ONCE = 2000; // best compromise between space used and speed
 public final static String[] JAVA_PROBLEM_MARKER_ATTRIBUTE_NAMES = {
-					IMarker.MESSAGE, 
-					IMarker.SEVERITY, 
-					IJavaModelMarker.ID, 
-					IMarker.CHAR_START, 
-					IMarker.CHAR_END, 
-					IMarker.LINE_NUMBER, 
-					IJavaModelMarker.ARGUMENTS};
+	IMarker.MESSAGE, 
+	IMarker.SEVERITY, 
+	IJavaModelMarker.ID, 
+	IMarker.CHAR_START, 
+	IMarker.CHAR_END, 
+	IMarker.LINE_NUMBER, 
+	IJavaModelMarker.ARGUMENTS,
+	IJavaModelMarker.CATEGORY_ID,	
+};
 public final static String[] JAVA_TASK_MARKER_ATTRIBUTE_NAMES = {
 	IMarker.MESSAGE, 
 	IMarker.PRIORITY, 
@@ -66,25 +73,41 @@
 	IMarker.CHAR_START, 
 	IMarker.CHAR_END, 
 	IMarker.LINE_NUMBER, 
-	IJavaModelMarker.ARGUMENTS};
+	IMarker.USER_EDITABLE,
+	IMarker.SOURCE_ID,
+};
 public final static Integer S_ERROR = new Integer(IMarker.SEVERITY_ERROR);
 public final static Integer S_WARNING = new Integer(IMarker.SEVERITY_WARNING);
 public final static Integer P_HIGH = new Integer(IMarker.PRIORITY_HIGH);
 public final static Integer P_NORMAL = new Integer(IMarker.PRIORITY_NORMAL);
 public final static Integer P_LOW = new Integer(IMarker.PRIORITY_LOW);
 
-protected AbstractImageBuilder(JavaBuilder javaBuilder) {
-	this.javaBuilder = javaBuilder;
-	this.newState = new State(javaBuilder);
-
+protected AbstractImageBuilder(JavaBuilder javaBuilder, boolean buildStarting, State newState) {
 	// local copies
+	this.javaBuilder = javaBuilder;
 	this.nameEnvironment = javaBuilder.nameEnvironment;
 	this.sourceLocations = this.nameEnvironment.sourceLocations;
 	this.notifier = javaBuilder.notifier;
+	this.keepStoringProblemMarkers = true; // may get disabled when missing classfiles are encountered
 
-	this.compiler = newCompiler();
-	this.workQueue = new WorkQueue();
-	this.problemSourceFiles = new ArrayList(3);
+	if (buildStarting) {
+		this.newState = newState == null ? new State(javaBuilder) : newState;
+		this.compiler = newCompiler();
+		this.workQueue = new WorkQueue();
+		this.problemSourceFiles = new ArrayList(3);
+
+		if (this.javaBuilder.participants != null) {
+			for (int i = 0, l = this.javaBuilder.participants.length; i < l; i++) {
+				if (this.javaBuilder.participants[i].isAnnotationProcessor()) {
+					// initialize this set so the builder knows to gather CUs that define Annotation types
+					// each Annotation processor participant is then asked to process these files AFTER
+					// the compile loop. The normal dependency loop will then recompile all affected types
+					this.filesWithAnnotations = new SimpleSet(1);
+					break;
+				}
+			}
+		}
+	}
 }
 
 public void acceptResult(CompilationResult result) {
@@ -137,17 +160,18 @@
 					if (duplicateTypeNames == null)
 						duplicateTypeNames = new ArrayList();
 					duplicateTypeNames.add(compoundName);
-					if (mainType == null)
+					if (mainType == null) {
 						try {
 							mainTypeName = compilationUnit.initialTypeName; // slash separated qualified name "p1/p1/A"
 							mainType = javaBuilder.javaProject.findType(mainTypeName.replace('/', '.'));
 						} catch (JavaModelException e) {
 							// ignore
 						}
+					}
 					IType type;
-					if (qualifiedTypeName.equals(mainTypeName))
+					if (qualifiedTypeName.equals(mainTypeName)) {
 						type = mainType;
-					else {
+					} else {
 						String simpleName = qualifiedTypeName.substring(qualifiedTypeName.lastIndexOf('/')+1);
 						type = mainType == null ? null : mainType.getCompilationUnit().getType(simpleName);
 					}
@@ -155,6 +179,8 @@
 					continue;
 				}
 				newState.recordLocatorForType(qualifiedTypeName, typeLocator);
+				if (!qualifiedTypeName.equals(compilationUnit.initialTypeName))
+					acceptSecondaryType(classFile);
 			}
 			try {
 				definedTypeNames.add(writeClassFile(classFile, compilationUnit, !isNestedType));
@@ -166,11 +192,75 @@
 					createProblemFor(compilationUnit.resource, null, Messages.build_inconsistentClassFile, JavaCore.ERROR); 
 			}
 		}
+		if (result.hasAnnotations && this.filesWithAnnotations != null) // only initialized if an annotation processor is attached
+			this.filesWithAnnotations.add(compilationUnit);
+
 		finishedWith(typeLocator, result, compilationUnit.getMainTypeName(), definedTypeNames, duplicateTypeNames);
 		notifier.compiled(compilationUnit);
 	}
 }
 
+protected void acceptSecondaryType(ClassFile classFile) {
+	// noop
+}
+
+protected void addAllSourceFiles(final ArrayList sourceFiles) throws CoreException {
+	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);
+		final int segmentCount = sourceLocation.sourceFolder.getFullPath().segmentCount();
+		final IContainer outputFolder = sourceLocation.binaryFolder;
+		final boolean isOutputFolder = sourceLocation.sourceFolder.equals(outputFolder);
+		sourceLocation.sourceFolder.accept(
+			new IResourceProxyVisitor() {
+				public boolean visit(IResourceProxy proxy) throws CoreException {
+					switch(proxy.getType()) {
+						case IResource.FILE :
+							if (org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(proxy.getName())) {
+								IResource resource = proxy.requestResource();
+								if (exclusionPatterns != null || inclusionPatterns != null)
+									if (Util.isExcluded(resource.getFullPath(), inclusionPatterns, exclusionPatterns, false))
+										return false;
+								sourceFiles.add(new SourceFile((IFile) resource, sourceLocation));
+							}
+							return false;
+						case IResource.FOLDER :
+							IPath folderPath = null;
+							if (isAlsoProject)
+								if (isExcludedFromProject(folderPath = proxy.requestFullPath()))
+									return false;
+							if (exclusionPatterns != null) {
+								if (folderPath == null)
+									folderPath = proxy.requestFullPath();
+								if (Util.isExcluded(folderPath, inclusionPatterns, exclusionPatterns, true)) {
+									// must walk children if inclusionPatterns != null, can skip them if == null
+									// but folder is excluded so do not create it in the output folder
+									return inclusionPatterns != null;
+								}
+							}
+							if (!isOutputFolder) {
+								if (folderPath == null)
+									folderPath = proxy.requestFullPath();
+								String packageName = folderPath.lastSegment();
+								if (packageName.length() > 0) {
+									String sourceLevel = javaBuilder.javaProject.getOption(JavaCore.COMPILER_SOURCE, true);
+									String complianceLevel = javaBuilder.javaProject.getOption(JavaCore.COMPILER_COMPLIANCE, true);
+									if (JavaConventions.validatePackageName(packageName, sourceLevel, complianceLevel).getSeverity() != IStatus.ERROR)
+										createFolder(folderPath.removeFirstSegments(segmentCount), outputFolder);
+								}
+							}
+					}
+					return true;
+				}
+			},
+			IResource.NONE
+		);
+		notifier.checkCancel();
+	}
+}
+
 protected void cleanUp() {
 	this.nameEnvironment.cleanup();
 
@@ -187,43 +277,67 @@
 * if they are affected by the changes.
 */
 protected void compile(SourceFile[] units) {
-	int unitsLength = units.length;
+	if (this.filesWithAnnotations != null && this.filesWithAnnotations.elementSize > 0)
+		// will add files that have annotations in acceptResult() & then processAnnotations() before exitting this method
+		this.filesWithAnnotations.clear();
 
+	// notify CompilationParticipants which source files are about to be compiled
+	BuildContext[] participantResults = this.javaBuilder.participants == null ? null : notifyParticipants(units);
+	if (participantResults != null && participantResults.length > units.length) {
+		units = new SourceFile[participantResults.length];
+		for (int i = participantResults.length; --i >= 0;)
+			units[i] = participantResults[i].sourceFile;
+	}
+
+	int unitsLength = units.length;
 	this.compiledAllAtOnce = unitsLength <= MAX_AT_ONCE;
 	if (this.compiledAllAtOnce) {
 		// do them all now
 		if (JavaBuilder.DEBUG)
 			for (int i = 0; i < unitsLength; i++)
 				System.out.println("About to compile " + units[i].typeLocator()); //$NON-NLS-1$
-		compile(units, null);
+		compile(units, null, true);
 	} else {
-		int i = 0;
+		SourceFile[] remainingUnits = new SourceFile[unitsLength]; // copy of units, removing units when about to compile
+		System.arraycopy(units, 0, remainingUnits, 0, unitsLength);
+		int doNow = unitsLength < MAX_AT_ONCE ? unitsLength : MAX_AT_ONCE;
+		SourceFile[] toCompile = new SourceFile[doNow];
+		int remainingIndex = 0;
 		boolean compilingFirstGroup = true;
-		while (i < unitsLength) {
-			int doNow = unitsLength < MAX_AT_ONCE ? unitsLength : MAX_AT_ONCE;
-			int index = 0;
-			SourceFile[] toCompile = new SourceFile[doNow];
-			while (i < unitsLength && index < doNow) {
+		while (remainingIndex < unitsLength) {
+			int count = 0;
+			while (remainingIndex < unitsLength && count < doNow) {
 				// Although it needed compiling when this method was called, it may have
 				// already been compiled when it was referenced by another unit.
-				SourceFile unit = units[i++];
-				if (compilingFirstGroup || workQueue.isWaiting(unit)) {
+				SourceFile unit = remainingUnits[remainingIndex];
+				if (unit != null && (compilingFirstGroup || this.workQueue.isWaiting(unit))) {
 					if (JavaBuilder.DEBUG)
-						System.out.println("About to compile " + unit.typeLocator()); //$NON-NLS-1$
-					toCompile[index++] = unit;
+						System.out.println("About to compile #" + remainingIndex + " : "+ unit.typeLocator()); //$NON-NLS-1$ //$NON-NLS-2$
+					toCompile[count++] = unit;
 				}
+				remainingUnits[remainingIndex++] = null;
 			}
-			if (index < doNow)
-				System.arraycopy(toCompile, 0, toCompile = new SourceFile[index], 0, index);
-			SourceFile[] additionalUnits = new SourceFile[unitsLength - i];
-			System.arraycopy(units, i, additionalUnits, 0, additionalUnits.length);
+			if (count < doNow)
+				System.arraycopy(toCompile, 0, toCompile = new SourceFile[count], 0, count);
+			if (!compilingFirstGroup)
+				for (int a = remainingIndex; a < unitsLength; a++)
+					if (remainingUnits[a] != null && this.workQueue.isCompiled(remainingUnits[a]))
+						remainingUnits[a] = null; // use the class file for this source file since its been compiled
+			compile(toCompile, remainingUnits, compilingFirstGroup);
 			compilingFirstGroup = false;
-			compile(toCompile, additionalUnits);
 		}
 	}
+
+	if (participantResults != null) {
+		for (int i = participantResults.length; --i >= 0;)
+			if (participantResults[i] != null)
+				recordParticipantResult(participantResults[i]);
+
+		processAnnotations(participantResults);
+	}
 }
 
-void compile(SourceFile[] units, SourceFile[] additionalUnits) {
+protected void compile(SourceFile[] units, SourceFile[] additionalUnits, boolean compilingFirstGroup) {
 	if (units.length == 0) return;
 	notifier.aboutToCompile(units[0]); // just to change the message
 
@@ -266,13 +380,37 @@
 		int start = range == null ? 0 : range.getOffset();
 		int end = range == null ? 1 : start + range.getLength();
 		marker.setAttributes(
-			new String[] {IMarker.MESSAGE, IMarker.SEVERITY, IMarker.CHAR_START, IMarker.CHAR_END},
-			new Object[] {message, new Integer(severity), new Integer(start), new Integer(end)});
+			new String[] {IMarker.MESSAGE, IMarker.SEVERITY, IMarker.CHAR_START, IMarker.CHAR_END, IMarker.SOURCE_ID},
+			new Object[] {message, new Integer(severity), new Integer(start), new Integer(end), JavaBuilder.SOURCE_ID});
 	} catch (CoreException e) {
 		throw internalException(e);
 	}
 }
 
+protected void deleteGeneratedFiles(IFile[] deletedGeneratedFiles) {
+	// no op by default
+}
+
+protected SourceFile findSourceFile(IFile file, boolean mustExist) {
+	if (mustExist && !file.exists()) return null;
+
+	// assumes the file exists in at least one of the source folders & is not excluded
+	ClasspathMultiDirectory md = sourceLocations[0];
+	if (sourceLocations.length > 1) {
+		IPath sourceFileFullPath = file.getFullPath();
+		for (int j = 0, m = sourceLocations.length; j < m; j++) {
+			if (sourceLocations[j].sourceFolder.getFullPath().isPrefixOf(sourceFileFullPath)) {
+				md = sourceLocations[j];
+				if (md.exclusionPatterns == null && md.inclusionPatterns == null)
+					break;
+				if (!Util.isExcluded(file, md.inclusionPatterns, md.exclusionPatterns))
+					break;
+			}
+		}
+	}
+	return new SourceFile(file, md);
+}
+
 protected void finishedWith(String sourceLocator, CompilationResult result, char[] mainTypeName, ArrayList definedTypeNames, ArrayList duplicateTypeNames) {
 	if (duplicateTypeNames == null) {
 		newState.record(sourceLocator, result.qualifiedReferences, result.simpleNameReferences, mainTypeName, definedTypeNames);
@@ -300,12 +438,30 @@
 	IFolder folder = outputFolder.getFolder(packagePath);
 	if (!folder.exists()) {
 		createFolder(packagePath.removeLastSegments(1), outputFolder);
-		folder.create(true, true, null);
-		folder.setDerived(true);
+		folder.create(IResource.FORCE | IResource.DERIVED, true, null);
 	}
 	return folder;
 }
 
+
+
+/* (non-Javadoc)
+ * @see org.eclipse.jdt.internal.core.builder.ICompilationUnitLocator#fromIFile(org.eclipse.core.resources.IFile)
+ */
+public ICompilationUnit fromIFile(IFile file) {
+	return findSourceFile(file, true);
+}
+
+protected void initializeAnnotationProcessorManager(Compiler newCompiler) {
+	AbstractAnnotationProcessorManager annotationManager = JavaModelManager.getJavaModelManager().createAnnotationProcessorManager();
+	if (annotationManager != null) {
+		annotationManager.configureFromPlatform(newCompiler, this, javaBuilder.javaProject);
+		annotationManager.setErr(new PrintWriter(System.err));
+		annotationManager.setOut(new PrintWriter(System.out));
+	}
+	newCompiler.annotationProcessorManager = annotationManager;
+}
+
 protected RuntimeException internalException(CoreException t) {
 	ImageBuilderInternalException imageBuilderException = new ImageBuilderInternalException(t);
 	if (inCompiler)
@@ -313,6 +469,18 @@
 	return imageBuilderException;
 }
 
+protected boolean isExcludedFromProject(IPath childPath) throws JavaModelException {
+	// answer whether the folder should be ignored when walking the project as a source folder
+	if (childPath.segmentCount() > 2) return false; // is a subfolder of a package
+
+	for (int j = 0, k = sourceLocations.length; j < k; j++) {
+		if (childPath.equals(sourceLocations[j].binaryFolder.getFullPath())) return true;
+		if (childPath.equals(sourceLocations[j].sourceFolder.getFullPath())) return true;
+	}
+	// skip default output folder which may not be used by any source folder
+	return childPath.equals(javaBuilder.javaProject.getOutputLocation());
+}
+
 protected Compiler newCompiler() {
 	// disable entire javadoc support if not interested in diagnostics
 	Map projectOptions = javaBuilder.javaProject.getOptions(true);
@@ -331,38 +499,126 @@
 	}
 	
 	// called once when the builder is initialized... can override if needed
+	CompilerOptions compilerOptions = new CompilerOptions(projectOptions);
+	compilerOptions.performMethodsFullRecovery = true;
+	compilerOptions.performStatementsRecovery = true;
 	Compiler newCompiler = new Compiler(
 		nameEnvironment,
 		DefaultErrorHandlingPolicies.proceedWithAllProblems(),
-		projectOptions,
+		compilerOptions,
 		this,
 		ProblemFactory.getProblemFactory(Locale.getDefault()));
 	CompilerOptions options = newCompiler.options;
-
+	
 	// enable the compiler reference info support
 	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];
-	}
 
+	if (options.complianceLevel >= ClassFileConstants.JDK1_6
+			&& options.processAnnotations) {
+		// support for Java 6 annotation processors
+		initializeAnnotationProcessorManager(newCompiler);
+	}
+	
 	return newCompiler;
 }
 
-protected boolean isExcludedFromProject(IPath childPath) throws JavaModelException {
-	// answer whether the folder should be ignored when walking the project as a source folder
-	if (childPath.segmentCount() > 2) return false; // is a subfolder of a package
+protected BuildContext[] notifyParticipants(SourceFile[] unitsAboutToCompile) {
+	BuildContext[] results = new BuildContext[unitsAboutToCompile.length];
+	for (int i = unitsAboutToCompile.length; --i >= 0;)
+		results[i] = new BuildContext(unitsAboutToCompile[i]);
 
-	for (int j = 0, k = sourceLocations.length; j < k; j++) {
-		if (childPath.equals(sourceLocations[j].binaryFolder.getFullPath())) return true;
-		if (childPath.equals(sourceLocations[j].sourceFolder.getFullPath())) return true;
+	// TODO (kent) do we expect to have more than one participant?
+	// and if so should we pass the generated files from the each processor to the others to process?
+	// and what happens if some participants do not expect to be called with only a few files, after seeing 'all' the files?
+	for (int i = 0, l = this.javaBuilder.participants.length; i < l; i++)
+		this.javaBuilder.participants[i].buildStarting(results, this instanceof BatchImageBuilder);
+
+	SimpleSet uniqueFiles = null;
+	CompilationParticipantResult[] toAdd = null;
+	int added = 0;
+	for (int i = results.length; --i >= 0;) {
+		CompilationParticipantResult result = results[i];
+		if (result == null) continue;
+
+		IFile[] deletedGeneratedFiles = result.deletedFiles;
+		if (deletedGeneratedFiles != null)
+			deleteGeneratedFiles(deletedGeneratedFiles);
+
+		IFile[] addedGeneratedFiles = result.addedFiles;
+		if (addedGeneratedFiles != null) {
+			for (int j = addedGeneratedFiles.length; --j >= 0;) {
+				SourceFile sourceFile = findSourceFile(addedGeneratedFiles[j], true);
+				if (sourceFile == null) continue;
+				if (uniqueFiles == null) {
+					uniqueFiles = new SimpleSet(unitsAboutToCompile.length + 3);
+					for (int f = unitsAboutToCompile.length; --f >= 0;)
+						uniqueFiles.add(unitsAboutToCompile[f]);
+				}
+				if (uniqueFiles.addIfNotIncluded(sourceFile) == sourceFile) {
+					CompilationParticipantResult newResult = new BuildContext(sourceFile);
+					// is there enough room to add all the addedGeneratedFiles.length ?
+					if (toAdd == null) {
+						toAdd = new CompilationParticipantResult[addedGeneratedFiles.length];
+					} else {
+						int length = toAdd.length;
+						if (added == length)
+							System.arraycopy(toAdd, 0, toAdd = new CompilationParticipantResult[length + addedGeneratedFiles.length], 0, length);
+					}
+					toAdd[added++] = newResult;
+				}
+			}
+		}
 	}
-	// skip default output folder which may not be used by any source folder
-	return childPath.equals(javaBuilder.javaProject.getOutputLocation());
+
+	if (added >0 ) {
+		int length = results.length;
+		System.arraycopy(results, 0, results = new BuildContext[length + added], 0 , length);
+		System.arraycopy(toAdd, 0, results, length, added);
+	}
+	return results;
+}
+
+protected abstract void processAnnotationResults(CompilationParticipantResult[] results);
+
+protected void processAnnotations(BuildContext[] results) {
+	boolean hasAnnotationProcessor = false;
+	for (int i = 0, l = this.javaBuilder.participants.length; !hasAnnotationProcessor && i < l; i++)
+		hasAnnotationProcessor = this.javaBuilder.participants[i].isAnnotationProcessor();
+	if (!hasAnnotationProcessor) return;
+
+	boolean foundAnnotations = this.filesWithAnnotations != null && this.filesWithAnnotations.elementSize > 0;
+	for (int i = results.length; --i >= 0;)
+		((CompilationParticipantResult) results[i]).reset(foundAnnotations && this.filesWithAnnotations.includes(results[i].sourceFile));
+
+	// even if no files have annotations, must still tell every annotation processor in case the file used to have them
+	for (int i = 0, l = this.javaBuilder.participants.length; i < l; i++)
+		if (this.javaBuilder.participants[i].isAnnotationProcessor())
+			this.javaBuilder.participants[i].processAnnotations(results);
+	processAnnotationResults(results);
+}
+
+protected void recordParticipantResult(CompilationParticipantResult result) {
+	// any added/changed/deleted generated files have already been taken care
+	// just record the problems and dependencies - do not expect there to be many
+	// must be called after we're finished with the compilation unit results but before incremental loop adds affected files
+	CategorizedProblem[] problems = result.problems;
+	if (problems != null && problems.length > 0) {
+		// existing problems have already been removed so just add these as new problems
+		this.notifier.updateProblemCounts(problems);
+		try {
+			storeProblemsFor(result.sourceFile, problems);
+		} catch (CoreException e) {
+			// must continue with compile loop so just log the CoreException
+			e.printStackTrace();
+		}
+	}
+
+	String[] dependencies = result.dependencies;
+	if (dependencies != null) {
+		ReferenceCollection refs = (ReferenceCollection) this.newState.references.get(result.sourceFile.typeLocator());
+		if (refs != null)
+			refs.addDependencies(dependencies);
+	}
 }
 
 /**
@@ -374,65 +630,98 @@
  *	 - its priority reflects the severity of the problem
  *	 - its range is the problem's range
  *	 - it has an extra attribute "ID" which holds the problem's id
+ *   - it's GENERATED_BY attribute is positioned to JavaBuilder.GENERATED_BY if
+ *     the problem was generated by JDT; else the GENERATED_BY attribute is 
+ *     carried from the problem to the marker in extra attributes, if present.
  */
-protected void storeProblemsFor(SourceFile sourceFile, IProblem[] problems) throws CoreException {
+protected void storeProblemsFor(SourceFile sourceFile, CategorizedProblem[] problems) throws CoreException {
 	if (sourceFile == null || problems == null || problems.length == 0) return;
+	 // once a classpath error is found, ignore all other problems for this project so the user can see the main error
+	// but still try to compile as many source files as possible to help the case when the base libraries are in source
+	if (!this.keepStoringProblemMarkers) return; // only want the one error recorded on this source file
 
-	String missingClassFile = null;
 	IResource resource = sourceFile.resource;
+	HashSet managedMarkerTypes = JavaModelManager.getJavaModelManager().compilationParticipants.managedMarkerTypes();
 	for (int i = 0, l = problems.length; i < l; i++) {
-		IProblem problem = problems[i];
+		CategorizedProblem problem = problems[i];
 		int id = problem.getID();
+
+		// handle missing classfile situation
 		if (id == IProblem.IsClassPathCorrect) {
-			JavaBuilder.removeProblemsAndTasksFor(javaBuilder.currentProject); // make this the only problem for this project
-			String[] args = problem.getArguments();
-			missingClassFile = args[0];
-		}
-
-		if (id != IProblem.Task) {
-			IMarker marker = resource.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
+			String missingClassfileName = problem.getArguments()[0];
+			if (JavaBuilder.DEBUG)
+				System.out.println(Messages.bind(Messages.build_incompleteClassPath, missingClassfileName));
+			boolean isInvalidClasspathError = JavaCore.ERROR.equals(javaBuilder.javaProject.getOption(JavaCore.CORE_INCOMPLETE_CLASSPATH, true));
+			// insert extra classpath problem, and make it the only problem for this project (optional)
+			if (isInvalidClasspathError && JavaCore.ABORT.equals(javaBuilder.javaProject.getOption(JavaCore.CORE_JAVA_BUILD_INVALID_CLASSPATH, true))) {
+				JavaBuilder.removeProblemsAndTasksFor(javaBuilder.currentProject); // make this the only problem for this project
+				this.keepStoringProblemMarkers = false;
+			}
+			IMarker marker = this.javaBuilder.currentProject.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
 			marker.setAttributes(
-				JAVA_PROBLEM_MARKER_ATTRIBUTE_NAMES,
-				new Object[] { 
-					problem.getMessage(),
-					problem.isError() ? S_ERROR : S_WARNING, 
-					new Integer(id),
-					new Integer(problem.getSourceStart()),
-					new Integer(problem.getSourceEnd() + 1),
-					new Integer(problem.getSourceLineNumber()),
-					Util.getProblemArgumentsForMarker(problem.getArguments())
-				});
+				new String[] {IMarker.MESSAGE, IMarker.SEVERITY, IJavaModelMarker.CATEGORY_ID, IMarker.SOURCE_ID},
+				new Object[] {
+					Messages.bind(Messages.build_incompleteClassPath, missingClassfileName),
+					new Integer(isInvalidClasspathError ? IMarker.SEVERITY_ERROR : IMarker.SEVERITY_WARNING),
+					new Integer(CategorizedProblem.CAT_BUILDPATH),
+					JavaBuilder.SOURCE_ID
+				}
+			);
+			// even if we're not keeping more markers, still fall through rest of the problem reporting, so that offending
+			// IsClassPathCorrect problem gets recorded since it may help locate the offending reference
 		}
 
-/* Do NOT want to populate the Java Model just to find the matching Java element.
- * Also cannot query compilation units located in folders with invalid package
- * names such as 'a/b.c.d/e'.
+		String markerType = problem.getMarkerType();
+		boolean managedProblem = false;
+		if (IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER.equals(markerType)
+				|| (managedProblem = managedMarkerTypes.contains(markerType))) {
+			IMarker marker = resource.createMarker(markerType);
 
-		// compute a user-friendly location
-		IJavaElement element = JavaCore.create(resource);
-		if (element instanceof org.eclipse.jdt.core.ICompilationUnit) { // try to find a finer grain element
-			org.eclipse.jdt.core.ICompilationUnit unit = (org.eclipse.jdt.core.ICompilationUnit) element;
-			IJavaElement fragment = unit.getElementAt(problem.getSourceStart());
-			if (fragment != null) element = fragment;
+			String[] attributeNames = JAVA_PROBLEM_MARKER_ATTRIBUTE_NAMES;
+			int standardLength = attributeNames.length;
+			String[] allNames = attributeNames;
+			int managedLength = managedProblem ? 0 : 1;
+			String[] extraAttributeNames = problem.getExtraMarkerAttributeNames();
+			int extraLength = extraAttributeNames == null ? 0 : extraAttributeNames.length;
+			if (managedLength > 0 || extraLength > 0) {
+				allNames = new String[standardLength + managedLength + extraLength];
+				System.arraycopy(attributeNames, 0, allNames, 0, standardLength);
+				if (managedLength > 0)
+					allNames[standardLength] = IMarker.SOURCE_ID;
+				System.arraycopy(extraAttributeNames, 0, allNames, standardLength + managedLength, extraLength);
+			}
+
+			Object[] allValues = new Object[allNames.length];
+			// standard attributes
+			int index = 0;
+			allValues[index++] = problem.getMessage(); // message
+			allValues[index++] = problem.isError() ? S_ERROR : S_WARNING; // severity
+			allValues[index++] = new Integer(id); // ID
+			allValues[index++] = new Integer(problem.getSourceStart()); // start
+			allValues[index++] = new Integer(problem.getSourceEnd() + 1); // end
+			allValues[index++] = new Integer(problem.getSourceLineNumber()); // line
+			allValues[index++] = Util.getProblemArgumentsForMarker(problem.getArguments()); // arguments
+			allValues[index++] = new Integer(problem.getCategoryID()); // category ID
+			// GENERATED_BY attribute for JDT problems
+			if (managedLength > 0)
+				allValues[index++] = JavaBuilder.SOURCE_ID;
+			// optional extra attributes
+			if (extraLength > 0)
+				System.arraycopy(problem.getExtraMarkerAttributeValues(), 0, allValues, index, extraLength);
+
+			marker.setAttributes(allNames, allValues);
+
+			if (!this.keepStoringProblemMarkers) return; // only want the one error recorded on this source file
 		}
-		String location = null;
-		if (element instanceof JavaElement)
-			location = ((JavaElement) element).readableName();
-		if (location != null)
-			marker.setAttribute(IMarker.LOCATION, location);
-*/
-
-		if (missingClassFile != null)
-			throw new MissingClassFileException(missingClassFile);
 	}
 }
 
-protected void storeTasksFor(SourceFile sourceFile, IProblem[] tasks) throws CoreException {
+protected void storeTasksFor(SourceFile sourceFile, CategorizedProblem[] tasks) throws CoreException {
 	if (sourceFile == null || tasks == null || tasks.length == 0) return;
 
 	IResource resource = sourceFile.resource;
 	for (int i = 0, l = tasks.length; i < l; i++) {
-		IProblem task = tasks[i];
+		CategorizedProblem task = tasks[i];
 		if (task.getID() == IProblem.Task) {
 			IMarker marker = resource.createMarker(IJavaModelMarker.TASK_MARKER);
 			Integer priority = P_NORMAL;
@@ -441,23 +730,40 @@
 				priority = P_HIGH;
 			else if (JavaCore.COMPILER_TASK_PRIORITY_LOW.equals(compilerPriority))
 				priority = P_LOW;
-			marker.setAttributes(
-				JAVA_TASK_MARKER_ATTRIBUTE_NAMES,
-				new Object[] { 
-					task.getMessage(),
-					priority,
-					new Integer(task.getID()),
-					new Integer(task.getSourceStart()),
-					new Integer(task.getSourceEnd() + 1),
-					new Integer(task.getSourceLineNumber()),
-					Boolean.FALSE,
-				});
+
+			String[] attributeNames = JAVA_TASK_MARKER_ATTRIBUTE_NAMES;
+			int standardLength = attributeNames.length;
+			String[] allNames = attributeNames;
+			String[] extraAttributeNames = task.getExtraMarkerAttributeNames();
+			int extraLength = extraAttributeNames == null ? 0 : extraAttributeNames.length;
+			if (extraLength > 0) {
+				allNames = new String[standardLength + extraLength];
+				System.arraycopy(attributeNames, 0, allNames, 0, standardLength);
+				System.arraycopy(extraAttributeNames, 0, allNames, standardLength, extraLength);
+			}
+
+			Object[] allValues = new Object[allNames.length];
+			// standard attributes
+			int index = 0;
+			allValues[index++] = task.getMessage();
+			allValues[index++] = priority;
+			allValues[index++] = new Integer(task.getID());
+			allValues[index++] = new Integer(task.getSourceStart());
+			allValues[index++] = new Integer(task.getSourceEnd() + 1);
+			allValues[index++] = new Integer(task.getSourceLineNumber());
+			allValues[index++] = Boolean.FALSE;
+			allValues[index++] = JavaBuilder.SOURCE_ID;
+			// optional extra attributes
+			if (extraLength > 0)
+				System.arraycopy(task.getExtraMarkerAttributeValues(), 0, allValues, index, extraLength);
+
+			marker.setAttributes(allNames, allValues);
 		}
 	}
 }
 
 protected void updateProblemsFor(SourceFile sourceFile, CompilationResult result) throws CoreException {
-	IProblem[] problems = result.getProblems();
+	CategorizedProblem[] problems = result.getProblems();
 	if (problems == null || problems.length == 0) return;
 
 	notifier.updateProblemCounts(problems);
@@ -465,13 +771,13 @@
 }
 
 protected void updateTasksFor(SourceFile sourceFile, CompilationResult result) throws CoreException {
-	IProblem[] tasks = result.getTasks();
+	CategorizedProblem[] tasks = result.getTasks();
 	if (tasks == null || tasks.length == 0) return;
 
 	storeTasksFor(sourceFile, tasks);
 }
 
-protected char[] writeClassFile(ClassFile classFile, SourceFile compilationUnit, boolean isSecondaryType) throws CoreException {
+protected char[] writeClassFile(ClassFile classFile, SourceFile compilationUnit, boolean isTopLevelType) throws CoreException {
 	String fileName = new String(classFile.fileName()); // the qualified type name "p1/p2/A"
 	IPath filePath = new Path(fileName);
 	IContainer outputFolder = compilationUnit.sourceLocation.binaryFolder; 
@@ -482,32 +788,27 @@
 	}
 
 	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;
-		}
+	writeClassFileBytes(classFile.getBytes(), file, fileName, isTopLevelType, compilationUnit);
+	if (classFile.isShared) {
+		this.compiler.lookupEnvironment.classFilePool.release(classFile);
 	}
-
 	// answer the name of the class file as in Y or Y$M
 	return filePath.lastSegment().toCharArray();
 }
 
-protected void writeClassFileBytes(byte[] bytes, IFile file, String qualifiedFileName, boolean isSecondaryType, boolean updateClassFile) throws CoreException {
+protected void writeClassFileBytes(byte[] bytes, IFile file, String qualifiedFileName, boolean isTopLevelType, SourceFile compilationUnit) throws CoreException {
 	if (file.exists()) {
 		// Deal with shared output folders... last one wins... no collision cases detected
 		if (JavaBuilder.DEBUG)
 			System.out.println("Writing changed class file " + file.getName());//$NON-NLS-1$
-		file.setContents(new ByteArrayInputStream(bytes), true, false, null);
 		if (!file.isDerived())
 			file.setDerived(true);
+		file.setContents(new ByteArrayInputStream(bytes), true, false, null);
 	} else {
 		// Default implementation just writes out the bytes for the new class file...
 		if (JavaBuilder.DEBUG)
 			System.out.println("Writing new class file " + file.getName());//$NON-NLS-1$
-		file.create(new ByteArrayInputStream(bytes), IResource.FORCE, null);
-		file.setDerived(true);
+		file.create(new ByteArrayInputStream(bytes), IResource.FORCE | IResource.DERIVED, null);
 	}
 }
 }
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 6adf478..2597273 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 046b1fb..0615520 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -14,6 +14,8 @@
 import org.eclipse.core.runtime.*;
 
 import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.compiler.*;
+import org.eclipse.jdt.internal.compiler.ClassFile;
 import org.eclipse.jdt.internal.core.util.Messages;
 import org.eclipse.jdt.internal.core.util.Util;
 
@@ -21,9 +23,16 @@
 
 public class BatchImageBuilder extends AbstractImageBuilder {
 
-protected BatchImageBuilder(JavaBuilder javaBuilder) {
-	super(javaBuilder);
+	IncrementalImageBuilder incrementalBuilder; // if annotations or secondary types have to be processed after the compile loop
+	ArrayList secondaryTypes; // qualified names for all secondary types found during batch compile
+	StringSet typeLocatorsWithUndefinedTypes; // type locators for all source files with errors that may be caused by 'not found' secondary types
+
+protected BatchImageBuilder(JavaBuilder javaBuilder, boolean buildStarting) {
+	super(javaBuilder, buildStarting, null);
 	this.nameEnvironment.isIncrementalBuild = false;
+	this.incrementalBuilder = null;
+	this.secondaryTypes = null;
+	this.typeLocatorsWithUndefinedTypes = null;
 }
 
 public void build() {
@@ -31,15 +40,15 @@
 		System.out.println("FULL build"); //$NON-NLS-1$
 
 	try {
-		notifier.subTask(Messages.build_cleaningOutput); 
+		notifier.subTask(Messages.bind(Messages.build_cleaningOutput, this.javaBuilder.currentProject.getName()));
 		JavaBuilder.removeProblemsAndTasksFor(javaBuilder.currentProject);
 		cleanOutputFolders(true);
-		notifier.updateProgressDelta(0.1f);
+		notifier.updateProgressDelta(0.05f);
 
 		notifier.subTask(Messages.build_analyzingSources); 
 		ArrayList sourceFiles = new ArrayList(33);
 		addAllSourceFiles(sourceFiles);
-		notifier.updateProgressDelta(0.15f);
+		notifier.updateProgressDelta(0.10f);
 
 		if (sourceFiles.size() > 0) {
 			SourceFile[] allSourceFiles = new SourceFile[sourceFiles.size()];
@@ -48,6 +57,12 @@
 			notifier.setProgressPerCompilationUnit(0.75f / allSourceFiles.length);
 			workQueue.addAll(allSourceFiles);
 			compile(allSourceFiles);
+
+			if (this.typeLocatorsWithUndefinedTypes != null)
+				if (this.secondaryTypes != null && !this.secondaryTypes.isEmpty())
+					rebuildTypesAffectedBySecondaryTypes();
+			if (this.incrementalBuilder != null)
+				this.incrementalBuilder.buildAfterBatchBuild();
 		}
 
 		if (javaBuilder.javaProject.hasCycleMarker())
@@ -59,52 +74,22 @@
 	}
 }
 
-protected void addAllSourceFiles(final ArrayList sourceFiles) throws CoreException {
-	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;
-					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.core.util.Util.isJavaLikeFileName(proxy.getName())) {
-								if (resource == null)
-									resource = proxy.requestResource();
-								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;
-				}
-			},
-			IResource.NONE
-		);
-		notifier.checkCancel();
-	}
+protected void acceptSecondaryType(ClassFile classFile) {
+	if (this.secondaryTypes != null)
+		this.secondaryTypes.add(classFile.fileName());
 }
 
 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) {
+		if (this.javaBuilder.participants != null)
+			for (int i = 0, l = this.javaBuilder.participants.length; i < l; i++)
+				this.javaBuilder.participants[i].cleanStarting(this.javaBuilder.javaProject);
+
 		ArrayList visited = new ArrayList(sourceLocations.length);
 		for (int i = 0, l = sourceLocations.length; i < l; i++) {
-			notifier.subTask(Messages.build_cleaningOutput); 
+			notifier.subTask(Messages.bind(Messages.build_cleaningOutput, this.javaBuilder.currentProject.getName())); 
 			ClasspathMultiDirectory sourceLocation = sourceLocations[i];
 			if (sourceLocation.hasIndependentOutputFolder) {
 				IContainer outputFolder = sourceLocation.binaryFolder;
@@ -142,34 +127,26 @@
 				sourceLocation.binaryFolder.accept(
 					new IResourceProxyVisitor() {
 						public boolean visit(IResourceProxy proxy) throws CoreException {
-							IResource resource = null;
 							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();
+									IResource resource = proxy.requestResource();
+									if (exclusionPatterns != null || inclusionPatterns != null)
+										if (Util.isExcluded(resource.getFullPath(), inclusionPatterns, exclusionPatterns, false))
+											return false;
 									resource.delete(IResource.FORCE, null);
 								}
 								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;
-							}
+							if (exclusionPatterns != null && inclusionPatterns == null) // must walk children if inclusionPatterns != null
+								if (Util.isExcluded(proxy.requestFullPath(), null, exclusionPatterns, true))
+									return false;
 							notifier.checkCancel();
 							return true;
 						}
 					},
 					IResource.NONE
 				);
-				if (!isOutputFolder && copyBack) {
-					notifier.checkCancel();
-					copyPackages(sourceLocation);
-				}
+				notifier.checkCancel();
 			}
 			notifier.checkCancel();
 		}
@@ -178,13 +155,24 @@
 			ClasspathMultiDirectory sourceLocation = sourceLocations[i];
 			if (sourceLocation.hasIndependentOutputFolder)
 				copyExtraResourcesBack(sourceLocation, false);
-			else if (!sourceLocation.sourceFolder.equals(sourceLocation.binaryFolder))
-				copyPackages(sourceLocation); // output folder is different from source folder
 			notifier.checkCancel();
 		}
 	}
 }
 
+protected void cleanUp() {
+	this.incrementalBuilder = null;
+	this.secondaryTypes = null;
+	this.typeLocatorsWithUndefinedTypes = null;
+	super.cleanUp();
+}
+
+protected void compile(SourceFile[] units, SourceFile[] additionalUnits, boolean compilingFirstGroup) {
+	if (additionalUnits != null && this.secondaryTypes == null)
+		this.secondaryTypes = new ArrayList(7);
+	super.compile(units, additionalUnits, compilingFirstGroup);
+}
+
 protected void copyExtraResourcesBack(ClasspathMultiDirectory sourceLocation, final boolean deletedAll) throws CoreException {
 	// When, if ever, does a builder need to copy resources files (not .java or .class) into the output folder?
 	// If we wipe the output folder at the beginning of the build then all 'extra' resources must be copied to the output folder.
@@ -207,7 +195,7 @@
 						resource = proxy.requestResource();
 						if (javaBuilder.filterExtraResource(resource)) return false;
 						if (exclusionPatterns != null || inclusionPatterns != null)
-							if (Util.isExcluded(resource, inclusionPatterns, exclusionPatterns))
+							if (Util.isExcluded(resource.getFullPath(), inclusionPatterns, exclusionPatterns, false))
 								return false;
 
 						IPath partialPath = resource.getFullPath().removeFirstSegments(segmentCount);
@@ -225,46 +213,17 @@
 							}
 							copiedResource.delete(IResource.FORCE, null); // last one wins
 						}
-						resource.copy(copiedResource.getFullPath(), IResource.FORCE, null);
-						copiedResource.setDerived(true);
+						createFolder(partialPath.removeLastSegments(1), outputFolder); // ensure package folder exists
+						resource.copy(copiedResource.getFullPath(), IResource.FORCE | IResource.DERIVED, null);
 						Util.setReadOnly(copiedResource, false); // just in case the original was read only
 						return false;
 					case IResource.FOLDER :
 						resource = proxy.requestResource();
 						if (javaBuilder.filterExtraResource(resource)) 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;
-			}
-		},
-		IResource.NONE
-	);
-}
-
-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(
-		new IResourceProxyVisitor() {
-			public boolean visit(IResourceProxy proxy) throws CoreException {
-				switch(proxy.getType()) {
-					case IResource.FILE :
-						return false;
-					case IResource.FOLDER :
-						IResource resource = proxy.requestResource();
-						if (javaBuilder.filterExtraResource(resource)) 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);
+						if (isAlsoProject && isExcludedFromProject(resource.getFullPath())) return false; // the sourceFolder == project
+						if (exclusionPatterns != null && inclusionPatterns == null) // must walk children if inclusionPatterns != null
+							if (Util.isExcluded(resource.getFullPath(), null, exclusionPatterns, true))
+								return false;
 				}
 				return true;
 			}
@@ -284,6 +243,48 @@
 	return null;
 }
 
+protected void processAnnotationResults(CompilationParticipantResult[] results) {
+	// to compile the compilation participant results, we need to incrementally recompile all affected types
+	// whenever the generated types are initially added or structurally changed
+	if (this.incrementalBuilder == null)
+		this.incrementalBuilder = new IncrementalImageBuilder(this);
+	this.incrementalBuilder.processAnnotationResults(results);
+}
+
+protected void rebuildTypesAffectedBySecondaryTypes() {
+	// to compile types that could not find 'missing' secondary types because of multiple
+	// compile groups, we need to incrementally recompile all affected types as if the missing
+	// secondary types have just been added, see bug 146324
+	if (this.incrementalBuilder == null)
+		this.incrementalBuilder = new IncrementalImageBuilder(this);
+
+	for (int i = this.secondaryTypes.size(); --i >=0;) {
+		char[] secondaryTypeName = (char[]) this.secondaryTypes.get(i);
+		IPath path = new Path(null, new String(secondaryTypeName));
+		this.incrementalBuilder.addDependentsOf(path, false);
+	}
+	this.incrementalBuilder.addAffectedSourceFiles(
+		this.incrementalBuilder.qualifiedStrings,
+		this.incrementalBuilder.simpleStrings,
+		this.typeLocatorsWithUndefinedTypes);
+}
+
+protected void storeProblemsFor(SourceFile sourceFile, CategorizedProblem[] problems) throws CoreException {
+	if (sourceFile == null || problems == null || problems.length == 0) return;
+
+	for (int i = problems.length; --i >= 0;) {
+		CategorizedProblem problem = problems[i];
+		if (problem != null && problem.getID() == IProblem.UndefinedType) {
+			if (this.typeLocatorsWithUndefinedTypes == null)
+				this.typeLocatorsWithUndefinedTypes = new StringSet(3);
+			this.typeLocatorsWithUndefinedTypes.add(sourceFile.typeLocator());
+			break;
+		}
+	}
+
+	super.storeProblemsFor(sourceFile, problems);
+}
+
 public String toString() {
 	return "batch image builder for:\n\tnew state: " + newState; //$NON-NLS-1$
 }
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 8d661fb..dbe17bc 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -13,6 +13,7 @@
 import org.eclipse.core.resources.*;
 import org.eclipse.core.runtime.*;
 
+import org.eclipse.jdt.core.compiler.CategorizedProblem;
 import org.eclipse.jdt.core.compiler.IProblem;
 import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
 import org.eclipse.jdt.internal.core.util.Messages;
@@ -203,7 +204,7 @@
 	this.previousSubtask = msg;
 }
 
-protected void updateProblemCounts(IProblem[] newProblems) {
+protected void updateProblemCounts(CategorizedProblem[] newProblems) {
 	for (int i = 0, l = newProblems.length; i < l; i++)
 		if (newProblems[i].isError()) newErrorCount++; else newWarningCount++;
 }
@@ -212,10 +213,10 @@
  * Update the problem counts from one compilation result given the old and new problems,
  * either of which may be null.
  */
-protected void updateProblemCounts(IMarker[] oldProblems, IProblem[] newProblems) {
+protected void updateProblemCounts(IMarker[] oldProblems, CategorizedProblem[] newProblems) {
 	if (newProblems != null) {
 		next : for (int i = 0, l = newProblems.length; i < l; i++) {
-			IProblem newProblem = newProblems[i];
+			CategorizedProblem newProblem = newProblems[i];
 			if (newProblem.getID() == IProblem.Task) continue; // skip task
 			boolean isError = newProblem.isError();
 			String message = newProblem.getMessage();
@@ -245,7 +246,7 @@
 
 			if (newProblems != null) {
 				for (int j = 0, m = newProblems.length; j < m; j++) {
-					IProblem pb = newProblems[j];
+					CategorizedProblem pb = newProblems[j];
 					if (pb.getID() == IProblem.Task) continue; // skip task
 					if (wasError == pb.isError() && message.equals(pb.getMessage()))
 						continue next;
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 24d54a9..724fd0b 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,20 +10,23 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.builder;
 
+import java.io.IOException;
+
 import org.eclipse.core.resources.*;
 import org.eclipse.core.runtime.*;
 
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
 import org.eclipse.jdt.internal.compiler.env.AccessRuleSet;
 import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
 import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
+import org.eclipse.jdt.internal.core.util.Util;
 
 public class ClasspathDirectory extends ClasspathLocation {
 
 IContainer binaryFolder; // includes .class files for a single directory
 boolean isOutputFolder;
-String binaryLocation;
 SimpleLookupTable directoryCache;
 String[] missingPackageHolder = new String[1];
 AccessRuleSet accessRuleSet;
@@ -31,8 +34,6 @@
 ClasspathDirectory(IContainer binaryFolder, boolean isOutputFolder, AccessRuleSet accessRuleSet) {
 	this.binaryFolder = binaryFolder;
 	this.isOutputFolder = isOutputFolder;
-	IPath location = binaryFolder.getLocation();
-	this.binaryLocation = location != null ? location.addTrailingSeparator().toString() : ""; //$NON-NLS-1$
 	this.directoryCache = new SimpleLookupTable(5);
 	this.accessRuleSet = accessRuleSet;
 }
@@ -48,7 +49,7 @@
 
 	try {
 		IResource container = binaryFolder.findMember(qualifiedPackageName); // this is a case-sensitive check
-		if (container instanceof IContainer && !isExcluded(container)) {
+		if (container instanceof IContainer) {
 			IResource[] members = ((IContainer) container).members();
 			dirList = new String[members.length];
 			int index = 0;
@@ -94,34 +95,21 @@
 public NameEnvironmentAnswer findClass(String binaryFileName, String qualifiedPackageName, String qualifiedBinaryFileName) {
 	if (!doesFileExist(binaryFileName, qualifiedPackageName, qualifiedBinaryFileName)) return null; // most common case
 
+	ClassFileReader reader = null;
 	try {
-		ClassFileReader reader = ClassFileReader.read(binaryLocation + qualifiedBinaryFileName);
-		if (reader != null) {
-			if (this.accessRuleSet == null)
-				return new NameEnvironmentAnswer(reader, null);
-			String fileNameWithoutExtension = qualifiedBinaryFileName.substring(0, qualifiedBinaryFileName.length() - SuffixConstants.SUFFIX_CLASS.length);
-			return new NameEnvironmentAnswer(reader, this.accessRuleSet.getViolatedRestriction(fileNameWithoutExtension.toCharArray()));
-		}
-	} catch (Exception e) {
-		// handle the case when the project is the output folder and the top-level package is a linked folder
-		if (binaryFolder instanceof IProject) {
-			IResource file = binaryFolder.findMember(qualifiedBinaryFileName);
-			if (file instanceof IFile) {
-				IPath location = file.getLocation();
-				if (location != null) {
-					try {
-						ClassFileReader reader = ClassFileReader.read(location.toString());
-						if (reader != null) {
-							if (this.accessRuleSet == null)
-								return new NameEnvironmentAnswer(reader, null);
-							String fileNameWithoutExtension = qualifiedBinaryFileName.substring(0, qualifiedBinaryFileName.length() - SuffixConstants.SUFFIX_CLASS.length);
-							return new NameEnvironmentAnswer(reader, this.accessRuleSet.getViolatedRestriction(fileNameWithoutExtension.toCharArray()));
-						}
-					} catch (Exception ignored) { // treat as if class file is missing
-					}
-				}
-			}
-		}
+		reader = Util.newClassFileReader(this.binaryFolder.getFile(new Path(qualifiedBinaryFileName)));
+	} catch (CoreException e) {
+		return null;
+	} catch (ClassFormatException e) {
+		return null;
+	} catch (IOException e) {
+		return null;
+	}
+	if (reader != null) {
+		if (this.accessRuleSet == null)
+			return new NameEnvironmentAnswer(reader, null);
+		String fileNameWithoutExtension = qualifiedBinaryFileName.substring(0, qualifiedBinaryFileName.length() - SuffixConstants.SUFFIX_CLASS.length);
+		return new NameEnvironmentAnswer(reader, this.accessRuleSet.getViolatedRestriction(fileNameWithoutExtension.toCharArray()));
 	}
 	return null;
 }
@@ -154,7 +142,7 @@
 }
 
 public String debugPathString() {
-	return this.binaryLocation;
+	return this.binaryFolder.getFullPath().toString();
 }
 
 
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 45bcc8c..000a090 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -18,8 +18,9 @@
 import org.eclipse.jdt.internal.compiler.env.AccessRuleSet;
 import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
 import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
+import org.eclipse.jdt.internal.compiler.util.SimpleSet;
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
-import org.eclipse.jdt.internal.core.util.SimpleSet;
+import org.eclipse.jdt.internal.core.util.Util;
 
 import java.io.*;
 import java.util.*;
@@ -64,9 +65,8 @@
 		while (last > 0) {
 			// extract the package name
 			String packageName = fileName.substring(0, last);
-			if (packageSet.includes(packageName))
-				continue nextEntry;
-			packageSet.add(packageName);
+			if (packageSet.addIfNotIncluded(packageName) == null)
+				continue nextEntry; // already existed
 			last = packageName.lastIndexOf('/');
 		}
 	}
@@ -86,8 +86,17 @@
 
 ClasspathJar(IFile resource, AccessRuleSet accessRuleSet) {
 	this.resource = resource;
-	IPath location = resource.getLocation();
-	this.zipFilename = location != null ? location.toString() : ""; //$NON-NLS-1$
+	try {
+		java.net.URI location = resource.getLocationURI();
+		if (location == null) {
+			this.zipFilename = ""; //$NON-NLS-1$
+		} else {
+			File localFile = Util.toLocalFile(location, null);
+			this.zipFilename = localFile.getPath();
+		}
+	} catch (CoreException e) {
+		// ignore
+	}	
 	this.zipFile = null;
 	this.knownPackageNames = null;
 	this.accessRuleSet = accessRuleSet;
@@ -185,9 +194,10 @@
 }
 
 public String debugPathString() {
-	if (this.lastModified == 0)
+	long time = lastModified();
+	if (time == 0)
 		return this.zipFilename;
-	return this.zipFilename + '(' + (new Date(this.lastModified)) + " : " + this.lastModified + ')'; //$NON-NLS-1$
+	return this.zipFilename + '(' + (new Date(time)) + " : " + time + ')'; //$NON-NLS-1$
 }
 
 }
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 d7cb036..89d1d67 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/CompilationParticipantResult.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/CompilationParticipantResult.java
new file mode 100755
index 0000000..1a71574
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/CompilationParticipantResult.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    IBM - rewrote spec
+ *    
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.core.builder;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.jdt.core.compiler.*;
+
+public class CompilationParticipantResult {
+	protected SourceFile sourceFile;
+	protected boolean hasAnnotations; // only set during processAnnotations
+	protected IFile[] addedFiles; // added/changed generated source files that need to be compiled
+	protected IFile[] deletedFiles; // previously generated source files that should be deleted
+	protected CategorizedProblem[] problems; // new problems to report against this compilationUnit
+	protected String[] dependencies; // fully-qualified type names of any new dependencies, each name is of the form 'p1.p2.A.B'
+
+protected CompilationParticipantResult(SourceFile sourceFile) {
+	this.sourceFile = sourceFile;
+	this.hasAnnotations = false;
+	this.addedFiles = null;
+	this.deletedFiles = null;
+	this.problems = null;
+	this.dependencies = null;
+}
+
+void reset(boolean detectedAnnotations) {
+	// called prior to processAnnotations
+	this.hasAnnotations = detectedAnnotations;
+	this.addedFiles = null;
+	this.deletedFiles = null;
+	this.problems = null;
+	this.dependencies = null;
+}
+
+public String toString() {
+	return this.sourceFile.toString();
+}
+
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ICompilationUnitLocator.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ICompilationUnitLocator.java
new file mode 100755
index 0000000..c3cdb56
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ICompilationUnitLocator.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2007 BEA Systems, Inc. 
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    wharley@bea.com - initial API and implementation
+ *    
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.core.builder;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
+
+/**
+ * Used to convert an IFile into an ICompilationUnit,
+ * for clients outside of this package.
+ * @since 3.3
+ */
+public interface ICompilationUnitLocator {
+	public ICompilationUnit fromIFile(IFile file);
+}
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 959f439..555539c 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 653bb23..1981876 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -13,8 +13,8 @@
 import org.eclipse.core.resources.*;
 import org.eclipse.core.runtime.*;
 
+import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.compiler.*;
-import org.eclipse.jdt.core.compiler.IProblem;
 import org.eclipse.jdt.internal.compiler.*;
 import org.eclipse.jdt.internal.compiler.classfmt.*;
 import org.eclipse.jdt.internal.compiler.problem.*;
@@ -24,6 +24,7 @@
 import org.eclipse.jdt.internal.core.util.Util;
 
 import java.io.*;
+import java.net.URI;
 import java.util.*;
 
 /**
@@ -38,20 +39,25 @@
 protected SimpleLookupTable secondaryTypesToRemove;
 protected boolean hasStructuralChanges;
 protected int compileLoop;
+protected boolean makeOutputFolderConsistent;
 
 public static int MaxCompileLoop = 5; // perform a full build if it takes more than ? incremental compile loops
 
-protected IncrementalImageBuilder(JavaBuilder javaBuilder) {
-	super(javaBuilder);
+protected IncrementalImageBuilder(JavaBuilder javaBuilder, State buildState) {
+	super(javaBuilder, true, buildState);
 	this.nameEnvironment.isIncrementalBuild = true;
-	this.newState.copyFrom(javaBuilder.lastState);
+	this.makeOutputFolderConsistent = JavaCore.ENABLED.equals(
+		javaBuilder.javaProject.getOption(JavaCore.CORE_JAVA_BUILD_RECREATE_MODIFIED_CLASS_FILES_IN_OUTPUT_FOLDER, true));
+}
 
-	this.sourceFiles = new ArrayList(33);
-	this.previousSourceFiles = null;
-	this.qualifiedStrings = new StringSet(3);
-	this.simpleStrings = new StringSet(3);
-	this.hasStructuralChanges = false;
-	this.compileLoop = 0;
+protected IncrementalImageBuilder(JavaBuilder javaBuilder) {
+	this(javaBuilder, null);
+	this.newState.copyFrom(javaBuilder.lastState);
+}
+
+protected IncrementalImageBuilder(BatchImageBuilder batchBuilder) {
+	this(batchBuilder.javaBuilder, batchBuilder.newState);
+	resetCollections();
 }
 
 public boolean build(SimpleLookupTable deltas) {
@@ -71,28 +77,38 @@
 	try {
 		resetCollections();
 
-		notifier.subTask(Messages.build_analyzingDeltas); 
-		IResourceDelta sourceDelta = (IResourceDelta) deltas.get(javaBuilder.currentProject);
-		if (sourceDelta != null)
-			if (!findSourceFiles(sourceDelta)) return false;
-		notifier.updateProgressDelta(0.10f);
+		notifier.subTask(Messages.build_analyzingDeltas);
+		if (javaBuilder.hasBuildpathErrors()) {
+			// if a mssing class file was detected in the last build, a build state was saved since its no longer fatal
+			// but we need to rebuild every source file since problems were not recorded
+			// AND to avoid the infinite build scenario if this project is involved in a cycle, see bug 160550
+			// we need to avoid unnecessary deltas caused by doing a full build in this case
+			javaBuilder.currentProject.deleteMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_ZERO);
+			addAllSourceFiles(sourceFiles);
+			notifier.updateProgressDelta(0.25f);
+		} else {
+			IResourceDelta sourceDelta = (IResourceDelta) deltas.get(javaBuilder.currentProject);
+			if (sourceDelta != null)
+				if (!findSourceFiles(sourceDelta)) return false;
+			notifier.updateProgressDelta(0.10f);
 
-		Object[] keyTable = deltas.keyTable;
-		Object[] valueTable = deltas.valueTable;
-		for (int i = 0, l = valueTable.length; i < l; i++) {
-			IResourceDelta delta = (IResourceDelta) valueTable[i];
-			if (delta != null) {
-				IProject p = (IProject) keyTable[i];
-				ClasspathLocation[] classFoldersAndJars = (ClasspathLocation[]) javaBuilder.binaryLocationsPerProject.get(p);
-				if (classFoldersAndJars != null)
-					if (!findAffectedSourceFiles(delta, classFoldersAndJars, p)) return false;
+			Object[] keyTable = deltas.keyTable;
+			Object[] valueTable = deltas.valueTable;
+			for (int i = 0, l = valueTable.length; i < l; i++) {
+				IResourceDelta delta = (IResourceDelta) valueTable[i];
+				if (delta != null) {
+					IProject p = (IProject) keyTable[i];
+					ClasspathLocation[] classFoldersAndJars = (ClasspathLocation[]) javaBuilder.binaryLocationsPerProject.get(p);
+					if (classFoldersAndJars != null)
+						if (!findAffectedSourceFiles(delta, classFoldersAndJars, p)) return false;
+				}
 			}
-		}
-		notifier.updateProgressDelta(0.10f);
+			notifier.updateProgressDelta(0.10f);
 
-		notifier.subTask(Messages.build_analyzingSources); 
-		addAffectedSourceFiles();
-		notifier.updateProgressDelta(0.05f);
+			notifier.subTask(Messages.build_analyzingSources); 
+			addAffectedSourceFiles();
+			notifier.updateProgressDelta(0.05f);
+		}
 
 		this.compileLoop = 0;
 		float increment = 0.40f;
@@ -131,45 +147,66 @@
 	return true;
 }
 
+protected void buildAfterBatchBuild() {
+	// called from a batch builder once all source files have been compiled AND some changes
+	// need to be propagated incrementally (annotations, missing secondary types)
+
+	if (JavaBuilder.DEBUG)
+		System.out.println("INCREMENTAL build after batch build @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$
+
+	// this is a copy of the incremental build loop
+	try {
+		addAffectedSourceFiles();
+		while (this.sourceFiles.size() > 0) {
+			notifier.checkCancel();
+			SourceFile[] allSourceFiles = new SourceFile[this.sourceFiles.size()];
+			this.sourceFiles.toArray(allSourceFiles);
+			resetCollections();
+			notifier.setProgressPerCompilationUnit(0.08f / allSourceFiles.length);
+			this.workQueue.addAll(allSourceFiles);
+			compile(allSourceFiles);
+			removeSecondaryTypes();
+			addAffectedSourceFiles();
+		}
+	} catch (CoreException e) {
+		throw internalException(e);
+	} finally {
+		cleanUp();
+	}
+}
+
 protected void addAffectedSourceFiles() {
 	if (qualifiedStrings.elementSize == 0 && simpleStrings.elementSize == 0) return;
 
+	addAffectedSourceFiles(qualifiedStrings, simpleStrings, null);
+}
+
+protected void addAffectedSourceFiles(StringSet qualifiedSet, StringSet simpleSet, StringSet affectedTypes) {
 	// the qualifiedStrings are of the form 'p1/p2' & the simpleStrings are just 'X'
-	char[][][] qualifiedNames = ReferenceCollection.internQualifiedNames(qualifiedStrings);
+	char[][][] internedQualifiedNames = ReferenceCollection.internQualifiedNames(qualifiedSet);
 	// if a well known qualified name was found then we can skip over these
-	if (qualifiedNames.length < qualifiedStrings.elementSize)
-		qualifiedNames = null;
-	char[][] simpleNames = ReferenceCollection.internSimpleNames(simpleStrings);
+	if (internedQualifiedNames.length < qualifiedSet.elementSize)
+		internedQualifiedNames = null;
+	char[][] internedSimpleNames = ReferenceCollection.internSimpleNames(simpleSet);
 	// if a well known name was found then we can skip over these
-	if (simpleNames.length < simpleStrings.elementSize)
-		simpleNames = null;
+	if (internedSimpleNames.length < simpleSet.elementSize)
+		internedSimpleNames = null;
 
 	Object[] keyTable = newState.references.keyTable;
 	Object[] valueTable = newState.references.valueTable;
 	next : for (int i = 0, l = valueTable.length; i < l; i++) {
-		ReferenceCollection refs = (ReferenceCollection) valueTable[i];
-		if (refs != null && refs.includes(qualifiedNames, simpleNames)) {
-			String typeLocator = (String) keyTable[i];
-			IFile file = javaBuilder.currentProject.getFile(typeLocator);
-			if (file.exists()) {
-				ClasspathMultiDirectory md = sourceLocations[0];
-				if (sourceLocations.length > 1) {
-					IPath sourceFileFullPath = file.getFullPath();
-					for (int j = 0, m = sourceLocations.length; j < m; j++) {
-						if (sourceLocations[j].sourceFolder.getFullPath().isPrefixOf(sourceFileFullPath)) {
-							md = sourceLocations[j];
-							if (md.exclusionPatterns == null && md.inclusionPatterns == null)
-								break;
-							if (!Util.isExcluded(file, md.inclusionPatterns, md.exclusionPatterns))
-								break;
-						}
-					}
-				}
-				SourceFile sourceFile = new SourceFile(file, md);
+		String typeLocator = (String) keyTable[i];
+		if (typeLocator != null) {
+			if (affectedTypes != null && !affectedTypes.includes(typeLocator)) continue next;
+			ReferenceCollection refs = (ReferenceCollection) valueTable[i];
+			if (refs.includes(internedQualifiedNames, internedSimpleNames)) {
+				IFile file = javaBuilder.currentProject.getFile(typeLocator);
+				SourceFile sourceFile = findSourceFile(file, true);
+				if (sourceFile == null) continue next;
 				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
-
+	
 				if (JavaBuilder.DEBUG)
 					System.out.println("  adding affected source file " + typeLocator); //$NON-NLS-1$
 				sourceFiles.add(sourceFile);
@@ -196,6 +233,36 @@
 			+ typeName + " in " + packageName); //$NON-NLS-1$
 }
 
+protected boolean checkForClassFileChanges(IResourceDelta binaryDelta, ClasspathMultiDirectory md, int segmentCount) throws CoreException {
+	IResource resource = binaryDelta.getResource();
+	// 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 true; // no need to go further with this delta since its children cannot be included
+
+			IResourceDelta[] children = binaryDelta.getAffectedChildren();
+			for (int i = 0, l = children.length; i < l; i++)
+				if (!checkForClassFileChanges(children[i], md, segmentCount))
+					return false;
+			return true;
+		case IResource.FILE :
+			if (!isExcluded && org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(resource.getName())) {
+				// perform full build if a managed class file has been changed
+				IPath typePath = resource.getFullPath().removeFirstSegments(segmentCount).removeFileExtension();
+				if (newState.isKnownType(typePath.toString())) {
+					if (JavaBuilder.DEBUG)
+						System.out.println("MUST DO FULL BUILD. Found change to class file " + typePath); //$NON-NLS-1$
+					return false;
+				}
+				return true;
+			}
+	}
+	return true;
+}
+
 protected void cleanUp() {
 	super.cleanUp();
 
@@ -208,6 +275,64 @@
 	this.compileLoop = 0;
 }
 
+protected void compile(SourceFile[] units, SourceFile[] additionalUnits, boolean compilingFirstGroup) {
+	if (compilingFirstGroup && additionalUnits != null) {
+		// add any source file from additionalUnits to units if it defines secondary types
+		// otherwise its possible during testing with MAX_AT_ONCE == 1 that a secondary type
+		// can cause an infinite loop as it alternates between not found and defined, see bug 146324
+		ArrayList extras = null;
+		for (int i = 0, l = additionalUnits.length; i < l; i++) {
+			SourceFile unit = additionalUnits[i];
+			if (unit != null && newState.getDefinedTypeNamesFor(unit.typeLocator()) != null) {
+				if (JavaBuilder.DEBUG)
+					System.out.println("About to compile file with secondary types "+ unit.typeLocator()); //$NON-NLS-1$
+				if (extras == null)
+					extras = new ArrayList(3);
+				extras.add(unit);
+			}
+		}
+		if (extras != null) {
+			int oldLength = units.length;
+			int toAdd = extras.size();
+			System.arraycopy(units, 0, units = new SourceFile[oldLength + toAdd], 0, oldLength);
+			for (int i = 0; i < toAdd; i++)
+				units[oldLength++] = (SourceFile) extras.get(i);
+		}
+	}
+	super.compile(units, additionalUnits, compilingFirstGroup);
+}
+
+protected void deleteGeneratedFiles(IFile[] deletedGeneratedFiles) {
+	// delete generated files and recompile any affected source files
+	try {
+		for (int j = deletedGeneratedFiles.length; --j >= 0;) {
+			IFile deletedFile = deletedGeneratedFiles[j];
+			if (deletedFile.exists()) continue; // only delete .class files for source files that were actually deleted
+
+			SourceFile sourceFile = findSourceFile(deletedFile, false);
+			String typeLocator = sourceFile.typeLocator();
+			int mdSegmentCount = sourceFile.sourceLocation.sourceFolder.getFullPath().segmentCount();
+			IPath typePath = sourceFile.resource.getFullPath().removeFirstSegments(mdSegmentCount).removeFileExtension();
+			addDependentsOf(typePath, true); // add dependents of the source file since its now deleted
+			previousSourceFiles = null; // existing source files did not see it as deleted since they were compiled before it was
+			char[][] definedTypeNames = newState.getDefinedTypeNamesFor(typeLocator);
+			if (definedTypeNames == null) { // defined a single type matching typePath
+				removeClassFile(typePath, sourceFile.sourceLocation.binaryFolder);
+			} else {
+				if (definedTypeNames.length > 0) { // skip it if it failed to successfully define a type
+					IPath packagePath = typePath.removeLastSegments(1);
+					for (int d = 0, l = definedTypeNames.length; d < l; d++)
+						removeClassFile(packagePath.append(new String(definedTypeNames[d])), sourceFile.sourceLocation.binaryFolder);
+				}
+			}
+			this.newState.removeLocator(typeLocator);
+		}
+	} catch (CoreException e) {
+		// must continue with compile loop so just log the CoreException
+		e.printStackTrace();
+	}
+}
+
 protected boolean findAffectedSourceFiles(IResourceDelta delta, ClasspathLocation[] classFoldersAndJars, IProject prereqProject) {
 	for (int i = 0, l = classFoldersAndJars.length; i < l; i++) {
 		ClasspathLocation bLocation = classFoldersAndJars[i];
@@ -306,15 +431,29 @@
 }
 
 protected boolean findSourceFiles(IResourceDelta delta) throws CoreException {
+	ArrayList visited = this.makeOutputFolderConsistent ? new ArrayList(sourceLocations.length) : null;
 	for (int i = 0, l = sourceLocations.length; i < l; i++) {
 		ClasspathMultiDirectory md = sourceLocations[i];
+		if (this.makeOutputFolderConsistent && md.hasIndependentOutputFolder && !visited.contains(md.binaryFolder)) {
+			// even a project which acts as its own source folder can have an independent/nested output folder
+			visited.add(md.binaryFolder);
+			IResourceDelta binaryDelta = delta.findMember(md.binaryFolder.getProjectRelativePath());
+			if (binaryDelta != null) {
+				int segmentCount = binaryDelta.getFullPath().segmentCount();
+				IResourceDelta[] children = binaryDelta.getAffectedChildren();
+				for (int j = 0, m = children.length; j < m; j++)
+					if (!checkForClassFileChanges(children[j], md, segmentCount))
+						return false;
+			}
+		}
 		if (md.sourceFolder.equals(javaBuilder.currentProject)) {
 			// skip nested source & output folders when the project is a source folder
 			int segmentCount = delta.getFullPath().segmentCount();
 			IResourceDelta[] children = delta.getAffectedChildren();
 			for (int j = 0, m = children.length; j < m; j++)
 				if (!isExcludedFromProject(children[j].getFullPath()))
-					findSourceFiles(children[j], md, segmentCount);
+					if (!findSourceFiles(children[j], md, segmentCount))
+						return false;
 		} else {
 			IResourceDelta sourceDelta = delta.findMember(md.sourceFolder.getProjectRelativePath());
 			if (sourceDelta != null) {
@@ -327,7 +466,8 @@
 				IResourceDelta[] children = sourceDelta.getAffectedChildren();
 				try {
 					for (int j = 0, m = children.length; j < m; j++)
-						findSourceFiles(children[j], md, segmentCount);
+						if (!findSourceFiles(children[j], md, segmentCount))
+							return false;
 				} catch (CoreException e) {
 					// catch the case that a package has been renamed and collides on disk with an as-yet-to-be-deleted package
 					if (e.getStatus().getCode() == IResourceStatus.CASE_VARIANT_EXISTS) {
@@ -344,7 +484,7 @@
 	return true;
 }
 
-protected void findSourceFiles(IResourceDelta sourceDelta, ClasspathMultiDirectory md, int segmentCount) throws CoreException {
+protected boolean findSourceFiles(IResourceDelta sourceDelta, ClasspathMultiDirectory md, int segmentCount) throws CoreException {
 	// 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();
@@ -354,31 +494,38 @@
 	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
+		        return true; // no need to go further with this delta since its children cannot be included
 
 			switch (sourceDelta.getKind()) {
 				case IResourceDelta.ADDED :
 				    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);
-				    }
+						// see if any known source file is from the same package... classpath already includes new package
+						if (sourceLocations.length > 1 && newState.isKnownPackage(addedPackagePath.toString())) {
+							if (JavaBuilder.DEBUG)
+								System.out.println("Skipped dependents of added package " + addedPackagePath); //$NON-NLS-1$
+						} else {
+							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();
 					for (int i = 0, l = children.length; i < l; i++)
-						findSourceFiles(children[i], md, segmentCount);
-					return;
+						if (!findSourceFiles(children[i], md, segmentCount))
+							return false;
+					return true;
 				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;
+							if (!findSourceFiles(children[i], md, segmentCount))
+								return false;
+						return true;
 				    }
 					IPath removedPackagePath = resource.getFullPath().removeFirstSegments(segmentCount);
 					if (sourceLocations.length > 1) {
@@ -388,8 +535,9 @@
 								createFolder(removedPackagePath, md.binaryFolder); // ensure package exists in the output folder
 								IResourceDelta[] removedChildren = sourceDelta.getAffectedChildren();
 								for (int j = 0, m = removedChildren.length; j < m; j++)
-									findSourceFiles(removedChildren[j], md, segmentCount);
-								return;
+									if (!findSourceFiles(removedChildren[j], md, segmentCount))
+										return false;
+								return true;
 							}
 						}
 					}
@@ -402,9 +550,9 @@
 					addDependentsOf(removedPackagePath, true);
 					newState.removePackage(sourceDelta);
 			}
-			return;
+			return true;
 		case IResource.FILE :
-			if (isExcluded) return;
+			if (isExcluded) return true;
 
 			String resourceName = resource.getName();
 			if (org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(resourceName)) {
@@ -421,7 +569,7 @@
 								System.out.println("Found added source file " + typeName); //$NON-NLS-1$
 							addDependentsOf(typePath, true);
 						}
-						return;
+						return true;
 					case IResourceDelta.REMOVED :
 						char[][] definedTypeNames = newState.getDefinedTypeNamesFor(typeLocator);
 						if (definedTypeNames == null) { // defined a single type matching typePath
@@ -445,20 +593,29 @@
 							}
 						}
 						newState.removeLocator(typeLocator);
-						return;
+						return true;
 					case IResourceDelta.CHANGED :
 						if ((sourceDelta.getFlags() & IResourceDelta.CONTENT) == 0
 								&& (sourceDelta.getFlags() & IResourceDelta.ENCODING) == 0)
-							return; // skip it since it really isn't changed
+							return true; // 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, true));
 				}
-				return;
+				return true;
 			} else if (org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(resourceName)) {
-				return; // skip class files
+				// perform full build if a managed class file has been changed
+				if (this.makeOutputFolderConsistent) {
+					IPath typePath = resource.getFullPath().removeFirstSegments(segmentCount).removeFileExtension();
+					if (newState.isKnownType(typePath.toString())) {
+						if (JavaBuilder.DEBUG)
+							System.out.println("MUST DO FULL BUILD. Found change to class file " + typePath); //$NON-NLS-1$
+						return false;
+					}
+				}
+				return true;
 			} else if (md.hasIndependentOutputFolder) {
-				if (javaBuilder.filterExtraResource(resource)) return;
+				if (javaBuilder.filterExtraResource(resource)) return true;
 
 				// copy all other resource deltas to the output folder
 				IPath resourcePath = resource.getFullPath().removeFirstSegments(segmentCount);
@@ -473,21 +630,20 @@
 						if (JavaBuilder.DEBUG)
 							System.out.println("Copying added file " + resourcePath); //$NON-NLS-1$
 						createFolder(resourcePath.removeLastSegments(1), md.binaryFolder); // ensure package exists in the output folder
-						resource.copy(outputFile.getFullPath(), IResource.FORCE, null);
-						outputFile.setDerived(true);
+						resource.copy(outputFile.getFullPath(), IResource.FORCE | IResource.DERIVED, null);
 						Util.setReadOnly(outputFile, false); // just in case the original was read only
-						return;
+						return true;
 					case IResourceDelta.REMOVED :
 						if (outputFile.exists()) {
 							if (JavaBuilder.DEBUG)
 								System.out.println("Deleting removed file " + resourcePath); //$NON-NLS-1$
 							outputFile.delete(IResource.FORCE, null);
 						}
-						return;
+						return true;
 					case IResourceDelta.CHANGED :
 						if ((sourceDelta.getFlags() & IResourceDelta.CONTENT) == 0
 								&& (sourceDelta.getFlags() & IResourceDelta.ENCODING) == 0)
-							return; // skip it since it really isn't changed
+							return true; // skip it since it really isn't changed
 						if (outputFile.exists()) {
 							if (JavaBuilder.DEBUG)
 								System.out.println("Deleting existing file " + resourcePath); //$NON-NLS-1$
@@ -496,13 +652,13 @@
 						if (JavaBuilder.DEBUG)
 							System.out.println("Copying changed file " + resourcePath); //$NON-NLS-1$
 						createFolder(resourcePath.removeLastSegments(1), md.binaryFolder); // ensure package exists in the output folder
-						resource.copy(outputFile.getFullPath(), IResource.FORCE, null);
-						outputFile.setDerived(true);
+						resource.copy(outputFile.getFullPath(), IResource.FORCE | IResource.DERIVED, null);
 						Util.setReadOnly(outputFile, false); // just in case the original was read only
 				}
-				return;
+				return true;
 			}
 	}
+	return true;
 }
 
 protected void finishedWith(String sourceLocator, CompilationResult result, char[] mainTypeName, ArrayList definedTypeNames, ArrayList duplicateTypeNames) {
@@ -532,6 +688,28 @@
 	super.finishedWith(sourceLocator, result, mainTypeName, definedTypeNames, duplicateTypeNames);
 }
 
+protected void processAnnotationResults(CompilationParticipantResult[] results) {
+	for (int i = results.length; --i >= 0;) {
+		CompilationParticipantResult result = results[i];
+		if (result == null) continue;
+
+		IFile[] deletedGeneratedFiles = result.deletedFiles;
+		if (deletedGeneratedFiles != null)
+			deleteGeneratedFiles(deletedGeneratedFiles);
+
+		IFile[] addedGeneratedFiles = result.addedFiles;
+		if (addedGeneratedFiles != null) {
+			for (int j = addedGeneratedFiles.length; --j >= 0;) {
+				SourceFile sourceFile = findSourceFile(addedGeneratedFiles[j], true);
+				if (sourceFile != null && !sourceFiles.contains(sourceFile))
+					this.sourceFiles.add(sourceFile);
+			}
+		}
+
+		recordParticipantResult(result);
+	}
+}
+
 protected void removeClassFile(IPath typePath, IContainer outputFolder) throws CoreException {
 	if (typePath.lastSegment().indexOf('$') == -1) { // is not a nested type
 		newState.removeQualifiedTypeName(typePath.toString());
@@ -561,23 +739,32 @@
 			}
 		}
 		this.secondaryTypesToRemove = null;
-		if (previousSourceFiles != null && previousSourceFiles.size() > 1)
-			this.previousSourceFiles = null; // cannot optimize recompile case when a secondary type is deleted
+		if (previousSourceFiles != null)
+			this.previousSourceFiles = null; // cannot optimize recompile case when a secondary type is deleted, see 181269
 	}
 }
 
 protected void resetCollections() {
-	previousSourceFiles = sourceFiles.isEmpty() ? null : (ArrayList) sourceFiles.clone();
+	if (this.sourceFiles == null) {
+		this.sourceFiles = new ArrayList(33);
+		this.previousSourceFiles = null;
+		this.qualifiedStrings = new StringSet(3);
+		this.simpleStrings = new StringSet(3);
+		this.hasStructuralChanges = false;
+		this.compileLoop = 0;
+	} else {
+		this.previousSourceFiles = this.sourceFiles.isEmpty() ? null : (ArrayList) this.sourceFiles.clone();
 
-	sourceFiles.clear();
-	qualifiedStrings.clear();
-	simpleStrings.clear();
-	workQueue.clear();
+		this.sourceFiles.clear();
+		this.qualifiedStrings.clear();
+		this.simpleStrings.clear();
+		this.workQueue.clear();
+	}
 }
 
 protected void updateProblemsFor(SourceFile sourceFile, CompilationResult result) throws CoreException {
 	IMarker[] markers = JavaBuilder.getProblemsFor(sourceFile.resource);
-	IProblem[] problems = result.getProblems();
+	CategorizedProblem[] problems = result.getProblems();
 	if (problems == null && markers.length == 0) return;
 
 	notifier.updateProblemCounts(markers, problems);
@@ -587,40 +774,70 @@
 
 protected void updateTasksFor(SourceFile sourceFile, CompilationResult result) throws CoreException {
 	IMarker[] markers = JavaBuilder.getTasksFor(sourceFile.resource);
-	IProblem[] tasks = result.getTasks();
+	CategorizedProblem[] tasks = result.getTasks();
 	if (tasks == null && markers.length == 0) return;
 
 	JavaBuilder.removeTasksFor(sourceFile.resource);
 	storeTasksFor(sourceFile, tasks);
 }
 
-protected void writeClassFileBytes(byte[] bytes, IFile file, String qualifiedFileName, boolean isSecondaryType, boolean updateClassFile) throws CoreException {
+protected void writeClassFileBytes(byte[] bytes, IFile file, String qualifiedFileName, boolean isTopLevelType, SourceFile compilationUnit) throws CoreException {
 	// Before writing out the class file, compare it to the previous file
-	// If structural changes occured then add dependent source files
+	// If structural changes occurred then add dependent source files
 	if (file.exists()) {
-		if (writeClassFileCheck(file, qualifiedFileName, bytes) || updateClassFile) { // see 46093
+		if (writeClassFileCheck(file, qualifiedFileName, bytes) || compilationUnit.updateClassFile) { // see 46093
 			if (JavaBuilder.DEBUG)
 				System.out.println("Writing changed class file " + file.getName());//$NON-NLS-1$
-			file.setContents(new ByteArrayInputStream(bytes), true, false, null);
 			if (!file.isDerived())
 				file.setDerived(true);
+			file.setContents(new ByteArrayInputStream(bytes), true, false, null);
 		} else if (JavaBuilder.DEBUG) {
 			System.out.println("Skipped over unchanged class file " + file.getName());//$NON-NLS-1$
 		}
 	} else {
-		if (isSecondaryType)
-			addDependentsOf(new Path(qualifiedFileName), true); // new secondary type
+		if (isTopLevelType)
+			addDependentsOf(new Path(qualifiedFileName), true); // new type
 		if (JavaBuilder.DEBUG)
 			System.out.println("Writing new class file " + file.getName());//$NON-NLS-1$
 		try {
-			file.create(new ByteArrayInputStream(bytes), IResource.FORCE, null);
+			file.create(new ByteArrayInputStream(bytes), IResource.FORCE | IResource.DERIVED, null);
 		} catch (CoreException e) {
-			if (e.getStatus().getCode() == IResourceStatus.CASE_VARIANT_EXISTS)
-				// catch the case that a nested type has been renamed and collides on disk with an as-yet-to-be-deleted type
+			if (e.getStatus().getCode() == IResourceStatus.CASE_VARIANT_EXISTS) {
+				IStatus status = e.getStatus();
+				if (status instanceof IResourceStatus) {
+					IPath oldFilePath = ((IResourceStatus) status).getPath();
+					char[] oldTypeName = oldFilePath.removeFileExtension().lastSegment().toCharArray();
+					char[][] previousTypeNames = newState.getDefinedTypeNamesFor(compilationUnit.typeLocator());
+					boolean fromSameFile = false;
+					if (previousTypeNames == null) {
+						fromSameFile = CharOperation.equals(compilationUnit.getMainTypeName(), oldTypeName);
+					} else {
+						for (int i = 0, l = previousTypeNames.length; i < l; i++) {
+							if (CharOperation.equals(previousTypeNames[i], oldTypeName)) {
+								fromSameFile = true;
+								break;
+							}
+						}
+					}
+					if (fromSameFile) {
+						// file is defined by the same compilationUnit, but won't be deleted until later so do it now
+						IFile collision = file.getParent().getFile(new Path(oldFilePath.lastSegment()));
+						collision.delete(true, false, null);
+						boolean success = false;
+						try {
+							file.create(new ByteArrayInputStream(bytes), IResource.FORCE | IResource.DERIVED, null);
+							success = true;
+						} catch (CoreException ignored) {
+							// ignore the second exception
+						}
+						if (success) return;
+					}
+				}
+				// catch the case that a type has been renamed and collides on disk with an as-yet-to-be-deleted type
 				throw new AbortCompilation(true, new AbortIncrementalBuildException(qualifiedFileName));
+			}
 			throw e; // rethrow
 		}
-		file.setDerived(true);
 	}
 }
 
@@ -632,9 +849,10 @@
 				if (newBytes[i] != oldBytes[i]) break notEqual;
 			return false; // bytes are identical so skip them
 		}
-		IPath location = file.getLocation();
+		URI location = file.getLocationURI();
 		if (location == null) return false; // unable to determine location of this class file
-		ClassFileReader reader = new ClassFileReader(oldBytes, location.toString().toCharArray());
+		String filePath = location.getSchemeSpecificPart();
+		ClassFileReader reader = new ClassFileReader(oldBytes, filePath.toCharArray());
 		// ignore local types since they're only visible inside a single method
 		if (!(reader.isLocal() || reader.isAnonymous()) && reader.hasStructuralChanges(newBytes)) {
 			if (JavaBuilder.DEBUG)
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 da7935d..e0e6173 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -14,7 +14,7 @@
 import org.eclipse.core.runtime.*;
 
 import org.eclipse.jdt.core.*;
-import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.core.compiler.*;
 import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
 import org.eclipse.jdt.internal.core.*;
 import org.eclipse.jdt.internal.core.util.Messages;
@@ -28,12 +28,14 @@
 IProject currentProject;
 JavaProject javaProject;
 IWorkspaceRoot workspaceRoot;
+CompilationParticipant[] participants;
 NameEnvironment nameEnvironment;
 SimpleLookupTable binaryLocationsPerProject; // maps a project to its binary resources (output folders, class folders, zip/jar files)
-State lastState;
+public State lastState;
 BuildNotifier notifier;
 char[][] extraResourceFileFilters;
 String[] extraResourceFolderFilters;
+public static final String SOURCE_ID = "JDT"; //$NON-NLS-1$
 
 public static boolean DEBUG = false;
 
@@ -46,8 +48,25 @@
 
 public static IMarker[] getProblemsFor(IResource resource) {
 	try {
-		if (resource != null && resource.exists())
-			return resource.findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
+		if (resource != null && resource.exists()) {
+			IMarker[] markers = resource.findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
+			Set markerTypes = JavaModelManager.getJavaModelManager().compilationParticipants.managedMarkerTypes();
+			if (markerTypes.isEmpty()) return markers;
+			ArrayList markerList = new ArrayList(5);
+			for (int i = 0, length = markers.length; i < length; i++) {
+				markerList.add(markers[i]);
+			}
+			Iterator iterator = markerTypes.iterator();
+			while (iterator.hasNext()) {
+				markers = resource.findMarkers((String) iterator.next(), false, IResource.DEPTH_INFINITE);
+				for (int i = 0, length = markers.length; i < length; i++) {
+					markerList.add(markers[i]);
+				}
+			}
+			IMarker[] result;
+			markerList.toArray(result = new IMarker[markerList.size()]);
+			return result;
+		}
 	} catch (CoreException e) {
 		// assume there are no problems
 	}
@@ -82,8 +101,16 @@
 
 public static void removeProblemsFor(IResource resource) {
 	try {
-		if (resource != null && resource.exists())
+		if (resource != null && resource.exists()) {
 			resource.deleteMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
+
+			// delete managed markers
+			Set markerTypes = JavaModelManager.getJavaModelManager().compilationParticipants.managedMarkerTypes();
+			if (markerTypes.size() == 0) return;
+			Iterator iterator = markerTypes.iterator();
+			while (iterator.hasNext())
+				resource.deleteMarkers((String) iterator.next(), false, IResource.DEPTH_INFINITE);
+		}
 	} catch (CoreException e) {
 		// assume there were no problems
 	}
@@ -103,6 +130,13 @@
 		if (resource != null && resource.exists()) {
 			resource.deleteMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
 			resource.deleteMarkers(IJavaModelMarker.TASK_MARKER, false, IResource.DEPTH_INFINITE);
+
+			// delete managed markers
+			Set markerTypes = JavaModelManager.getJavaModelManager().compilationParticipants.managedMarkerTypes();
+			if (markerTypes.size() == 0) return;
+			Iterator iterator = markerTypes.iterator();
+			while (iterator.hasNext())
+				resource.deleteMarkers((String) iterator.next(), false, IResource.DEPTH_INFINITE);
 		}
 	} catch (CoreException e) {
 		// assume there were no problems
@@ -129,10 +163,12 @@
 	boolean ok = false;
 	try {
 		notifier.checkCancel();
-		initializeBuilder();
+		kind = initializeBuilder(kind, true);
 
 		if (isWorthBuilding()) {
 			if (kind == FULL_BUILD) {
+				if (DEBUG)
+					System.out.println("Performing full build as requested by user"); //$NON-NLS-1$
 				buildAll();
 			} else {
 				if ((this.lastState = getLastState(currentProject)) == null) {
@@ -142,18 +178,25 @@
 				} else if (hasClasspathChanged()) {
 					// if the output location changes, do not delete the binary files from old location
 					// the user may be trying something
+					if (DEBUG)
+						System.out.println("Performing full build since classpath has changed"); //$NON-NLS-1$
 					buildAll();
 				} else if (nameEnvironment.sourceLocations.length > 0) {
 					// if there is no source to compile & no classpath changes then we are done
 					SimpleLookupTable deltas = findDeltas();
-					if (deltas == null)
+					if (deltas == null) {
+						if (DEBUG)
+							System.out.println("Performing full build since deltas are missing after incremental request"); //$NON-NLS-1$
 						buildAll();
-					else if (deltas.elementSize > 0)
+					} else if (deltas.elementSize > 0) {
 						buildDeltas(deltas);
-					else if (DEBUG)
+					} else if (DEBUG) {
 						System.out.println("Nothing to build since deltas were empty"); //$NON-NLS-1$
+					}
 				} else {
 					if (hasStructuralDelta()) { // double check that a jar file didn't get replaced in a binary project
+						if (DEBUG)
+							System.out.println("Performing full build since there are structural deltas"); //$NON-NLS-1$
 						buildAll();
 					} else {
 						if (DEBUG)
@@ -167,28 +210,41 @@
 	} catch (CoreException e) {
 		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, Messages.bind(Messages.build_inconsistentProject, e.getLocalizedMessage())); 
-		marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
+		marker.setAttributes(
+			new String[] {IMarker.MESSAGE, IMarker.SEVERITY, IJavaModelMarker.CATEGORY_ID, IMarker.SOURCE_ID},
+			new Object[] {
+				Messages.bind(Messages.build_inconsistentProject, e.getLocalizedMessage()),
+				new Integer(IMarker.SEVERITY_ERROR),
+				new Integer(CategorizedProblem.CAT_BUILDPATH),
+				JavaBuilder.SOURCE_ID
+			}
+		);
 	} catch (ImageBuilderInternalException e) {
 		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, Messages.bind(Messages.build_inconsistentProject, e.getLocalizedMessage())); 
-		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
-		if (DEBUG)
-			System.out.println(Messages.bind(Messages.build_incompleteClassPath, e.missingClassFile)); 
-		IMarker marker = currentProject.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
-		marker.setAttribute(IMarker.MESSAGE, Messages.bind(Messages.build_incompleteClassPath, e.missingClassFile)); 
-		marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
+		marker.setAttributes(
+			new String[] {IMarker.MESSAGE, IMarker.SEVERITY, IJavaModelMarker.CATEGORY_ID, IMarker.SOURCE_ID},
+			new Object[] {
+				Messages.bind(Messages.build_inconsistentProject, e.getLocalizedMessage()),
+				new Integer(IMarker.SEVERITY_ERROR),
+				new Integer(CategorizedProblem.CAT_BUILDPATH),
+				JavaBuilder.SOURCE_ID
+			}
+		);
 	} catch (MissingSourceFileException e) {
 		// do not log this exception since its thrown to handle aborted compiles because of missing source files
 		if (DEBUG)
-			System.out.println(Messages.bind(Messages.build_missingSourceFile, e.missingSourceFile)); 
+			System.out.println(Messages.bind(Messages.build_missingSourceFile, e.missingSourceFile));
 		removeProblemsAndTasksFor(currentProject); // make this the only problem for this project
 		IMarker marker = currentProject.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
-		marker.setAttribute(IMarker.MESSAGE, Messages.bind(Messages.build_missingSourceFile, e.missingSourceFile)); 
-		marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
+		marker.setAttributes(
+			new String[] {IMarker.MESSAGE, IMarker.SEVERITY, IMarker.SOURCE_ID},
+			new Object[] {
+				Messages.bind(Messages.build_missingSourceFile, e.missingSourceFile),
+				new Integer(IMarker.SEVERITY_ERROR),
+				JavaBuilder.SOURCE_ID
+			}
+		);
 	} finally {
 		if (!ok)
 			// If the build failed, clear the previously built state, forcing a full build next time.
@@ -205,26 +261,29 @@
 
 private void buildAll() {
 	notifier.checkCancel();
-	notifier.subTask(Messages.build_preparingBuild); 
+	notifier.subTask(Messages.bind(Messages.build_preparingBuild, this.currentProject.getName()));
 	if (DEBUG && lastState != null)
 		System.out.println("Clearing last state : " + lastState); //$NON-NLS-1$
 	clearLastState();
-	BatchImageBuilder imageBuilder = new BatchImageBuilder(this);
+	BatchImageBuilder imageBuilder = new BatchImageBuilder(this, true);
 	imageBuilder.build();
 	recordNewState(imageBuilder.newState);
 }
 
 private void buildDeltas(SimpleLookupTable deltas) {
 	notifier.checkCancel();
-	notifier.subTask(Messages.build_preparingBuild); 
+	notifier.subTask(Messages.bind(Messages.build_preparingBuild, this.currentProject.getName()));
 	if (DEBUG && lastState != null)
 		System.out.println("Clearing last state : " + lastState); //$NON-NLS-1$
 	clearLastState(); // clear the previously built state so if the build fails, a full build will occur next time
 	IncrementalImageBuilder imageBuilder = new IncrementalImageBuilder(this);
-	if (imageBuilder.build(deltas))
+	if (imageBuilder.build(deltas)) {
 		recordNewState(imageBuilder.newState);
-	else
+	} else {
+		if (DEBUG)
+			System.out.println("Performing full build since incremental build failed"); //$NON-NLS-1$
 		buildAll();
+	}
 }
 
 protected void clean(IProgressMonitor monitor) throws CoreException {
@@ -239,17 +298,23 @@
 	try {
 		notifier.checkCancel();
 
-		initializeBuilder();
+		initializeBuilder(CLEAN_BUILD, true);
 		if (DEBUG)
 			System.out.println("Clearing last state as part of clean : " + lastState); //$NON-NLS-1$
 		clearLastState();
 		removeProblemsAndTasksFor(currentProject);
-		new BatchImageBuilder(this).cleanOutputFolders(false);
+		new BatchImageBuilder(this, false).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, Messages.bind(Messages.build_inconsistentProject, e.getLocalizedMessage())); 
-		marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
+		marker.setAttributes(
+			new String[] {IMarker.MESSAGE, IMarker.SEVERITY, IMarker.SOURCE_ID},
+			new Object[] {
+				Messages.bind(Messages.build_inconsistentProject, e.getLocalizedMessage()),
+				new Integer(IMarker.SEVERITY_ERROR),
+				JavaBuilder.SOURCE_ID
+			}
+		);
 	} finally {
 		notifier.done();
 		cleanup();
@@ -260,6 +325,7 @@
 }
 
 private void cleanup() {
+	this.participants = null;
 	this.nameEnvironment = null;
 	this.binaryLocationsPerProject = null;
 	this.lastState = null;
@@ -294,7 +360,7 @@
 }
 
 private SimpleLookupTable findDeltas() {
-	notifier.subTask(Messages.bind(Messages.build_readingDelta, currentProject.getName())); 
+	notifier.subTask(Messages.bind(Messages.build_readingDelta, currentProject.getName()));
 	IResourceDelta delta = getDelta(currentProject);
 	SimpleLookupTable deltas = new SimpleLookupTable(3);
 	if (delta != null) {
@@ -330,7 +396,7 @@
 				if (canSkip) continue nextProject; // project has no structural changes in its output folders
 			}
 
-			notifier.subTask(Messages.bind(Messages.build_readingDelta, p.getName())); 
+			notifier.subTask(Messages.bind(Messages.build_readingDelta, p.getName()));
 			delta = getDelta(p);
 			if (delta != null) {
 				if (delta.getKind() != IResourceDelta.NO_CHANGE) {
@@ -355,7 +421,7 @@
 }
 
 /* Return the list of projects for which it requires a resource delta. This builder's project
-* is implicitly included and need not be specified. Builders must re-specify the list 
+* is implicitly included and need not be specified. Builders must re-specify the list
 * of interesting projects every time they are run as this is not carried forward
 * beyond the next build. Missing projects should be specified but will be ignored until
 * they are added to the workspace.
@@ -365,7 +431,7 @@
 
 	ArrayList projects = new ArrayList();
 	try {
-		IClasspathEntry[] entries = javaProject.getExpandedClasspath(true);
+		IClasspathEntry[] entries = javaProject.getExpandedClasspath();
 		for (int i = 0, l = entries.length; i < l; i++) {
 			IClasspathEntry entry = entries[i];
 			IPath path = entry.getPath();
@@ -373,6 +439,8 @@
 			switch (entry.getEntryKind()) {
 				case IClasspathEntry.CPE_PROJECT :
 					p = workspaceRoot.getProject(path.lastSegment()); // missing projects are considered too
+					if (((ClasspathEntry) entry).isOptional() && !JavaProject.hasJavaNature(p)) // except if entry is optional
+						p = null;
 					break;
 				case IClasspathEntry.CPE_LIBRARY :
 					if (includeBinaryPrerequisites && path.segmentCount() > 1) {
@@ -393,6 +461,14 @@
 	return result;
 }
 
+boolean hasBuildpathErrors() throws CoreException {
+	IMarker[] markers = this.currentProject.findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_ZERO);
+	for (int i = 0, l = markers.length; i < l; i++)
+		if (markers[i].getAttribute(IJavaModelMarker.CATEGORY_ID, -1) == CategorizedProblem.CAT_BUILDPATH)
+			return true;
+	return false;
+}
+
 private boolean hasClasspathChanged() {
 	ClasspathMultiDirectory[] newSourceLocations = nameEnvironment.sourceLocations;
 	ClasspathMultiDirectory[] oldSourceLocations = lastState.sourceLocations;
@@ -458,6 +534,14 @@
 	return false;
 }
 
+private boolean hasJavaBuilder(IProject project) throws CoreException {
+	ICommand[] buildCommands = project.getDescription().getBuildSpec();
+	for (int i = 0, l = buildCommands.length; i < l; i++)
+		if (buildCommands[i].getBuilderName().equals(JavaCore.BUILDER_ID))
+			return true;
+	return false;
+}
+
 private boolean hasStructuralDelta() {
 	// handle case when currentProject has only .class file folders and/or jar files... no source/output folders
 	IResourceDelta delta = getDelta(currentProject);
@@ -480,55 +564,65 @@
 	return false;
 }
 
-private void initializeBuilder() throws CoreException {
+private int initializeBuilder(int kind, boolean forBuild) throws CoreException {
+	// some calls just need the nameEnvironment initialized so skip the rest
 	this.javaProject = (JavaProject) JavaCore.create(currentProject);
 	this.workspaceRoot = currentProject.getWorkspace().getRoot();
 
-	// Flush the existing external files cache if this is the beginning of a build cycle
-	String projectName = currentProject.getName();
-	if (builtProjects == null || builtProjects.contains(projectName)) {
-		JavaModel.flushExternalFileCache();
-		builtProjects = new ArrayList();
+	if (forBuild) {
+		// cache the known participants for this project
+		this.participants = JavaModelManager.getJavaModelManager().compilationParticipants.getCompilationParticipants(this.javaProject);
+		if (this.participants != null)
+			for (int i = 0, l = this.participants.length; i < l; i++)
+				if (this.participants[i].aboutToBuild(this.javaProject) == CompilationParticipant.NEEDS_FULL_BUILD)
+					kind = FULL_BUILD;
+
+		// Flush the existing external files cache if this is the beginning of a build cycle
+		String projectName = currentProject.getName();
+		if (builtProjects == null || builtProjects.contains(projectName)) {
+			JavaModel.flushExternalFileCache();
+			builtProjects = new ArrayList();
+		}
+		builtProjects.add(projectName);
 	}
-	builtProjects.add(projectName);
 
 	this.binaryLocationsPerProject = new SimpleLookupTable(3);
-	this.nameEnvironment = new NameEnvironment(workspaceRoot, javaProject, binaryLocationsPerProject);
+	this.nameEnvironment = new NameEnvironment(workspaceRoot, javaProject, binaryLocationsPerProject, notifier);
 
-	String filterSequence = javaProject.getOption(JavaCore.CORE_JAVA_BUILD_RESOURCE_COPY_FILTER, true);
-	char[][] filters = filterSequence != null && filterSequence.length() > 0
-		? CharOperation.splitAndTrimOn(',', filterSequence.toCharArray())
-		: null;
-	if (filters == null) {
-		this.extraResourceFileFilters = null;
-		this.extraResourceFolderFilters = null;
-	} else {
-		int fileCount = 0, folderCount = 0;
-		for (int i = 0, l = filters.length; i < l; i++) {
-			char[] f = filters[i];
-			if (f.length == 0) continue;
-			if (f[f.length - 1] == '/') folderCount++; else fileCount++;
-		}
-		this.extraResourceFileFilters = new char[fileCount][];
-		this.extraResourceFolderFilters = new String[folderCount];
-		for (int i = 0, l = filters.length; i < l; i++) {
-			char[] f = filters[i];
-			if (f.length == 0) continue;
-			if (f[f.length - 1] == '/')
-				extraResourceFolderFilters[--folderCount] = new String(f, 0, f.length - 1);
-			else
-				extraResourceFileFilters[--fileCount] = f;
+	if (forBuild) {
+		String filterSequence = javaProject.getOption(JavaCore.CORE_JAVA_BUILD_RESOURCE_COPY_FILTER, true);
+		char[][] filters = filterSequence != null && filterSequence.length() > 0
+			? CharOperation.splitAndTrimOn(',', filterSequence.toCharArray())
+			: null;
+		if (filters == null) {
+			this.extraResourceFileFilters = null;
+			this.extraResourceFolderFilters = null;
+		} else {
+			int fileCount = 0, folderCount = 0;
+			for (int i = 0, l = filters.length; i < l; i++) {
+				char[] f = filters[i];
+				if (f.length == 0) continue;
+				if (f[f.length - 1] == '/') folderCount++; else fileCount++;
+			}
+			this.extraResourceFileFilters = new char[fileCount][];
+			this.extraResourceFolderFilters = new String[folderCount];
+			for (int i = 0, l = filters.length; i < l; i++) {
+				char[] f = filters[i];
+				if (f.length == 0) continue;
+				if (f[f.length - 1] == '/')
+					extraResourceFolderFilters[--folderCount] = new String(f, 0, f.length - 1);
+				else
+					extraResourceFileFilters[--fileCount] = f;
+			}
 		}
 	}
+	return kind;
 }
 
 private boolean isClasspathBroken(IClasspathEntry[] classpath, IProject p) throws CoreException {
-	if (classpath == JavaProject.INVALID_CLASSPATH) // the .classpath file could not be read
-		return true;
-
 	IMarker[] markers = p.findMarkers(IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false, IResource.DEPTH_ZERO);
 	for (int i = 0, l = markers.length; i < l; i++)
-		if (((Integer) markers[i].getAttribute(IMarker.SEVERITY)).intValue() == IMarker.SEVERITY_ERROR)
+		if (markers[i].getAttribute(IMarker.SEVERITY, -1) == IMarker.SEVERITY_ERROR)
 			return true;
 	return false;
 }
@@ -546,8 +640,15 @@
 		removeProblemsAndTasksFor(currentProject); // remove all compilation problems
 
 		IMarker marker = currentProject.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
-		marker.setAttribute(IMarker.MESSAGE, Messages.build_abortDueToClasspathProblems); 
-		marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
+		marker.setAttributes(
+			new String[] {IMarker.MESSAGE, IMarker.SEVERITY, IJavaModelMarker.CATEGORY_ID, IMarker.SOURCE_ID},
+			new Object[] {
+				Messages.build_abortDueToClasspathProblems,
+				new Integer(IMarker.SEVERITY_ERROR),
+				new Integer(CategorizedProblem.CAT_BUILDPATH),
+				JavaBuilder.SOURCE_ID
+			}
+		);
 		return false;
 	}
 
@@ -557,24 +658,40 @@
 	// make sure all prereq projects have valid build states... only when aborting builds since projects in cycles do not have build states
 	// except for projects involved in a 'warning' cycle (see below)
 	IProject[] requiredProjects = getRequiredProjects(false);
-	next : for (int i = 0, l = requiredProjects.length; i < l; i++) {
+	for (int i = 0, l = requiredProjects.length; i < l; i++) {
 		IProject p = requiredProjects[i];
 		if (getLastState(p) == null)  {
 			// The prereq project has no build state: if this prereq project has a 'warning' cycle marker then allow build (see bug id 23357)
 			JavaProject prereq = (JavaProject) JavaCore.create(p);
-			if (prereq.hasCycleMarker() && JavaCore.WARNING.equals(javaProject.getOption(JavaCore.CORE_CIRCULAR_CLASSPATH, true)))
+			if (prereq.hasCycleMarker() && JavaCore.WARNING.equals(javaProject.getOption(JavaCore.CORE_CIRCULAR_CLASSPATH, true))) {
+				if (DEBUG)
+					System.out.println("Continued to build even though prereq project " + p.getName() //$NON-NLS-1$
+						+ " was not built since its part of a cycle"); //$NON-NLS-1$
 				continue;
+			}
+			if (!hasJavaBuilder(p)) {
+				if (DEBUG)
+					System.out.println("Continued to build even though prereq project " + p.getName() //$NON-NLS-1$
+						+ " is not built by JavaBuilder"); //$NON-NLS-1$
+				continue;
+			}
 			if (DEBUG)
 				System.out.println("Aborted build because prereq project " + p.getName() //$NON-NLS-1$
 					+ " was not built"); //$NON-NLS-1$
 
 			removeProblemsAndTasksFor(currentProject); // make this the only problem for this project
 			IMarker marker = currentProject.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
-			marker.setAttribute(IMarker.MESSAGE,
-				isClasspathBroken(prereq.getRawClasspath(), p)
-					? Messages.bind(Messages.build_prereqProjectHasClasspathProblems, p.getName()) 
-					: Messages.bind(Messages.build_prereqProjectMustBeRebuilt, p.getName())); 
-			marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
+			marker.setAttributes(
+				new String[] {IMarker.MESSAGE, IMarker.SEVERITY, IJavaModelMarker.CATEGORY_ID, IMarker.SOURCE_ID},
+				new Object[] {
+					isClasspathBroken(prereq.getRawClasspath(), p)
+						? Messages.bind(Messages.build_prereqProjectHasClasspathProblems, p.getName())
+						: Messages.bind(Messages.build_prereqProjectMustBeRebuilt, p.getName()),
+					new Integer(IMarker.SEVERITY_ERROR),
+					new Integer(CategorizedProblem.CAT_BUILDPATH),
+					JavaBuilder.SOURCE_ID
+				}
+			);
 			return false;
 		}
 	}
@@ -595,7 +712,7 @@
 		if (participantPath != currentPath) {
 			IProject project = workspaceRoot.getProject(participantPath.segment(0));
 			if (hasBeenBuilt(project)) {
-				if (DEBUG) 
+				if (DEBUG)
 					System.out.println("Requesting another build iteration since cycle participant " + project.getName() //$NON-NLS-1$
 						+ " has not yet seen some structural changes"); //$NON-NLS-1$
 				needRebuild();
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
deleted file mode 100644
index 481bc45..0000000
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/MissingClassFileException.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.builder;
-
-/**
- * Exception thrown when the build should be aborted because a referenced
- * class file cannot be found.
- */
-public class MissingClassFileException extends RuntimeException {
-
-	protected String missingClassFile;
-	private static final long serialVersionUID = 3060418973806972616L; // backward compatible
-
-public MissingClassFileException(String missingClassFile) {
-	this.missingClassFile = missingClassFile;
-}
-}
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 f19b704..328f235 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 3fe31fc..23b7163 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -18,9 +18,9 @@
 import org.eclipse.jdt.internal.compiler.env.*;
 import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
 import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
+import org.eclipse.jdt.internal.compiler.util.SimpleSet;
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
 import org.eclipse.jdt.internal.core.*;
-import org.eclipse.jdt.internal.core.util.Util;
 
 import java.io.*;
 import java.util.*;
@@ -30,12 +30,14 @@
 boolean isIncrementalBuild;
 ClasspathMultiDirectory[] sourceLocations;
 ClasspathLocation[] binaryLocations;
-	
-String[] initialTypeNames; // assumed that each name is of the form "a/b/ClassName"
-SourceFile[] additionalUnits;
+BuildNotifier notifier;
 
-NameEnvironment(IWorkspaceRoot root, JavaProject javaProject, SimpleLookupTable binaryLocationsPerProject) throws CoreException {
+SimpleSet initialTypeNames; // assumed that each name is of the form "a/b/ClassName"
+SimpleLookupTable additionalUnits;
+
+NameEnvironment(IWorkspaceRoot root, JavaProject javaProject, SimpleLookupTable binaryLocationsPerProject, BuildNotifier notifier) throws CoreException {
 	this.isIncrementalBuild = false;
+	this.notifier = notifier;
 	computeClasspathLocations(root, javaProject, binaryLocationsPerProject);
 	setNames(null, null);
 }
@@ -84,11 +86,11 @@
 		int severity = JavaCore.ERROR.equals(javaProject.getOption(JavaCore.CORE_CIRCULAR_CLASSPATH, true))
 			? IMarker.SEVERITY_ERROR
 			: IMarker.SEVERITY_WARNING;
-		if (severity != ((Integer) cycleMarker.getAttribute(IMarker.SEVERITY)).intValue())
+		if (severity != cycleMarker.getAttribute(IMarker.SEVERITY, severity))
 			cycleMarker.setAttribute(IMarker.SEVERITY, severity);
 	}
 
-	IClasspathEntry[] classpathEntries = javaProject.getExpandedClasspath(true/*ignore unresolved variable*/, false/*don't create markers*/, null/*preferred cp*/, null/*preferred output*/);
+	IClasspathEntry[] classpathEntries = javaProject.getExpandedClasspath();
 	ArrayList sLocations = new ArrayList(classpathEntries.length);
 	ArrayList bLocations = new ArrayList(classpathEntries.length);
 	nextEntry : for (int i = 0, l = classpathEntries.length; i < l; i++) {
@@ -109,7 +111,7 @@
 				} else {
 					outputFolder = root.getFolder(outputPath);
 					if (!outputFolder.exists())
-						createFolder(outputFolder);
+						createOutputFolder(outputFolder);
 				}
 				sLocations.add(
 					ClasspathLocation.forSourceFolder((IContainer) target, outputFolder, entry.fullInclusionPatternChars(), entry.fullExclusionPatternChars()));
@@ -136,11 +138,7 @@
 							: (IContainer) root.getFolder(prereqOutputPath);
 						if (binaryFolder.exists() && !seen.contains(binaryFolder)) {
 							seen.add(binaryFolder);
-							ClasspathLocation bLocation = 
-								ClasspathLocation.forBinaryFolder(
-										binaryFolder, 
-										true, 
-										entry.getAccessRuleSet());
+							ClasspathLocation bLocation = ClasspathLocation.forBinaryFolder(binaryFolder, true, entry.getAccessRuleSet());
 							bLocations.add(bLocation);
 							if (binaryLocationsPerProject != null) { // normal builder mode
 								ClasspathLocation[] existingLocations = (ClasspathLocation[]) binaryLocationsPerProject.get(prereqProject);
@@ -250,45 +248,36 @@
 		binaryLocations[i].cleanup();
 }
 
-private void createFolder(IContainer folder) throws CoreException {
-	if (!folder.exists()) {
-		createFolder(folder.getParent());
-		((IFolder) folder).create(true, true, null);
+private void createOutputFolder(IContainer outputFolder) throws CoreException {
+	createParentFolder(outputFolder.getParent());
+	((IFolder) outputFolder).create(IResource.FORCE | IResource.DERIVED, true, null);
+}
+
+private void createParentFolder(IContainer parent) throws CoreException {
+	if (!parent.exists()) {
+		createParentFolder(parent.getParent());
+		((IFolder) parent).create(true, true, null);
 	}
 }
 
 private NameEnvironmentAnswer findClass(String qualifiedTypeName, char[] typeName) {
-	if (initialTypeNames != null) {
-		// TODO (kent) should use a hash set to avoid linear search once massive source set is being processed
-		for (int i = 0, l = initialTypeNames.length; i < l; i++) {
-			if (qualifiedTypeName.equals(initialTypeNames[i])) {
-				if (isIncrementalBuild)
-					// catch the case that a type inside a source file has been renamed but other class files are looking for it
-					throw new AbortCompilation(true, new AbortIncrementalBuildException(qualifiedTypeName));
-				return null; // looking for a file which we know was provided at the beginning of the compilation
-			}
-		}
+	if (this.notifier != null)
+		this.notifier.checkCancelWithinCompiler();
+
+	if (this.initialTypeNames != null && this.initialTypeNames.includes(qualifiedTypeName)) {
+		if (isIncrementalBuild)
+			// catch the case that a type inside a source file has been renamed but other class files are looking for it
+			throw new AbortCompilation(true, new AbortIncrementalBuildException(qualifiedTypeName));
+		return null; // looking for a file which we know was provided at the beginning of the compilation
 	}
 
-	if (additionalUnits != null && sourceLocations.length > 0) {
+	if (this.additionalUnits != null && this.sourceLocations.length > 0) {
 		// if an additional source file is waiting to be compiled, answer it BUT not if this is a secondary type search
 		// if we answer X.java & it no longer defines Y then the binary type looking for Y will think the class path is wrong
 		// let the recompile loop fix up dependents when the secondary type Y has been deleted from X.java
-		IPath qSourceFilePath = new Path(qualifiedTypeName); // doesn't have file extension
-		int qSegmentCount = qSourceFilePath.segmentCount();
-		next : for (int i = 0, l = additionalUnits.length; i < l; i++) {
-			SourceFile additionalUnit = additionalUnits[i];
-			IPath fullPath = additionalUnit.resource.getFullPath();
-			int prefixCount = additionalUnit.sourceLocation.sourceFolder.getFullPath().segmentCount();
-			if (qSegmentCount == fullPath.segmentCount() - prefixCount) {
-				for (int j = 0; j < qSegmentCount - 1; j++)
-					if (!qSourceFilePath.segment(j).equals(fullPath.segment(j + prefixCount)))
-						continue next;
-				if (!Util.equalsIgnoreJavaLikeExtension(fullPath.segment(qSegmentCount-1 + prefixCount), qSourceFilePath.segment(qSegmentCount-1)))
-					continue next;
-				return new NameEnvironmentAnswer(additionalUnit, null /*no access restriction*/);
-			}
-		}
+		SourceFile unit = (SourceFile) this.additionalUnits.get(qualifiedTypeName); // doesn't have file extension
+		if (unit != null)
+			return new NameEnvironmentAnswer(unit, null /*no access restriction*/);
 	}
 
 	String qBinaryFileName = qualifiedTypeName + SUFFIX_STRING_class;
@@ -301,10 +290,21 @@
 	}
 
 	// NOTE: the output folders are added at the beginning of the binaryLocations
+	NameEnvironmentAnswer suggestedAnswer = null;
 	for (int i = 0, l = binaryLocations.length; i < l; i++) {
 		NameEnvironmentAnswer answer = binaryLocations[i].findClass(binaryFileName, qPackageName, qBinaryFileName);
-		if (answer != null) return answer;
+		if (answer != null) {
+			if (!answer.ignoreIfBetter()) {
+				if (answer.isBetter(suggestedAnswer))
+					return answer;
+			} else if (answer.isBetter(suggestedAnswer))
+				// remember suggestion and keep looking
+				suggestedAnswer = answer;
+		}
 	}
+	if (suggestedAnswer != null)
+		// no better answer was found
+		return suggestedAnswer;
 	return null;
 }
 
@@ -336,9 +336,27 @@
 	return false;
 }
 
-void setNames(String[] initialTypeNames, SourceFile[] additionalUnits) {
-	this.initialTypeNames = initialTypeNames;
-	this.additionalUnits = additionalUnits;
+void setNames(String[] typeNames, SourceFile[] additionalFiles) {
+	// convert the initial typeNames to a set
+	if (typeNames == null) {
+		this.initialTypeNames = null;
+	} else {
+		this.initialTypeNames = new SimpleSet(typeNames.length);
+		for (int i = 0, l = typeNames.length; i < l; i++)
+			this.initialTypeNames.add(typeNames[i]);
+	}
+	// map the additional source files by qualified type name
+	if (additionalFiles == null) {
+		this.additionalUnits = null;
+	} else {
+		this.additionalUnits = new SimpleLookupTable(additionalFiles.length);
+		for (int i = 0, l = additionalFiles.length; i < l; i++) {
+			SourceFile additionalUnit = additionalFiles[i];
+			if (additionalUnit != null)
+				this.additionalUnits.put(additionalUnit.initialTypeName, additionalFiles[i]);
+		}
+	}
+
 	for (int i = 0, l = sourceLocations.length; i < l; i++)
 		sourceLocations[i].reset();
 	for (int i = 0, l = binaryLocations.length; i < l; i++)
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 590df26..bcc19d6 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 6f81509..da2281c 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 4ba3cf3..e7354be 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 3521aec..22e01e5 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -7,6 +7,7 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ *     Tim Hanson <thanson@bea.com> - fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=137634
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.builder;
 
@@ -23,6 +24,36 @@
 	this.simpleNameReferences = internSimpleNames(simpleNameReferences, true);
 }
 
+void addDependencies(String[] typeNameDependencies) {
+	// if each qualified type name is already known then all of its subNames can be skipped
+	// and its expected that very few qualified names in typeNameDependencies need to be added
+	// but could always take 'p1.p2.p3.X' and make all qualified names 'p1' 'p1.p2' 'p1.p2.p3' 'p1.p2.p3.X', then intern
+	char[][][] qNames = new char[typeNameDependencies.length][][];
+	for (int i = typeNameDependencies.length; --i >= 0;)
+		qNames[i] = CharOperation.splitOn('.', typeNameDependencies[i].toCharArray());
+	qNames = internQualifiedNames(qNames);
+
+	next : for (int i = qNames.length; --i >= 0;) {
+		char[][] qualifiedTypeName = qNames[i];
+		while (!includes(qualifiedTypeName)) {
+			if (!includes(qualifiedTypeName[qualifiedTypeName.length - 1])) {
+				int length = this.simpleNameReferences.length;
+				System.arraycopy(this.simpleNameReferences, 0, this.simpleNameReferences = new char[length + 1][], 0, length);
+				this.simpleNameReferences[length] = qualifiedTypeName[qualifiedTypeName.length - 1];				
+			}
+			int length = this.qualifiedNameReferences.length;
+			System.arraycopy(this.qualifiedNameReferences, 0, this.qualifiedNameReferences = new char[length + 1][][], 0, length);
+			this.qualifiedNameReferences[length] = qualifiedTypeName;
+
+			qualifiedTypeName = CharOperation.subarray(qualifiedTypeName, 0, qualifiedTypeName.length - 1);
+			char[][][] temp = internQualifiedNames(new char[][][] {qualifiedTypeName});
+			if (temp == EmptyQualifiedNames)
+				continue next; // qualifiedTypeName is a well known name
+			qualifiedTypeName = temp[0];
+		}
+	}
+}
+
 boolean includes(char[] simpleName) {
 	for (int i = 0, l = simpleNameReferences.length; i < l; i++)
 		if (simpleName == simpleNameReferences[i]) return true;
@@ -157,7 +188,7 @@
 		keepers[index++] = internedNames.add(qualifiedName);
 	}
 	if (length > index) {
-		if (length == 0) return EmptyQualifiedNames;
+		if (index == 0) return EmptyQualifiedNames;
 		System.arraycopy(keepers, 0, keepers = new char[index][][], 0, index);
 	}
 	return keepers;
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 61c27f8..f55e29d 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -21,7 +21,7 @@
 
 public class SourceFile implements ICompilationUnit {
 
-IFile resource;
+public IFile resource;
 ClasspathMultiDirectory sourceLocation;
 String initialTypeName;
 boolean updateClassFile;
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 f3230c9..c5d7e48 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -18,6 +18,7 @@
 import org.eclipse.jdt.internal.compiler.env.AccessRule;
 import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
 import org.eclipse.jdt.internal.core.ClasspathAccessRule;
+import org.eclipse.jdt.internal.core.JavaModelManager;
 
 import java.io.*;
 import java.util.*;
@@ -31,7 +32,7 @@
 // keyed by the project relative path of the type (ie. "src1/p1/p2/A.java"), value is a ReferenceCollection or an AdditionalTypeCollection
 SimpleLookupTable references;
 // keyed by qualified type name "p1/p2/A", value is the project relative path which defines this type "src1/p1/p2/A.java"
-SimpleLookupTable typeLocators;
+public SimpleLookupTable typeLocators;
 
 int buildNumber;
 long lastStructuralBuildTime;
@@ -43,7 +44,7 @@
 private StringSet structurallyChangedTypes;
 public static int MaxStructurallyChangedTypes = 100; // keep track of ? structurally changed types, otherwise consider all to be changed
 
-public static final byte VERSION = 0x0013; // added timestamps to external jars
+public static final byte VERSION = 0x0015; // changed access rule presentation
 
 static final byte SOURCE_FOLDER = 1;
 static final byte BINARY_FOLDER = 2;
@@ -65,10 +66,17 @@
 	this.typeLocators = new SimpleLookupTable(7);
 
 	this.buildNumber = 0; // indicates a full build
-	this.lastStructuralBuildTime = System.currentTimeMillis();
+	this.lastStructuralBuildTime = computeStructuralBuildTime(javaBuilder.lastState == null ? 0 : javaBuilder.lastState.lastStructuralBuildTime);
 	this.structuralBuildTimes = new SimpleLookupTable(3);
 }
 
+long computeStructuralBuildTime(long previousTime) {
+	long newTime = System.currentTimeMillis();
+	if (newTime <= previousTime)
+		newTime = previousTime + 1;
+	return newTime;
+}
+
 void copyFrom(State lastState) {
 	this.knownPackageNames = null;
 	this.previousStructuralBuildTime = lastState.previousStructuralBuildTime;
@@ -96,8 +104,7 @@
 				this.typeLocators.put(keyTable[i], valueTable[i]);
 	}
 }
-
-char[][] getDefinedTypeNamesFor(String typeLocator) {
+public char[][] getDefinedTypeNamesFor(String typeLocator) {
 	Object c = references.get(typeLocator);
 	if (c instanceof AdditionalTypeCollection)
 		return ((AdditionalTypeCollection) c).definedTypeNames;
@@ -144,9 +151,13 @@
 	return false;
 }
 
+boolean isKnownType(String qualifiedTypeName) {
+	return typeLocators.containsKey(qualifiedTypeName);
+}
+
 void record(String typeLocator, char[][][] qualifiedRefs, char[][] simpleRefs, char[] mainTypeName, ArrayList typeNames) {
 	if (typeNames.size() == 1 && CharOperation.equals(mainTypeName, (char[]) typeNames.get(0))) {
-			references.put(typeLocator, new ReferenceCollection(qualifiedRefs, simpleRefs));
+		references.put(typeLocator, new ReferenceCollection(qualifiedRefs, simpleRefs));
 	} else {
 		char[][] definedTypeNames = new char[typeNames.size()][]; // can be empty when no types are defined
 		typeNames.toArray(definedTypeNames);
@@ -316,7 +327,7 @@
 private static char[][] readNames(DataInputStream in) throws IOException {
 	int length = in.readInt();
 	char[][] names = new char[length][];
-	for (int i = 0; i < length; i++) 
+	for (int i = 0; i < length; i++)
 		names[i] = readName(in);
 	return names;
 }
@@ -330,9 +341,12 @@
 		int problemId = in.readInt();
 		accessRules[i] = new ClasspathAccessRule(pattern, problemId);
 	}
-	String messageTemplate = in.readUTF();
-	AccessRuleSet accessRuleSet = new AccessRuleSet(accessRules);
-	accessRuleSet.messageTemplate = messageTemplate;
+	JavaModelManager manager = JavaModelManager.getJavaModelManager();
+	String[] messageTemplates = new String[AccessRuleSet.MESSAGE_TEMPLATES_LENGTH];
+	for (int i = 0; i < AccessRuleSet.MESSAGE_TEMPLATES_LENGTH; i++) {
+		messageTemplates[i] = manager.intern(in.readUTF());
+	}
+	AccessRuleSet accessRuleSet = new AccessRuleSet(accessRules, messageTemplates);
 	return accessRuleSet;
 }
 
@@ -347,7 +361,7 @@
 void tagAsStructurallyChanged() {
 	this.previousStructuralBuildTime = this.lastStructuralBuildTime;
 	this.structurallyChangedTypes = new StringSet(7);
-	this.lastStructuralBuildTime = System.currentTimeMillis();
+	this.lastStructuralBuildTime = computeStructuralBuildTime(this.previousStructuralBuildTime);
 }
 
 boolean wasStructurallyChanged(IProject prereqProject, State prereqState) {
@@ -374,10 +388,10 @@
 	Object[] valueTable;
 
 /*
- * byte			VERSION
+ * byte		VERSION
  * String		project name
- * int				build number
- * int				last structural build number
+ * int			build number
+ * int			last structural build number
 */
 	out.writeByte(VERSION);
 	out.writeUTF(javaProjectName);
@@ -386,7 +400,7 @@
 
 /*
  * ClasspathMultiDirectory[]
- * int				id
+ * int			id
  * String		path(s)
 */
 	out.writeInt(length = sourceLocations.length);
@@ -401,7 +415,7 @@
 
 /*
  * ClasspathLocation[]
- * int				id
+ * int			id
  * String		path(s)
 */
 	out.writeInt(length = binaryLocations.length);
@@ -438,7 +452,7 @@
 /*
  * Structural build numbers table
  * String		prereq project name
- * int				last structural build number
+ * int			last structural build number
 */
 	out.writeInt(length = structuralBuildTimes.elementSize);
 	if (length > 0) {
@@ -456,10 +470,10 @@
 	}
 
 /*
- * String[]		Interned type locators
+ * String[]	Interned type locators
  */
 	out.writeInt(length = references.elementSize);
-	ArrayList internedTypeLocators = new ArrayList(length);
+	SimpleLookupTable internedTypeLocators = new SimpleLookupTable(length);
 	if (length > 0) {
 		keyTable = references.keyTable;
 		for (int i = 0, l = keyTable.length; i < l; i++) {
@@ -467,7 +481,7 @@
 				length--;
 				String key = (String) keyTable[i];
 				out.writeUTF(key);
-				internedTypeLocators.add(key);
+				internedTypeLocators.put(key, new Integer(internedTypeLocators.elementSize));
 			}
 		}
 		if (JavaBuilder.DEBUG && length != 0)
@@ -477,7 +491,7 @@
 /*
  * Type locators table
  * String		type name
- * int				interned locator id
+ * int			interned locator id
  */
 	out.writeInt(length = typeLocators.elementSize);
 	if (length > 0) {
@@ -487,7 +501,8 @@
 			if (keyTable[i] != null) {
 				length--;
 				out.writeUTF((String) keyTable[i]);
-				out.writeInt(internedTypeLocators.indexOf(valueTable[i]));
+				Integer index = (Integer) internedTypeLocators.get(valueTable[i]);
+				out.writeInt(index.intValue());
 			}
 		}
 		if (JavaBuilder.DEBUG && length != 0)
@@ -496,10 +511,10 @@
 
 /*
  * char[][][]	Interned qualified names
- * char[][]		Interned simple names
+ * char[][]	Interned simple names
  */
-	ArrayList internedQualifiedNames = new ArrayList(31);
-	ArrayList internedSimpleNames = new ArrayList(31);
+	SimpleLookupTable internedQualifiedNames = new SimpleLookupTable(31);
+	SimpleLookupTable internedSimpleNames = new SimpleLookupTable(31);
 	valueTable = references.valueTable;
 	for (int i = 0, l = valueTable.length; i < l; i++) {
 		if (valueTable[i] != null) {
@@ -507,39 +522,57 @@
 			char[][][] qNames = collection.qualifiedNameReferences;
 			for (int j = 0, m = qNames.length; j < m; j++) {
 				char[][] qName = qNames[j];
-				if (!internedQualifiedNames.contains(qName)) { // remember the names have been interned
-					internedQualifiedNames.add(qName);
+				if (!internedQualifiedNames.containsKey(qName)) { // remember the names have been interned
+					internedQualifiedNames.put(qName, new Integer(internedQualifiedNames.elementSize));
 					for (int k = 0, n = qName.length; k < n; k++) {
 						char[] sName = qName[k];
-						if (!internedSimpleNames.contains(sName)) // remember the names have been interned
-							internedSimpleNames.add(sName);
+						if (!internedSimpleNames.containsKey(sName)) // remember the names have been interned
+							internedSimpleNames.put(sName, new Integer(internedSimpleNames.elementSize));
 					}
 				}
 			}
 			char[][] sNames = collection.simpleNameReferences;
 			for (int j = 0, m = sNames.length; j < m; j++) {
 				char[] sName = sNames[j];
-				if (!internedSimpleNames.contains(sName)) // remember the names have been interned
-					internedSimpleNames.add(sName);
+				if (!internedSimpleNames.containsKey(sName)) // remember the names have been interned
+					internedSimpleNames.put(sName, new Integer(internedSimpleNames.elementSize));
 			}
 		}
 	}
-	char[][] internedArray = new char[internedSimpleNames.size()][];
-	internedSimpleNames.toArray(internedArray);
+	char[][] internedArray = new char[internedSimpleNames.elementSize][];
+	Object[] simpleNames = internedSimpleNames.keyTable;
+	Object[] positions = internedSimpleNames.valueTable;
+	for (int i = positions.length; --i >= 0; ) {
+		if (positions[i] != null) {
+			int index = ((Integer) positions[i]).intValue();
+			internedArray[index] = (char[]) simpleNames[i];
+		}
+	}
 	writeNames(internedArray, out);
 	// now write the interned qualified names as arrays of interned simple names
-	out.writeInt(length = internedQualifiedNames.size());
+	char[][][] internedQArray = new char[internedQualifiedNames.elementSize][][];
+	Object[] qualifiedNames = internedQualifiedNames.keyTable;
+	positions = internedQualifiedNames.valueTable;
+	for (int i = positions.length; --i >= 0; ) {
+		if (positions[i] != null) {
+			int index = ((Integer) positions[i]).intValue();
+			internedQArray[index] = (char[][]) qualifiedNames[i];
+		}
+	}
+	out.writeInt(length = internedQArray.length);
 	for (int i = 0; i < length; i++) {
-		char[][] qName = (char[][]) internedQualifiedNames.get(i);
+		char[][] qName = internedQArray[i];
 		int qLength = qName.length;
 		out.writeInt(qLength);
-		for (int j = 0; j < qLength; j++)
-			out.writeInt(internedSimpleNames.indexOf(qName[j]));
+		for (int j = 0; j < qLength; j++) {
+			Integer index = (Integer) internedSimpleNames.get(qName[j]);
+			out.writeInt(index.intValue());
+		}
 	}
 
 /*
  * References table
- * int			interned locator id
+ * int		interned locator id
  * ReferenceCollection
 */
 	out.writeInt(length = references.elementSize);
@@ -548,7 +581,8 @@
 		for (int i = 0, l = keyTable.length; i < l; i++) {
 			if (keyTable[i] != null) {
 				length--;
-				out.writeInt(internedTypeLocators.indexOf(keyTable[i]));
+				Integer index = (Integer) internedTypeLocators.get(keyTable[i]);
+				out.writeInt(index.intValue());
 				ReferenceCollection collection = (ReferenceCollection) valueTable[i];
 				if (collection instanceof AdditionalTypeCollection) {
 					out.writeByte(1);
@@ -560,13 +594,17 @@
 				char[][][] qNames = collection.qualifiedNameReferences;
 				int qLength = qNames.length;
 				out.writeInt(qLength);
-				for (int j = 0; j < qLength; j++)
-					out.writeInt(internedQualifiedNames.indexOf(qNames[j]));
+				for (int j = 0; j < qLength; j++) {
+					index = (Integer) internedQualifiedNames.get(qNames[j]);
+					out.writeInt(index.intValue());
+				}
 				char[][] sNames = collection.simpleNameReferences;
 				int sLength = sNames.length;
 				out.writeInt(sLength);
-				for (int j = 0; j < sLength; j++)
-					out.writeInt(internedSimpleNames.indexOf(sNames[j]));
+				for (int j = 0; j < sLength; j++) {
+					index = (Integer) internedSimpleNames.get(sNames[j]);
+					out.writeInt(index.intValue());
+				}
 			}
 		}
 		if (JavaBuilder.DEBUG && length != 0)
@@ -595,13 +633,14 @@
 		AccessRule[] accessRules = accessRuleSet.getAccessRules();
 		int length = accessRules.length;
 		out.writeInt(length);
-		if (length != 0) { 
+		if (length != 0) {
 			for (int i = 0; i < length; i++) {
 				AccessRule accessRule = accessRules[i];
 				writeName(accessRule.pattern, out);
 				out.writeInt(accessRule.problemId);
 			}
-			out.writeUTF(accessRuleSet.messageTemplate);
+			for (int i = 0; i < AccessRuleSet.MESSAGE_TEMPLATES_LENGTH; i++)
+				out.writeUTF(accessRuleSet.messageTemplates[i]);
 		}
 	}
 }
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 a5e0b70..0b70452 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 03427d9..f7897f3 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,7 +10,7 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.builder;
 
-import org.eclipse.jdt.internal.core.util.SimpleSet;
+import org.eclipse.jdt.internal.compiler.util.SimpleSet;
 
 public class WorkQueue {
 
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 f0656bf..f533a79 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -13,15 +13,11 @@
 import java.util.Locale;
 import java.util.Map;
 
-import org.eclipse.core.resources.IMarker;
-import org.eclipse.core.resources.ResourcesPlugin;
-import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.ICompilationUnit;
 import org.eclipse.jdt.core.IImportDeclaration;
 import org.eclipse.jdt.core.IJavaElement;
-import org.eclipse.jdt.core.IJavaModelMarker;
 import org.eclipse.jdt.core.IJavaModelStatusConstants;
 import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.IType;
@@ -276,6 +272,9 @@
 protected INameEnvironment getBuildNameEnvironment() {
 	return new NameEnvironment(getProject());
 }
+public char[] getVarClassName() {
+	return this.context.getVarClassName();
+}
 
 /**
  * @see org.eclipse.jdt.core.eval.IEvaluationContext#getImports()
@@ -392,21 +391,9 @@
 				requestor.acceptClass(packageName, className, completionName, modifiers, completionStart, completionEnd);
 			}
 			public void acceptError(IProblem error) {
-				if (true) return; // was disabled in 1.0
-
-				try {
-					IMarker marker = ResourcesPlugin.getWorkspace().getRoot().createMarker(IJavaModelMarker.TRANSIENT_PROBLEM);
-					marker.setAttribute(IJavaModelMarker.ID, error.getID());
-					marker.setAttribute(IMarker.CHAR_START, error.getSourceStart());
-					marker.setAttribute(IMarker.CHAR_END, error.getSourceEnd() + 1);
-					marker.setAttribute(IMarker.LINE_NUMBER, error.getSourceLineNumber());
-					marker.setAttribute(IMarker.MESSAGE, error.getMessage());
-					marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
-					requestor.acceptError(marker);
-				} catch(CoreException e){
-					// ignore
-				}
+				// was disabled in 1.0
 			}
+			
 			public void acceptField(char[] declaringTypePackageName, char[] declaringTypeName, char[] name, char[] typePackageName, char[] typeName, char[] completionName, int modifiers, int completionStart, int completionEnd, int relevance) {
 				requestor.acceptField(declaringTypePackageName, declaringTypeName, name, typePackageName, typeName, completionName, modifiers, completionStart, completionEnd);
 			}
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 39c5bff..939d078 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 bcdee8d..77f26d4 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -14,13 +14,16 @@
 import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.jdt.core.IJavaModelMarker;
-import org.eclipse.jdt.core.compiler.IProblem;
+import org.eclipse.jdt.core.compiler.CategorizedProblem;
 import org.eclipse.jdt.core.eval.ICodeSnippetRequestor;
 import org.eclipse.jdt.internal.compiler.ClassFile;
+import org.eclipse.jdt.internal.core.builder.JavaBuilder;
 import org.eclipse.jdt.internal.eval.IRequestor;
  
 public class RequestorWrapper implements IRequestor {
+	
 	ICodeSnippetRequestor requestor;
+	
 public RequestorWrapper(ICodeSnippetRequestor requestor) {
 	this.requestor = requestor;
 }
@@ -47,7 +50,7 @@
 /**
  * @see ICodeSnippetRequestor
  */
-public void acceptProblem(IProblem problem, char[] fragmentSource, int fragmentKind) {
+public void acceptProblem(CategorizedProblem problem, char[] fragmentSource, int fragmentKind) {
 	try {
 		IMarker marker = ResourcesPlugin.getWorkspace().getRoot().createMarker(IJavaModelMarker.TRANSIENT_PROBLEM);
 		marker.setAttribute(IJavaModelMarker.ID, problem.getID());
@@ -57,6 +60,7 @@
 		//marker.setAttribute(IMarker.LOCATION, "#" + problem.getSourceLineNumber());
 		marker.setAttribute(IMarker.MESSAGE, problem.getMessage());
 		marker.setAttribute(IMarker.SEVERITY, (problem.isWarning() ? IMarker.SEVERITY_WARNING : IMarker.SEVERITY_ERROR));
+		marker.setAttribute(IMarker.SOURCE_ID, JavaBuilder.SOURCE_ID);
 		this.requestor.acceptProblem(marker, new String(fragmentSource), fragmentKind);
 	} catch (CoreException e) {
 		e.printStackTrace();
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 c960f20..20786c0 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 4bb296e..7b61e06 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -12,17 +12,18 @@
 
 import org.eclipse.jdt.core.Signature;
 import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.env.IBinaryAnnotation;
 import org.eclipse.jdt.internal.compiler.env.IBinaryField;
 import org.eclipse.jdt.internal.compiler.env.IBinaryMethod;
 import org.eclipse.jdt.internal.compiler.env.IBinaryNestedType;
 import org.eclipse.jdt.internal.compiler.env.IBinaryType;
-import org.eclipse.jdt.internal.compiler.env.IConstants;
-import org.eclipse.jdt.internal.compiler.env.IGenericType;
 import org.eclipse.jdt.internal.core.search.indexing.IIndexConstants;
 
 public class HierarchyBinaryType implements IBinaryType {
 	private int modifiers;
-	private int kind;
+	private char[] sourceName;
 	private char[] name;
 	private char[] enclosingTypeName;
 	private char[] superclass;
@@ -30,27 +31,14 @@
 	private char[][] typeParameterSignatures;
 	private char[] genericSignature;
 	
-public HierarchyBinaryType(int modifiers, char[] qualification, char[] typeName, char[] enclosingTypeName, char[][] typeParameterSignatures, char typeSuffix){
+public HierarchyBinaryType(int modifiers, char[] qualification, char[] sourceName, char[] enclosingTypeName, char[][] typeParameterSignatures, char typeSuffix){
 
 	this.modifiers = modifiers;
-	switch(typeSuffix) {
-		case IIndexConstants.CLASS_SUFFIX :
-			this.kind = IGenericType.CLASS_DECL;
-			break;
-		case IIndexConstants.INTERFACE_SUFFIX :
-			this.kind = IGenericType.INTERFACE_DECL;
-			break;
-		case IIndexConstants.ENUM_SUFFIX :
-			this.kind = IGenericType.ENUM_DECL;
-			break;
-		case IIndexConstants.ANNOTATION_TYPE_SUFFIX :
-			this.kind = IGenericType.ANNOTATION_TYPE_DECL;
-			break;
-	}
+	this.sourceName = sourceName;
 	if (enclosingTypeName == null){
-		this.name = CharOperation.concat(qualification, typeName, '/');
+		this.name = CharOperation.concat(qualification, sourceName, '/');
 	} else {
-		this.name = CharOperation.concat(qualification, '/', enclosingTypeName, '$', typeName); //rebuild A$B name
+		this.name = CharOperation.concat(qualification, '/', enclosingTypeName, '$', sourceName); //rebuild A$B name
 		this.enclosingTypeName = CharOperation.concat(qualification, enclosingTypeName,'/');
 		CharOperation.replace(this.enclosingTypeName, '.', '/');
 	}
@@ -100,12 +88,6 @@
 	return this.genericSignature;
 }
 /**
- * @see org.eclipse.jdt.internal.compiler.env.IGenericType#getKind()
- */
-public int getKind() {
-	return this.kind;
-}
-/**
  * Answer the resolved names of the receiver's interfaces in the
  * class file format as specified in section 4.2 of the Java 2 VM spec
  * or null if the array is empty.
@@ -146,6 +128,11 @@
 public char[] getName() {
 	return this.name;
 }
+
+public char[] getSourceName() {
+	return this.sourceName;
+}
+
 /**
  * Answer the resolved name of the receiver's superclass in the
  * class file format as specified in section 4.2 of the Java 2 VM spec
@@ -189,7 +176,7 @@
 	if (superClassOrInterface == IIndexConstants.CLASS_SUFFIX){
 		// interfaces are indexed as having superclass references to Object by default,
 		// this is an artifact used for being able to query them only.
-		if (this.kind == IGenericType.INTERFACE_DECL) return; 
+		if (TypeDeclaration.kind(this.modifiers) == TypeDeclaration.INTERFACE_DECL) return; 
 		char[] encodedName = CharOperation.concat(superQualification, superTypeName, '/');
 		CharOperation.replace(encodedName, '.', '/'); 
 		this.superclass = encodedName;
@@ -207,17 +194,17 @@
 }
 public String toString() {
 	StringBuffer buffer = new StringBuffer();
-	if (this.modifiers == IConstants.AccPublic) {
+	if (this.modifiers == ClassFileConstants.AccPublic) {
 		buffer.append("public "); //$NON-NLS-1$
 	}
-	switch (this.kind) {
-		case IGenericType.CLASS_DECL :
+	switch (TypeDeclaration.kind(this.modifiers)) {
+		case TypeDeclaration.CLASS_DECL :
 			buffer.append("class "); //$NON-NLS-1$
 			break;		
-		case IGenericType.INTERFACE_DECL :
+		case TypeDeclaration.INTERFACE_DECL :
 			buffer.append("interface "); //$NON-NLS-1$
 			break;		
-		case IGenericType.ENUM_DECL :
+		case TypeDeclaration.ENUM_DECL :
 			buffer.append("enum "); //$NON-NLS-1$
 			break;		
 	}
@@ -244,6 +231,13 @@
 /**
  * @see org.eclipse.jdt.internal.compiler.env.IBinaryType
  */
+public IBinaryAnnotation[] getAnnotations() {
+	return null;
+}
+
+/**
+ * @see org.eclipse.jdt.internal.compiler.env.IBinaryType
+ */
 public char[] sourceFileName() {
 	return null;
 }
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 90bf5d0..6902412 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -13,27 +13,21 @@
 import java.util.HashMap;
 import java.util.Map;
 
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.OperationCanceledException;
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
 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.lookup.ReferenceBinding;
 import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
 import org.eclipse.jdt.internal.core.*;
-import org.eclipse.jdt.internal.core.BasicCompilationUnit;
-import org.eclipse.jdt.internal.core.ClassFile;
-import org.eclipse.jdt.internal.core.JarPackageFragmentRoot;
-import org.eclipse.jdt.internal.core.JavaElement;
-import org.eclipse.jdt.internal.core.JavaModelManager;
-import org.eclipse.jdt.internal.core.JavaProject;
-import org.eclipse.jdt.internal.core.NameLookup;
-import org.eclipse.jdt.internal.core.Openable;
-import org.eclipse.jdt.internal.core.SearchableEnvironment;
-import org.eclipse.jdt.internal.core.SourceTypeElementInfo;
+import org.eclipse.jdt.internal.core.util.ResourceCompilationUnit;
 import org.eclipse.jdt.internal.core.util.Util;
 
 public abstract class HierarchyBuilder {
@@ -83,14 +77,16 @@
 		} else {
 			unitsToLookInside = workingCopies;
 		}
-		SearchableEnvironment searchableEnvironment = project.newSearchableNameEnvironment(unitsToLookInside);
-		this.nameLookup = searchableEnvironment.nameLookup;
-		this.hierarchyResolver =
-			new HierarchyResolver(
-				searchableEnvironment,
-				project.getOptions(true),
-				this,
-				new DefaultProblemFactory());
+		if (project != null) {
+			SearchableEnvironment searchableEnvironment = project.newSearchableNameEnvironment(unitsToLookInside);
+			this.nameLookup = searchableEnvironment.nameLookup;
+			this.hierarchyResolver =
+				new HierarchyResolver(
+					searchableEnvironment,
+					project.getOptions(true),
+					this,
+					new DefaultProblemFactory());
+		}
 		this.infoToHandle = new HashMap(5);
 		this.focusQualifiedName = focusType == null ? null : focusType.getFullyQualifiedName();
 	}
@@ -160,17 +156,17 @@
 			}
 		}
 		// now do the caching
-		switch (type.getKind()) {
-			case IGenericType.CLASS_DECL :
-			case IGenericType.ENUM_DECL :
+		switch (TypeDeclaration.kind(type.getModifiers())) {
+			case TypeDeclaration.CLASS_DECL :
+			case TypeDeclaration.ENUM_DECL :
 				if (superclassHandle == null) {
 					this.hierarchy.addRootClass(typeHandle);
 				} else {
 					this.hierarchy.cacheSuperclass(typeHandle, superclassHandle);
 				}
 				break;
-			case IGenericType.INTERFACE_DECL :
-			case IGenericType.ANNOTATION_TYPE_DECL :
+			case TypeDeclaration.INTERFACE_DECL :
+			case TypeDeclaration.ANNOTATION_TYPE_DECL :
 				this.hierarchy.addInterface(typeHandle);
 				break;
 		}		
@@ -224,14 +220,14 @@
 	protected IType lookupBinaryHandle(IBinaryType typeInfo) {
 		int flag;
 		String qualifiedName;
-		switch (typeInfo.getKind()) {
-			case IGenericType.CLASS_DECL :
+		switch (TypeDeclaration.kind(typeInfo.getModifiers())) {
+			case TypeDeclaration.CLASS_DECL :
 				flag = NameLookup.ACCEPT_CLASSES;
 				break;
-			case IGenericType.INTERFACE_DECL :
+			case TypeDeclaration.INTERFACE_DECL :
 				flag = NameLookup.ACCEPT_INTERFACES;
 				break;
-			case IGenericType.ENUM_DECL :
+			case TypeDeclaration.ENUM_DECL :
 				flag = NameLookup.ACCEPT_ENUMS;
 				break;
 			default:
@@ -242,7 +238,15 @@
 		char[] bName = typeInfo.getName();
 		qualifiedName = new String(ClassFile.translatedName(bName));
 		if (qualifiedName.equals(this.focusQualifiedName)) return getType();
-		return this.nameLookup.findType(qualifiedName, false, flag);
+		NameLookup.Answer answer = this.nameLookup.findType(qualifiedName,
+			false,
+			flag,
+			true/* consider secondary types */,
+			false/* do NOT wait for indexes */,
+			false/*don't check restrictions*/,
+			null);
+		return answer == null || answer.type == null || !answer.type.isBinary() ? null : answer.type;
+		
 	}
 	protected void worked(IProgressMonitor monitor, int work) {
 		if (monitor != null) {
@@ -256,9 +260,9 @@
 /**
  * Create an ICompilationUnit info from the given compilation unit on disk.
  */
-protected ICompilationUnit createCompilationUnitFromPath(Openable handle, String osPath) {
+protected ICompilationUnit createCompilationUnitFromPath(Openable handle, IFile file) {
 	final char[] elementName = handle.getElementName().toCharArray();
-	return new BasicCompilationUnit(null/* no source*/, null/* no package */, osPath, handle) {
+	return new ResourceCompilationUnit(file, file.getLocationURI()) {
 		public char[] getFileName() {
 			return elementName;
 		}
@@ -268,10 +272,10 @@
  * Creates the type info from the given class file on disk and
  * adds it to the given list of infos.
  */
-protected IBinaryType createInfoFromClassFile(Openable handle, String osPath) {
+protected IBinaryType createInfoFromClassFile(Openable handle, IResource file) {
 	IBinaryType info = null;
 	try {
-		info = org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader.read(osPath);
+		info = Util.newClassFileReader(file);
 	} catch (org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException e) {
 		if (TypeHierarchy.DEBUG) {
 			e.printStackTrace();
@@ -282,6 +286,11 @@
 			e.printStackTrace();
 		}
 		return null;
+	} catch (CoreException e) {
+		if (TypeHierarchy.DEBUG) {
+			e.printStackTrace();
+		}
+		return null;
 	}						
 	this.infoToHandle.put(info, handle);
 	return info;
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 da7f0c4..b79754b 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -27,6 +27,7 @@
 import java.util.HashSet;
 import java.util.Map;
 
+import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
@@ -40,9 +41,6 @@
 import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
 import org.eclipse.jdt.internal.compiler.IProblemFactory;
 import org.eclipse.jdt.internal.compiler.ast.*;
-import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
-import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
-import org.eclipse.jdt.internal.compiler.ast.TypeReference;
 import org.eclipse.jdt.internal.compiler.env.AccessRestriction;
 import org.eclipse.jdt.internal.compiler.env.IBinaryType;
 import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
@@ -52,18 +50,12 @@
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.compiler.impl.ITypeRequestor;
 import org.eclipse.jdt.internal.compiler.lookup.*;
-import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding;
-import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
-import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
-import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
-import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
 import org.eclipse.jdt.internal.compiler.parser.Parser;
 import org.eclipse.jdt.internal.compiler.parser.SourceTypeConverter;
 import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
 import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
 import org.eclipse.jdt.internal.compiler.util.Messages;
 import org.eclipse.jdt.internal.core.*;
-import org.eclipse.jdt.internal.core.Member;
 import org.eclipse.jdt.internal.core.util.ASTNodeFinder;
 import org.eclipse.jdt.internal.core.util.HandleFactory;
 
@@ -100,6 +92,10 @@
  * @param packageBinding
  */
 public void accept(IBinaryType binaryType, PackageBinding packageBinding, AccessRestriction accessRestriction) {
+	IProgressMonitor progressMonitor = this.builder.hierarchy.progressMonitor;
+	if (progressMonitor != null && progressMonitor.isCanceled())
+		throw new OperationCanceledException();
+	
 	BinaryTypeBinding typeBinding = this.lookupEnvironment.createBinaryTypeFrom(binaryType, packageBinding, accessRestriction);
 	try {
 		this.remember(binaryType, typeBinding);
@@ -126,6 +122,10 @@
  * @param packageBinding
  */
 public void accept(ISourceType[] sourceTypes, PackageBinding packageBinding, AccessRestriction accessRestriction) {
+	IProgressMonitor progressMonitor = this.builder.hierarchy.progressMonitor;
+	if (progressMonitor != null && progressMonitor.isCanceled())
+		throw new OperationCanceledException();
+	
 	// find most enclosing type first (needed when explicit askForType(...) is done 
 	// with a member type (e.g. p.A$B))
 	ISourceType sourceType = sourceTypes[0];
@@ -163,32 +163,39 @@
  */
 private IType findSuperClass(IGenericType type, ReferenceBinding typeBinding) {
 	ReferenceBinding superBinding = typeBinding.superclass();
+	
 	if (superBinding != null) {
 		superBinding = (ReferenceBinding) superBinding.erasure();
-		if (superBinding.id == TypeIds.T_JavaLangObject && typeBinding.isHierarchyInconsistent()) {
-			char[] superclassName;
-			char separator;
-			if (type instanceof IBinaryType) {
-				superclassName = ((IBinaryType)type).getSuperclassName();
-				separator = '/';
-			} else if (type instanceof ISourceType) {
-				superclassName = ((ISourceType)type).getSuperclassName();
-				separator = '.';
-			} else if (type instanceof HierarchyType) {
-				superclassName = ((HierarchyType)type).superclassName;
-				separator = '.';
-			} else {
+		if (typeBinding.isHierarchyInconsistent()) {
+			if (superBinding.problemId() == ProblemReasons.NotFound) {
+				this.hasMissingSuperClass = true;
+				this.builder.hierarchy.missingTypes.add(new String(superBinding.sourceName)); // note: this could be Map$Entry
 				return null;
-			}
-			
-			if (superclassName != null) { // check whether subclass of Object due to broken hierarchy (as opposed to explicitly extending it)
-				int lastSeparator = CharOperation.lastIndexOf(separator, superclassName);
-				char[] simpleName = lastSeparator == -1 ? superclassName : CharOperation.subarray(superclassName, lastSeparator+1, superclassName.length);
-				if (!CharOperation.equals(simpleName, TypeConstants.OBJECT)) {
-					this.hasMissingSuperClass = true;
-					this.builder.hierarchy.missingTypes.add(new String(simpleName));
+			} else if ((superBinding.id == TypeIds.T_JavaLangObject)) {
+				char[] superclassName;
+				char separator;
+				if (type instanceof IBinaryType) {
+					superclassName = ((IBinaryType)type).getSuperclassName();
+					separator = '/';
+				} else if (type instanceof ISourceType) {
+					superclassName = ((ISourceType)type).getSuperclassName();
+					separator = '.';
+				} else if (type instanceof HierarchyType) {
+					superclassName = ((HierarchyType)type).superclassName;
+					separator = '.';
+				} else {
 					return null;
 				}
+				
+				if (superclassName != null) { // check whether subclass of Object due to broken hierarchy (as opposed to explicitly extending it)
+					int lastSeparator = CharOperation.lastIndexOf(separator, superclassName);
+					char[] simpleName = lastSeparator == -1 ? superclassName : CharOperation.subarray(superclassName, lastSeparator+1, superclassName.length);
+					if (!CharOperation.equals(simpleName, TypeConstants.OBJECT)) {
+						this.hasMissingSuperClass = true;
+						this.builder.hierarchy.missingTypes.add(new String(simpleName));
+						return null;
+					}
+				}
 			}
 		}
 		for (int t = this.typeIndex; t >= 0; t--) {
@@ -218,7 +225,7 @@
 				superInterfaceNames = sourceType.getInterfaceNames();
 			}
 		} else {
-			if (sourceType.getKind() == IGenericType.ANNOTATION_TYPE_DECL)
+			if (TypeDeclaration.kind(sourceType.getModifiers()) == TypeDeclaration.ANNOTATION_TYPE_DECL)
 				superInterfaceNames = new char[][] {TypeConstants.CharArray_JAVA_LANG_ANNOTATION_ANNOTATION};
 			else
 				superInterfaceNames = sourceType.getInterfaceNames();
@@ -240,7 +247,7 @@
 		return null;
 	}
 	
-	ReferenceBinding[] interfaceBindings = typeBinding.superInterfaces();
+	ReferenceBinding[] interfaceBindings = typeBinding.superInterfaces();	
 	int bindingIndex = 0;
 	int bindingLength = interfaceBindings == null ? 0 : interfaceBindings.length;
 	int length = superInterfaceNames == null ? 0 : superInterfaceNames.length;
@@ -248,18 +255,20 @@
 	int index = 0;
 	next : for (int i = 0; i < length; i++) {
 		char[] superInterfaceName = superInterfaceNames[i];
-		int lastSeparator = CharOperation.lastIndexOf(separator, superInterfaceName);
-		int start = lastSeparator + 1; 
 		int end = superInterfaceName.length;
 		
+		// find the end of simple name
+		int genericStart = CharOperation.indexOf(Signature.C_GENERIC_START, superInterfaceName);
+		if (genericStart != -1) end = genericStart;
+				
+		// find the start of simple name
+		int lastSeparator = CharOperation.lastIndexOf(separator, superInterfaceName, 0, end);
+		int start = lastSeparator + 1; 
+		
 		// case of binary inner type -> take the last part
 		int lastDollar = CharOperation.lastIndexOf('$', superInterfaceName, start);
 		if (lastDollar != -1) start = lastDollar + 1;
 		
-		// case of a parameterized type -> take the first part
-		int genericStart = CharOperation.indexOf(Signature.C_GENERIC_START, superInterfaceName, start);
-		if (genericStart != -1) end = genericStart;
-		
 		char[] simpleName = CharOperation.subarray(superInterfaceName, start, end);
 		
 		if (bindingIndex < bindingLength) {
@@ -282,6 +291,59 @@
 		System.arraycopy(superinterfaces, 0, superinterfaces = new IType[index], 0, index);
 	return superinterfaces;
 }
+private void fixSupertypeBindings() {
+	for (int current = this.typeIndex; current >= 0; current--) {
+		ReferenceBinding typeBinding = this.typeBindings[current];
+	
+		
+		if (typeBinding instanceof SourceTypeBinding) {
+			ClassScope scope = ((SourceTypeBinding) typeBinding).scope;
+			if (scope != null) {
+				TypeDeclaration typeDeclaration = scope.referenceContext;
+				TypeReference superclassRef = typeDeclaration == null ? null : typeDeclaration.superclass;
+				TypeBinding superclass = superclassRef == null ? null : superclassRef.resolvedType;
+				if (superclass instanceof ProblemReferenceBinding) {
+					superclass = ((ProblemReferenceBinding) superclass).closestMatch();
+				}
+				if (superclass != null) 
+					((SourceTypeBinding) typeBinding).superclass = (ReferenceBinding) superclass;
+	
+				TypeReference[] superInterfaces = typeDeclaration == null ? null : typeDeclaration.superInterfaces;
+				int length;
+				ReferenceBinding[] interfaceBindings = typeBinding.superInterfaces();
+				if (superInterfaces != null && (length = superInterfaces.length) > (interfaceBindings == null ? 0 : interfaceBindings.length)) { // check for interfaceBindings being null (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=139689)
+					interfaceBindings = new ReferenceBinding[length];
+					int index = 0;
+					for (int i = 0; i < length; i++) {
+						ReferenceBinding superInterface = (ReferenceBinding) superInterfaces[i].resolvedType;
+						if (superInterface instanceof ProblemReferenceBinding)
+							superInterface = superInterface.closestMatch();
+						if (superInterface != null)
+							interfaceBindings[index++] = superInterface;
+					}
+					if (index < length)
+						System.arraycopy(interfaceBindings, 0, interfaceBindings = new ReferenceBinding[index], 0 , index);
+					((SourceTypeBinding) typeBinding).superInterfaces = interfaceBindings;
+				}
+			}		
+		} else if (typeBinding instanceof BinaryTypeBinding) {
+			try {
+				typeBinding.superclass();
+			} catch (AbortCompilation e) {
+				// allow subsequent call to superclass() to succeed so that we don't have to catch AbortCompilation everywhere
+				((BinaryTypeBinding) typeBinding).tagBits &= ~TagBits.HasUnresolvedSuperclass;
+				this.builder.hierarchy.missingTypes.add(new String(typeBinding.superclass().sourceName()));
+				this.hasMissingSuperClass = true;
+			}
+			try {
+				typeBinding.superInterfaces();
+			} catch (AbortCompilation e) {
+				// allow subsequent call to superInterfaces() to succeed so that we don't have to catch AbortCompilation everywhere
+				((BinaryTypeBinding) typeBinding).tagBits &= ~TagBits.HasUnresolvedSuperinterfaces;
+			}
+		}
+	}	
+}
 private void remember(IGenericType suppliedType, ReferenceBinding typeBinding) {
 	if (typeBinding == null) return;
 	
@@ -309,7 +371,7 @@
 		// simple super class name
 		char[] superclassName = null;
 		TypeReference superclass;
-		if ((typeDeclaration.bits & ASTNode.IsAnonymousTypeMASK) != 0) {
+		if ((typeDeclaration.bits & ASTNode.IsAnonymousType) != 0) {
 			superclass = typeDeclaration.allocation.type;
 		} else {
 			superclass = typeDeclaration.superclass;
@@ -334,7 +396,6 @@
 	
 		HierarchyType hierarchyType = new HierarchyType(
 			type, 
-			typeDeclaration.kind(),
 			typeDeclaration.name,
 			typeDeclaration.binding.modifiers,
 			superclassName,
@@ -408,6 +469,9 @@
 		}
 	}
 	
+	// be resilient and fix super type bindings
+	fixSupertypeBindings();
+	
 	int objectIndex = -1;
 	for (int current = this.typeIndex; current >= 0; current--) {
 		ReferenceBinding typeBinding = this.typeBindings[current];
@@ -459,7 +523,7 @@
 public void resolve(IGenericType suppliedType) {
 	try {
 		if (suppliedType.isBinaryType()) {
-			BinaryTypeBinding binaryTypeBinding = this.lookupEnvironment.cacheBinaryType((IBinaryType) suppliedType, null /*no access restriction*/);
+			BinaryTypeBinding binaryTypeBinding = this.lookupEnvironment.cacheBinaryType((IBinaryType) suppliedType, false/*don't need field and method (bug 125067)*/, null /*no access restriction*/);
 			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;
@@ -570,9 +634,8 @@
 					if (containsLocalType) 	parsedUnit.bits |= ASTNode.HasAllMethodBodies;
 				} else {
 					// create parsed unit from file
-					IResource file = cu.getResource();
-					String osPath = file.getLocation().toOSString();
-					ICompilationUnit sourceUnit = this.builder.createCompilationUnitFromPath(openable, osPath);
+					IFile file = (IFile) cu.getResource();
+					ICompilationUnit sourceUnit = this.builder.createCompilationUnitFromPath(openable, file);
 					
 					CompilationResult unitResult = new CompilationResult(sourceUnit, i, openablesLength, this.options.maxProblemsPerUnit); 
 					parsedUnit = parser.dietParse(sourceUnit, unitResult);
@@ -609,13 +672,12 @@
 						binaryType = this.builder.createInfoFromClassFileInJar(classFile);
 					} else {
 						IResource file = classFile.getResource();
-						String osPath = file.getLocation().toOSString();
-						binaryType = this.builder.createInfoFromClassFile(classFile, osPath);
+						binaryType = this.builder.createInfoFromClassFile(classFile, file);
 					}
 				}
 				if (binaryType != null) {
 					try {
-						BinaryTypeBinding binaryTypeBinding = this.lookupEnvironment.cacheBinaryType(binaryType, null /*no access restriction*/);
+						BinaryTypeBinding binaryTypeBinding = this.lookupEnvironment.cacheBinaryType(binaryType, false/*don't need field and method (bug 125067)*/, null /*no access restriction*/);
 						remember(binaryType, binaryTypeBinding);
 						if (openable.equals(focusOpenable)) {
 							focusBinaryBinding = binaryTypeBinding;
@@ -650,7 +712,10 @@
 					if (containsLocalType) { // NB: no-op if method bodies have been already parsed
 						parser.getMethodBodies(parsedUnit);
 					}
-					this.lookupEnvironment.completeTypeBindings(parsedUnit, true/*build constructor only*/);
+					// complete type bindings and build fields and methods only for local types
+					// (in this case the constructor is needed when resolving local types)
+					// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=145333)
+					this.lookupEnvironment.completeTypeBindings(parsedUnit, containsLocalType);
 				} catch (AbortCompilation e) {
 					// classpath problem for this type: don't try to resolve (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=49809)
 					hasLocalType[i] = false;
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 1ba6b06..11e668e 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -21,7 +21,6 @@
 public class HierarchyType implements IGenericType {
 
 	public IType typeHandle;
-	public int kind;
 	public char[] name;
 	public int modifiers;
 	public char[] superclassName;
@@ -29,14 +28,12 @@
 	
 public HierarchyType(
 	IType typeHandle, 
-	int kind,
 	char[] name, 
 	int modifiers, 
 	char[] superclassName,
 	char[][] superInterfaceNames) {
 		
 	this.typeHandle = typeHandle;
-	this.kind = kind;
 	this.name = name;
 	this.modifiers = modifiers;
 	this.superclassName = superclassName;
@@ -48,12 +45,7 @@
 public char[] getFileName() {
 	return this.typeHandle.getCompilationUnit().getElementName().toCharArray();
 }
-/**
- * @see org.eclipse.jdt.internal.compiler.env.IGenericType#getKind()
- */
-public int getKind() {
-	return this.kind;
-}
+
 /**
  * Answer an int whose bits are set according the access constants
  * defined by the VM spec.
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 2fed303..7355ef1 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -12,8 +12,11 @@
 
 import java.util.*;
 
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
 import org.eclipse.core.runtime.SubProgressMonitor;
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.compiler.CharOperation;
@@ -23,6 +26,7 @@
 import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
 import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
 import org.eclipse.jdt.internal.compiler.util.HashtableOfObject;
+import org.eclipse.jdt.internal.compiler.util.HashtableOfObjectToInt;
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
 import org.eclipse.jdt.internal.core.*;
 import org.eclipse.jdt.internal.core.search.IndexQueryRequestor;
@@ -33,6 +37,7 @@
 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;
+import org.eclipse.jdt.internal.core.util.Util;
 
 public class IndexBasedHierarchyBuilder extends HierarchyBuilder implements SuffixConstants {
 	public static final int MAXTICKS = 800; // heuristic so that there still progress for deep hierachies
@@ -43,10 +48,6 @@
 	 * the region).
 	 */
 	protected Map cuToHandle;
-	/**
-	 * A map from compilation unit handles to working copies.
-	 */
-	protected Map handleToWorkingCopy;
 
 	/**
 	 * The scope this hierarchy builder should restrain results to.
@@ -61,7 +62,7 @@
 	/**
 	 * Collection used to queue subtype index queries
 	 */
-	private static class Queue {
+	static class Queue {
 		public char[][] names = new char[10][];
 		public int start = 0;
 		public int end = -1;
@@ -119,7 +120,7 @@
 				allPossibleSubtypes = this.determinePossibleSubTypes(localTypes, possibleSubtypesMonitor);
 			} else {
 				// local or anonymous type
-				allPossibleSubtypes = new String[0];
+				allPossibleSubtypes = CharOperation.NO_STRINGS;
 			}
 			if (allPossibleSubtypes != null) {
 				IProgressMonitor buildMonitor = 
@@ -138,13 +139,38 @@
 	}
 }
 private void buildForProject(JavaProject project, ArrayList potentialSubtypes, org.eclipse.jdt.core.ICompilationUnit[] workingCopies, HashSet localTypes, IProgressMonitor monitor) throws JavaModelException {
-	// copy vectors into arrays
-	int openablesLength = potentialSubtypes.size();
-	Openable[] openables = new Openable[openablesLength];
-	potentialSubtypes.toArray(openables);
-
 	// resolve
+	int openablesLength = potentialSubtypes.size();
 	if (openablesLength > 0) {
+		// copy vectors into arrays
+		Openable[] openables = new Openable[openablesLength];
+		potentialSubtypes.toArray(openables);
+
+		// sort in the order of roots and in reverse alphabetical order for .class file
+		// since requesting top level types in the process of caching an enclosing type is
+		// not supported by the lookup environment
+		IPackageFragmentRoot[] roots = project.getPackageFragmentRoots();
+		int rootsLength = roots.length;
+		final HashtableOfObjectToInt indexes = new HashtableOfObjectToInt(openablesLength);
+		for (int i = 0; i < openablesLength; i++) {
+			IJavaElement root = openables[i].getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
+			int index;
+			for (index = 0; index < rootsLength; index++) {
+				if (roots[index].equals(root))
+					break;
+			}		
+			indexes.put(openables[i], index);
+		}
+		Arrays.sort(openables, new Comparator() {
+			public int compare(Object a, Object b) {
+				int aIndex = indexes.get(a);
+				int bIndex = indexes.get(b);
+				if (aIndex != bIndex)
+					return aIndex - bIndex;
+				return ((Openable) b).getElementName().compareTo(((Openable) a).getElementName());
+			}
+		});
+		
 		IType focusType = this.getType();
 		boolean inProjectOfFocusType = focusType != null && focusType.getJavaProject().equals(project);
 		org.eclipse.jdt.core.ICompilationUnit[] unitsToLookInside = null;
@@ -175,10 +201,13 @@
 			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;
+				if (!inProjectOfFocusType) {
+					char[] typeQualifiedName = focusType.getTypeQualifiedName('.').toCharArray();
+					String[] packageName = ((PackageFragment) focusType.getPackageFragment()).names;
+					if (searchableEnvironment.findType(typeQualifiedName, Util.toCharArrays(packageName)) == null) {
+						// focus type is not visible in this project: no need to go further
+						return;
+					}
 				}
 			} else {
 				// local or anonymous type
@@ -238,17 +267,12 @@
 		length++;
 	}
 	
-	// sort by projects
 	/*
-	 * NOTE: To workaround pb with hierarchy resolver that requests top  
-	 * level types in the process of caching an enclosing type, this needs to
-	 * be sorted in reverse alphabetical order so that top level types are cached
-	 * before their inner types.
+	 * Sort in alphabetical order so that potential subtypes are grouped per project
 	 */
-	org.eclipse.jdt.internal.core.util.Util.sortReverseOrder(allPotentialSubTypes);
-	
-	ArrayList potentialSubtypes = new ArrayList();
+	Arrays.sort(allPotentialSubTypes);
 
+	ArrayList potentialSubtypes = new ArrayList();
 	try {
 		// create element infos for subtypes
 		HandleFactory factory = new HandleFactory();
@@ -330,19 +354,19 @@
 		if (monitor != null) monitor.done();
 	}
 }
-protected ICompilationUnit createCompilationUnitFromPath(Openable handle, String osPath) {
-	ICompilationUnit unit = super.createCompilationUnitFromPath(handle, osPath);
+protected ICompilationUnit createCompilationUnitFromPath(Openable handle, IFile file) {
+	ICompilationUnit unit = super.createCompilationUnitFromPath(handle, file);
 	this.cuToHandle.put(unit, handle);
 	return unit;
 }
-protected IBinaryType createInfoFromClassFile(Openable classFile, String osPath) {
+protected IBinaryType createInfoFromClassFile(Openable classFile, IResource file) {
 	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);
+		return super.createInfoFromClassFile(classFile, file);
 	}
 }
 protected IBinaryType createInfoFromClassFileInJar(Openable classFile) {
@@ -421,7 +445,7 @@
 	final Map binariesFromIndexMatches,
 	final IPathRequestor pathRequestor,
 	int waitingPolicy,	// WaitUntilReadyToSearch | ForceImmediateSearch | CancelIfNotReadyToSearch
-	IProgressMonitor progressMonitor) {
+	final IProgressMonitor progressMonitor) {
 
 	/* embed constructs inside arrays so as to pass them to (inner) collector */
 	final Queue queue = new Queue();
@@ -436,7 +460,7 @@
 			boolean isLocalOrAnonymous = record.enclosingTypeName == IIndexConstants.ONE_ZERO;
 			pathRequestor.acceptPath(documentPath, isLocalOrAnonymous);
 			char[] typeName = record.simpleName;
-			int suffix = documentPath.toLowerCase().indexOf(SUFFIX_STRING_class);
+			int suffix = documentPath.toLowerCase().lastIndexOf(SUFFIX_STRING_class);
 			if (suffix != -1){ 
 				HierarchyBinaryType binaryType = (HierarchyBinaryType)binariesFromIndexMatches.get(documentPath);
 				if (binaryType == null){
@@ -468,8 +492,14 @@
 		}		
 	};
 
+	int superRefKind;
+	try {
+		superRefKind = type.isClass() ? SuperTypeReferencePattern.ONLY_SUPER_CLASSES : SuperTypeReferencePattern.ALL_SUPER_TYPES;
+	} catch (JavaModelException e) {
+		superRefKind = SuperTypeReferencePattern.ALL_SUPER_TYPES;
+	}
 	SuperTypeReferencePattern pattern =
-		new SuperTypeReferencePattern(null, null, false, SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE);
+		new SuperTypeReferencePattern(null, null, superRefKind, SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE);
 	MatchLocator.setFocus(pattern, type);
 	SubTypeSearchJob job = new SubTypeSearchJob(
 		pattern, 
@@ -490,7 +520,16 @@
 
 			// 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
+			indexManager.performConcurrentJob(job, waitingPolicy, progressMonitor == null ? null : new NullProgressMonitor() { 
+				// don't report progress since this is too costly for deep hierarchies
+				// just handle isCanceled() (seehttps://bugs.eclipse.org/bugs/show_bug.cgi?id=179511)
+				public void setCanceled(boolean value) {
+					progressMonitor.setCanceled(value);
+				}
+				public boolean isCanceled() {
+					return progressMonitor.isCanceled();
+				}
+			});
 			if (progressMonitor != null && ++ticks <= MAXTICKS)
 				progressMonitor.worked(1);
 
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 b0ae80a..70c737b 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -13,6 +13,7 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.Map;
 
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.SubProgressMonitor;
@@ -27,6 +28,7 @@
 import org.eclipse.jdt.internal.core.JavaModelManager;
 import org.eclipse.jdt.internal.core.JavaProject;
 import org.eclipse.jdt.internal.core.Openable;
+import org.eclipse.jdt.internal.core.SearchableEnvironment;
 
 public class RegionBasedHierarchyBuilder extends HierarchyBuilder {
 	
@@ -69,26 +71,29 @@
  */
 private void createTypeHierarchyBasedOnRegion(HashMap allOpenablesInRegion, IProgressMonitor monitor) {
 	
-	int size = allOpenablesInRegion.size();
-	if (size != 0) {
+	try {
+		int size = allOpenablesInRegion.size();		
+		if (monitor != null) monitor.beginTask("", size * 2/* 1 for build binding, 1 for connect hierarchy*/); //$NON-NLS-1$
 		this.infoToHandle = new HashMap(size);
-	}
+		Iterator javaProjects = allOpenablesInRegion.entrySet().iterator();
+		while (javaProjects.hasNext()) {
+			Map.Entry entry = (Map.Entry) javaProjects.next();  
+			JavaProject project = (JavaProject) entry.getKey();
+			ArrayList allOpenables = (ArrayList) entry.getValue();
+			Openable[] openables = new Openable[allOpenables.size()];
+			allOpenables.toArray(openables);
 	
-	Iterator javaProjects = allOpenablesInRegion.keySet().iterator();
-	while (javaProjects.hasNext()) {
-		ArrayList allOpenables = (ArrayList) allOpenablesInRegion.get(javaProjects.next());
-		Openable[] openables = new Openable[allOpenables.size()];
-		allOpenables.toArray(openables);
-	
-		try {
-			// resolve
-			if (monitor != null) monitor.beginTask("", size * 2/* 1 for build binding, 1 for connect hierarchy*/); //$NON-NLS-1$
-			if (size > 0) {
+			try {
+				// resolve
+				SearchableEnvironment searchableEnvironment = project.newSearchableNameEnvironment(this.hierarchy.workingCopies);
+				this.nameLookup = searchableEnvironment.nameLookup;
 				this.hierarchyResolver.resolve(openables, null, monitor);
-			}
-		} finally {
-			if (monitor != null) monitor.done();
+			} catch (JavaModelException e) {
+				// project doesn't exit: ignore
+			} 
 		}
+	} finally {
+		if (monitor != null) monitor.done();
 	}
 }
 	
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 f9ae011..4dd08ac 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -14,17 +14,11 @@
 
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.jdt.core.*;
-import org.eclipse.jdt.core.IJavaElement;
-import org.eclipse.jdt.core.IJavaElementDelta;
-import org.eclipse.jdt.core.IJavaProject;
-import org.eclipse.jdt.core.IOpenable;
-import org.eclipse.jdt.core.IRegion;
-import org.eclipse.jdt.core.IType;
-import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.search.IJavaSearchScope;
 import org.eclipse.jdt.internal.core.CompilationUnit;
 import org.eclipse.jdt.internal.core.JavaElement;
 import org.eclipse.jdt.internal.core.Openable;
+import org.eclipse.jdt.internal.core.Region;
 import org.eclipse.jdt.internal.core.TypeVector;
 
 public class RegionBasedTypeHierarchy extends TypeHierarchy {
@@ -42,8 +36,37 @@
  */
 public RegionBasedTypeHierarchy(IRegion region, ICompilationUnit[] workingCopies, IType type, boolean computeSubtypes) {
 	super(type, workingCopies, (IJavaSearchScope)null, computeSubtypes);
-	this.region = region;
+	
+	Region newRegion = new Region() {
+		public void add(IJavaElement element) {
+			if (!contains(element)) {
+				//"new" element added to region
+				removeAllChildren(element);
+				fRootElements.add(element);
+				if (element.getElementType() == IJavaElement.JAVA_PROJECT) {
+					// add jar roots as well so that jars don't rely on their parent to know 
+					// if they are contained in the region
+					// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=146615)
+					try {
+						IPackageFragmentRoot[] roots = ((IJavaProject) element).getPackageFragmentRoots();
+						for (int i = 0, length = roots.length; i < length; i++) {
+							if (roots[i].isArchive() && !fRootElements.contains(roots[i]))
+								fRootElements.add(roots[i]);
+						}
+					} catch (JavaModelException e) {
+						// project doesn't exist
+					}
+				}
+				fRootElements.trimToSize();
+			}
+		}
+	};
 	IJavaElement[] elements = region.getElements();
+	for (int i = 0, length = elements.length; i < length; i++) {
+		newRegion.add(elements[i]);
+		
+	}
+	this.region = newRegion;
 	if (elements.length > 0)
 		this.project = elements[0].getJavaProject();
 }
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 8c8609b..7397703 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -25,31 +25,11 @@
 import org.eclipse.core.runtime.ISafeRunnable;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.OperationCanceledException;
-import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.SafeRunner;
 import org.eclipse.jdt.core.*;
-import org.eclipse.jdt.core.ElementChangedEvent;
-import org.eclipse.jdt.core.IClasspathEntry;
-import org.eclipse.jdt.core.IElementChangedListener;
-import org.eclipse.jdt.core.IJavaElement;
-import org.eclipse.jdt.core.IJavaElementDelta;
-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.ITypeHierarchy;
-import org.eclipse.jdt.core.ITypeHierarchyChangedListener;
-import org.eclipse.jdt.core.JavaCore;
-import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.search.IJavaSearchScope;
 import org.eclipse.jdt.core.search.SearchEngine;
 import org.eclipse.jdt.internal.core.*;
-import org.eclipse.jdt.internal.core.CompilationUnit;
-import org.eclipse.jdt.internal.core.JavaElement;
-import org.eclipse.jdt.internal.core.JavaModelStatus;
-import org.eclipse.jdt.internal.core.JavaProject;
-import org.eclipse.jdt.internal.core.Openable;
-import org.eclipse.jdt.internal.core.Region;
-import org.eclipse.jdt.internal.core.TypeVector;
 import org.eclipse.jdt.internal.core.util.Messages;
 import org.eclipse.jdt.internal.core.util.Util;
 
@@ -170,7 +150,7 @@
  * Creates a TypeHierarchy on the given type.
  */
 public TypeHierarchy(IType type, ICompilationUnit[] workingCopies, IJavaSearchScope scope, boolean computeSubtypes) {
-	this.focusType = type;
+	this.focusType = type == null ? null : (IType) ((JavaElement) type).unresolved(); // unsure the focus type is unresolved (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=92357)
 	this.workingCopies = workingCopies;
 	this.computeSubtypes = computeSubtypes;
 	this.scope = scope;
@@ -378,7 +358,7 @@
 	listeners = (ArrayList)listeners.clone();
 	for (int i= 0; i < listeners.size(); i++) {
 		final ITypeHierarchyChangedListener listener= (ITypeHierarchyChangedListener)listeners.get(i);
-		Platform.run(new ISafeRunnable() {
+		SafeRunner.run(new ISafeRunnable() {
 			public void handleException(Throwable exception) {
 				Util.log(exception, "Exception occurred in listener of Type hierarchy change notification"); //$NON-NLS-1$
 			}
@@ -544,14 +524,15 @@
  * @see #getExtendingInterfaces
  */
 private IType[] getExtendingInterfaces0(IType extendedInterface) {
-	Iterator iter = this.typeToSuperInterfaces.keySet().iterator();
+	Iterator iter = this.typeToSuperInterfaces.entrySet().iterator();
 	ArrayList interfaceList = new ArrayList();
 	while (iter.hasNext()) {
-		IType type = (IType) iter.next();
+		Map.Entry entry = (Map.Entry) iter.next();
+		IType type = (IType) entry.getKey();
 		if (!this.isInterface(type)) {
 			continue;
 		}
-		IType[] superInterfaces = (IType[]) this.typeToSuperInterfaces.get(type);
+		IType[] superInterfaces = (IType[]) entry.getValue();
 		if (superInterfaces != null) {
 			for (int i = 0; i < superInterfaces.length; i++) {
 				IType superInterface = superInterfaces[i];
@@ -580,14 +561,15 @@
  */
 private IType[] getImplementingClasses0(IType interfce) {
 	
-	Iterator iter = this.typeToSuperInterfaces.keySet().iterator();
+	Iterator iter = this.typeToSuperInterfaces.entrySet().iterator();
 	ArrayList iMenters = new ArrayList();
 	while (iter.hasNext()) {
-		IType type = (IType) iter.next();
+		Map.Entry entry = (Map.Entry) iter.next();
+		IType type = (IType) entry.getKey();
 		if (this.isInterface(type)) {
 			continue;
 		}
-		IType[] types = (IType[]) this.typeToSuperInterfaces.get(type);
+		IType[] types = (IType[]) entry.getValue();
 		for (int i = 0; i < types.length; i++) {
 			IType iFace = types[i];
 			if (iFace.equals(interfce)) {
@@ -769,7 +751,7 @@
 		String superclassName = type.getSuperclassName();
 		if (superclassName != null) {
 			int lastSeparator = superclassName.lastIndexOf('.');
-			String simpleName = (lastSeparator > -1) ? superclassName.substring(lastSeparator) : superclassName;
+			String simpleName = superclassName.substring(lastSeparator+1);
 			if (hasTypeNamed(simpleName)) return true;
 		}
 	
@@ -779,7 +761,7 @@
 			for (int i = 0, length = superinterfaceNames.length; i < length; i++) {
 				String superinterfaceName = superinterfaceNames[i];
 				int lastSeparator = superinterfaceName.lastIndexOf('.');
-				String simpleName = (lastSeparator > -1) ? superinterfaceName.substring(lastSeparator) : superinterfaceName;
+				String simpleName = superinterfaceName.substring(lastSeparator+1);
 				if (hasTypeNamed(simpleName)) return true;
 			}
 		}
@@ -873,7 +855,7 @@
 		case IJavaElementDelta.ADDED :
 			try {
 				// if the added project is on the classpath, then the hierarchy has changed
-				IClasspathEntry[] classpath = ((JavaProject)this.javaProject()).getExpandedClasspath(true);
+				IClasspathEntry[] classpath = ((JavaProject)this.javaProject()).getExpandedClasspath();
 				for (int i = 0; i < classpath.length; i++) {
 					if (classpath[i].getEntryKind() == IClasspathEntry.CPE_PROJECT 
 							&& classpath[i].getPath().equals(element.getPath())) {
@@ -882,7 +864,7 @@
 				}
 				if (this.focusType != null) {
 					// if the hierarchy's project is on the added project classpath, then the hierarchy has changed
-					classpath = ((JavaProject)element).getExpandedClasspath(true);
+					classpath = ((JavaProject)element).getExpandedClasspath();
 					IPath hierarchyProject = javaProject().getPath();
 					for (int i = 0; i < classpath.length; i++) {
 						if (classpath[i].getEntryKind() == IClasspathEntry.CPE_PROJECT 
@@ -948,12 +930,9 @@
 					for (int i = 0; i < elements.length; i++) {
 						JavaProject javaProject = (JavaProject)elements[i];
 						try {
-							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)) {
-									return true;
-								}
+							IClasspathEntry entry = javaProject.getClasspathEntryFor(rootPath);
+							if (entry != null) {
+								return true;
 							}
 						} catch (JavaModelException e) {
 							// igmore this project
@@ -1233,11 +1212,11 @@
 	try {
 		this.progressMonitor = monitor;
 		if (monitor != null) {
-			if (this.focusType != null) {
-				monitor.beginTask(Messages.bind(Messages.hierarchy_creatingOnType, this.focusType.getFullyQualifiedName()), 100); 
-			} else {
-				monitor.beginTask(Messages.hierarchy_creating, 100); 
-			}
+			monitor.beginTask(
+					this.focusType != null ? 
+							Messages.bind(Messages.hierarchy_creatingOnType, this.focusType.getFullyQualifiedName()) : 
+							Messages.hierarchy_creating, 
+					100); 
 		}
 		long start = -1;
 		if (DEBUG) {
@@ -1307,30 +1286,32 @@
 			hashtable.put(this.focusType, index);
 			hashtable2.put(index, this.focusType);
 		}
-		Object[] types = this.classToSuperclass.keySet().toArray();
+		Object[] types = this.classToSuperclass.entrySet().toArray();
 		for (int i = 0; i < types.length; i++) {
-			Object t = types[i];
+			Map.Entry entry = (Map.Entry) types[i];
+			Object t = entry.getKey();
 			if(hashtable.get(t) == null) {
 				Integer index = new Integer(count++);
 				hashtable.put(t, index);
 				hashtable2.put(index, t);
 			}
-			Object superClass = this.classToSuperclass.get(t);
+			Object superClass = entry.getValue();
 			if(superClass != null && hashtable.get(superClass) == null) {
 				Integer index = new Integer(count++);
 				hashtable.put(superClass, index);
 				hashtable2.put(index, superClass);
 			}
 		}
-		types = this.typeToSuperInterfaces.keySet().toArray();
+		types = this.typeToSuperInterfaces.entrySet().toArray();
 		for (int i = 0; i < types.length; i++) {
-			Object t = types[i];
+			Map.Entry entry = (Map.Entry) types[i];
+			Object t = entry.getKey();
 			if(hashtable.get(t) == null) {
 				Integer index = new Integer(count++);
 				hashtable.put(t, index);
 				hashtable2.put(index, t);
 			}
-			Object[] sp = (Object[])this.typeToSuperInterfaces.get(t);
+			Object[] sp = (Object[]) entry.getValue();
 			if(sp != null) {
 				for (int j = 0; j < sp.length; j++) {
 					Object superInterface = sp[j];
@@ -1392,10 +1373,11 @@
 		output.write(SEPARATOR1);
 		
 		// save superclasses
-		types = this.classToSuperclass.keySet().toArray();
+		types = this.classToSuperclass.entrySet().toArray();
 		for (int i = 0; i < types.length; i++) {
-			IJavaElement key = (IJavaElement)types[i];
-			IJavaElement value = (IJavaElement)this.classToSuperclass.get(key);
+			Map.Entry entry = (Map.Entry) types[i];
+			IJavaElement key = (IJavaElement) entry.getKey();
+			IJavaElement value = (IJavaElement) entry.getValue();
 			
 			output.write(((Integer)hashtable.get(key)).toString().getBytes());
 			output.write('>');
@@ -1405,10 +1387,11 @@
 		output.write(SEPARATOR1);
 		
 		// save superinterfaces
-		types = this.typeToSuperInterfaces.keySet().toArray();
+		types = this.typeToSuperInterfaces.entrySet().toArray();
 		for (int i = 0; i < types.length; i++) {
-			IJavaElement key = (IJavaElement)types[i];
-			IJavaElement[] values = (IJavaElement[])this.typeToSuperInterfaces.get(key);
+			Map.Entry entry = (Map.Entry) types[i];
+			IJavaElement key = (IJavaElement) entry.getKey();
+			IJavaElement[] values = (IJavaElement[]) entry.getValue();
 			
 			if(values.length > 0) {
 				output.write(((Integer)hashtable.get(key)).toString().getBytes());
@@ -1491,17 +1474,16 @@
 			toString(buffer, this.focusType, 1, false);
 		} else {
 			buffer.append("Sub types of root classes:\n"); //$NON-NLS-1$
-			IType[] roots= getRootClasses();
+			IJavaElement[] roots = Util.sortCopy(getRootClasses());
 			for (int i= 0; i < roots.length; i++) {
-				toString(buffer, roots[i], 1, false);
+				toString(buffer, (IType) roots[i], 1, false);
 			}
 		}
 		if (this.rootClasses.size > 1) {
 			buffer.append("Root classes:\n"); //$NON-NLS-1$
-			IType[] roots = this.getRootClasses();
+			IJavaElement[] roots = Util.sortCopy(getRootClasses());
 			for (int i = 0, length = roots.length; i < length; i++) {
-				IType type = roots[i];
-				toString(buffer, type, 1, false);
+				toString(buffer, (IType) roots[i], 1, false);
 			}
 		} else if (this.rootClasses.size == 0) {
 			// see http://bugs.eclipse.org/bugs/show_bug.cgi?id=24691
@@ -1519,11 +1501,12 @@
  */
 private void toString(StringBuffer buffer, IType type, int indent, boolean ascendant) {
 	IType[] types= ascendant ? getSupertypes(type) : getSubtypes(type);
-	for (int i= 0; i < types.length; i++) {
+	IJavaElement[] sortedTypes = Util.sortCopy(types);
+	for (int i= 0; i < sortedTypes.length; i++) {
 		for (int j= 0; j < indent; j++) {
 			buffer.append("  "); //$NON-NLS-1$
 		}
-		JavaElement element = (JavaElement)types[i];
+		JavaElement element = (JavaElement)sortedTypes[i];
 		buffer.append(element.toStringWithAncestors(false/*don't show key*/));
 		buffer.append('\n');
 		toString(buffer, types[i], indent + 1, ascendant);
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 3702006..7c67a47 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 db3c55b..8e75cee 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 914af5c..3e68d04 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -14,8 +14,8 @@
 import java.util.Map;
 
 import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.compiler.CategorizedProblem;
 import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.core.compiler.IProblem;
 import org.eclipse.jdt.core.jdom.*;
 import org.eclipse.jdt.internal.compiler.DocumentElementParser;
 import org.eclipse.jdt.internal.compiler.IDocumentElementRequestor;
@@ -121,7 +121,7 @@
  *
  * @see IDocumentElementRequestor
  */
-public void acceptProblem(IProblem problem){
+public void acceptProblem(CategorizedProblem problem){
 	if (fBuildingSingleMember && fFinishedSingleMember) {
 		return;
 	}
@@ -268,7 +268,10 @@
 		return null;
 	}
 	if (fNode != null) fNode.normalize(this);
-	return (IDOMType)fNode;
+	if (fNode instanceof IDOMType) {
+		return (IDOMType) fNode;
+	}
+	return null;
 }
 /**
  * Creates a new DOMMethod and inizializes.
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 e06d1bb..d150c83 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 eba8825..3994126 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 1a99239..8c40c0a 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 cba8276..74aaf01 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 f5555f2..19c1242 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -13,7 +13,7 @@
 import org.eclipse.jdt.core.Flags;
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.jdom.*;
-import org.eclipse.jdt.internal.compiler.env.IConstants;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
 import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
 /**
  * DOMMember provides an implementation of IDOMMember.
@@ -283,10 +283,10 @@
 	setHasComment(comment != null);
 	/* see 1FVIJAH */
 	if (comment != null && comment.indexOf("@deprecated") >= 0) { //$NON-NLS-1$
-		fFlags= fFlags | IConstants.AccDeprecated;
+		fFlags= fFlags | ClassFileConstants.AccDeprecated;
 		return;
 	}
-	fFlags= fFlags & (~IConstants.AccDeprecated);
+	fFlags= fFlags & (~ClassFileConstants.AccDeprecated);
 }
 /**
  * @see IDOMMember#setFlags(int)
@@ -294,9 +294,9 @@
 public void setFlags(int flags) {
 	becomeDetailed();
 	if (Flags.isDeprecated(fFlags)) {
-		fFlags= flags | IConstants.AccDeprecated;
+		fFlags= flags | ClassFileConstants.AccDeprecated;
 	} else {
-		fFlags= flags & (~IConstants.AccDeprecated);
+		fFlags= flags & (~ClassFileConstants.AccDeprecated);
 	}
 	fragment();
 	fModifiers= generateFlags();
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 c83d0eb..db80cfc 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -118,7 +118,7 @@
 	 * The formal type parameters.
 	 * @since 3.0
 	 */
-	protected String[] fTypeParameters = new String[0];
+	protected String[] fTypeParameters = CharOperation.NO_STRINGS;
 
 	/**
 	 * Default value for this attotation type member (only),
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 b9d4291..8da9dbf 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 3bc7454..4280885 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 f3a708d..faff058 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -15,6 +15,7 @@
 import org.eclipse.jdt.core.ICompilationUnit;
 import org.eclipse.jdt.core.IJavaElement;
 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.*;
 import org.eclipse.jdt.internal.compiler.parser.Scanner;
@@ -32,8 +33,6 @@
  */ 
 // TODO (jerome) - add implementation support for 1.5 features
 /* package */ class DOMType extends DOMMember implements IDOMType {
-
-	private static final String[] EMPTY_SUPERINTERFACES = new String[] {};
 	/**
 	 * The 'class' or 'interface' keyword if altered
 	 * from the documents contents, otherwise <code>null</code>.
@@ -114,13 +113,13 @@
 	 * <code>null</code> when this type does not extend
 	 * or implement any interfaces.
 	 */
-	protected String[] fSuperInterfaces= new String[0];
+	protected String[] fSuperInterfaces= CharOperation.NO_STRINGS;
 	
 	/**
 	 * The formal type parameters.
 	 * @since 3.0
 	 */
-	protected String[] fTypeParameters = new String[0];
+	protected String[] fTypeParameters = CharOperation.NO_STRINGS;
 
 	/**
 	 * Indicates this type is an enum class.
@@ -325,6 +324,9 @@
 		} else {
 			if (fSuperclassRange[0] < 0) {
 				buffer.append(' ');
+			} else if (fImplementsRange[0] > 0) {
+				buffer.append(fDocument, fSuperclassRange[1] + 1, fImplementsRange[0] - fSuperclassRange[1] - 1);
+				buffer.append(fDocument, fInterfacesRange[1] + 1, fOpenBodyRange[0] - fInterfacesRange[1] - 1);
 			} else {
 				buffer.append(fDocument, fSuperclassRange[1] + 1, fOpenBodyRange[0] - fSuperclassRange[1] - 1);
 			}
@@ -693,7 +695,7 @@
 	fSuperInterfaces= names;
 	if (names.length == 0) {
 		fInterfaces= null;
-		fSuperInterfaces= EMPTY_SUPERINTERFACES;
+		fSuperInterfaces= CharOperation.NO_STRINGS;
 		setMask(MASK_TYPE_HAS_INTERFACES, false);
 	} else {
 		setMask(MASK_TYPE_HAS_INTERFACES, true);
@@ -785,7 +787,7 @@
 		// annotation types are always interface with no superclass or superinterfaces
 		setClass(false);
 		setSuperclass(null);
-		setSuperInterfaces(new String[0]);
+		setSuperInterfaces(CharOperation.NO_STRINGS);
 	}
 }
 
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 f53b02c..db9bcba 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 e9b126e..ff5b800 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 6442feb..b90c530 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -13,13 +13,13 @@
 import java.util.Map;
 
 import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.compiler.CategorizedProblem;
 import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.core.compiler.IProblem;
 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.ast.TypeDeclaration;
 import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
-import org.eclipse.jdt.internal.compiler.env.IGenericType;
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
 /**
@@ -33,13 +33,13 @@
 /**
  * Does nothing.
  */
-public void acceptProblem(IProblem problem) {
+public void acceptProblem(CategorizedProblem problem) {
 	// nothing to do
 }
 
-public void acceptImport(int declarationStart, int declarationEnd, char[] name, boolean onDemand, int modifiers) {
+public void acceptImport(int declarationStart, int declarationEnd, char[][] tokens, boolean onDemand, int modifiers) {
 	int[] sourceRange = {declarationStart, declarationEnd};
-	String importName = new String(name);
+	String importName = new String(CharOperation.concatWith(tokens, '.'));
 	/** name is set to contain the '*' */
 	if (onDemand) {
 		importName+=".*"; //$NON-NLS-1$
@@ -130,7 +130,7 @@
 		int[] sourceRange = {typeInfo.declarationStart, -1}; // will be fixed in the exit
 		int[] nameRange = new int[] {typeInfo.nameSourceStart, typeInfo.nameSourceEnd};
 		fNode = new DOMType(fDocument, sourceRange, new String(typeInfo.name), nameRange,
-			typeInfo.modifiers, CharOperation.charArrayToStringArray(typeInfo.superinterfaces), typeInfo.kind == IGenericType.CLASS_DECL); // TODO (jerome) should pass in kind
+			typeInfo.modifiers, CharOperation.charArrayToStringArray(typeInfo.superinterfaces), TypeDeclaration.kind(typeInfo.modifiers) == TypeDeclaration.CLASS_DECL); // TODO (jerome) should pass in kind
 		addChild(fNode);
 		fStack.push(fNode);
 		
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 f0d7e6f..e4364ba 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -121,7 +121,7 @@
 			int count = 0;
 			public boolean visit(TypeDeclaration typeDeclaration, BlockScope scope) {
 				if (result != null) return false;
-				if ((typeDeclaration.bits & ASTNode.IsAnonymousTypeMASK) != 0) {
+				if ((typeDeclaration.bits & ASTNode.IsAnonymousType) != 0) {
 					if (findAnonymous && ++count == occurenceCount) {
 						result = typeDeclaration;
 					}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Annotation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Annotation.java
index 3a2343d..475021f 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Annotation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Annotation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/AnnotationComponent.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/AnnotationComponent.java
index 93e194b..30ed3c5 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/AnnotationComponent.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/AnnotationComponent.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/AnnotationDefaultAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/AnnotationDefaultAttribute.java
index 4f7e49c..ad4cd78 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/AnnotationDefaultAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/AnnotationDefaultAttribute.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/BindingKeyParser.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/BindingKeyParser.java
index 81b4fe7..d0248ce 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/BindingKeyParser.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/BindingKeyParser.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005 IBM Corporation and others.
+ * Copyright (c) 2005, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -17,7 +17,9 @@
 	
 	int keyStart;
 	
-	class Scanner {
+	static final char C_THROWN = '|';
+
+	static class Scanner {
 		static final int PACKAGE = 0;
 		static final int TYPE = 1;
 		static final int FIELD = 2;
@@ -116,10 +118,10 @@
 			return this.index < this.source.length && "LIZVCDBFJS[!".indexOf(this.source[this.index]) != -1; //$NON-NLS-1$
 		}
 		
-		boolean isAtFlagsStart() {
+		boolean isAtThrownStart() {
 			return 
 				this.index < this.source.length
-				&& this.source[this.index] == '^';
+				&& this.source[this.index] == C_THROWN;
 		}
 		
 		boolean isAtTypeVariableStart() {
@@ -161,7 +163,8 @@
 						break;
 					case 'L':
 					case 'T':
-						if (this.index == previousTokenEnd) {
+						if (this.index == previousTokenEnd 
+								&& (this.index == 0 || this.source[this.index-1] != '.')) { // case of field or method starting with one of the character above
 							this.start = this.index+1;
 						}
 						break;
@@ -174,28 +177,6 @@
 							return this.token;
 						}
 						break;
-					case '^':
-						if (this.index == previousTokenEnd) {
-							this.index++;
-							this.start = this.index;
-							while (this.index < length && Character.isDigit(this.source[this.index]))
-								this.index++;
-							this.token = FLAGS;
-							return this.token;
-						} else {
-							switch (this.token) {
-								case METHOD:
-								case LOCAL_VAR:
-									this.token = LOCAL_VAR;
-									break;
-								case TYPE:
-								case BASE_TYPE:
-									if (this.index > this.start && this.source[this.start-1] == '.')
-										this.token = FIELD;
-									break;
-							}							
-							return this.token;
-						}
 					case '$':
 					case '~':
 						if (this.index == previousTokenEnd) {
@@ -306,7 +287,7 @@
 				switch (this.source[this.index]) {
 					case '#':
 					case '%':
-					case '^':
+					case C_THROWN:
 						return;
 					case ':':
 						if (braket == 0)
@@ -325,6 +306,11 @@
 			}
 		}
 		
+		void skipThrownStart() {
+			while (this.index < this.source.length && this.source[this.index] == C_THROWN)
+				this.index++;
+		}
+
 		void skipParametersStart() {
 			while (this.index < this.source.length && (this.source[this.index] == '<' || this.source[this.index] == '%'))
 				this.index++;
@@ -429,6 +415,10 @@
 		// default is to do nothing
 	}
 	
+	public void consumeException() {
+		// default is to do nothing
+	}
+
 	public void consumeField(char[] fieldName) {
 		// default is to do nothing
 	}
@@ -541,72 +531,75 @@
 	}
 
 	public void parse(boolean pauseAfterFullyQualifiedName) {
-		if (!this.parsingPaused) {
-			// fully qualified name
-			parseFullyQualifiedName();
-			if (pauseAfterFullyQualifiedName) {
-				this.parsingPaused = true;
+		try {
+			if (!this.parsingPaused) {
+				// fully qualified name
+				parseFullyQualifiedName();
+				parseSecondaryType();
+				if (pauseAfterFullyQualifiedName) {
+					this.parsingPaused = true;
+					return;
+				}
+			}
+			if (!hasTypeName()) {
+				consumeKey();
 				return;
 			}
-		}
-		if (!hasTypeName()) {
-			consumeKey();
-			return;
-		}
-		consumeTopLevelType();
-		parseSecondaryType();
-		parseInnerType();
-		
-		if (this.scanner.isAtParametersStart()) {
-			this.scanner.skipParametersStart();
-			if (this.scanner.isAtTypeParameterStart())	{		
-				// generic type
-				parseGenericType();
-			 	// skip ";>"
-			 	this.scanner.skipParametersEnd();
-				// local type in generic type
-				parseInnerType();
-			} else if (this.scanner.isAtTypeArgumentStart())
-				// parameterized type
-				parseParameterizedType(null/*top level type or member type with raw enclosing type*/, false/*no raw*/);
-			else if (this.scanner.isAtRawTypeEnd())
-				// raw type
-				parseRawType();
-		} else {
-			// non-generic type
-			consumeNonGenericType();
-		}
-		
-		consumeType();
-		this.scanner.skipTypeEnd();
-		parseFlags();
-		
-		if (this.scanner.isAtFieldOrMethodStart()) {
-			switch (this.scanner.nextToken()) {
- 				case Scanner.FIELD:
- 					parseField();
- 					return;
- 				case Scanner.METHOD:
- 					parseMethod();
- 					if (this.scanner.isAtLocalVariableStart()) {
- 						parseLocalVariable();
- 					} else if (this.scanner.isAtTypeVariableStart()) {
-						parseTypeVariable();
-					}
-			 		break;
- 				default:
- 					malformedKey();
- 					return;
+			consumeTopLevelType();
+			parseInnerType();
+			
+			if (this.scanner.isAtParametersStart()) {
+				this.scanner.skipParametersStart();
+				if (this.scanner.isAtTypeParameterStart())	{		
+					// generic type
+					parseGenericType();
+				 	// skip ";>"
+				 	this.scanner.skipParametersEnd();
+					// local type in generic type
+					parseInnerType();
+				} else if (this.scanner.isAtTypeArgumentStart())
+					// parameterized type
+					parseParameterizedType(null/*top level type or member type with raw enclosing type*/, false/*no raw*/);
+				else if (this.scanner.isAtRawTypeEnd())
+					// raw type
+					parseRawType();
+			} else {
+				// non-generic type
+				consumeNonGenericType();
 			}
-		} else if (this.scanner.isAtTypeVariableStart()) {
-			parseTypeVariable();
-		} else if (this.scanner.isAtWildcardStart()) {
-			parseWildcard();
-		} else if (this.scanner.isAtTypeWithCaptureStart()) {
-			parseTypeWithCapture();
+			
+			consumeType();
+			this.scanner.skipTypeEnd();
+			
+			if (this.scanner.isAtFieldOrMethodStart()) {
+				switch (this.scanner.nextToken()) {
+					case Scanner.FIELD:
+						parseField();
+						return;
+					case Scanner.METHOD:
+						parseMethod();
+						if (this.scanner.isAtLocalVariableStart()) {
+							parseLocalVariable();
+						} else if (this.scanner.isAtTypeVariableStart()) {
+							parseTypeVariable();
+						}
+				 		break;
+					default:
+						malformedKey();
+						return;
+				}
+			} else if (this.scanner.isAtTypeVariableStart()) {
+				parseTypeVariable();
+			} else if (this.scanner.isAtWildcardStart()) {
+				parseWildcard();
+			} else if (this.scanner.isAtTypeWithCaptureStart()) {
+				parseTypeWithCapture();
+			}
+			
+			consumeKey();
+		} catch (IllegalArgumentException e) {
+			// the given key was illegal
 		}
-		
-		consumeKey();
 	}
 	
 	private void parseFullyQualifiedName() {
@@ -704,7 +697,6 @@
 			parseLocalVariable();
 		} else {
 		 	consumeLocalVar(varName);
-			parseFlags();
 		}
  	}
 	
@@ -713,7 +705,9 @@
 	 	this.scanner.skipMethodSignature();
 	 	char[] signature = this.scanner.getTokenSource();
 	 	consumeMethod(selector, signature);
-		parseFlags();
+	 	if (this.scanner.isAtThrownStart()) {
+			parseThrownExceptions();
+	 	}
 		if (this.scanner.isAtParametersStart())
 			parseParameterizedMethod();
 	}
@@ -743,9 +737,14 @@
  		consumeField(fieldName);
 	}
 	
-	private void parseFlags() {
-		if (!this.scanner.isAtFlagsStart() || this.scanner.nextToken() != Scanner.FLAGS) return;
-		consumeModifiers(this.scanner.getTokenSource());
+	private void parseThrownExceptions() {
+		while (this.scanner.isAtThrownStart()) {
+			this.scanner.skipThrownStart();
+			BindingKeyParser parser = newParser();
+			parser.parse();
+			consumeParser(parser);
+			consumeException();
+		}
 	}
 	
 	private void parseParameterizedType(char[] typeName, boolean isRaw) {
@@ -758,7 +757,6 @@
 	 	this.scanner.skipParametersEnd();
 		consumeParameterizedType(typeName, isRaw);
 		this.scanner.skipTypeEnd();
-		parseFlags();
 	 	if (this.scanner.isAtMemberTypeStart() && this.scanner.nextToken() == Scanner.TYPE) {
 	 		typeName = this.scanner.getTokenSource();
 			if (this.scanner.isAtParametersStart()) {
@@ -772,6 +770,15 @@
 	private void parseRawType() {
 		this.scanner.skipParametersEnd();
 		consumeRawType();
+		this.scanner.skipTypeEnd();
+	 	if (this.scanner.isAtMemberTypeStart() && this.scanner.nextToken() == Scanner.TYPE) {
+	 		char[] typeName = this.scanner.getTokenSource();
+			if (this.scanner.isAtParametersStart()) {
+				this.scanner.skipParametersStart();
+		 		parseParameterizedType(typeName, this.scanner.isAtRawTypeEnd());
+			} else
+				consumeParameterizedType(typeName, true/*raw*/);
+	 	}
 	}
 	
 	private void parseReturnType() {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/BindingKeyResolver.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/BindingKeyResolver.java
index 27c74f2..32e16ba 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/BindingKeyResolver.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/BindingKeyResolver.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005 IBM Corporation and others.
+ * Copyright (c) 2005, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -27,7 +27,6 @@
 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.Wildcard;
 import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
-import org.eclipse.jdt.internal.compiler.lookup.BaseTypes;
 import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding;
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
@@ -38,7 +37,6 @@
 import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
 import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
 import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
-import org.eclipse.jdt.internal.compiler.lookup.ParameterizedGenericMethodBinding;
 import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
 import org.eclipse.jdt.internal.compiler.lookup.RawTypeBinding;
 import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
@@ -57,6 +55,7 @@
 	ReferenceBinding genericType;
 	MethodBinding methodBinding;
 	
+	char[] secondarySimpleName;
 	CompilationUnitDeclaration parsedUnit;
 	BlockScope scope;
 	TypeBinding typeBinding;
@@ -188,8 +187,12 @@
 		this.typeBinding = captureFinder.capture;
 	}
 	
+	public void consumeException() {
+		this.types = new ArrayList();
+	}
+
 	public void consumeField(char[] fieldName) {
-		FieldBinding[] fields = ((ReferenceBinding) this.typeBinding).fields();
+		FieldBinding[] fields = ((ReferenceBinding) this.typeBinding).availableFields(); // resilience
 	 	for (int i = 0, length = fields.length; i < length; i++) {
 			FieldBinding field = fields[i];
 			if (CharOperation.equals(fieldName, field.name)) {
@@ -205,9 +208,9 @@
 			return;
 		TypeBinding[] arguments = getTypeBindingArguments();
 		if (arguments.length != this.methodBinding.typeVariables().length)
-			this.methodBinding = new ParameterizedGenericMethodBinding(this.methodBinding, (RawTypeBinding) null, this.environment);
+			this.methodBinding = this.environment.createParameterizedGenericMethod(this.methodBinding, (RawTypeBinding) null);
 		else
-	 		this.methodBinding = new ParameterizedGenericMethodBinding(this.methodBinding, arguments, this.environment);
+	 		this.methodBinding = this.environment.createParameterizedGenericMethod(this.methodBinding, arguments);
 		this.compilerBinding = this.methodBinding;
 	}
 	
@@ -235,7 +238,7 @@
 	}
 
 	public void consumeMethod(char[] selector, char[] signature) {
-		MethodBinding[] methods = ((ReferenceBinding) this.typeBinding).methods();
+		MethodBinding[] methods = ((ReferenceBinding) this.typeBinding).availableMethods(); // resilience
 	 	for (int i = 0, methodLength = methods.length; i < methodLength; i++) {
 			MethodBinding method = methods[i];
 			if (CharOperation.equals(selector, method.selector) || (selector.length == 0 && method.isConstructor())) {
@@ -264,8 +267,13 @@
 	public void consumeParameterizedType(char[] simpleTypeName, boolean isRaw) {
 		TypeBinding[] arguments = getTypeBindingArguments();
 		if (simpleTypeName != null) {
-			// parameterized member type with parameterized enclosing type
-			this.genericType = this.genericType.getMemberType(simpleTypeName);
+			if (this.genericType == null) {
+				// parameterized member type with raw enclosing type
+				this.genericType = ((ReferenceBinding) this.typeBinding).getMemberType(simpleTypeName);
+			} else {
+				// parameterized member type with parameterized enclosing type
+				this.genericType = this.genericType.getMemberType(simpleTypeName);
+			}
 			if (!isRaw)
 				this.typeBinding = this.environment.createParameterizedType(this.genericType, arguments, (ReferenceBinding) this.typeBinding);
 			else
@@ -298,12 +306,10 @@
 	
 	public void consumeRawType() {
 		if (this.typeBinding == null) return;
-		this.typeBinding = this.environment.createRawType((ReferenceBinding) this.typeBinding, this.typeBinding.enclosingType());
+		this.typeBinding = this.environment.convertToRawType(this.typeBinding);
 	}
 	public void consumeSecondaryType(char[] simpleTypeName) {
-		if (this.parsedUnit == null) return;
-		this.typeDeclaration = null; // start from the parsed unit
-		this.typeBinding = getTypeBinding(simpleTypeName);
+		this.secondarySimpleName = simpleTypeName;
 	}
 	
 	public void consumeFullyQualifiedName(char[] fullyQualifiedName) {
@@ -318,7 +324,7 @@
 		if (this.parsedUnit == null) {
 			this.typeBinding = getBinaryBinding();
 		} else {
-			char[] typeName = this.compoundName[this.compoundName.length-1];
+			char[] typeName = this.secondarySimpleName == null ? this.compoundName[this.compoundName.length-1] : this.secondarySimpleName;
 			this.typeBinding = getTypeBinding(typeName);
 		}
 	}
@@ -333,7 +339,7 @@
 	public void consumeTypeVariable(char[] position, char[] typeVariableName) {
 		if (position.length > 0) {
 			int pos = Integer.parseInt(new String(position));
-			MethodBinding[] methods = ((ReferenceBinding) this.typeBinding).methods();
+			MethodBinding[] methods = ((ReferenceBinding) this.typeBinding).availableMethods(); // resilience
 			if (methods != null && pos < methods.length) {
 				this.methodBinding = methods[pos];
 			}
@@ -380,25 +386,25 @@
 	private TypeBinding getBaseTypeBinding(char[] signature) {
 		switch (signature[0]) {
 			case 'I' :
-				return BaseTypes.IntBinding;
+				return TypeBinding.INT;
 			case 'Z' :
-				return BaseTypes.BooleanBinding;
+				return TypeBinding.BOOLEAN;
 			case 'V' :
-				return BaseTypes.VoidBinding;
+				return TypeBinding.VOID;
 			case 'C' :
-				return BaseTypes.CharBinding;
+				return TypeBinding.CHAR;
 			case 'D' :
-				return BaseTypes.DoubleBinding;
+				return TypeBinding.DOUBLE;
 			case 'B' :
-				return BaseTypes.ByteBinding;
+				return TypeBinding.BYTE;
 			case 'F' :
-				return BaseTypes.FloatBinding;
+				return TypeBinding.FLOAT;
 			case 'J' :
-				return BaseTypes.LongBinding;
+				return TypeBinding.LONG;
 			case 'S' :
-				return BaseTypes.ShortBinding;
+				return TypeBinding.SHORT;
 			case 'N':
-				return BaseTypes.NullBinding;
+				return TypeBinding.NULL;
 			default :
 				return null;
 		}
@@ -419,11 +425,21 @@
 	 * This key's scanner should be positioned on the package token.
 	 */
 	public CompilationUnitDeclaration getCompilationUnitDeclaration() {
-		char[][] name = compoundName();
+		char[][] name = this.compoundName;
 		if (name.length == 0) return null;
 		if (this.environment == null) return null;
 		ReferenceBinding binding = this.environment.getType(name);
-		if (!(binding instanceof SourceTypeBinding)) return null;
+		if (!(binding instanceof SourceTypeBinding)) {
+			if (this.secondarySimpleName == null) 
+				return null;
+			// case of a secondary type with no primary type (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=177115)
+			int length = name.length;
+			System.arraycopy(name, 0, name = new char[length][], 0, length-1);
+			name[length-1] = this.secondarySimpleName;
+			binding = this.environment.getType(name);
+			if (!(binding instanceof SourceTypeBinding))
+				return null;
+		}
 		SourceTypeBinding sourceTypeBinding = (SourceTypeBinding) binding;
 		if (sourceTypeBinding.scope == null) 
 			return null;
@@ -436,8 +452,13 @@
 	 * This key's scanner should be positioned on the package token.
 	 */
 	public Binding getCompilerBinding() {
-		parse();
-		return this.compilerBinding;
+		try {
+			parse();
+			return this.compilerBinding;
+		} catch (RuntimeException e) {
+			Util.log(e, "Could not create binding from binding key: " + getKey()); //$NON-NLS-1$
+			return null;
+		}
 	}
 	
 	private TypeBinding getTypeBinding(char[] simpleTypeName) {
@@ -465,7 +486,11 @@
 		TypeBinding[] arguments = new TypeBinding[size];
 		for (int i = 0; i < size; i++) {
 			BindingKeyResolver resolver = (BindingKeyResolver) this.types.get(i);
-			arguments[i] = (TypeBinding) resolver.compilerBinding;
+			TypeBinding compilerBinding2 = (TypeBinding) resolver.compilerBinding;
+			if (compilerBinding2 == null) {
+				throw new IllegalArgumentException();
+			}
+			arguments[i] = compilerBinding2;
 		}
 		this.types = new ArrayList();
 		return arguments;
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 fb90197..aab2c32 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,6 +10,8 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.util;
 
+import org.eclipse.jdt.internal.compiler.util.Util;
+
 /**
  * The <code>CharArrayBuffer</code> is intended as a lightweight partial implementation
  * of the StringBuffer class, but using <code>char[]'s</code> instead of Strings.
@@ -182,10 +184,10 @@
 }
 /**
  * Returns the contents of the buffer as a String, or
- * <code>null</code> if the buffer is empty.
+ * an empty string if the buffer is empty.
  */
 public String toString() {
 	char[] contents = getContents();
-	return (contents != null) ? new String(contents) : null;
+	return (contents != null) ? new String(contents) : Util.EMPTY_STRING;
 }
 }
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 fb5b1cc..60ad871 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 9b1916e..e018a72 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -25,10 +25,10 @@
 import org.eclipse.jdt.core.util.IMethodInfo;
 import org.eclipse.jdt.core.util.IModifierConstants;
 import org.eclipse.jdt.core.util.ISourceAttribute;
+import org.eclipse.jdt.internal.compiler.util.Util;
 
 public class ClassFileReader extends ClassFileStruct implements IClassFileReader {
 	private static final IFieldInfo[] NO_FIELD_INFOS = new IFieldInfo[0];
-	private static final int[] NO_INTERFACE_INDEXES = new int[0];
 	private static final char[][] NO_INTERFACES_NAMES = CharOperation.NO_CHAR_CHAR;
 	private static final IMethodInfo[] NO_METHOD_INFOS = new IMethodInfo[0];
 	private int accessFlags;
@@ -139,6 +139,9 @@
 					case IConstantPoolConstant.CONSTANT_NameAndType :
 						constantPoolOffsets[i] = readOffset;
 						readOffset += IConstantPoolConstant.CONSTANT_NameAndType_SIZE;
+						break;
+					default:
+						throw new ClassFormatException(ClassFormatException.INVALID_TAG_CONSTANT);
 				}
 			}
 			
@@ -165,7 +168,7 @@
 			this.interfacesCount = u2At(classFileBytes, readOffset, 0);
 			readOffset += 2;
 			this.interfaceNames = NO_INTERFACES_NAMES;
-			this.interfaceIndexes = NO_INTERFACE_INDEXES;
+			this.interfaceIndexes = Util.EMPTY_INT_ARRAY;
 			if (this.interfacesCount != 0) {
 				if ((decodingFlags & IClassFileReader.SUPER_INTERFACES) != IClassFileReader.CONSTANT_POOL) {
 					this.interfaceNames = new char[this.interfacesCount][];
@@ -275,6 +278,7 @@
 		} catch(ClassFormatException e) {
 			throw e;
 		} catch (Exception e) {
+			e.printStackTrace();
 			throw new ClassFormatException(ClassFormatException.ERROR_TRUNCATED_INPUT); 
 		}
 	}
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 53a5f5c..faca05d 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 abb55f0..21a7dfe 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -82,12 +82,15 @@
 				this.attributes[attributesIndex++] = this.localVariableAttribute;
 			} else if (equals(attributeName, IAttributeNamesConstants.LOCAL_VARIABLE_TYPE_TABLE)) {
 				this.attributes[attributesIndex++] = new LocalVariableTypeAttribute(classFileBytes, constantPool, offset + readOffset);
+			} else if (equals(attributeName, IAttributeNamesConstants.STACK_MAP_TABLE)) {
+				this.attributes[attributesIndex++] = new StackMapTableAttribute(classFileBytes, constantPool, offset + readOffset);
+			} else if (equals(attributeName, IAttributeNamesConstants.STACK_MAP)) {
+				this.attributes[attributesIndex++] = new StackMapAttribute(classFileBytes, constantPool, offset + readOffset);
 			} else {
 				this.attributes[attributesIndex++] = new ClassFileAttribute(classFileBytes, constantPool, offset + readOffset);
 			}
 			readOffset += (6 + u4At(classFileBytes, readOffset + 2, offset));
 		}
-		
 	}
 	/**
 	 * @see ICodeAttribute#getAttributes()
@@ -906,7 +909,7 @@
 				case IOpcodeMnemonics.TABLESWITCH :
 					int startpc = pc;
 					pc++;
-					while (((pc - this.codeOffset) % 4) != 0) {
+					while (((pc - this.codeOffset) & 0x03) != 0) { // faster than % 4
 						pc++;
 					}
 					int defaultOffset = i4At(this.classFileBytes, 0, pc);
@@ -926,7 +929,7 @@
 				case IOpcodeMnemonics.LOOKUPSWITCH :
 					startpc = pc;
 					pc++;
-					while (((pc - this.codeOffset) % 4) != 0) {
+					while (((pc - this.codeOffset) & 0x03) != 0) {
 						pc++;
 					}
 					defaultOffset = i4At(this.classFileBytes, 0, pc);
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
index 656ef07..8a31b54 100644
--- 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
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2002, 2004 IBM Corporation and others.
+ * Copyright (c) 2002, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -13,7 +13,7 @@
 import java.util.Locale;
 import java.util.Map;
 
-import org.eclipse.jdt.core.compiler.IProblem;
+import org.eclipse.jdt.core.compiler.CategorizedProblem;
 import org.eclipse.jdt.internal.compiler.CompilationResult;
 import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
 import org.eclipse.jdt.internal.compiler.ast.ASTNode;
@@ -35,16 +35,16 @@
 
 	private RecordedParsingInformation getRecordedParsingInformation(CompilationResult compilationResult, CommentRecorderParser parser) {
 		int problemsCount = compilationResult.problemCount;
-		IProblem[] problems = null;
+		CategorizedProblem[] problems = null;
 		if (problemsCount != 0) {
-			final IProblem[] compilationResultProblems = compilationResult.problems;
+			final CategorizedProblem[] compilationResultProblems = compilationResult.problems;
 			if (compilationResultProblems.length == problemsCount) {
 				problems = compilationResultProblems;
 			} else {
-				System.arraycopy(compilationResultProblems, 0, (problems = new IProblem[problemsCount]), 0, problemsCount);
+				System.arraycopy(compilationResultProblems, 0, (problems = new CategorizedProblem[problemsCount]), 0, problemsCount);
 			}
 		}
-		return new RecordedParsingInformation(problems, compilationResult.lineSeparatorPositions, parser.getCommentsPositions());
+		return new RecordedParsingInformation(problems, compilationResult.getLineSeparatorPositions(), parser.getCommentsPositions());
 	}
 
 	public ASTNode[] parseClassBodyDeclarations(char[] source, Map settings, boolean recordParsingInformation) {
@@ -62,7 +62,9 @@
 					new DefaultProblemFactory(Locale.getDefault()));
 					
 		CommentRecorderParser parser = new CommentRecorderParser(problemReporter, false);
-
+		parser.setMethodsFullRecovery(false);
+		parser.setStatementsRecovery(false);
+		
 		ICompilationUnit sourceUnit = 
 			new CompilationUnit(
 				source, 
@@ -158,11 +160,11 @@
 		return result;
 	}
 
-	public ConstructorDeclaration parseStatements(char[] source, Map settings, boolean recordParsingInformation) {
-		return parseStatements(source, 0, source.length, settings, recordParsingInformation);
+	public ConstructorDeclaration parseStatements(char[] source, Map settings, boolean recordParsingInformation, boolean enabledStatementRecovery) {
+		return parseStatements(source, 0, source.length, settings, recordParsingInformation, enabledStatementRecovery);
 	}
 	
-	public ConstructorDeclaration parseStatements(char[] source, int offset, int length, Map settings, boolean recordParsingInformation) {
+	public ConstructorDeclaration parseStatements(char[] source, int offset, int length, Map settings, boolean recordParsingInformation, boolean enabledStatementRecovery) {
 		if (source == null) {
 			throw new IllegalArgumentException();
 		}
@@ -172,6 +174,8 @@
 					compilerOptions, 
 					new DefaultProblemFactory(Locale.getDefault()));
 		CommentRecorderParser parser = new CommentRecorderParser(problemReporter, false);
+		parser.setMethodsFullRecovery(false);
+		parser.setStatementsRecovery(enabledStatementRecovery);
 		
 		ICompilationUnit sourceUnit = 
 			new CompilationUnit(
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
index 541adfc..cbbcc38 100644
--- 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
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -11,6 +11,7 @@
 package org.eclipse.jdt.internal.core.util;
 
 import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.compiler.parser.Parser;
 import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
@@ -70,7 +71,7 @@
 			break nextComment;
 		}
 		if (deprecated) {
-			checkAndSetModifiers(AccDeprecated);
+			checkAndSetModifiers(ClassFileConstants.AccDeprecated);
 		}
 		// modify the modifier source start to point at the first comment
 		if (lastCommentIndex >= 0 && checkDeprecated) {
@@ -89,13 +90,6 @@
 		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() {
@@ -170,7 +164,8 @@
 			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;
+				if (org.eclipse.jdt.internal.compiler.util.Util.getLineNumber(position, this.scanner.lineEnds, 0, this.scanner.linePtr) 
+						!= org.eclipse.jdt.internal.compiler.util.Util.getLineNumber(immediateCommentEnd, this.scanner.lineEnds, 0, this.scanner.linePtr)) break;
 				position = immediateCommentEnd;
 				validCount--; // flush this comment
 				index++;
@@ -223,6 +218,13 @@
 	/* (non-Javadoc)
 	 * @see org.eclipse.jdt.internal.compiler.parser.Parser#initialize()
 	 */
+	public void initialize(boolean initializeNLS) {
+		super.initialize(initializeNLS);
+		this.commentPtr = -1;
+	}
+	/* (non-Javadoc)
+	 * @see org.eclipse.jdt.internal.compiler.parser.Parser#initialize()
+	 */
 	public void initialize() {
 		super.initialize();
 		this.commentPtr = -1;
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
index 90a5464..050cf09 100644
--- 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
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 91c18d4..1fc2355 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 bda70f9..6456c31 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 e672880..f13e850 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -1472,33 +1472,24 @@
 	 */
 	public void _invokespecial(int pc, int index, IConstantPoolEntry constantMethodref) {
 		dumpPcNumber(pc);
+		final String signature = returnMethodSignature(constantMethodref);
 		buffer.append(Messages.bind(Messages.classformat_invokespecial, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.INVOKESPECIAL],
 			Integer.toString(index),
-			Util.toString(
-				constantMethodref.getClassName(),
-				constantMethodref.getMethodName(),
-				constantMethodref.getMethodDescriptor(),
-				true,
-				isCompact())
+			signature
 		}));
 		writeNewLine();
 	}
-
 	/**
 	 * @see IBytecodeVisitor#_invokestatic(int, int, IConstantPoolEntry)
 	 */
 	public void _invokestatic(int pc, int index, IConstantPoolEntry constantMethodref) {
 		dumpPcNumber(pc);
+		final String signature = returnMethodSignature(constantMethodref);
 		buffer.append(Messages.bind(Messages.classformat_invokestatic, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.INVOKESTATIC],
 			Integer.toString(index),
-			Util.toString(
-				constantMethodref.getClassName(),
-				constantMethodref.getMethodName(),
-				constantMethodref.getMethodDescriptor(),
-				true,
-				isCompact())
+			signature
 		}));
 		writeNewLine();
 	}
@@ -1508,15 +1499,11 @@
 	 */
 	public void _invokevirtual(int pc, int index, IConstantPoolEntry constantMethodref) {
 		dumpPcNumber(pc);
+		final String signature = returnMethodSignature(constantMethodref);
 		buffer.append(Messages.bind(Messages.classformat_invokevirtual,new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.INVOKEVIRTUAL],
 			Integer.toString(index),
-			Util.toString(
-				constantMethodref.getClassName(),
-				constantMethodref.getMethodName(),
-				constantMethodref.getMethodDescriptor(),
-				true,
-				isCompact())
+			signature
 		}));
 		writeNewLine();
 	}
@@ -1789,7 +1776,7 @@
 				buffer.append(Messages.bind(Messages.classformat_ldc_w_string, new String[] {
 					OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.LDC_W],
 					Integer.toString(index),
-					constantPoolEntry.getStringValue()
+					Disassembler.escapeString(constantPoolEntry.getStringValue())
 				}));
 				break;
 			case IConstantPoolConstant.CONSTANT_Class :
@@ -1826,7 +1813,7 @@
 				buffer.append(Messages.bind(Messages.classformat_ldc_w_string, new String[] {
 					OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.LDC],
 					Integer.toString(index),
-					constantPoolEntry.getStringValue()
+					Disassembler.escapeString(constantPoolEntry.getStringValue())
 				}));
 				break;
 			case IConstantPoolConstant.CONSTANT_Class :
@@ -2131,8 +2118,7 @@
 		buffer.append(Messages.bind(Messages.classformat_multianewarray, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.MULTIANEWARRAY],
 			Integer.toString(index),
-			returnConstantClassName(constantClass),
-			appendDimensions(dimensions)
+			returnConstantClassName(constantClass)
 		}));
 		writeNewLine();
 	}
@@ -2428,21 +2414,23 @@
 		writeNewLine();
 	}
 
-	private String appendDimensions(int dimensions) {
-		StringBuffer stringBuffer = new StringBuffer();
-		for (int i = 0; i < dimensions; i++) {
-			stringBuffer.append(Messages.disassembler_arraydimensions); 
-		}
-		return String.valueOf(stringBuffer);
-	}
-
 	private boolean isCompact() {
 		return (this.mode & ClassFileBytesDisassembler.COMPACT) != 0;
 	}
 
 	private String returnConstantClassName(IConstantPoolEntry constantClass) {
-		char[] classInfoName = constantClass.getClassInfoName();
-		return returnClassName(classInfoName);
+		char[] className = constantClass.getClassInfoName();
+		if (className.length == 0) {
+			return EMPTY_CLASS_NAME;
+		}
+		switch(className[0]) {
+			case '[' :
+				StringBuffer classNameBuffer = new StringBuffer();
+				Util.appendTypeSignature(className, 0, classNameBuffer, isCompact());
+				return classNameBuffer.toString();
+			default:
+				return returnClassName(className);	
+		}
 	}
 	private String returnClassName(char[] classInfoName) {
 		if (classInfoName.length == 0) {
@@ -2462,6 +2450,19 @@
 		return returnClassName(className);
 	}
 
+	private String returnMethodSignature(IConstantPoolEntry constantMethodref) {
+		final char[] methodDescriptor = constantMethodref.getMethodDescriptor();
+		CharOperation.replace(methodDescriptor, '$', '#');
+		final char[] signature = Util.toString(
+				constantMethodref.getClassName(),
+				constantMethodref.getMethodName(),
+				methodDescriptor,
+				true,
+				isCompact()).toCharArray();
+		CharOperation.replace(signature, '#', '$');
+		return String.valueOf(signature);
+	}
+
 	private void writeNewLine() {
 		this.buffer.append(lineSeparator);
 	}	
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/DefaultStackMapFrame.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/DefaultStackMapFrame.java
new file mode 100755
index 0000000..94d2f3f
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/DefaultStackMapFrame.java
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core.util;
+
+import org.eclipse.jdt.core.util.ClassFormatException;
+import org.eclipse.jdt.core.util.IConstantPool;
+import org.eclipse.jdt.core.util.IStackMapFrame;
+import org.eclipse.jdt.core.util.IVerificationTypeInfo;
+
+/**
+ * Default implementation of IStackMapFrame
+ */
+public class DefaultStackMapFrame extends ClassFileStruct implements IStackMapFrame {
+	private static final IVerificationTypeInfo[] EMPTY_LOCALS_OR_STACK_ITEMS = new IVerificationTypeInfo[0];
+
+	private int readOffset;
+	private int numberOfLocals;
+	private int numberOfStackItems;
+	private IVerificationTypeInfo[] locals;
+	private IVerificationTypeInfo[] stackItems;
+	private int offsetDelta;
+	
+	/**
+	 * Constructor for StackMapFrame.
+	 * 
+	 * @param classFileBytes
+	 * @param constantPool
+	 * @param offset
+	 * @throws ClassFormatException
+	 */
+	public DefaultStackMapFrame(
+			byte[] classFileBytes,
+			IConstantPool constantPool,
+			int offset) throws ClassFormatException {
+		// FULL_FRAME
+		this.offsetDelta = u2At(classFileBytes, 0, offset);
+		int tempLocals = u2At(classFileBytes, 2, offset);
+		this.numberOfLocals = tempLocals;
+		if (tempLocals != 0) {
+			this.locals = new IVerificationTypeInfo[tempLocals];
+			this.readOffset = 4;
+			for (int i = 0; i < tempLocals; i++) {
+				VerificationInfo verificationInfo = new VerificationInfo(classFileBytes, constantPool, offset + this.readOffset);
+				this.locals[i] = verificationInfo;
+				this.readOffset += verificationInfo.sizeInBytes();
+			}
+		} else {
+			this.locals = EMPTY_LOCALS_OR_STACK_ITEMS;
+		}
+		int tempStackItems = u2At(classFileBytes, readOffset, offset);
+		this.readOffset += 2;
+		this.numberOfStackItems = tempStackItems;
+		if (tempStackItems != 0) {
+			this.stackItems = new IVerificationTypeInfo[tempStackItems];
+			for (int i = 0; i < tempStackItems; i++) {
+				VerificationInfo verificationInfo = new VerificationInfo(classFileBytes, constantPool, offset + this.readOffset);
+				this.stackItems[i] = verificationInfo;
+				this.readOffset += verificationInfo.sizeInBytes();
+			}
+		} else {
+			this.stackItems = EMPTY_LOCALS_OR_STACK_ITEMS;
+		}
+	}
+	int sizeInBytes() {
+		return this.readOffset;
+	}
+	public int getFrameType() {
+		return 255; // full_frame
+	}
+	public IVerificationTypeInfo[] getLocals() {
+		return this.locals;
+	}
+	public int getNumberOfLocals() {
+		return this.numberOfLocals;
+	}
+	public int getNumberOfStackItems() {
+		return this.numberOfStackItems;
+	}
+	public int getOffsetDelta() {
+		return this.offsetDelta;
+	}
+	public IVerificationTypeInfo[] getStackItems() {
+		return this.stackItems;
+	}
+}
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 1be2fa0..69dbaab 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,28 +10,15 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.util;
 
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
 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.*;
-import org.eclipse.jdt.core.util.ClassFormatException;
-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.IConstantPoolConstant;
-import org.eclipse.jdt.core.util.IConstantPoolEntry;
-import org.eclipse.jdt.core.util.IConstantValueAttribute;
-import org.eclipse.jdt.core.util.IExceptionAttribute;
-import org.eclipse.jdt.core.util.IExceptionTableEntry;
-import org.eclipse.jdt.core.util.IFieldInfo;
-import org.eclipse.jdt.core.util.IInnerClassesAttribute;
-import org.eclipse.jdt.core.util.IInnerClassesAttributeEntry;
-import org.eclipse.jdt.core.util.ILineNumberAttribute;
-import org.eclipse.jdt.core.util.ILocalVariableAttribute;
-import org.eclipse.jdt.core.util.ILocalVariableTableEntry;
-import org.eclipse.jdt.core.util.IMethodInfo;
-import org.eclipse.jdt.core.util.IModifierConstants;
-import org.eclipse.jdt.core.util.ISourceAttribute;
+import org.eclipse.jdt.internal.compiler.codegen.AttributeNamesConstants;
+import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
 
 /**
  * Disassembler of .class files. It generates an output in the Writer that looks close to
@@ -39,13 +26,11 @@
  */
 public class Disassembler extends ClassFileBytesDisassembler {
 
-	private static final String EMPTY_CLASS_NAME = "\"\""; //$NON-NLS-1$
 	private static final char[] ANY_EXCEPTION = Messages.classfileformat_anyexceptionhandler.toCharArray();	 
-	private static final String EMPTY_OUTPUT = ""; //$NON-NLS-1$
-	private static final String VERSION_UNKNOWN = "unknown";//$NON-NLS-1$
+	private static final String VERSION_UNKNOWN = Messages.classfileformat_versionUnknown;
 
 	private boolean appendModifier(StringBuffer buffer, int accessFlags, int modifierConstant, String modifier, boolean firstModifier) {
-		if ((accessFlags & modifierConstant) != 0) {		
+		if ((accessFlags & modifierConstant) != 0) {
 			if (!firstModifier) {
 				buffer.append(Messages.disassembler_space); 
 			}
@@ -57,65 +42,128 @@
 		return firstModifier;
 	}
 	
+	private void decodeModifiers(StringBuffer buffer, int accessFlags, int[] checkBits) {
+		decodeModifiers(buffer, accessFlags, false, false, checkBits);
+	}
+	
+	private void decodeModifiers(StringBuffer buffer, int accessFlags, boolean printDefault, boolean asBridge, int[] checkBits) {
+		if (checkBits == null) return;
+		boolean firstModifier = true;
+		for (int i = 0, max = checkBits.length; i < max; i++) {
+			switch(checkBits[i]) {
+				case IModifierConstants.ACC_PUBLIC :
+					firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_PUBLIC, "public", firstModifier); //$NON-NLS-1$
+					break;
+				case IModifierConstants.ACC_PROTECTED :
+					firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_PROTECTED, "protected", firstModifier); //$NON-NLS-1$
+					break;
+				case IModifierConstants.ACC_PRIVATE :
+					firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_PRIVATE, "private", firstModifier); //$NON-NLS-1$
+					break;
+				case IModifierConstants.ACC_ABSTRACT :
+					firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_ABSTRACT, "abstract", firstModifier); //$NON-NLS-1$
+					break;
+				case IModifierConstants.ACC_STATIC :
+					firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_STATIC, "static", firstModifier); //$NON-NLS-1$
+					break;
+				case IModifierConstants.ACC_FINAL :
+					firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_FINAL, "final", firstModifier); //$NON-NLS-1$
+					break;
+				case IModifierConstants.ACC_SYNCHRONIZED :
+					firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_SYNCHRONIZED, "synchronized", firstModifier); //$NON-NLS-1$
+					break;
+				case IModifierConstants.ACC_NATIVE :
+					firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_NATIVE, "native", firstModifier); //$NON-NLS-1$
+					break;
+				case IModifierConstants.ACC_STRICT :
+					firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_STRICT, "strictfp", firstModifier); //$NON-NLS-1$
+					break;
+				case IModifierConstants.ACC_TRANSIENT :
+					firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_TRANSIENT, "transient", firstModifier); //$NON-NLS-1$
+					break;
+				case IModifierConstants.ACC_VOLATILE :
+				// case IModifierConstants.ACC_BRIDGE :
+					if (asBridge) {
+						firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_BRIDGE, "bridge", firstModifier); //$NON-NLS-1$
+					} else {
+						firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_VOLATILE, "volatile", firstModifier); //$NON-NLS-1$
+					}
+					break;
+				case IModifierConstants.ACC_ENUM :
+					firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_ENUM, "enum", firstModifier); //$NON-NLS-1$
+					break;
+			}
+		}
+		if (!firstModifier) {
+			if (!printDefault) buffer.append(Messages.disassembler_space); 
+		} else if (printDefault) {
+			// no modifier: package default visibility
+			buffer.append("default"); //$NON-NLS-1$
+		}
+	}
+	
 	private void decodeModifiersForField(StringBuffer buffer, int accessFlags) {
-		boolean firstModifier = true;
-		firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_PUBLIC, "public", firstModifier); //$NON-NLS-1$
-		firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_PROTECTED, "protected", firstModifier); //$NON-NLS-1$
-		firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_PRIVATE, "private", firstModifier); //$NON-NLS-1$
-		firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_STATIC, "static", firstModifier); //$NON-NLS-1$
-		firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_FINAL, "final", firstModifier); //$NON-NLS-1$
-		firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_TRANSIENT, "transient", firstModifier); //$NON-NLS-1$
-		firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_VOLATILE, "volatile", firstModifier); //$NON-NLS-1$
-		firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_ENUM, "enum", firstModifier); //$NON-NLS-1$
-		if (!firstModifier) {
-			buffer.append(Messages.disassembler_space); 
-		}
-	}	
+		decodeModifiers(buffer, accessFlags, new int[] {
+				IModifierConstants.ACC_PUBLIC,
+				IModifierConstants.ACC_PROTECTED,
+				IModifierConstants.ACC_PRIVATE,
+				IModifierConstants.ACC_STATIC,
+				IModifierConstants.ACC_FINAL,
+				IModifierConstants.ACC_TRANSIENT,
+				IModifierConstants.ACC_VOLATILE,
+				IModifierConstants.ACC_ENUM
+		});
+	}
 
-	private final void decodeModifiersForInnerClasses(StringBuffer buffer, int accessFlags) {
-		boolean firstModifier = true;
-		firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_PUBLIC, "public", firstModifier); //$NON-NLS-1$
-		firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_PROTECTED, "protected", firstModifier); //$NON-NLS-1$
-		firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_PRIVATE, "private", firstModifier); //$NON-NLS-1$
-		firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_ABSTRACT, "abstract", firstModifier); //$NON-NLS-1$
-		firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_STATIC, "static", firstModifier); //$NON-NLS-1$
-		firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_FINAL, "final", firstModifier); //$NON-NLS-1$
-		if (!firstModifier) {
-			buffer.append(Messages.disassembler_space); 
-		}
+	private void decodeModifiersForFieldForWorkingCopy(StringBuffer buffer, int accessFlags) {
+		decodeModifiers(buffer, accessFlags, new int[] {
+				IModifierConstants.ACC_PUBLIC,
+				IModifierConstants.ACC_PROTECTED,
+				IModifierConstants.ACC_PRIVATE,
+				IModifierConstants.ACC_STATIC,
+				IModifierConstants.ACC_FINAL,
+				IModifierConstants.ACC_TRANSIENT,
+				IModifierConstants.ACC_VOLATILE,
+		});
+	}	
+	
+	private final void decodeModifiersForInnerClasses(StringBuffer buffer, int accessFlags, boolean printDefault) {
+		decodeModifiers(buffer, accessFlags, printDefault, false, new int[] {
+				IModifierConstants.ACC_PUBLIC,
+				IModifierConstants.ACC_PROTECTED,
+				IModifierConstants.ACC_PRIVATE,
+				IModifierConstants.ACC_ABSTRACT,
+				IModifierConstants.ACC_STATIC,
+				IModifierConstants.ACC_FINAL,
+		});
 	}
 
 	private final void decodeModifiersForMethod(StringBuffer buffer, int accessFlags) {
-		boolean firstModifier = true;
-		firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_PUBLIC, "public", firstModifier); //$NON-NLS-1$
-		firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_PROTECTED, "protected", firstModifier); //$NON-NLS-1$
-		firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_PRIVATE, "private", firstModifier); //$NON-NLS-1$
-		firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_ABSTRACT, "abstract", firstModifier); //$NON-NLS-1$
-		firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_STATIC, "static", firstModifier); //$NON-NLS-1$
-		firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_FINAL, "final", firstModifier); //$NON-NLS-1$
-		firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_SYNCHRONIZED, "synchronized", firstModifier); //$NON-NLS-1$
-		firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_NATIVE, "native", firstModifier); //$NON-NLS-1$
-		firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_STRICT, "strictfp", firstModifier); //$NON-NLS-1$
-		firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_BRIDGE, "bridge", firstModifier); //$NON-NLS-1$
-		if (!firstModifier) {
-			buffer.append(Messages.disassembler_space); 
-		}
+		decodeModifiers(buffer, accessFlags, false, true, new int[] {
+				IModifierConstants.ACC_PUBLIC,
+				IModifierConstants.ACC_PROTECTED,
+				IModifierConstants.ACC_PRIVATE,
+				IModifierConstants.ACC_ABSTRACT,
+				IModifierConstants.ACC_STATIC,
+				IModifierConstants.ACC_FINAL,
+				IModifierConstants.ACC_SYNCHRONIZED,
+				IModifierConstants.ACC_NATIVE,
+				IModifierConstants.ACC_STRICT,
+				IModifierConstants.ACC_BRIDGE,
+		});
 	}
 
 	private final void decodeModifiersForType(StringBuffer buffer, int accessFlags) {
-		boolean firstModifier = true;
-		firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_PUBLIC, "public", firstModifier); //$NON-NLS-1$
-		firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_ABSTRACT, "abstract", firstModifier); //$NON-NLS-1$
-		firstModifier = appendModifier(buffer, accessFlags, IModifierConstants.ACC_FINAL, "final", firstModifier); //$NON-NLS-1$
-		if (!firstModifier) {
-			buffer.append(Messages.disassembler_space); 
-		}
+		decodeModifiers(buffer, accessFlags, new int[] {
+				IModifierConstants.ACC_PUBLIC,
+				IModifierConstants.ACC_ABSTRACT,
+				IModifierConstants.ACC_FINAL,
+		});
 	}
-
-	private String decodeStringValue(char[] chars) {
+	public static String escapeString(String s) {
 		StringBuffer buffer = new StringBuffer();
-		for (int i = 0, max = chars.length; i < max; i++) {
-			char c = chars[i];
+		for (int i = 0, max = s.length(); i < max; i++) {
+			char c = s.charAt(i);
 			switch(c) {
 				case '\b' :
 					buffer.append("\\b"); //$NON-NLS-1$
@@ -132,15 +180,6 @@
 				case '\r' :
 					buffer.append("\\r"); //$NON-NLS-1$
 					break;
-				case '\"':
-					buffer.append("\\\""); //$NON-NLS-1$
-					break;
-				case '\'':
-					buffer.append("\\\'"); //$NON-NLS-1$
-					break;
-				case '\\':
-					buffer.append("\\\\"); //$NON-NLS-1$
-					break;
 				case '\0' :
 					buffer.append("\\0"); //$NON-NLS-1$
 					break;
@@ -172,7 +211,58 @@
 		return buffer.toString();
 	}
 
-	private String decodeStringValue(String s) {
+	static String decodeStringValue(char[] chars) {
+		StringBuffer buffer = new StringBuffer();
+		for (int i = 0, max = chars.length; i < max; i++) {
+			char c = chars[i];
+			switch(c) {
+				case '\b' :
+					buffer.append("\\b"); //$NON-NLS-1$
+					break;
+				case '\t' :
+					buffer.append("\\t"); //$NON-NLS-1$
+					break;
+				case '\n' :
+					buffer.append("\\n"); //$NON-NLS-1$
+					break;
+				case '\f' :
+					buffer.append("\\f"); //$NON-NLS-1$
+					break;
+				case '\r' :
+					buffer.append("\\r"); //$NON-NLS-1$
+					break;
+				case '\0' :
+					buffer.append("\\0"); //$NON-NLS-1$
+					break;
+				case '\1' :
+					buffer.append("\\1"); //$NON-NLS-1$
+					break;
+				case '\2' :
+					buffer.append("\\2"); //$NON-NLS-1$
+					break;
+				case '\3' :
+					buffer.append("\\3"); //$NON-NLS-1$
+					break;
+				case '\4' :
+					buffer.append("\\4"); //$NON-NLS-1$
+					break;
+				case '\5' :
+					buffer.append("\\5"); //$NON-NLS-1$
+					break;
+				case '\6' :
+					buffer.append("\\6"); //$NON-NLS-1$
+					break;
+				case '\7' :
+					buffer.append("\\7"); //$NON-NLS-1$
+					break;			
+				default:
+					buffer.append(c);
+			}
+		}
+		return buffer.toString();
+	}
+
+	static String decodeStringValue(String s) {
 		return decodeStringValue(s.toCharArray());
 	}
 
@@ -180,14 +270,32 @@
 	 * @see org.eclipse.jdt.core.util.ClassFileBytesDisassembler#disassemble(byte[], java.lang.String)
 	 */
 	public String disassemble(byte[] classFileBytes, String lineSeparator) throws ClassFormatException {
-		return disassemble(new ClassFileReader(classFileBytes, IClassFileReader.ALL), lineSeparator, ClassFileBytesDisassembler.DEFAULT);
+		try {
+			return disassemble(new ClassFileReader(classFileBytes, IClassFileReader.ALL), lineSeparator, ClassFileBytesDisassembler.DEFAULT);
+		} catch (ArrayIndexOutOfBoundsException e) {
+			StringWriter stringWriter = new StringWriter();
+			PrintWriter writer = new PrintWriter(stringWriter);
+			e.printStackTrace(writer);
+			writer.flush();
+			writer.close();
+			throw new ClassFormatException(String.valueOf(stringWriter.getBuffer()));
+		}
 	}
 
 	/**
 	 * @see org.eclipse.jdt.core.util.ClassFileBytesDisassembler#disassemble(byte[], java.lang.String, int)
 	 */
 	public String disassemble(byte[] classFileBytes, String lineSeparator, int mode) throws ClassFormatException {
-		return disassemble(new ClassFileReader(classFileBytes, IClassFileReader.ALL), lineSeparator, mode);
+		try {
+			return disassemble(new ClassFileReader(classFileBytes, IClassFileReader.ALL), lineSeparator, mode);
+		} catch (ArrayIndexOutOfBoundsException e) {
+			StringWriter stringWriter = new StringWriter();
+			PrintWriter writer = new PrintWriter(stringWriter);
+			e.printStackTrace(writer);
+			writer.flush();
+			writer.close();
+			throw new ClassFormatException(String.valueOf(stringWriter.getBuffer()));
+		}
 	}
 
 	private void disassemble(IAnnotation annotation, StringBuffer buffer, String lineSeparator, int tabNumber) {
@@ -321,20 +429,97 @@
 			}));
 	}
 
+	private void disassembleEnumConstructor(IClassFileReader classFileReader, char[] className, IMethodInfo methodInfo, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
+		writeNewLine(buffer, lineSeparator, tabNumber);
+		final ICodeAttribute codeAttribute = methodInfo.getCodeAttribute();
+		char[] methodDescriptor = methodInfo.getDescriptor();
+		final IClassFileAttribute runtimeVisibleAnnotationsAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.RUNTIME_VISIBLE_ANNOTATIONS);
+		final IClassFileAttribute runtimeInvisibleAnnotationsAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.RUNTIME_INVISIBLE_ANNOTATIONS);
+		// disassemble compact version of annotations
+		if (runtimeInvisibleAnnotationsAttribute != null) {
+			disassembleAsModifier((IRuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber + 1, mode);
+			writeNewLine(buffer, lineSeparator, tabNumber);
+		}
+		if (runtimeVisibleAnnotationsAttribute != null) {
+			disassembleAsModifier((IRuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber + 1, mode);
+			writeNewLine(buffer, lineSeparator, tabNumber);
+		}
+		final int accessFlags = methodInfo.getAccessFlags();
+		decodeModifiersForMethod(buffer, accessFlags & IModifierConstants.ACC_PRIVATE);
+		CharOperation.replace(methodDescriptor, '/', '.');
+		final boolean isVarArgs = (accessFlags & IModifierConstants.ACC_VARARGS) != 0;
+		final char[] signature = Signature.toCharArray(methodDescriptor, returnClassName(className, '.', COMPACT), getParameterNames(methodDescriptor, codeAttribute, accessFlags) , !checkMode(mode, COMPACT), false, isVarArgs);
+		int index = CharOperation.indexOf(',', signature);
+		index = CharOperation.indexOf(',', signature, index + 1);
+		buffer.append(signature, 0, CharOperation.indexOf('(', signature) + 1);
+		buffer.append(signature, index + 2, signature.length - index - 2);
+		IExceptionAttribute exceptionAttribute = methodInfo.getExceptionAttribute();
+		if (exceptionAttribute != null) {
+			buffer.append(" throws "); //$NON-NLS-1$
+			char[][] exceptionNames = exceptionAttribute.getExceptionNames();
+			int length = exceptionNames.length;
+			for (int i = 0; i < length; i++) {
+				if (i != 0) {
+					buffer
+    					.append(Messages.disassembler_comma)
+    					.append(Messages.disassembler_space);
+				}
+				char[] exceptionName = exceptionNames[i];
+				CharOperation.replace(exceptionName, '/', '.');
+				buffer.append(returnClassName(exceptionName, '.', mode));
+			}
+		}
+		if (((accessFlags & IModifierConstants.ACC_NATIVE) == 0)
+				&& ((accessFlags & IModifierConstants.ACC_ABSTRACT) == 0)) {
+			buffer.append(" {"); //$NON-NLS-1$
+			final char[] returnType = Signature.getReturnType(methodDescriptor);
+			if (returnType.length == 1) {
+				switch(returnType[0]) {
+					case 'V' :
+						writeNewLine(buffer, lineSeparator, tabNumber);							
+						break;
+					case 'I' :
+					case 'B' :
+					case 'J' :
+					case 'D' :
+					case 'F' :
+					case 'S' :
+					case 'C' :
+						writeNewLine(buffer, lineSeparator, tabNumber + 1);
+						buffer.append("return 0;"); //$NON-NLS-1$
+						writeNewLine(buffer, lineSeparator, tabNumber);							
+						break;
+					default :
+						// boolean
+						writeNewLine(buffer, lineSeparator, tabNumber + 1);
+						buffer.append("return false;"); //$NON-NLS-1$
+						writeNewLine(buffer, lineSeparator, tabNumber);							
+				}
+			} else {
+				// object
+				writeNewLine(buffer, lineSeparator, tabNumber + 1);
+				buffer.append("return null;"); //$NON-NLS-1$
+				writeNewLine(buffer, lineSeparator, tabNumber);							
+			}
+			buffer.append('}');
+		} else {
+			buffer.append(';');
+		}
+	}
+	
 	/**
 	 * Disassemble a method info header
 	 */
-	private void disassemble(IClassFileReader classFileReader, IMethodInfo methodInfo, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
+	private void disassemble(IClassFileReader classFileReader, char[] className, IMethodInfo methodInfo, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
 		writeNewLine(buffer, lineSeparator, tabNumber);
-		ICodeAttribute codeAttribute = methodInfo.getCodeAttribute();
-		char[] methodDescriptor = methodInfo.getDescriptor();
-		IClassFileAttribute classFileAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.SIGNATURE);
-		ISignatureAttribute signatureAttribute = (ISignatureAttribute) classFileAttribute;
-		IClassFileAttribute runtimeVisibleAnnotationsAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.RUNTIME_VISIBLE_ANNOTATIONS);
-		IClassFileAttribute runtimeInvisibleAnnotationsAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.RUNTIME_INVISIBLE_ANNOTATIONS);
-		IClassFileAttribute runtimeVisibleParameterAnnotationsAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS);
-		IClassFileAttribute runtimeInvisibleParameterAnnotationsAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS);
-		IClassFileAttribute annotationDefaultAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.ANNOTATION_DEFAULT);
+		final ICodeAttribute codeAttribute = methodInfo.getCodeAttribute();
+		final char[] methodDescriptor = methodInfo.getDescriptor();
+		final ISignatureAttribute signatureAttribute = (ISignatureAttribute) Util.getAttribute(methodInfo, IAttributeNamesConstants.SIGNATURE);
+		final IClassFileAttribute runtimeVisibleAnnotationsAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.RUNTIME_VISIBLE_ANNOTATIONS);
+		final IClassFileAttribute runtimeInvisibleAnnotationsAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.RUNTIME_INVISIBLE_ANNOTATIONS);
+		final IClassFileAttribute runtimeVisibleParameterAnnotationsAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS);
+		final IClassFileAttribute runtimeInvisibleParameterAnnotationsAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS);
+		final IClassFileAttribute annotationDefaultAttribute = Util.getAttribute(methodInfo, IAttributeNamesConstants.ANNOTATION_DEFAULT);
 		if (checkMode(mode, SYSTEM | DETAILED)) {
 			buffer.append(Messages.bind(Messages.classfileformat_methoddescriptor,
 				new String[] {
@@ -361,55 +546,112 @@
 		if (checkMode(mode, DETAILED)) {
 			// disassemble compact version of annotations
 			if (runtimeInvisibleAnnotationsAttribute != null) {
-				disassembleAsModifier((IRuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber + 1);
+				disassembleAsModifier((IRuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber + 1, mode);
 				writeNewLine(buffer, lineSeparator, tabNumber);
 			}
 			if (runtimeVisibleAnnotationsAttribute != null) {
-				disassembleAsModifier((IRuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber + 1);
+				disassembleAsModifier((IRuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber + 1, mode);
 				writeNewLine(buffer, lineSeparator, tabNumber);
 			}
 		}
-		int accessFlags = methodInfo.getAccessFlags();
+		final int accessFlags = methodInfo.getAccessFlags();
 		decodeModifiersForMethod(buffer, accessFlags);
-		if (methodInfo.isSynthetic()) {
+		if (methodInfo.isSynthetic() && !checkMode(mode, WORKING_COPY)) {
 			buffer.append("synthetic"); //$NON-NLS-1$
 			buffer.append(Messages.disassembler_space); 
 		}
 		CharOperation.replace(methodDescriptor, '/', '.');
-		char[] methodName;
+		final boolean isVarArgs = isVarArgs(methodInfo);
 		if (methodInfo.isConstructor()) {
-			methodName = classFileReader.getClassName();
-			buffer.append(Signature.toCharArray(methodDescriptor, methodName, getParameterNames(methodDescriptor, codeAttribute, accessFlags) , false, false, (accessFlags & IModifierConstants.ACC_VARARGS) != 0));
+			if (checkMode(mode, WORKING_COPY) && signatureAttribute != null) {
+				final char[] signature = signatureAttribute.getSignature();
+				CharOperation.replace(signature, '/', '.');
+				disassembleGenericSignature(mode, buffer, signature);
+				buffer.append(' ');
+				buffer.append(Signature.toCharArray(signature, returnClassName(className, '.', COMPACT), getParameterNames(methodDescriptor, codeAttribute, accessFlags) , !checkMode(mode, COMPACT), false, isVarArgs));
+			} else {
+				buffer.append(Signature.toCharArray(methodDescriptor, returnClassName(className, '.', COMPACT), getParameterNames(methodDescriptor, codeAttribute, accessFlags) , !checkMode(mode, COMPACT), false, isVarArgs));
+			}
 		} else if (methodInfo.isClinit()) {
 			buffer.append(Messages.bind(Messages.classfileformat_clinitname));
 		} else {
-			methodName = methodInfo.getName();
-			buffer.append(Signature.toCharArray(methodDescriptor, methodName, getParameterNames(methodDescriptor, codeAttribute, accessFlags) , false, true, (accessFlags & IModifierConstants.ACC_VARARGS) != 0));
+			if (checkMode(mode, WORKING_COPY) && signatureAttribute != null) {
+				final char[] signature = signatureAttribute.getSignature();
+				CharOperation.replace(signature, '/', '.');
+				disassembleGenericSignature(mode, buffer, signature);
+				buffer.append(' ');
+				buffer.append(Signature.toCharArray(signature, methodInfo.getName(), getParameterNames(methodDescriptor, codeAttribute, accessFlags) , !checkMode(mode, COMPACT), true, isVarArgs));
+			} else {
+				buffer.append(Signature.toCharArray(methodDescriptor, methodInfo.getName(), getParameterNames(methodDescriptor, codeAttribute, accessFlags) , !checkMode(mode, COMPACT), true, isVarArgs));
+			}
 		}
 		IExceptionAttribute exceptionAttribute = methodInfo.getExceptionAttribute();
 		if (exceptionAttribute != null) {
 			buffer.append(" throws "); //$NON-NLS-1$
 			char[][] exceptionNames = exceptionAttribute.getExceptionNames();
 			int length = exceptionNames.length;
-			for (int i = 0; i < length - 1; i++) {
+			for (int i = 0; i < length; i++) {
+				if (i != 0) {
+					buffer
+						.append(Messages.disassembler_comma)
+						.append(Messages.disassembler_space);
+				}
 				char[] exceptionName = exceptionNames[i];
 				CharOperation.replace(exceptionName, '/', '.');
-				buffer
-					.append(returnClassName(exceptionName, '.', mode))
-					.append(Messages.disassembler_comma)
-					.append(Messages.disassembler_space); 
+				buffer.append(returnClassName(exceptionName, '.', mode));
 			}
-			char[] exceptionName = exceptionNames[length - 1];
-			CharOperation.replace(exceptionName, '/', '.');
-			buffer.append(returnClassName(exceptionName, '.', mode));
 		}
 		if (checkMode(mode, DETAILED)) {
 			if (annotationDefaultAttribute != null) {
 				buffer.append(" default "); //$NON-NLS-1$
-				disassembleAsModifier((IAnnotationDefaultAttribute) annotationDefaultAttribute, buffer, lineSeparator, tabNumber);
+				disassembleAsModifier((IAnnotationDefaultAttribute) annotationDefaultAttribute, buffer, lineSeparator, tabNumber, mode);
 			}
 		}
-		buffer.append(Messages.disassembler_endofmethodheader); 
+		if (checkMode(mode, WORKING_COPY)) {
+			// put the annotation default attribute if needed
+			if (annotationDefaultAttribute != null) {
+				buffer.append(" default "); //$NON-NLS-1$
+				disassembleAsModifier((IAnnotationDefaultAttribute) annotationDefaultAttribute, buffer, lineSeparator, tabNumber, mode);
+			}
+			if (((accessFlags & IModifierConstants.ACC_NATIVE) == 0)
+					&& ((accessFlags & IModifierConstants.ACC_ABSTRACT) == 0)) {
+				buffer.append(" {"); //$NON-NLS-1$
+				final char[] returnType = Signature.getReturnType(methodDescriptor);
+				if (returnType.length == 1) {
+					switch(returnType[0]) {
+						case 'V' :
+							writeNewLine(buffer, lineSeparator, tabNumber);
+							break;
+						case 'I' :
+						case 'B' :
+						case 'J' :
+						case 'D' :
+						case 'F' :
+						case 'S' :
+						case 'C' :
+							writeNewLine(buffer, lineSeparator, tabNumber + 1);
+							buffer.append("return 0;"); //$NON-NLS-1$
+							writeNewLine(buffer, lineSeparator, tabNumber);
+							break;
+						default :
+							// boolean
+							writeNewLine(buffer, lineSeparator, tabNumber + 1);
+							buffer.append("return false;"); //$NON-NLS-1$
+							writeNewLine(buffer, lineSeparator, tabNumber);
+					}
+				} else {
+					// object
+					writeNewLine(buffer, lineSeparator, tabNumber + 1);
+					buffer.append("return null;"); //$NON-NLS-1$
+					writeNewLine(buffer, lineSeparator, tabNumber);
+				}
+				buffer.append('}');
+			} else {
+				buffer.append(';');
+			}	
+		} else {
+			buffer.append(Messages.disassembler_endofmethodheader);
+		}
 		
 		if (checkMode(mode, SYSTEM | DETAILED)) {
 			if (codeAttribute != null) {
@@ -474,13 +716,21 @@
 	 * @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;
+		if (classFileReader == null) return org.eclipse.jdt.internal.compiler.util.Util.EMPTY_STRING;
+		char[] className = classFileReader.getClassName();
+		if (className == null) {
+			// incomplete initialization. We cannot go further.
+			return org.eclipse.jdt.internal.compiler.util.Util.EMPTY_STRING;
+		}
+		className= CharOperation.replaceOnCopy(className, '/', '.');
+		final int classNameLength = className.length;
+		final int accessFlags = classFileReader.getAccessFlags();
+		final boolean isEnum = (accessFlags & IModifierConstants.ACC_ENUM) != 0;
+
 		StringBuffer buffer = new StringBuffer();
-	
 		ISourceAttribute sourceAttribute = classFileReader.getSourceFileAttribute();
 		IClassFileAttribute classFileAttribute = Util.getAttribute(classFileReader, IAttributeNamesConstants.SIGNATURE);
 		ISignatureAttribute signatureAttribute = (ISignatureAttribute) classFileAttribute;
-		final int accessFlags = classFileReader.getAccessFlags();
 		if (checkMode(mode, SYSTEM | DETAILED)) {
 			int minorVersion = classFileReader.getMinorVersion();
 			int majorVersion = classFileReader.getMajorVersion();
@@ -489,7 +739,7 @@
 				buffer.append(Messages.disassembler_sourceattributeheader); 
 				buffer.append(sourceAttribute.getSourceFileName());
 			}
-			String versionNumber = VERSION_UNKNOWN;//$NON-NLS-1$
+			String versionNumber = VERSION_UNKNOWN;
 			if (minorVersion == 3 && majorVersion == 45) {
 				versionNumber = JavaCore.VERSION_1_1;
 			} else if (minorVersion == 0 && majorVersion == 46) {
@@ -500,6 +750,10 @@
 				versionNumber = JavaCore.VERSION_1_4;
 			} else if (minorVersion == 0 && majorVersion == 49) {
 				versionNumber = JavaCore.VERSION_1_5;
+			} else if (minorVersion == 0 && majorVersion == 50) {
+				versionNumber = JavaCore.VERSION_1_6;
+			} else if (minorVersion == 0 && majorVersion == 51) {
+				versionNumber = JavaCore.VERSION_1_7;
 			}
 			buffer.append(
 				Messages.bind(Messages.classfileformat_versiondetails,
@@ -510,7 +764,7 @@
 					((accessFlags & IModifierConstants.ACC_SUPER) != 0
 							? Messages.classfileformat_superflagisset
 							: Messages.classfileformat_superflagisnotset)
-					+ (isDeprecated(classFileReader) ? ", deprecated" : EMPTY_OUTPUT)//$NON-NLS-1$
+					+ (isDeprecated(classFileReader) ? ", deprecated" : org.eclipse.jdt.internal.compiler.util.Util.EMPTY_STRING)//$NON-NLS-1$
 				}));
 			writeNewLine(buffer, lineSeparator, 0);
 			if (signatureAttribute != null) {
@@ -518,12 +772,16 @@
 				writeNewLine(buffer, lineSeparator, 0);
 			}
 		}
-		char[] className = classFileReader.getClassName();
-		if (className == null) {
-			// incomplete initialization. We cannot go further.
-			return buffer.toString();
-		}
+		final int lastDotIndexInClassName = CharOperation.lastIndexOf('.', className);
 		
+		if (checkMode(mode, WORKING_COPY) && lastDotIndexInClassName != -1) { 
+			// we print a package declaration
+			buffer.append("package ");//$NON-NLS-1$
+			buffer.append(className, 0, lastDotIndexInClassName);
+			buffer.append(';');
+			writeNewLine(buffer, lineSeparator, 0);
+		}
+
 		IInnerClassesAttribute innerClassesAttribute = classFileReader.getInnerClassesAttribute();
 		IClassFileAttribute runtimeVisibleAnnotationsAttribute = Util.getAttribute(classFileReader, IAttributeNamesConstants.RUNTIME_VISIBLE_ANNOTATIONS);
 		IClassFileAttribute runtimeInvisibleAnnotationsAttribute = Util.getAttribute(classFileReader, IAttributeNamesConstants.RUNTIME_INVISIBLE_ANNOTATIONS);
@@ -531,80 +789,105 @@
 		if (checkMode(mode, DETAILED)) {
 			// disassemble compact version of annotations
 			if (runtimeInvisibleAnnotationsAttribute != null) {
-				disassembleAsModifier((IRuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, 1);
+				disassembleAsModifier((IRuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, 1, mode);
 				writeNewLine(buffer, lineSeparator, 0);
 			}
 			if (runtimeVisibleAnnotationsAttribute != null) {
-				disassembleAsModifier((IRuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, 1);
+				disassembleAsModifier((IRuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, 1, mode);
 				writeNewLine(buffer, lineSeparator, 0);
 			}
 		}
 		boolean decoded = false;
-		if (innerClassesAttribute != null) {
-			// search the right entry
-			IInnerClassesAttributeEntry[] entries = innerClassesAttribute.getInnerClassAttributesEntries();
-			for (int i = 0, max = entries.length; i < max ; i++) {
-				IInnerClassesAttributeEntry entry = entries[i];
-				char[] innerClassName = entry.getInnerClassName();
-				if (innerClassName != null) {
-					if (CharOperation.equals(classFileReader.getClassName(), innerClassName)) {
-						decodeModifiersForInnerClasses(buffer, entry.getAccessFlags());
-						decoded = true;
+		if (isEnum && checkMode(mode, WORKING_COPY)) {
+			decodeModifiersForType(buffer, accessFlags & IModifierConstants.ACC_PUBLIC);
+		} else {
+			if (innerClassesAttribute != null) {
+				// search the right entry
+				IInnerClassesAttributeEntry[] entries = innerClassesAttribute.getInnerClassAttributesEntries();
+				for (int i = 0, max = entries.length; i < max ; i++) {
+					IInnerClassesAttributeEntry entry = entries[i];
+					char[] innerClassName = entry.getInnerClassName();
+					if (innerClassName != null) {
+						if (CharOperation.equals(classFileReader.getClassName(), innerClassName)) {
+							decodeModifiersForInnerClasses(buffer, entry.getAccessFlags(), false);
+							decoded = true;
+						}
 					}
 				}
 			}
-		}
-		if (!decoded) {
-			decodeModifiersForType(buffer, accessFlags);
-			if (isSynthetic(classFileReader)) {
-				buffer.append("synthetic"); //$NON-NLS-1$
-				buffer.append(Messages.disassembler_space); 
+			if (!decoded) {
+				decodeModifiersForType(buffer, accessFlags);
+				if (isSynthetic(classFileReader)) {
+					buffer.append("synthetic"); //$NON-NLS-1$
+					buffer.append(Messages.disassembler_space); 
+				}
 			}
 		}
 		
-		if ((accessFlags & IModifierConstants.ACC_ENUM) != 0) {
+		final boolean isAnnotation = (accessFlags & IModifierConstants.ACC_ANNOTATION) != 0;
+		boolean isInterface = false;
+		if (isEnum) {
 			buffer.append("enum "); //$NON-NLS-1$
 		} else if (classFileReader.isClass()) {
 			buffer.append("class "); //$NON-NLS-1$
 		} else {
-			if ((accessFlags & IModifierConstants.ACC_ANNOTATION) != 0) {
+			if (isAnnotation) {
 				buffer.append("@"); //$NON-NLS-1$
 			}
 			buffer.append("interface "); //$NON-NLS-1$
+			isInterface = true;
 		}
-		CharOperation.replace(className, '/', '.');
-		buffer.append(className);
+		
+		if (checkMode(mode, WORKING_COPY)) {
+			// we print the simple class name
+			final int start = lastDotIndexInClassName + 1;
+			buffer.append(className, start, classNameLength - start);
+			className = CharOperation.subarray(className, start, classNameLength);
+			if (signatureAttribute != null) {
+				disassembleGenericSignature(mode, buffer, signatureAttribute.getSignature());
+			}
+		} else {
+			buffer.append(className);
+		}
 		
 		char[] superclassName = classFileReader.getSuperclassName();
 		if (superclassName != null) {
-			buffer.append(" extends "); //$NON-NLS-1$
 			CharOperation.replace(superclassName, '/', '.');
-			buffer.append(returnClassName(superclassName, '.', mode));
-		}
-		char[][] superclassInterfaces = classFileReader.getInterfaceNames();
-		int length = superclassInterfaces.length;
-		if (length != 0) {
-			buffer.append(" implements "); //$NON-NLS-1$
-			for (int i = 0; i < length - 1; i++) {
-				char[] superinterface = superclassInterfaces[i];
-				CharOperation.replace(superinterface, '/', '.');
-				buffer
-					.append(returnClassName(superinterface, '.', mode))
-					.append(Messages.disassembler_comma)
-					.append(Messages.disassembler_space); 
+			if (!isJavaLangObject(superclassName) && !isEnum) {
+				buffer.append(" extends "); //$NON-NLS-1$
+				buffer.append(returnClassName(superclassName, '.', mode));
 			}
-			char[] superinterface = superclassInterfaces[length - 1];
-			CharOperation.replace(superinterface, '/', '.');
-			buffer.append(returnClassName(superinterface, '.', mode));
+		}
+		if (!isAnnotation || !checkMode(mode, WORKING_COPY)) {
+			char[][] superclassInterfaces = classFileReader.getInterfaceNames();
+			int length = superclassInterfaces.length;
+			if (length != 0) {
+				if (isInterface) {
+					buffer.append(" extends "); //$NON-NLS-1$
+				} else {
+					buffer.append(" implements "); //$NON-NLS-1$
+				}
+				for (int i = 0; i < length; i++) {
+					if (i != 0) {
+						buffer
+							.append(Messages.disassembler_comma)
+							.append(Messages.disassembler_space); 
+					}
+					char[] superinterface = superclassInterfaces[i];
+					CharOperation.replace(superinterface, '/', '.');
+					buffer
+						.append(returnClassName(superinterface, '.', mode));
+				}
+			}
 		}
 		buffer.append(Messages.bind(Messages.disassembler_opentypedeclaration)); 
 		if (checkMode(mode, SYSTEM)) {
 			disassemble(classFileReader.getConstantPool(), buffer, lineSeparator, 1);
 		}
-		disassembleTypeMembers(classFileReader, buffer, lineSeparator, 1, mode);
+		disassembleTypeMembers(classFileReader, className, buffer, lineSeparator, 1, mode, isEnum);
 		if (checkMode(mode, SYSTEM | DETAILED)) {
 			IClassFileAttribute[] attributes = classFileReader.getAttributes();
-			length = attributes.length;
+			int length = attributes.length;
 			IEnclosingMethodAttribute enclosingMethodAttribute = getEnclosingMethodAttribute(classFileReader);
 			int remainingAttributesLength = length;
 			if (innerClassesAttribute != null) {
@@ -656,7 +939,54 @@
 		buffer.append(Messages.disassembler_closetypedeclaration); 
 		return buffer.toString();
 	}
+
+	private void disassembleGenericSignature(int mode, StringBuffer buffer, final char[] signature) {
+		CharOperation.replace(signature, '/', '.');
+		final char[][] typeParameters = Signature.getTypeParameters(signature);
+		final int typeParametersLength = typeParameters.length;
+		if (typeParametersLength != 0) {
+			buffer.append('<');
+			for (int i = 0; i < typeParametersLength; i++) {
+				if (i != 0) {
+					buffer.append(Messages.disassembler_comma);
+				}
+				// extract the name
+				buffer.append(typeParameters[i], 0, CharOperation.indexOf(':', typeParameters[i]));
+				final char[][] bounds = Signature.getTypeParameterBounds(typeParameters[i]);
+				final int boundsLength = bounds.length;
+				if (boundsLength != 0) {
+					if (boundsLength == 1) {
+						final char[] bound = bounds[0];
+						// check if this is java.lang.Object
+						if (!isJavaLangObject(Signature.toCharArray(bound))) {
+							buffer.append(" extends "); //$NON-NLS-1$
+							buffer.append(returnClassName(Signature.toCharArray(bound), '.', mode));
+						}
+					} else {
+						buffer.append(" extends "); //$NON-NLS-1$
+						for (int j= 0; j < boundsLength; j++) {
+							if (j != 0) {
+								buffer.append(" & "); //$NON-NLS-1$
+							}
+							buffer.append(returnClassName(Signature.toCharArray(bounds[j]), '.', mode));
+						}
+					}
+				}
+			}
+			buffer.append('>');
+		}
+	}
+
+	private boolean isJavaLangObject(final char[] className) {
+		return CharOperation.equals(TypeConstants.JAVA_LANG_OBJECT, CharOperation.splitOn('.', className));
+	}
 	
+	private boolean isVarArgs(IMethodInfo methodInfo) {
+		int accessFlags = methodInfo.getAccessFlags();
+		if ((accessFlags & IModifierConstants.ACC_VARARGS) != 0) return true;
+		// check the presence of the unspecified Varargs attribute
+		return Util.getAttribute(methodInfo, AttributeNamesConstants.VarargsName) != null;
+	}
 	private void disassemble(ICodeAttribute codeAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
 		writeNewLine(buffer, lineSeparator, tabNumber - 1);
 		DefaultBytecodeVisitor visitor = new DefaultBytecodeVisitor(codeAttribute, buffer, lineSeparator, tabNumber, mode);
@@ -667,19 +997,25 @@
 			buffer.append(Messages.classformat_classformatexception);
 			writeNewLine(buffer, lineSeparator, tabNumber + 1);
 		}
-		int exceptionTableLength = codeAttribute.getExceptionTableLength();
+		final int exceptionTableLength = codeAttribute.getExceptionTableLength();
+		boolean isFirstAttribute = true;
 		if (exceptionTableLength != 0) {
 			final int tabNumberForExceptionAttribute = tabNumber + 2;
+			isFirstAttribute = false;
 			dumpTab(tabNumberForExceptionAttribute, buffer);
-			IExceptionTableEntry[] exceptionTableEntries = codeAttribute.getExceptionTable();
+			final IExceptionTableEntry[] exceptionTableEntries = codeAttribute.getExceptionTable();
 			buffer.append(Messages.disassembler_exceptiontableheader); 
 			writeNewLine(buffer, lineSeparator, tabNumberForExceptionAttribute + 1);
-			for (int i = 0; i < exceptionTableLength - 1; i++) {
+			for (int i = 0; i < exceptionTableLength; i++) {
+				if (i != 0) {
+					writeNewLine(buffer, lineSeparator, tabNumberForExceptionAttribute + 1);
+				}
 				IExceptionTableEntry exceptionTableEntry = exceptionTableEntries[i];
 				char[] catchType;
 				if (exceptionTableEntry.getCatchTypeIndex() != 0) {
 					catchType = exceptionTableEntry.getCatchType();
 					CharOperation.replace(catchType, '/', '.');
+					catchType = returnClassName(catchType, '.', mode);
 				} else {
 					catchType = ANY_EXCEPTION;
 				}
@@ -690,56 +1026,49 @@
 						Integer.toString(exceptionTableEntry.getHandlerPC()),
 						new String(catchType)
 					}));
-				writeNewLine(buffer, lineSeparator, tabNumberForExceptionAttribute + 1);
 			}
-			IExceptionTableEntry exceptionTableEntry = exceptionTableEntries[exceptionTableLength - 1];
-			char[] catchType;
-			if (exceptionTableEntry.getCatchTypeIndex() != 0) {
-				catchType = exceptionTableEntry.getCatchType();
-				CharOperation.replace(catchType, '/', '.');
-			} else {
-				catchType = ANY_EXCEPTION;
-			}
-			buffer.append(Messages.bind(Messages.classfileformat_exceptiontableentry,
-				new String[] {
-					Integer.toString(exceptionTableEntry.getStartPC()),
-					Integer.toString(exceptionTableEntry.getEndPC()),
-					Integer.toString(exceptionTableEntry.getHandlerPC()),
-					new String(catchType)
-				}));
-			writeNewLine(buffer, lineSeparator, 0);
 		}
-		ILineNumberAttribute lineNumberAttribute = codeAttribute.getLineNumberAttribute();
-		int lineAttributeLength = lineNumberAttribute == null ? 0 : lineNumberAttribute.getLineNumberTableLength();
+		final ILineNumberAttribute lineNumberAttribute = codeAttribute.getLineNumberAttribute();
+		final int lineAttributeLength = lineNumberAttribute == null ? 0 : lineNumberAttribute.getLineNumberTableLength();
 		if (lineAttributeLength != 0) {
 			int tabNumberForLineAttribute = tabNumber + 2;
-			dumpTab(tabNumberForLineAttribute, buffer);
+			if (!isFirstAttribute) {
+				writeNewLine(buffer, lineSeparator, tabNumberForLineAttribute);
+			} else {
+				dumpTab(tabNumberForLineAttribute, buffer);
+				isFirstAttribute = false;
+			}
 			buffer.append(Messages.disassembler_linenumberattributeheader); 
 			writeNewLine(buffer, lineSeparator, tabNumberForLineAttribute + 1);
 			int[][] lineattributesEntries = lineNumberAttribute.getLineNumberTable();
-			for (int i = 0; i < lineAttributeLength - 1; i++) {
+			for (int i = 0; i < lineAttributeLength; i++) {
+				if (i != 0) {
+					writeNewLine(buffer, lineSeparator, tabNumberForLineAttribute + 1);
+				}
 				buffer.append(Messages.bind(Messages.classfileformat_linenumbertableentry,
 					new String[] {
 						Integer.toString(lineattributesEntries[i][0]),
 						Integer.toString(lineattributesEntries[i][1])
 					}));
-				writeNewLine(buffer, lineSeparator, tabNumberForLineAttribute + 1);
 			}
-			buffer.append(Messages.bind(Messages.classfileformat_linenumbertableentry,
-				new String[] {
-					Integer.toString(lineattributesEntries[lineAttributeLength - 1][0]),
-					Integer.toString(lineattributesEntries[lineAttributeLength - 1][1])
-				}));
 		} 
-		ILocalVariableAttribute localVariableAttribute = codeAttribute.getLocalVariableAttribute();
-		int localVariableAttributeLength = localVariableAttribute == null ? 0 : localVariableAttribute.getLocalVariableTableLength();
+		final ILocalVariableAttribute localVariableAttribute = codeAttribute.getLocalVariableAttribute();
+		final int localVariableAttributeLength = localVariableAttribute == null ? 0 : localVariableAttribute.getLocalVariableTableLength();
 		if (localVariableAttributeLength != 0) {
 			int tabNumberForLocalVariableAttribute = tabNumber + 2;
-			writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute);
+			if (!isFirstAttribute) {
+				writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute);
+			} else {
+				isFirstAttribute = false;
+				dumpTab(tabNumberForLocalVariableAttribute, buffer);
+			}
 			buffer.append(Messages.disassembler_localvariabletableattributeheader); 
 			writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute + 1);
 			ILocalVariableTableEntry[] localVariableTableEntries = localVariableAttribute.getLocalVariableTable();
-			for (int i = 0; i < localVariableAttributeLength - 1; i++) {
+			for (int i = 0; i < localVariableAttributeLength; i++) {
+				if (i != 0) {
+					writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute + 1);
+				}
 				ILocalVariableTableEntry localVariableTableEntry = localVariableTableEntries[i];
 				int index= localVariableTableEntry.getIndex();
 				int startPC = localVariableTableEntry.getStartPC();
@@ -754,32 +1083,25 @@
 						Integer.toString(index),
 						new String(returnClassName(typeName, '.', mode))
 					}));
-				writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute + 1);
 			}
-			ILocalVariableTableEntry localVariableTableEntry = localVariableTableEntries[localVariableAttributeLength - 1];
-			int index= localVariableTableEntry.getIndex();
-			int startPC = localVariableTableEntry.getStartPC();
-			int length  = localVariableTableEntry.getLength();
-			final char[] typeName = Signature.toCharArray(localVariableTableEntry.getDescriptor());
-			CharOperation.replace(typeName, '/', '.');
-			buffer.append(Messages.bind(Messages.classfileformat_localvariabletableentry,
-				new String[] {
-					Integer.toString(startPC),
-					Integer.toString(startPC + length),
-					new String(localVariableTableEntry.getName()),
-					Integer.toString(index),
-					new String(returnClassName(typeName, '.', mode))
-				}));
-		} 
-		ILocalVariableTypeTableAttribute localVariableTypeAttribute= getLocalVariableTypeAttribute(codeAttribute);
-		int localVariableTypeTableLength = localVariableTypeAttribute == null ? 0 : localVariableTypeAttribute.getLocalVariableTypeTableLength();
+		}
+		final ILocalVariableTypeTableAttribute localVariableTypeAttribute= (ILocalVariableTypeTableAttribute) getAttribute(IAttributeNamesConstants.LOCAL_VARIABLE_TYPE_TABLE, codeAttribute);
+		final int localVariableTypeTableLength = localVariableTypeAttribute == null ? 0 : localVariableTypeAttribute.getLocalVariableTypeTableLength();
 		if (localVariableTypeTableLength != 0) {
 			int tabNumberForLocalVariableAttribute = tabNumber + 2;
-			writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute);
+			if (!isFirstAttribute) {
+				writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute);
+			} else {
+				isFirstAttribute = false;
+				dumpTab(tabNumberForLocalVariableAttribute, buffer);
+			}
 			buffer.append(Messages.disassembler_localvariabletypetableattributeheader); 
 			writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute + 1);
 			ILocalVariableTypeTableEntry[] localVariableTypeTableEntries = localVariableTypeAttribute.getLocalVariableTypeTable();
-			for (int i = 0; i < localVariableTypeTableLength - 1; i++) {
+			for (int i = 0; i < localVariableTypeTableLength; i++) {
+				if (i != 0) {
+					writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute + 1);
+				}
 				ILocalVariableTypeTableEntry localVariableTypeTableEntry = localVariableTypeTableEntries[i];
 				int index= localVariableTypeTableEntry.getIndex();
 				int startPC = localVariableTypeTableEntry.getStartPC();
@@ -794,23 +1116,176 @@
 						Integer.toString(index),
 						new String(returnClassName(typeName, '.', mode))
 					}));
-				writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute + 1);
 			}
-			ILocalVariableTypeTableEntry localVariableTypeTableEntry = localVariableTypeTableEntries[localVariableTypeTableLength - 1];
-			int index= localVariableTypeTableEntry.getIndex();
-			int startPC = localVariableTypeTableEntry.getStartPC();
-			int length  = localVariableTypeTableEntry.getLength();
-			final char[] typeName = Signature.toCharArray(localVariableTypeTableEntry.getSignature());
-			CharOperation.replace(typeName, '/', '.');
-			buffer.append(Messages.bind(Messages.classfileformat_localvariabletableentry,
-				new String[] {
-					Integer.toString(startPC),
-					Integer.toString(startPC + length),
-					new String(localVariableTypeTableEntry.getName()),
-					Integer.toString(index),
-					new String(returnClassName(typeName, '.', mode))
-				}));
-		} 
+		}
+		final int length = codeAttribute.getAttributesCount();
+		if (length != 0) {
+			IClassFileAttribute[] attributes = codeAttribute.getAttributes();
+			for (int i = 0; i < length; i++) {
+				IClassFileAttribute attribute = attributes[i];
+				if (CharOperation.equals(attribute.getAttributeName(), IAttributeNamesConstants.STACK_MAP_TABLE)) {
+					IStackMapTableAttribute stackMapTableAttribute = (IStackMapTableAttribute) attribute;
+					if (!isFirstAttribute) {
+						writeNewLine(buffer, lineSeparator, tabNumber + 2);
+					} else {
+						isFirstAttribute = false;
+						dumpTab(tabNumber + 1, buffer);
+					}
+					int numberOfEntries = stackMapTableAttribute.getNumberOfEntries();
+					buffer.append(Messages.bind(Messages.disassembler_stackmaptableattributeheader, Integer.toString(numberOfEntries)));
+					if (numberOfEntries != 0) {
+						disassemble(stackMapTableAttribute, buffer, lineSeparator, tabNumber, mode);
+					}
+				} else if (CharOperation.equals(attribute.getAttributeName(), IAttributeNamesConstants.STACK_MAP)) {
+					IStackMapAttribute stackMapAttribute = (IStackMapAttribute) attribute;
+					if (!isFirstAttribute) {
+						writeNewLine(buffer, lineSeparator, tabNumber + 2);
+					} else {
+						isFirstAttribute = false;
+						dumpTab(tabNumber + 1, buffer);
+					}
+					int numberOfEntries = stackMapAttribute.getNumberOfEntries();
+					buffer.append(Messages.bind(Messages.disassembler_stackmapattributeheader, Integer.toString(numberOfEntries)));
+					if (numberOfEntries != 0) {
+						disassemble(stackMapAttribute, buffer, lineSeparator, tabNumber, mode);
+					}
+				} else if (attribute != lineNumberAttribute
+						&& attribute != localVariableAttribute
+						&& attribute != localVariableTypeAttribute) {
+					if (!isFirstAttribute) {
+						writeNewLine(buffer, lineSeparator, tabNumber + 2);
+					} else {
+						isFirstAttribute = false;
+						dumpTab(tabNumber + 1, buffer);
+					}
+					buffer.append(Messages.bind(Messages.disassembler_genericattributeheader,
+						new String[] {
+							new String(attribute.getAttributeName()),
+							Long.toString(attribute.getAttributeLength())
+						}));
+				}
+			}
+		}
+	}
+	
+	private void disassemble(IStackMapTableAttribute attribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
+		writeNewLine(buffer, lineSeparator, tabNumber + 3);
+		int numberOfEntries = attribute.getNumberOfEntries();
+		final IStackMapFrame[] stackMapFrames = attribute.getStackMapFrame();
+		int absolutePC = -1;
+		for (int j = 0; j < numberOfEntries; j++) {
+			if (j > 0) {
+				writeNewLine(buffer, lineSeparator, tabNumber + 3);
+			}
+			final IStackMapFrame frame = stackMapFrames[j];
+			// disassemble each frame
+			int type = frame.getFrameType();
+			int offsetDelta = frame.getOffsetDelta();
+			if (absolutePC == -1) {
+				absolutePC = offsetDelta;
+			} else {
+				absolutePC += (offsetDelta + 1);
+			}
+			switch(type) {
+				case 247 : // SAME_LOCALS_1_STACK_ITEM_EXTENDED
+					buffer.append(
+						Messages.bind(
+							Messages.disassembler_frame_same_locals_1_stack_item_extended,
+							Integer.toString(absolutePC),
+							disassemble(frame.getStackItems(), mode)));
+					break;
+				case 248 :
+				case 249 :
+				case 250:
+					// CHOP
+					buffer.append(
+							Messages.bind(
+								Messages.disassembler_frame_chop,
+								Integer.toString(absolutePC),
+								Integer.toString(251 - type)));
+					break;
+				case 251 :
+					// SAME_FRAME_EXTENDED
+					buffer.append(
+							Messages.bind(
+								Messages.disassembler_frame_same_frame_extended,
+								Integer.toString(absolutePC)));
+					break;
+				case 252 :
+				case 253 :
+				case 254 :
+					// APPEND
+					buffer.append(
+							Messages.bind(
+								Messages.disassembler_frame_append,
+								Integer.toString(absolutePC),
+								disassemble(frame.getLocals(), mode)));
+					break;
+				case 255 :
+					// FULL_FRAME
+					buffer.append(
+							Messages.bind(
+								Messages.disassembler_frame_full_frame,
+								new String[] {
+									Integer.toString(absolutePC),
+									Integer.toString(frame.getNumberOfLocals()),
+									disassemble(frame.getLocals(), mode),
+									Integer.toString(frame.getNumberOfStackItems()),
+									disassemble(frame.getStackItems(), mode),
+									dumpNewLineWithTabs(lineSeparator, tabNumber + 5)
+								}));
+					break;
+				default:
+					if (type <= 63) {
+						// SAME_FRAME
+						offsetDelta = type;
+						buffer.append(
+								Messages.bind(
+									Messages.disassembler_frame_same_frame,
+									Integer.toString(absolutePC)));
+					} else if (type <= 127) {
+						// SAME_LOCALS_1_STACK_ITEM
+						offsetDelta = type - 64;
+						buffer.append(
+								Messages.bind(
+									Messages.disassembler_frame_same_locals_1_stack_item,
+									Integer.toString(absolutePC),
+									disassemble(frame.getStackItems(), mode)));
+					}
+			}
+		}
+	}
+
+	private void disassemble(IStackMapAttribute attribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
+		writeNewLine(buffer, lineSeparator, tabNumber + 3);
+		int numberOfEntries = attribute.getNumberOfEntries();
+		final IStackMapFrame[] stackMapFrames = attribute.getStackMapFrame();
+		int absolutePC = -1;
+		for (int j = 0; j < numberOfEntries; j++) {
+			if (j > 0) {
+				writeNewLine(buffer, lineSeparator, tabNumber + 3);
+			}
+			final IStackMapFrame frame = stackMapFrames[j];
+			// disassemble each frame
+			int offsetDelta = frame.getOffsetDelta();
+			if (absolutePC == -1) {
+				absolutePC = offsetDelta;
+			} else {
+				absolutePC += (offsetDelta + 1);
+			}
+			// FULL_FRAME
+			buffer.append(
+					Messages.bind(
+						Messages.disassembler_frame_full_frame,
+						new String[] {
+							Integer.toString(absolutePC),
+							Integer.toString(frame.getNumberOfLocals()),
+							disassemble(frame.getLocals(), mode),
+							Integer.toString(frame.getNumberOfStackItems()),
+							disassemble(frame.getStackItems(), mode),
+							dumpNewLineWithTabs(lineSeparator, tabNumber + 5)
+						}));
+		}
 	}
 
 	private void disassemble(IConstantPool constantPool, StringBuffer buffer, String lineSeparator, int tabNumber) {
@@ -819,6 +1294,9 @@
 		buffer.append(Messages.disassembler_constantpoolheader); 
 		writeNewLine(buffer, lineSeparator, tabNumber + 1);
 		for (int i = 1; i < length; i++) {
+			if (i != 1) {
+				writeNewLine(buffer, lineSeparator, tabNumber + 1);
+			}
 			IConstantPoolEntry constantPoolEntry = constantPool.decodeEntry(i);
 			switch (constantPool.getEntryKind(i)) {
 				case IConstantPoolConstant.CONSTANT_Class :
@@ -913,19 +1391,16 @@
 							new String[] {
 								Integer.toString(i),
 								Integer.toString(constantPoolEntry.getStringIndex()),
-								constantPoolEntry.getStringValue()}));
+								decodeStringValue(constantPoolEntry.getStringValue())}));
 					break;
 				case IConstantPoolConstant.CONSTANT_Utf8 :
 					buffer.append(
 						Messages.bind(Messages.disassembler_constantpool_utf8,
 							new String[] {
 								Integer.toString(i),
-								new String(constantPoolEntry.getUtf8Value())}));
+								decodeStringValue(new String(constantPoolEntry.getUtf8Value()))}));
 					break;
 			}
-			if (i < length - 1) {
-				writeNewLine(buffer, lineSeparator, tabNumber + 1);
-			}
 		}
 	}
 
@@ -939,23 +1414,72 @@
 			.append(Messages.disassembler_constantpoolindex) 
 			.append(enclosingMethodAttribute.getMethodNameAndTypeIndex())
 			.append(" ")//$NON-NLS-1$
-			.append(enclosingMethodAttribute.getEnclosingClass()); //$NON-NLS-1$
+			.append(enclosingMethodAttribute.getEnclosingClass());
 		if (enclosingMethodAttribute.getMethodNameAndTypeIndex() != 0) {
 			buffer
 				.append(".")//$NON-NLS-1$
-				.append(enclosingMethodAttribute.getMethodName()) //$NON-NLS-1$
-				.append(enclosingMethodAttribute.getMethodDescriptor()); //$NON-NLS-1$
+				.append(enclosingMethodAttribute.getMethodName())
+				.append(enclosingMethodAttribute.getMethodDescriptor());
 		}
 	}
 	
+	private void disassembleEnumConstants(IFieldInfo fieldInfo, StringBuffer buffer, String lineSeparator, int tabNumber, char[][] argumentTypes, int mode) {
+		writeNewLine(buffer, lineSeparator, tabNumber);
+		final IClassFileAttribute runtimeVisibleAnnotationsAttribute = Util.getAttribute(fieldInfo, IAttributeNamesConstants.RUNTIME_VISIBLE_ANNOTATIONS);
+		final IClassFileAttribute runtimeInvisibleAnnotationsAttribute = Util.getAttribute(fieldInfo, IAttributeNamesConstants.RUNTIME_INVISIBLE_ANNOTATIONS);
+		// disassemble compact version of annotations
+		if (runtimeInvisibleAnnotationsAttribute != null) {
+			disassembleAsModifier((IRuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber + 1, mode);
+			writeNewLine(buffer, lineSeparator, tabNumber);
+		}
+		if (runtimeVisibleAnnotationsAttribute != null) {
+			disassembleAsModifier((IRuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber + 1, mode);
+			writeNewLine(buffer, lineSeparator, tabNumber);
+		}
+		buffer.append(new String(fieldInfo.getName()));
+		buffer.append('(');
+		final int length = argumentTypes.length;
+		if (length != 0) {
+			// insert default value for corresponding argument types
+			for (int i = 0; i < length; i++) {
+				if (i != 0) {
+					buffer.append(Messages.disassembler_comma);
+				}
+				final char[] type = argumentTypes[i];
+				switch(type.length) {
+					case 1 :
+						switch(type[0]) {
+							case 'B' :
+							case 'I' :
+							case 'J' :
+							case 'D' :
+							case 'F' :
+							case 'S' :
+								buffer.append('0');
+								break;
+							case 'Z' :
+								buffer.append("false"); //$NON-NLS-1$
+								break;
+							case 'C' :
+								buffer.append("\' \'"); //$NON-NLS-1$
+								break;
+						}
+						break;
+					default :
+						buffer.append("null"); //$NON-NLS-1$
+				}
+			}
+		}
+		buffer.append(')').append(Messages.disassembler_comma);
+	}
+	
 	/**
 	 * Disassemble a field info
 	 */
 	private void disassemble(IFieldInfo fieldInfo, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
 		writeNewLine(buffer, lineSeparator, tabNumber);
-		char[] fieldDescriptor = fieldInfo.getDescriptor();
-		IClassFileAttribute classFileAttribute = Util.getAttribute(fieldInfo, IAttributeNamesConstants.SIGNATURE);
-		ISignatureAttribute signatureAttribute = (ISignatureAttribute) classFileAttribute;
+		final char[] fieldDescriptor = fieldInfo.getDescriptor();
+		final ISignatureAttribute signatureAttribute = (ISignatureAttribute) Util.getAttribute(fieldInfo, IAttributeNamesConstants.SIGNATURE);
 		if (checkMode(mode, SYSTEM | DETAILED)) {
 			buffer.append(Messages.bind(Messages.classfileformat_fieldddescriptor,
 				new String[] {
@@ -971,25 +1495,34 @@
 				writeNewLine(buffer, lineSeparator, tabNumber);
 			}
 		}
-		IClassFileAttribute runtimeVisibleAnnotationsAttribute = Util.getAttribute(fieldInfo, IAttributeNamesConstants.RUNTIME_VISIBLE_ANNOTATIONS);
-		IClassFileAttribute runtimeInvisibleAnnotationsAttribute = Util.getAttribute(fieldInfo, IAttributeNamesConstants.RUNTIME_INVISIBLE_ANNOTATIONS);
+		final IClassFileAttribute runtimeVisibleAnnotationsAttribute = Util.getAttribute(fieldInfo, IAttributeNamesConstants.RUNTIME_VISIBLE_ANNOTATIONS);
+		final IClassFileAttribute runtimeInvisibleAnnotationsAttribute = Util.getAttribute(fieldInfo, IAttributeNamesConstants.RUNTIME_INVISIBLE_ANNOTATIONS);
 		if (checkMode(mode, DETAILED)) {
 			// disassemble compact version of annotations
 			if (runtimeInvisibleAnnotationsAttribute != null) {
-				disassembleAsModifier((IRuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber + 1);
+				disassembleAsModifier((IRuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber + 1, mode);
 				writeNewLine(buffer, lineSeparator, tabNumber);
 			}
 			if (runtimeVisibleAnnotationsAttribute != null) {
-				disassembleAsModifier((IRuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber + 1);
+				disassembleAsModifier((IRuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber + 1, mode);
 				writeNewLine(buffer, lineSeparator, tabNumber);
 			}
 		}
-		decodeModifiersForField(buffer, fieldInfo.getAccessFlags());
-		if (fieldInfo.isSynthetic()) {
-			buffer.append("synthetic"); //$NON-NLS-1$
-			buffer.append(Messages.disassembler_space); 
+		if (checkMode(mode, WORKING_COPY)) {
+			decodeModifiersForFieldForWorkingCopy(buffer, fieldInfo.getAccessFlags());
+			if (signatureAttribute != null) {
+				buffer.append(returnClassName(getSignatureForField(signatureAttribute.getSignature()), '.', mode));
+			} else {
+				buffer.append(returnClassName(getSignatureForField(fieldDescriptor), '.', mode));
+			}
+		} else {
+			decodeModifiersForField(buffer, fieldInfo.getAccessFlags());
+			if (fieldInfo.isSynthetic()) {
+				buffer.append("synthetic"); //$NON-NLS-1$
+				buffer.append(Messages.disassembler_space);
+			}
+			buffer.append(returnClassName(getSignatureForField(fieldDescriptor), '.', mode));
 		}
-		buffer.append(getSignatureForField(fieldDescriptor));
 		buffer.append(' ');
 		buffer.append(new String(fieldInfo.getName()));
 		IConstantValueAttribute constantValueAttribute = fieldInfo.getConstantValueAttribute();
@@ -1004,7 +1537,18 @@
 					buffer.append(constantPoolEntry.getFloatValue() + "f"); //$NON-NLS-1$
 					break;
 				case IConstantPoolConstant.CONSTANT_Double :
-					buffer.append(constantPoolEntry.getDoubleValue());
+					final double doubleValue = constantPoolEntry.getDoubleValue();
+					if (checkMode(mode, ClassFileBytesDisassembler.WORKING_COPY)) {
+						if (doubleValue == Double.POSITIVE_INFINITY) {
+							buffer.append("1.0 / 0.0"); //$NON-NLS-1$
+						} else if (doubleValue == Double.NEGATIVE_INFINITY) {
+							buffer.append("-1.0 / 0.0"); //$NON-NLS-1$
+						} else {
+							buffer.append(constantPoolEntry.getDoubleValue());
+						}
+					} else {
+						buffer.append(constantPoolEntry.getDoubleValue());
+					}
 					break;
 				case IConstantPoolConstant.CONSTANT_Integer:
 					switch(fieldDescriptor[0]) {
@@ -1062,7 +1606,11 @@
 		int length = innerClassesAttributeEntries.length;
 		int innerClassNameIndex, outerClassNameIndex, innerNameIndex, accessFlags;
 		IInnerClassesAttributeEntry innerClassesAttributeEntry;
-		for (int i = 0; i < length - 1; i++) {
+		for (int i = 0; i < length; i++) {
+			if (i != 0) {
+				buffer.append(Messages.disassembler_comma);
+				writeNewLine(buffer, lineSeparator, tabNumber + 1);				
+			}
 			innerClassesAttributeEntry = innerClassesAttributeEntries[i];
 			innerClassNameIndex = innerClassesAttributeEntry.getInnerClassNameIndex();
 			outerClassNameIndex = innerClassesAttributeEntry.getOuterClassNameIndex();
@@ -1107,59 +1655,10 @@
 				.append(Messages.disassembler_inner_accessflags) 
 				.append(accessFlags)
 				.append(Messages.disassembler_space); 
-			decodeModifiersForInnerClasses(buffer, accessFlags);
+			decodeModifiersForInnerClasses(buffer, accessFlags, true);
 			buffer
-				.append(Messages.disassembler_closeinnerclassentry) 
-				.append(Messages.disassembler_comma); 
-			writeNewLine(buffer, lineSeparator, tabNumber + 1);
+				.append(Messages.disassembler_closeinnerclassentry);
 		}
-		// last entry
-		innerClassesAttributeEntry = innerClassesAttributeEntries[length - 1];
-		innerClassNameIndex = innerClassesAttributeEntry.getInnerClassNameIndex();
-		outerClassNameIndex = innerClassesAttributeEntry.getOuterClassNameIndex();
-		innerNameIndex = innerClassesAttributeEntry.getInnerNameIndex();
-		accessFlags = innerClassesAttributeEntry.getAccessFlags();
-		buffer
-			.append(Messages.disassembler_openinnerclassentry) 
-			.append(Messages.disassembler_inner_class_info_name) 
-			.append(Messages.disassembler_constantpoolindex) 
-			.append(innerClassNameIndex);
-		if (innerClassNameIndex != 0) {
-			buffer
-				.append(Messages.disassembler_space) 
-				.append(innerClassesAttributeEntry.getInnerClassName());
-		}
-		buffer
-			.append(Messages.disassembler_comma) 
-			.append(Messages.disassembler_space) 
-			.append(Messages.disassembler_outer_class_info_name) 
-			.append(Messages.disassembler_constantpoolindex) 
-			.append(outerClassNameIndex);
-		if (outerClassNameIndex != 0) {
-			buffer	
-				.append(Messages.disassembler_space) 
-				.append(innerClassesAttributeEntry.getOuterClassName());
-		}
-		writeNewLine(buffer, lineSeparator, tabNumber);
-		dumpTab(tabNumber, buffer);
-		buffer.append(Messages.disassembler_space); 
-		buffer
-			.append(Messages.disassembler_inner_name) 
-			.append(Messages.disassembler_constantpoolindex) 
-			.append(innerNameIndex);
-		if (innerNameIndex != 0) {
-			buffer
-				.append(Messages.disassembler_space) 
-				.append(innerClassesAttributeEntry.getInnerName());
-		}
-		buffer
-			.append(Messages.disassembler_comma) 
-			.append(Messages.disassembler_space) 
-			.append(Messages.disassembler_inner_accessflags) 
-			.append(accessFlags)
-			.append(Messages.disassembler_space); 
-		decodeModifiersForInnerClasses(buffer, accessFlags);
-		buffer.append(Messages.disassembler_closeinnerclassentry); 
 	}
 
 	private void disassemble(int index, IParameterAnnotation parameterAnnotation, StringBuffer buffer, String lineSeparator, int tabNumber) {
@@ -1208,26 +1707,79 @@
 		}
 	}
 
-	private void disassembleAsModifier(IAnnotation annotation, StringBuffer buffer, String lineSeparator, int tabNumber) {
-		final char[] typeName = CharOperation.replaceOnCopy(annotation.getTypeName(), '/', '.');
-		buffer.append('@').append(Signature.toCharArray(typeName)).append('(');
-		final IAnnotationComponent[] components = annotation.getComponents();
-		for (int i = 0, max = components.length; i < max; i++) {
-			if (i > 0) {
-				buffer.append(',');
-				writeNewLine(buffer, lineSeparator, tabNumber);
+	private String disassemble(IVerificationTypeInfo[] infos, int mode) {
+		StringBuffer buffer = new StringBuffer();
+		buffer.append('{');
+		for (int i = 0, max = infos.length; i < max; i++) {
+			if(i != 0) {
+				buffer
+						.append(Messages.disassembler_comma)
+						.append(Messages.disassembler_space);
 			}
-			disassembleAsModifier(components[i], buffer, lineSeparator, tabNumber + 1);
+			switch(infos[i].getTag()) {
+				case IVerificationTypeInfo.ITEM_DOUBLE :
+					buffer.append("double"); //$NON-NLS-1$
+					break;
+				case IVerificationTypeInfo.ITEM_FLOAT :
+					buffer.append("float"); //$NON-NLS-1$
+					break;
+				case IVerificationTypeInfo.ITEM_INTEGER :
+					buffer.append("int"); //$NON-NLS-1$
+					break;
+				case IVerificationTypeInfo.ITEM_LONG :
+					buffer.append("long"); //$NON-NLS-1$
+					break;
+				case IVerificationTypeInfo.ITEM_NULL :
+					buffer.append("null"); //$NON-NLS-1$
+					break;
+				case IVerificationTypeInfo.ITEM_OBJECT :
+					char[] classTypeName = infos[i].getClassTypeName();
+					CharOperation.replace(classTypeName, '/', '.');
+					if (classTypeName.length > 0 && classTypeName[0] == '[') { // length check for resilience
+						classTypeName = Signature.toCharArray(classTypeName);
+					}
+					buffer.append(returnClassName(classTypeName, '.', mode));
+					break;
+				case IVerificationTypeInfo.ITEM_TOP :
+					buffer.append("_"); //$NON-NLS-1$
+					break;
+				case IVerificationTypeInfo.ITEM_UNINITIALIZED :
+					buffer.append("uninitialized("); //$NON-NLS-1$
+					buffer.append(infos[i].getOffset());
+					buffer.append(')');
+					break;
+				case IVerificationTypeInfo.ITEM_UNINITIALIZED_THIS :
+					buffer.append("uninitialized_this"); //$NON-NLS-1$
+			}
 		}
-		buffer.append(')');
+		buffer.append('}');
+		return String.valueOf(buffer);
 	}
 
-	private void disassembleAsModifier(IAnnotationComponent annotationComponent, StringBuffer buffer, String lineSeparator, int tabNumber) {
+	private void disassembleAsModifier(IAnnotation annotation, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
+		final char[] typeName = CharOperation.replaceOnCopy(annotation.getTypeName(), '/', '.');
+		buffer.append('@').append(returnClassName(Signature.toCharArray(typeName), '.', mode));
+		final IAnnotationComponent[] components = annotation.getComponents();
+		final int length = components.length;
+		if (length != 0) {
+			buffer.append('(');
+			for (int i = 0; i < length; i++) {
+				if (i > 0) {
+					buffer.append(',');
+					writeNewLine(buffer, lineSeparator, tabNumber);
+				}
+				disassembleAsModifier(components[i], buffer, lineSeparator, tabNumber + 1, mode);
+			}
+			buffer.append(')');
+		}
+	}
+
+	private void disassembleAsModifier(IAnnotationComponent annotationComponent, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
 		buffer.append(annotationComponent.getComponentName()).append('=');
-		disassembleAsModifier(annotationComponent.getComponentValue(), buffer, lineSeparator, tabNumber + 1);
+		disassembleAsModifier(annotationComponent.getComponentValue(), buffer, lineSeparator, tabNumber + 1, mode);
 	}
 
-	private void disassembleAsModifier(IAnnotationComponentValue annotationComponentValue, StringBuffer buffer, String lineSeparator, int tabNumber) {
+	private void disassembleAsModifier(IAnnotationComponentValue annotationComponentValue, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
 		switch(annotationComponentValue.getTag()) {
 			case IAnnotationComponentValue.BYTE_TAG:
 			case IAnnotationComponentValue.CHAR_TAG:
@@ -1271,7 +1823,7 @@
 					case IConstantPoolConstant.CONSTANT_Utf8:
 						value = "\"" + decodeStringValue(constantPoolEntry.getUtf8Value()) + "\"";//$NON-NLS-1$//$NON-NLS-2$
 				}
-				buffer.append(value); //$NON-NLS-1$
+				buffer.append(value);
 				break;
 			case IAnnotationComponentValue.ENUM_TAG:
 				final char[] typeName = CharOperation.replaceOnCopy(annotationComponentValue.getEnumConstantTypeName(), '/', '.');
@@ -1285,7 +1837,7 @@
 				break;
 			case IAnnotationComponentValue.ANNOTATION_TAG:
 				IAnnotation annotation = annotationComponentValue.getAnnotationValue();
-				disassembleAsModifier(annotation, buffer, lineSeparator, tabNumber + 1);
+				disassembleAsModifier(annotation, buffer, lineSeparator, tabNumber + 1, mode);
 				break;
 			case IAnnotationComponentValue.ARRAY_TAG:
 				final IAnnotationComponentValue[] annotationComponentValues = annotationComponentValue.getAnnotationComponentValues();
@@ -1294,48 +1846,129 @@
 					if (i > 0) {
 						buffer.append(',');
 					}
-					disassembleAsModifier(annotationComponentValues[i], buffer, lineSeparator, tabNumber + 1);
+					disassembleAsModifier(annotationComponentValues[i], buffer, lineSeparator, tabNumber + 1, mode);
 				}
 				buffer.append('}');
 		}
 	}
 
-	private void disassembleAsModifier(IAnnotationDefaultAttribute annotationDefaultAttribute, StringBuffer buffer, String lineSeparator, int tabNumber) {
+	private void disassembleAsModifier(IAnnotationDefaultAttribute annotationDefaultAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
 		IAnnotationComponentValue componentValue = annotationDefaultAttribute.getMemberValue();
-		disassembleAsModifier(componentValue, buffer, lineSeparator, tabNumber + 1);
+		disassembleAsModifier(componentValue, buffer, lineSeparator, tabNumber + 1, mode);
 	}
 	
-	private void disassembleAsModifier(IRuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber) {
+	private void disassembleAsModifier(IRuntimeInvisibleAnnotationsAttribute runtimeInvisibleAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
 		IAnnotation[] annotations = runtimeInvisibleAnnotationsAttribute.getAnnotations();
 		for (int i = 0, max = annotations.length; i < max; i++) {
-			disassembleAsModifier(annotations[i], buffer, lineSeparator, tabNumber + 1);
+			disassembleAsModifier(annotations[i], buffer, lineSeparator, tabNumber + 1, mode);
 		}
 	}
 
-	private void disassembleAsModifier(IRuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber) {
+	private void disassembleAsModifier(IRuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
 		IAnnotation[] annotations = runtimeVisibleAnnotationsAttribute.getAnnotations();
 		for (int i = 0, max = annotations.length; i < max; i++) {
-			disassembleAsModifier(annotations[i], buffer, lineSeparator, tabNumber + 1);
+			disassembleAsModifier(annotations[i], buffer, lineSeparator, tabNumber + 1, mode);
 		}
 	}
 
-	private void disassembleTypeMembers(IClassFileReader classFileReader, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
+	private void disassembleTypeMembers(IClassFileReader classFileReader, char[] className, StringBuffer buffer, String lineSeparator, int tabNumber, int mode, boolean isEnum) {
 		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);
+		if (isEnum && checkMode(mode, WORKING_COPY)) {
+			int index = 0;
+			final int fieldsLength = fields.length;
+			IMethodInfo[] methods = classFileReader.getMethodInfos();
+			char[][] constructorArguments = getConstructorArgumentsForEnum(methods);
+			enumConstantLoop: for (; index < fieldsLength; index++) {
+				final IFieldInfo fieldInfo = fields[index];
+				final int accessFlags = fieldInfo.getAccessFlags();
+				if ((accessFlags & IModifierConstants.ACC_ENUM) != 0) {
+					writeNewLine(buffer, lineSeparator, tabNumber);
+					disassembleEnumConstants(fields[index], buffer, lineSeparator, tabNumber, constructorArguments, mode);
+				} else {
+					break enumConstantLoop;
+				}
+			}
+			buffer.append(';');
+			boolean foundSyntheticField = false;
+			fieldLoop: for (; index < fieldsLength; index++) {
+				if (!foundSyntheticField && CharOperation.equals(TypeConstants.SYNTHETIC_ENUM_VALUES, fields[index].getName())) {
+					foundSyntheticField = true;
+					continue fieldLoop;
+				}
+				writeNewLine(buffer, lineSeparator, tabNumber);
+				disassemble(fields[index], buffer, lineSeparator, tabNumber, mode);
+			}
+			methodLoop: for (int i = 0, max = methods.length; i < max; i++) {
+				final IMethodInfo methodInfo = methods[i];
+				if (CharOperation.equals(methodInfo.getName(), TypeConstants.VALUES)) {
+					final char[] descriptor = methodInfo.getDescriptor();
+					CharOperation.replace(descriptor, '/', '.');
+					if (Signature.getParameterCount(descriptor) == 0) {
+						if (CharOperation.equals(returnClassName(Signature.getReturnType(descriptor), '.', mode),
+								CharOperation.concat(new char[] {'[', 'L'}, className, new char[] {';'}))) {
+							continue methodLoop;
+						}
+					}
+				} else if (CharOperation.equals(methodInfo.getName(), TypeConstants.VALUEOF)) {
+					final char[] descriptor = methodInfo.getDescriptor();
+					CharOperation.replace(descriptor, '/', '.');
+					final char[][] parameterTypes = Signature.getParameterTypes(descriptor);
+					if (parameterTypes.length == 1
+							&& CharOperation.equals(parameterTypes[0], "Ljava.lang.String;".toCharArray())) { //$NON-NLS-1$
+						if (CharOperation.equals(returnClassName(Signature.getReturnType(descriptor), '.', mode),
+								CharOperation.concat('L', className, ';'))) {
+							continue methodLoop;
+						}
+					}
+				} else if (methodInfo.isClinit() || methodInfo.isSynthetic()) {
+					continue methodLoop;
+				} else if (methodInfo.isConstructor()) {
+					writeNewLine(buffer, lineSeparator, tabNumber);
+					disassembleEnumConstructor(classFileReader, className, methodInfo, buffer, lineSeparator, tabNumber, mode);
+				} else {
+					writeNewLine(buffer, lineSeparator, tabNumber);
+					disassemble(classFileReader, className, methodInfo, buffer, lineSeparator, tabNumber, mode);
+				}
+			}
+		} else {
+			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, className, methods[i], buffer, lineSeparator, tabNumber, mode);
+			}
 		}
 	}
 	
+	private char[][] getConstructorArgumentsForEnum(final IMethodInfo[] methods) {
+		loop: for (int i = 0, max = methods.length; i < max; i++) {
+			IMethodInfo methodInfo = methods[i];
+			if (methodInfo.isConstructor()) {
+				char[][] parameterTypes = Signature.getParameterTypes(methodInfo.getDescriptor());
+				final int length = parameterTypes.length;
+				if (length >= 2) {
+					return CharOperation.subarray(parameterTypes, 2, length);
+				}
+			} else {
+				continue loop;
+			}
+		}
+		return null;
+	}
+
 	private final void dumpTab(int tabNumber, StringBuffer buffer) {
 		for (int i = 0; i < tabNumber; i++) {
 			buffer.append(Messages.disassembler_indentation); 
 		}
+	}
+	
+	private final String dumpNewLineWithTabs(String lineSeparator, int tabNumber) {
+		StringBuffer buffer = new StringBuffer();
+		writeNewLine(buffer, lineSeparator, tabNumber);
+		return String.valueOf(buffer);
 	} 
 	
 	/**
@@ -1354,29 +1987,11 @@
 		}
 		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) {
+	private IClassFileAttribute getAttribute(final char[] attributeName, final 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];
+			if (CharOperation.equals(attributes[i].getAttributeName(), attributeName)) {
+				return attributes[i];
 			}
 		}
 		return null;
@@ -1390,33 +2005,66 @@
 			ILocalVariableAttribute localVariableAttribute = codeAttribute.getLocalVariableAttribute();
 			if (localVariableAttribute != null) {
 				ILocalVariableTableEntry[] entries = localVariableAttribute.getLocalVariableTable();
-				int startingIndex = (accessFlags & IModifierConstants.ACC_STATIC) != 0 ? 0 : 1;
+				final int startingIndex = (accessFlags & IModifierConstants.ACC_STATIC) != 0 ? 0 : 1;
 				for (int i = 0; i < paramCount; i++) {
-					ILocalVariableTableEntry searchedEntry = getEntryFor(startingIndex + i, entries);
+					ILocalVariableTableEntry searchedEntry = getEntryFor(getLocalIndex(startingIndex, i, methodDescriptor), entries);
 					if (searchedEntry != null) {
 						parameterNames[i] = searchedEntry.getName();
 					} else {
-						parameterNames[i] = Messages.disassembler_parametername.toCharArray(); 
+						parameterNames[i] = CharOperation.concat(Messages.disassembler_parametername.toCharArray(), Integer.toString(i).toCharArray()); 
 					}
 				}
 			} else {
 				for (int i = 0; i < paramCount; i++) {
-					parameterNames[i] = Messages.disassembler_parametername.toCharArray(); 
+					parameterNames[i] = CharOperation.concat(Messages.disassembler_parametername.toCharArray(), Integer.toString(i).toCharArray()); 
 				}
 			}
 		} else {
 			for (int i = 0; i < paramCount; i++) {
-				parameterNames[i] = Messages.disassembler_parametername.toCharArray(); 
+				parameterNames[i] = CharOperation.concat(Messages.disassembler_parametername.toCharArray(), Integer.toString(i).toCharArray()); 
 			}
 		}
 		return parameterNames;
 	}
+	
+	private int getLocalIndex(final int startingSlot, final int index, final char[] methodDescriptor) {
+		int slot = startingSlot;
+		final char[][] types = Signature.getParameterTypes(methodDescriptor);
+		for (int i = 0; i < index; i++) {
+			final char[] type = types[i];
+			switch(type.length) {
+				case 1 :
+					switch(type[0]) {
+						case 'D' :
+						case 'J' :
+							slot += 2;
+							break;
+						default :
+							slot++;
+					}
+					break;
+				default :
+					slot++;
+			}
+		}
+		return slot;
+	}
+
+	private ILocalVariableTableEntry getEntryFor(final int index, final ILocalVariableTableEntry[] entries) {
+		for (int i = 0, max = entries.length; i < max; i++) {
+			ILocalVariableTableEntry entry = entries[i];
+			if (index == entry.getIndex()) {
+				return entry;
+			}
+		}
+		return null;
+	}
 
 	private char[] getSignatureForField(char[] fieldDescriptor) {
 		char[] newFieldDescriptor = CharOperation.replaceOnCopy(fieldDescriptor, '/', '.');
-		newFieldDescriptor = CharOperation.replaceOnCopy(newFieldDescriptor, '$', '~');
+		newFieldDescriptor = CharOperation.replaceOnCopy(newFieldDescriptor, '$', '%');
 		char[] fieldDescriptorSignature = Signature.toCharArray(newFieldDescriptor);
-		CharOperation.replace(fieldDescriptorSignature, '~', '$');
+		CharOperation.replace(fieldDescriptorSignature, '%', '$');
 		return fieldDescriptorSignature;
 	}
 	
@@ -1452,18 +2100,16 @@
 		return (mode & ClassFileBytesDisassembler.COMPACT) != 0;
 	}
 
-	private String returnClassName(char[] classInfoName, char separator, int mode) {
+	private char[] returnClassName(char[] classInfoName, char separator, int mode) {
 		if (classInfoName.length == 0) {
-			return EMPTY_CLASS_NAME;
+			return CharOperation.NO_CHAR;
 		} else if (isCompact(mode)) {
 			int lastIndexOfSlash = CharOperation.lastIndexOf(separator, classInfoName);
 			if (lastIndexOfSlash != -1) {
-				return new String(classInfoName, lastIndexOfSlash + 1, classInfoName.length - lastIndexOfSlash - 1);
+				return CharOperation.subarray(classInfoName, lastIndexOfSlash + 1, classInfoName.length);
 			}
-			return new String(classInfoName);
-		} else {
-			return new String(classInfoName);
 		}
+		return classInfoName;
 	}
 	
 	private void writeNewLine(StringBuffer buffer, String lineSeparator, int tabNumber) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/EnclosingMethodAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/EnclosingMethodAttribute.java
index 83a5f40..bfa9a60 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/EnclosingMethodAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/EnclosingMethodAttribute.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 d0a6ff2..519bfcf 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -20,10 +20,7 @@
 /**
  * Default implementation of IExceptionAttribute.
  */
-public class ExceptionAttribute extends ClassFileAttribute implements IExceptionAttribute {
-	private static final int[] NO_EXCEPTION_INDEXES = new int[0];
-	private static final char[][] NO_EXCEPTION_NAMES = CharOperation.NO_CHAR_CHAR;
-	
+public class ExceptionAttribute extends ClassFileAttribute implements IExceptionAttribute {	
 	private int exceptionsNumber;
 	private char[][] exceptionNames;
 	private int[] exceptionIndexes;
@@ -32,8 +29,8 @@
 		super(classFileBytes, constantPool, offset);
 		this.exceptionsNumber = u2At(classFileBytes, 6, offset);
 		int exceptionLength = this.exceptionsNumber;
-		this.exceptionNames = NO_EXCEPTION_NAMES;
-		this.exceptionIndexes = NO_EXCEPTION_INDEXES;
+		this.exceptionNames = CharOperation.NO_CHAR_CHAR;
+		this.exceptionIndexes = org.eclipse.jdt.internal.compiler.util.Util.EMPTY_INT_ARRAY;
 		if (exceptionLength != 0) {
 			this.exceptionNames = new char[exceptionLength][];
 			this.exceptionIndexes = new int[exceptionLength];
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 37d4abc..f01ea37 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 3ab3e51..8a0dcc1 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 522f6c3..4807441 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -69,6 +69,7 @@
 		this.javaModel = JavaModelManager.getJavaModelManager().getJavaModel();
 	}
 	
+
 	/**
 	 * Creates an Openable handle from the given resource path.
 	 * The resource path can be a path to a file in the workbench (eg. /Proj/com/ibm/jdt/core/HandleFactory.java)
@@ -83,9 +84,12 @@
 		int separatorIndex;
 		if ((separatorIndex= resourcePath.indexOf(IJavaSearchScope.JAR_FILE_ENTRY_SEPARATOR)) > -1) {
 			// path to a class file inside a jar
-			String jarPath= resourcePath.substring(0, separatorIndex);
 			// Optimization: cache package fragment root handle and package handles
-			if (!jarPath.equals(this.lastPkgFragmentRootPath)) {
+			int rootPathLength;
+			if (this.lastPkgFragmentRootPath == null 
+					|| (rootPathLength = this.lastPkgFragmentRootPath.length()) != resourcePath.length()
+					|| !resourcePath.regionMatches(0, this.lastPkgFragmentRootPath, 0, rootPathLength)) {
+				String jarPath= resourcePath.substring(0, separatorIndex);
 				IPackageFragmentRoot root= this.getJarPkgFragmentRoot(jarPath, scope);
 				if (root == null)
 					return null; // match is outside classpath
@@ -151,7 +155,7 @@
 				return (Openable) classFile;
 			}
 		}
-	}
+	}	
 	
 	/**
 	 * Returns a handle denoting the class member identified by its scope.
@@ -254,13 +258,10 @@
 			//        is NOT on the classpath of org.eclipse.swt.win32
 			IFile jarFile = (IFile)target;
 			JavaProject javaProject = (JavaProject) this.javaModel.getJavaProject(jarFile);
-			IClasspathEntry[] classpathEntries;
 			try {
-				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);
-					}
+				IClasspathEntry entry = javaProject.getClasspathEntryFor(jarPath);
+				if (entry != null) {
+					return javaProject.getPackageFragmentRoot(jarFile);
 				}
 			} catch (JavaModelException e) {
 				// ignore and try to find another project
@@ -306,16 +307,14 @@
 		for (int i= 0, projectCount= projects.length; i < projectCount; i++) {
 			try {
 				JavaProject javaProject= (JavaProject)projects[i];
-				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) {
-							// internal jar
-							return javaProject.getPackageFragmentRoot((IFile)target);
-						} else {
-							// external jar
-							return javaProject.getPackageFragmentRoot0(jarPath);
-						}
+				IClasspathEntry classpathEnty = javaProject.getClasspathEntryFor(jarPath);
+				if (classpathEnty != null) {
+					if (target instanceof IFile) {
+						// internal jar
+						return javaProject.getPackageFragmentRoot((IFile)target);
+					} else {
+						// external jar
+						return javaProject.getPackageFragmentRoot0(jarPath);
 					}
 				}
 			} catch (JavaModelException e) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/HashSetOfArray.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/HashSetOfArray.java
new file mode 100755
index 0000000..984b74b
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/HashSetOfArray.java
@@ -0,0 +1,149 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core.util;
+
+/**
+ * HashSet of Object[]
+ */
+public final class HashSetOfArray implements Cloneable {
+	
+	// to avoid using Enumerations, walk the individual tables skipping nulls
+	public Object[][] set;
+
+	public int elementSize; // number of elements in the table
+	int threshold;
+
+	public HashSetOfArray() {
+		this(13);
+	}
+
+	public HashSetOfArray(int size) {
+
+		this.elementSize = 0;
+		this.threshold = size; // size represents the expected number of elements
+		int extraRoom = (int) (size * 1.75f);
+		if (this.threshold == extraRoom)
+			extraRoom++;
+		this.set = new Object[extraRoom][];
+	}
+
+	public Object clone() throws CloneNotSupportedException {
+		HashSetOfArray result = (HashSetOfArray) super.clone();
+		result.elementSize = this.elementSize;
+		result.threshold = this.threshold;
+
+		int length = this.set.length;
+		result.set = new Object[length][];
+		System.arraycopy(this.set, 0, result.set, 0, length);
+
+		return result;
+	}
+
+	public boolean contains(Object[] array) {
+		int length = this.set.length;
+		int index = hashCode(array) % length;
+		int arrayLength = array.length;
+		Object[] currentArray;
+		while ((currentArray = this.set[index]) != null) {
+			if (currentArray.length == arrayLength && Util.equalArraysOrNull(currentArray, array))
+				return true;
+			if (++index == length) {
+				index = 0;
+			}
+		}
+		return false;
+	}
+
+	private int hashCode(Object[] element) {
+		return hashCode(element, element.length);
+	}
+	
+	private int hashCode(Object[] element, int length) {
+		int hash = 0;
+		for (int i = length-1; i >= 0; i--)
+			hash = Util.combineHashCodes(hash, element[i].hashCode());
+		return hash & 0x7FFFFFFF;
+	}
+	
+	public Object add(Object[] array) {
+		int length = this.set.length;
+		int index = hashCode(array) % length;
+		int arrayLength = array.length;
+		Object[] currentArray;
+		while ((currentArray = this.set[index]) != null) {
+			if (currentArray.length == arrayLength && Util.equalArraysOrNull(currentArray, array))
+				return this.set[index] = array;
+			if (++index == length) {
+				index = 0;
+			}
+		}
+		this.set[index] = array;
+
+		// assumes the threshold is never equal to the size of the table
+		if (++this.elementSize > threshold)
+			rehash();
+		return array;
+	}
+
+	public Object remove(Object[] array) {
+		int length = this.set.length;
+		int index = hashCode(array) % length;
+		int arrayLength = array.length;
+		Object[] currentArray;
+		while ((currentArray = this.set[index]) != null) {
+			if (currentArray.length == arrayLength && Util.equalArraysOrNull(currentArray, array)) {
+				Object existing = this.set[index];
+				this.elementSize--;
+				this.set[index] = null;
+				rehash();
+				return existing;
+			}
+			if (++index == length) {
+				index = 0;
+			}
+		}
+		return null;
+	}
+
+	private void rehash() {
+
+		HashSetOfArray newHashSet = new HashSetOfArray(elementSize * 2);		// double the number of expected elements
+		Object[] currentArray;
+		for (int i = this.set.length; --i >= 0;)
+			if ((currentArray = this.set[i]) != null)
+				newHashSet.add(currentArray);
+
+		this.set = newHashSet.set;
+		this.threshold = newHashSet.threshold;
+	}
+
+	public int size() {
+		return elementSize;
+	}
+
+	public String toString() {
+		StringBuffer buffer = new StringBuffer();
+		Object[] element;
+		for (int i = 0, length = this.set.length; i < length; i++)
+			if ((element = this.set[i]) != null) {
+				buffer.append('{');
+				for (int j = 0, length2 = element.length; j < length2; j++) {
+					buffer.append(element[j]);
+					if (j != length2-1) 
+						buffer.append(", "); //$NON-NLS-1$
+				}
+				buffer.append("}");  //$NON-NLS-1$
+				if (i != length-1)
+					buffer.append('\n');
+			}
+		return buffer.toString();
+	}
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/HashtableOfArrayToObject.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/HashtableOfArrayToObject.java
index 79b712f..f20a91c 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/HashtableOfArrayToObject.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/HashtableOfArrayToObject.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -53,39 +53,45 @@
 	}
 
 	public boolean containsKey(Object[] key) {
-
-		int index = hashCode(key) % this.valueTable.length;
+		int length = this.keyTable.length;
+		int index = hashCode(key) % length;
 		int keyLength = key.length;
 		Object[] currentKey;
 		while ((currentKey = this.keyTable[index]) != null) {
 			if (currentKey.length == keyLength && Util.equalArraysOrNull(currentKey, key))
 				return true;
-			index = (index + 1) % this.keyTable.length;
+			if (++index == length) {
+				index = 0;
+			}
 		}
 		return false;
 	}
 
 	public Object get(Object[] key) {
-
-		int index = hashCode(key) % this.valueTable.length;
+		int length = this.keyTable.length;
+		int index = hashCode(key) % length;
 		int keyLength = key.length;
 		Object[] currentKey;
 		while ((currentKey = this.keyTable[index]) != null) {
 			if (currentKey.length == keyLength && Util.equalArraysOrNull(currentKey, key))
 				return this.valueTable[index];
-			index = (index + 1) % keyTable.length;
+			if (++index == length) {
+				index = 0;
+			}
 		}
 		return null;
 	}
 
 	public Object[] getKey(Object[] key, int keyLength) {
-
-		int index = hashCode(key, keyLength) % this.valueTable.length;
+		int length = this.keyTable.length;
+		int index = hashCode(key, keyLength) % length;
 		Object[] currentKey;
 		while ((currentKey = this.keyTable[index]) != null) {
 			if (currentKey.length == keyLength && Util.equalArrays(currentKey, key, keyLength))
 				return currentKey;
-			index = (index + 1) % this.keyTable.length;
+			if (++index == length) {
+				index = 0;
+			}
 		}
 		return null;
 	}
@@ -96,20 +102,22 @@
 	
 	private int hashCode(Object[] element, int length) {
 		int hash = 0;
-		for (int i = 0; i < length; i++)
+		for (int i = length-1; i >= 0; i--)
 			hash = Util.combineHashCodes(hash, element[i].hashCode());
 		return hash & 0x7FFFFFFF;
 	}
 	
 	public Object put(Object[] key, Object value) {
-
-		int index = hashCode(key) % this.valueTable.length;
+		int length = this.keyTable.length;
+		int index = hashCode(key) % length;
 		int keyLength = key.length;
 		Object[] currentKey;
 		while ((currentKey = this.keyTable[index]) != null) {
 			if (currentKey.length == keyLength && Util.equalArraysOrNull(currentKey, key))
 				return this.valueTable[index] = value;
-			index = (index + 1) % keyTable.length;
+			if (++index == length) {
+				index = 0;
+			}
 		}
 		this.keyTable[index] = key;
 		this.valueTable[index] = value;
@@ -121,8 +129,8 @@
 	}
 
 	public Object removeKey(Object[] key) {
-
-		int index = hashCode(key) % this.valueTable.length;
+		int length = this.keyTable.length;
+		int index = hashCode(key) % length;
 		int keyLength = key.length;
 		Object[] currentKey;
 		while ((currentKey = this.keyTable[index]) != null) {
@@ -134,7 +142,9 @@
 				rehash();
 				return value;
 			}
-			index = (index + 1) % this.keyTable.length;
+			if (++index == length) {
+				index = 0;
+			}
 		}
 		return null;
 	}
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 3a968bf..925b887 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 e282405..29caa9e 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 3bb2b75..9cec55a 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 80b18c5..9ac227c 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/KeyToSignature.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/KeyToSignature.java
index 99ff0e2..54f13af 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/KeyToSignature.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/KeyToSignature.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005 IBM Corporation and others.
+ * Copyright (c) 2005, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -25,11 +25,13 @@
 	public static final int SIGNATURE = 0;
 	public static final int TYPE_ARGUMENTS = 1;
 	public static final int DECLARING_TYPE = 2;
+	public static final int THROWN_EXCEPTIONS = 3;
 	
 	public StringBuffer signature = new StringBuffer();
 	private int kind;
 	private ArrayList arguments = new ArrayList();
 	private ArrayList typeParameters = new ArrayList();
+	private ArrayList thrownExceptions = new ArrayList();
 	private int mainTypeStart = -1;
 	private int mainTypeEnd;
 	private int typeSigStart = -1;
@@ -68,10 +70,21 @@
 	
 	public void consumeMethod(char[] selector, char[] methodSignature) {
 		this.arguments = new ArrayList();
-		if (this.kind == SIGNATURE) {
-			this.signature = new StringBuffer();
-			CharOperation.replace(methodSignature, '/', '.');
-			this.signature.append(methodSignature);
+		CharOperation.replace(methodSignature, '/', '.');
+		switch(this.kind) {
+			case SIGNATURE:
+				this.signature = new StringBuffer();
+				this.signature.append(methodSignature);
+				break;
+			case THROWN_EXCEPTIONS:
+				if (CharOperation.indexOf('^', methodSignature) > 0) {
+					char[][] types = Signature.getThrownExceptionTypes(methodSignature);
+					int length = types.length;
+					for (int i=0; i<length; i++) {
+						this.thrownExceptions.add(new String(types[i]));
+					}
+				}
+				break;
 		}
 	}
 	
@@ -198,6 +211,16 @@
 		}
 	}
 	
+	public void consumeException() {
+		int size = this.arguments.size();
+		if (size > 0) {
+			for (int i=0; i<size; i++) {
+				this.thrownExceptions.add(((KeyToSignature) this.arguments.get(i)).signature.toString());
+			}
+			this.arguments = new ArrayList();
+		}
+	}
+	
 	public void consumeFullyQualifiedName(char[] fullyQualifiedName) {
 		this.typeSigStart = this.signature.length();
 		this.signature.append('L');
@@ -252,6 +275,7 @@
 		KeyToSignature keyToSignature = (KeyToSignature) this.arguments.get(0);
 		this.signature = keyToSignature.signature;
 		this.arguments = keyToSignature.arguments;
+		this.thrownExceptions = keyToSignature.thrownExceptions;
 	}
 	
 	public void consumeWildCard(int wildCardKind) {
@@ -275,6 +299,15 @@
 		}
 	}
 	
+	public String[] getThrownExceptions() {
+		int length = this.thrownExceptions.size();
+		String[] result = new String[length];
+		for (int i = 0; i < length; i++) {
+			result[i] = (String) this.thrownExceptions.get(i);
+		}
+		return result;
+	}
+	
 	public String[] getTypeArguments() {
 		int length = this.arguments.size();
 		String[] result = new String[length];
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 405afa5..14933ec 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,6 +10,7 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.util;
 
+import java.text.NumberFormat;
 import java.util.Enumeration;
 import java.util.Hashtable;
 
@@ -160,6 +161,9 @@
 		}
 		return newCache;
 	}
+	public double fillingRatio() {
+		return (fCurrentSpace) * 100.0 / fSpaceLimit;
+	}
 	/**
 	 * Flushes all entries from the cache.
 	 */
@@ -170,7 +174,6 @@
 		fEntryTable = new Hashtable();  // Clear it out
 		fEntryQueue = fEntryQueueTail = null;  
 		while (entry != null) {  // send deletion notifications in LRU order
-			privateNotifyDeletionFromCache(entry);
 			entry = entry._fPrevious;
 		}
 	}
@@ -290,6 +293,20 @@
 		return new LRUCache(size);
 	}
 	/**
+	 * Answers the value in the cache at the given key.
+	 * If the value is not in the cache, returns null
+	 *
+	 * This function does not modify timestamps.
+	 */
+	public Object peek(Object key) {
+		
+		LRUCacheEntry entry = (LRUCacheEntry) fEntryTable.get(key);
+		if (entry == null) {
+			return null;
+		}
+		return entry._fValue;
+	}
+	/**
 	 * Adds an entry for the given key/value/space.
 	 */
 	protected void privateAdd (Object key, Object value, int space) {
@@ -325,14 +342,6 @@
 		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).
@@ -347,7 +356,6 @@
 		if (!shuffle) {
 			fEntryTable.remove(entry._fKey);
 			fCurrentSpace -= entry._fSpace;
-			privateNotifyDeletionFromCache(entry);
 		}
 
 		/* if this was the first entry */
@@ -443,45 +451,57 @@
 			return 1;
 		}
 	}
-/**
- * Returns a String that represents the value of this object.  This method
- * is for debugging purposes only.
- */
-public String toString() {
-	return 
-		"LRUCache " + (fCurrentSpace * 100.0 / fSpaceLimit) + "% full\n" + //$NON-NLS-1$ //$NON-NLS-2$
-		this.toStringContents();
-}
-/**
- * Returns a String that represents the contents of this object.  This method
- * is for debugging purposes only.
- */
-protected String toStringContents() {
-	StringBuffer result = new StringBuffer();
-	int length = fEntryTable.size();
-	Object[] unsortedKeys = new Object[length];
-	String[] unsortedToStrings = new String[length];
-	Enumeration e = this.keys();
-	for (int i = 0; i < length; i++) {
-		Object key = e.nextElement();
-		unsortedKeys[i] = key;
-		unsortedToStrings[i] = 
-			(key instanceof org.eclipse.jdt.internal.core.JavaElement) ?
-				((org.eclipse.jdt.internal.core.JavaElement)key).getElementName() :
-				key.toString();
+	/**
+	 * Returns a String that represents the value of this object.  This method
+	 * is for debugging purposes only.
+	 */
+	public String toString() {
+		return 
+			toStringFillingRation("LRUCache") + //$NON-NLS-1$
+			toStringContents();
 	}
-	ToStringSorter sorter = new ToStringSorter();
-	sorter.sort(unsortedKeys, unsortedToStrings);
-	for (int i = 0; i < length; i++) {
-		String toString = sorter.sortedStrings[i];
-		Object value = this.get(sorter.sortedObjects[i]);
-		result.append(toString);		
-		result.append(" -> "); //$NON-NLS-1$
-		result.append(value);
-		result.append("\n"); //$NON-NLS-1$
+	
+	/**
+	 * Returns a String that represents the contents of this object.  This method
+	 * is for debugging purposes only.
+	 */
+	protected String toStringContents() {
+		StringBuffer result = new StringBuffer();
+		int length = fEntryTable.size();
+		Object[] unsortedKeys = new Object[length];
+		String[] unsortedToStrings = new String[length];
+		Enumeration e = this.keys();
+		for (int i = 0; i < length; i++) {
+			Object key = e.nextElement();
+			unsortedKeys[i] = key;
+			unsortedToStrings[i] = 
+				(key instanceof org.eclipse.jdt.internal.core.JavaElement) ?
+					((org.eclipse.jdt.internal.core.JavaElement)key).getElementName() :
+					key.toString();
+		}
+		ToStringSorter sorter = new ToStringSorter();
+		sorter.sort(unsortedKeys, unsortedToStrings);
+		for (int i = 0; i < length; i++) {
+			String toString = sorter.sortedStrings[i];
+			Object value = this.get(sorter.sortedObjects[i]);
+			result.append(toString);		
+			result.append(" -> "); //$NON-NLS-1$
+			result.append(value);
+			result.append("\n"); //$NON-NLS-1$
+		}
+		return result.toString();
 	}
-	return result.toString();
-}
+	
+	public String toStringFillingRation(String cacheName) {
+		StringBuffer buffer = new StringBuffer(cacheName);
+		buffer.append('[');
+		buffer.append(getSpaceLimit());
+		buffer.append("]: "); //$NON-NLS-1$
+		buffer.append(NumberFormat.getInstance().format(fillingRatio()));
+		buffer.append("% full"); //$NON-NLS-1$
+		return buffer.toString();
+	}
+
 	/**
 	 * Updates the timestamp for the given entry, ensuring that the queue is 
 	 * kept in correct order.  The entry must exist
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 edfe140..3f5c296 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 00fe845..60c82c6 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 1f2a8f4..4dc11ad 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/LocalVariableTypeAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/LocalVariableTypeAttribute.java
index 91e87dc..cfd1173 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/LocalVariableTypeAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/LocalVariableTypeAttribute.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/LocalVariableTypeTableEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/LocalVariableTypeTableEntry.java
index e3eb83d..a3bbabd 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/LocalVariableTypeTableEntry.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/LocalVariableTypeTableEntry.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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
index 7d7c76f..e3d0095 100644
--- 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
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Messages.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Messages.java
index 6b5bf2e..d2b890e 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Messages.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Messages.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -36,7 +36,13 @@
 	public static String element_nullName;
 	public static String element_nullType;
 	public static String element_illegalParent;
-	public static String sourcetype_invalidName;
+	public static String javamodel_initialization;
+	public static String javamodel_building_after_upgrade;
+	public static String javamodel_configuring;
+	public static String javamodel_configuring_classpath_containers;
+	public static String javamodel_configuring_searchengine;
+	public static String javamodel_getting_build_state_number;
+	public static String javamodel_refreshing_external_jars;
 	public static String operation_needElements;
 	public static String operation_needName;
 	public static String operation_needPath;
@@ -98,6 +104,7 @@
 	public static String build_prereqProjectHasClasspathProblems;
 	public static String build_prereqProjectMustBeRebuilt;
 	public static String build_abortDueToClasspathProblems;
+	public static String status_cannot_retrieve_attached_javadoc;	
 	public static String status_cannotUseDeviceOnPath;
 	public static String status_coreException;
 	public static String status_defaultPackageReadOnly;
@@ -119,9 +126,11 @@
 	public static String status_OK;
 	public static String status_readOnly;
 	public static String status_targetException;
+	public static String status_unknown_javadoc_format;
 	public static String status_updateConflict;
 	public static String classpath_buildPath;
 	public static String classpath_cannotNestEntryInEntry;
+	public static String classpath_cannotNestEntryInEntryNoExclusion;
 	public static String classpath_cannotNestEntryInLibrary;
 	public static String classpath_cannotNestEntryInOutput;
 	public static String classpath_cannotNestOutputInEntry;
@@ -159,15 +168,21 @@
 	public static String classpath_disabledMultipleOutputLocations;
 	public static String classpath_incompatibleLibraryJDKLevel;
 	public static String classpath_duplicateEntryExtraAttribute;
+	public static String classpath_deprecated_variable;
 	public static String file_notFound;
 	public static String file_badFormat;
 	public static String path_nullPath;
 	public static String path_mustBeAbsolute;
 	public static String cache_invalidLoadFactor;
 	public static String savedState_jobName;
-	public static String javamodel_initialization;
 	public static String restrictedAccess_project;
 	public static String restrictedAccess_library;
+	public static String restrictedAccess_constructor_project;
+	public static String restrictedAccess_constructor_library;
+	public static String restrictedAccess_field_project;
+	public static String restrictedAccess_field_library;
+	public static String restrictedAccess_method_project;
+	public static String restrictedAccess_method_library;
 	public static String convention_unit_nullName;
 	public static String convention_unit_notJavaName;
 	public static String convention_classFile_nullName;
@@ -204,6 +219,7 @@
 	public static String dom_addAncestorAsSibling;
 	public static String dom_addNullInterface;
 	public static String dom_nullInterfaces;
+	public static String importRewrite_processDescription;
 	public static String correction_nullRequestor;
 	public static String correction_nullUnit;
 	public static String engine_searching;
@@ -270,6 +286,8 @@
 	public static String disassembler_runtimevisibleparameterannotationsattributeheader;
 	public static String disassembler_runtimeinvisibleparameterannotationsattributeheader;
 	public static String disassembler_parameterannotationentrystart;
+	public static String disassembler_stackmaptableattributeheader;
+	public static String disassembler_stackmapattributeheader;
 	public static String classfileformat_versiondetails;
 	public static String classfileformat_methoddescriptor;
 	public static String classfileformat_fieldddescriptor;
@@ -312,6 +330,15 @@
 	public static String classfileformat_exceptiontableentry;
 	public static String classfileformat_linenumbertableentry;
 	public static String classfileformat_localvariabletableentry;
+	public static String classfileformat_versionUnknown;
+	
+	public static String disassembler_frame_same_locals_1_stack_item_extended;
+	public static String disassembler_frame_chop;
+	public static String disassembler_frame_same_frame_extended;
+	public static String disassembler_frame_append;
+	public static String disassembler_frame_full_frame;
+	public static String disassembler_frame_same_frame;
+	public static String disassembler_frame_same_locals_1_stack_item;
 
 	static {
 		NLS.initializeMessages(BUNDLE_NAME, Messages.class);
@@ -360,4 +387,4 @@
 	public static String bind(String message, Object[] bindings) {
 		return MessageFormat.format(message, bindings);
 	}
-}
\ No newline at end of file
+}
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 9cae81d..b874fbf 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ParameterAnnotation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ParameterAnnotation.java
index c99113f..3e7d304 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ParameterAnnotation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ParameterAnnotation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 6d9095f..db587e2 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,18 +10,15 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.util;
 
-import java.util.Iterator;
-
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.compiler.IScanner;
 import org.eclipse.jdt.core.compiler.ITerminalSymbols;
 import org.eclipse.jdt.core.compiler.InvalidInputException;
 import org.eclipse.jdt.internal.compiler.CompilationResult;
-import org.eclipse.jdt.internal.compiler.ast.StringLiteral;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
-import org.eclipse.jdt.internal.compiler.parser.NLSLine;
-import org.eclipse.jdt.internal.compiler.parser.Scanner;
+import org.eclipse.jdt.internal.compiler.parser.NLSTag;
 import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
+import org.eclipse.jdt.internal.compiler.util.Util;
 
 public class PublicScanner implements IScanner, ITerminalSymbols {
 	
@@ -35,8 +32,8 @@
 	 - sourceStart gives the position into the stream
 	 - currentPosition-1 gives the sourceEnd position into the stream 
 	*/
-	protected long sourceLevel;
-	protected long complianceLevel;
+	public long sourceLevel;
+	public long complianceLevel;
 
 	// 1.4 feature 
 	public boolean useAssertAsAnIndentifier = false;
@@ -68,7 +65,7 @@
 	public boolean scanningFloatLiteral = false;
 
 	//support for /** comments
-	public static int COMMENT_ARRAYS_SIZE = 30;
+	public final static int COMMENT_ARRAYS_SIZE = 30;
 	public int[] commentStops = new int[COMMENT_ARRAYS_SIZE];
 	public int[] commentStarts = new int[COMMENT_ARRAYS_SIZE];
 	public int[] commentTagStarts = new int[COMMENT_ARRAYS_SIZE];
@@ -111,7 +108,7 @@
 	public static final String UNTERMINATED_COMMENT = "Unterminated_Comment"; //$NON-NLS-1$
 	public static final String INVALID_CHAR_IN_STRING = "Invalid_Char_In_String"; //$NON-NLS-1$
 	public static final String INVALID_DIGIT = "Invalid_Digit"; //$NON-NLS-1$
-	private static final int[] EMPTY_LINE_ENDS = new int[0];
+	private static final int[] EMPTY_LINE_ENDS = Util.EMPTY_INT_ARRAY;
 
 	//----------------optimized identifier managment------------------
 	static final char[] charArray_a = new char[] {'a'}, 
@@ -145,69 +142,17 @@
 		new char[] {'\u0000', '\u0000', '\u0000', '\u0000', '\u0000', '\u0000'}; 
 	static final int TableSize = 30, InternalTableSize = 6; //30*6 =210 entries
 	
-	public final static int MAX_OBVIOUS = 128;
-	static final int[] ObviousIdentCharNatures = new int[MAX_OBVIOUS];
-	public final static int C_LETTER = 4;
-	public final static int C_DIGIT = 3;
-	public final static int C_SEPARATOR = 2;
-	public final static int C_SPACE = 1;
-	static {
-		for (int i = '0'; i <= '9'; i++) 
-			ObviousIdentCharNatures[i] = C_DIGIT;
-		
-		for (int i = 'a'; i <= 'z'; i++) 
-			ObviousIdentCharNatures[i] = C_LETTER;
-		for (int i = 'A'; i <= 'Z'; i++) 
-			ObviousIdentCharNatures[i] = C_LETTER;
-		ObviousIdentCharNatures['_'] = C_LETTER;
-		ObviousIdentCharNatures['$'] = C_LETTER;
-		
-		ObviousIdentCharNatures[10] = C_SPACE; // \ u000a: LINE FEED
-		ObviousIdentCharNatures[12] = C_SPACE; // \ u000c: FORM FEED
-		ObviousIdentCharNatures[13] = C_SPACE; //  \ u000d: CARRIAGE RETURN
-		ObviousIdentCharNatures[32] = C_SPACE; //  \ u0020: SPACE
-		ObviousIdentCharNatures[ 9] = C_SPACE; // \ u0009: HORIZONTAL TABULATION
-		
-		ObviousIdentCharNatures['.'] = C_SEPARATOR;
-		ObviousIdentCharNatures[':'] = C_SEPARATOR;
-		ObviousIdentCharNatures[';'] = C_SEPARATOR;
-		ObviousIdentCharNatures[','] = C_SEPARATOR;
-		ObviousIdentCharNatures['['] = C_SEPARATOR;
-		ObviousIdentCharNatures[']'] = C_SEPARATOR;
-		ObviousIdentCharNatures['('] = C_SEPARATOR;
-		ObviousIdentCharNatures[')'] = C_SEPARATOR;
-		ObviousIdentCharNatures['{'] = C_SEPARATOR;
-		ObviousIdentCharNatures['}'] = C_SEPARATOR;
-		ObviousIdentCharNatures['+'] = C_SEPARATOR;
-		ObviousIdentCharNatures['-'] = C_SEPARATOR;
-		ObviousIdentCharNatures['*'] = C_SEPARATOR;
-		ObviousIdentCharNatures['/'] = C_SEPARATOR;
-		ObviousIdentCharNatures['='] = C_SEPARATOR;
-		ObviousIdentCharNatures['&'] = C_SEPARATOR;
-		ObviousIdentCharNatures['|'] = C_SEPARATOR;
-		ObviousIdentCharNatures['?'] = C_SEPARATOR;
-		ObviousIdentCharNatures['<'] = C_SEPARATOR;
-		ObviousIdentCharNatures['>'] = C_SEPARATOR;
-		ObviousIdentCharNatures['!'] = C_SEPARATOR;
-		ObviousIdentCharNatures['%'] = C_SEPARATOR;
-		ObviousIdentCharNatures['^'] = C_SEPARATOR;
-		ObviousIdentCharNatures['~'] = C_SEPARATOR;
-		ObviousIdentCharNatures['"'] = C_SEPARATOR;
-		ObviousIdentCharNatures['\''] = C_SEPARATOR;
-	}
-	
 	public static final int OptimizedLength = 7;
 	public /*static*/ final char[][][][] charArray_length = 
 		new char[OptimizedLength][TableSize][InternalTableSize][]; 
 	// support for detecting non-externalized string literals
-	public NLSLine currentLine= null;
-	public static final String TAG_PREFIX= "//$NON-NLS-"; //$NON-NLS-1$
-	public static final int TAG_PREFIX_LENGTH= TAG_PREFIX.length();
-	public static final String TAG_POSTFIX= "$"; //$NON-NLS-1$
-	public static final int TAG_POSTFIX_LENGTH= TAG_POSTFIX.length();
-	public StringLiteral[] nonNLSStrings = null;
-	public boolean checkNonExternalizedStringLiterals = false;
-	public boolean wasNonExternalizedStringLiteral = false;
+	public static final char[] TAG_PREFIX= "//$NON-NLS-".toCharArray(); //$NON-NLS-1$
+	public static final int TAG_PREFIX_LENGTH= TAG_PREFIX.length;
+	public static final char TAG_POSTFIX= '$';
+	public static final int TAG_POSTFIX_LENGTH= 1;
+	private NLSTag[] nlsTags = null;
+	protected int nlsTagsPtr;
+	public boolean checkNonExternalizedStringLiterals;
 	
 	// generic support
 	public boolean returnOnlyGreater = false;
@@ -226,6 +171,7 @@
 		newEntry4 = 0, 
 		newEntry5 = 0, 
 		newEntry6 = 0;
+	public boolean insideRecovery = false;
 
 	public static final int RoundBracket = 0;
 	public static final int SquareBracket = 1;
@@ -243,57 +189,51 @@
 }
 
 public PublicScanner(
-	boolean tokenizeComments, 
-	boolean tokenizeWhiteSpace, 
-	boolean checkNonExternalizedStringLiterals, 
-	long sourceLevel,
-	long complianceLevel,
-	char[][] taskTags,
-	char[][] taskPriorities,
-	boolean isTaskCaseSensitive) {
+		boolean tokenizeComments, 
+		boolean tokenizeWhiteSpace, 
+		boolean checkNonExternalizedStringLiterals, 
+		long sourceLevel,
+		long complianceLevel,
+		char[][] taskTags,
+		char[][] taskPriorities,
+		boolean isTaskCaseSensitive) {
 
 	this.eofPosition = Integer.MAX_VALUE;
 	this.tokenizeComments = tokenizeComments;
 	this.tokenizeWhiteSpace = tokenizeWhiteSpace;
-	this.checkNonExternalizedStringLiterals = checkNonExternalizedStringLiterals;
 	this.sourceLevel = sourceLevel;
 	this.complianceLevel = complianceLevel;
+	this.checkNonExternalizedStringLiterals = checkNonExternalizedStringLiterals;
 	this.taskTags = taskTags;
 	this.taskPriorities = taskPriorities;
 	this.isTaskCaseSensitive = isTaskCaseSensitive;
 }
 
 public PublicScanner(
-	boolean tokenizeComments, 
-	boolean tokenizeWhiteSpace, 
-	boolean checkNonExternalizedStringLiterals, 
-	long sourceLevel,
-	char[][] taskTags,
-	char[][] taskPriorities,
-	boolean isTaskCaseSensitive) {
+		boolean tokenizeComments, 
+		boolean tokenizeWhiteSpace, 
+		boolean checkNonExternalizedStringLiterals, 
+		long sourceLevel,
+		char[][] taskTags,
+		char[][] taskPriorities,
+		boolean isTaskCaseSensitive) {
 
-	this.eofPosition = Integer.MAX_VALUE;
-	this.tokenizeComments = tokenizeComments;
-	this.tokenizeWhiteSpace = tokenizeWhiteSpace;
-	this.checkNonExternalizedStringLiterals = checkNonExternalizedStringLiterals;
-	this.sourceLevel = sourceLevel;
-	this.complianceLevel = sourceLevel;
-	this.taskTags = taskTags;
-	this.taskPriorities = taskPriorities;
-	this.isTaskCaseSensitive = isTaskCaseSensitive;
+	this(
+		tokenizeComments,
+		tokenizeWhiteSpace,
+		checkNonExternalizedStringLiterals,
+		sourceLevel,
+		sourceLevel,
+		taskTags,
+		taskPriorities,
+		isTaskCaseSensitive);
 }
 
-public  final boolean atEnd() {
+public final boolean atEnd() {
 	// This code is not relevant if source is 
 	// Only a part of the real stream input
 
-	return this.source.length == this.currentPosition;
-}
-
-protected void checkNonExternalizedString() {
-	if (this.currentLine == null) 
-		return;
-	parseTags(this.currentLine);
+	return this.eofPosition <= this.currentPosition;
 }
 
 // chech presence of task: tags
@@ -308,7 +248,7 @@
 	}
 	int foundTaskIndex = this.foundTaskCount;
 	char previous = src[commentStart+1]; // should be '*' or '/'
-	nextChar : for (
+	for (
 		int i = commentStart + 2; i < commentEnd && i < this.eofPosition; i++) {
 		char[] tag = null;
 		char[] priority = null;
@@ -320,8 +260,8 @@
 				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)) {
+				if (ScannerHelper.isJavaIdentifierStart(tag[0])) {
+					if (ScannerHelper.isJavaIdentifierPart(previous)) {
 						continue nextTag;
 					}
 				}
@@ -331,14 +271,14 @@
 					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
+						if (this.isTaskCaseSensitive || (ScannerHelper.toLowerCase(sc) != ScannerHelper.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]))
+				if (i+tagLength < commentEnd && ScannerHelper.isJavaIdentifierPart(src[i+tagLength-1])) {
+					if (ScannerHelper.isJavaIdentifierPart(src[i + tagLength]))
 						continue nextTag;
 				}
 				if (this.foundTaskTags == null) {
@@ -368,6 +308,7 @@
 		}
 		previous = src[i];
 	}
+	boolean containsEmptyTask = false;
 	for (int i = foundTaskIndex; i < this.foundTaskCount; i++) {
 		// retrieve message start and end positions
 		int msgStart = this.foundTaskPositions[i][0] + this.foundTaskTags[i].length;
@@ -396,8 +337,12 @@
 			if (end == -1)
 				end = max_value;
 		}
-		if (msgStart == end)
-			continue; // empty
+		if (msgStart == end) {
+			// if the description is empty, we might want to see if two tags are not sharing the same message
+			// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=110797
+			containsEmptyTask = true;
+			continue;
+		}
 		// trim the message
 		while (CharOperation.isWhitespace(src[end]) && msgStart <= end)
 			end--;
@@ -411,6 +356,19 @@
 		System.arraycopy(src, msgStart, message, 0, messageLength);
 		this.foundTaskMessages[i] = message;
 	}
+	if (containsEmptyTask) {
+		for (int i = foundTaskIndex, max = this.foundTaskCount; i < max; i++) {
+			if (this.foundTaskMessages[i].length == 0) {
+				loop: for (int j = i + 1; j < max; j++) {
+					if (this.foundTaskMessages[j].length != 0) {
+						this.foundTaskMessages[i] = this.foundTaskMessages[j];
+						this.foundTaskPositions[i][1] = this.foundTaskPositions[j][1];
+						break loop;
+					}
+				}
+			}
+		}
+	}
 }
 
 public char[] getCurrentIdentifierSource() {
@@ -427,7 +385,7 @@
 			this.withoutUnicodePtr); 
 	} else {
 		int length = this.currentPosition - this.startPosition;
-		if (length == this.source.length) return this.source;
+		if (length == this.eofPosition) return this.source;
 		switch (length) { // see OptimizedLength
 			case 1 :
 				return optimizedCurrentTokenSource1();
@@ -451,7 +409,7 @@
 public int getCurrentTokenEndPosition(){
 	return this.currentPosition - 1;
 }
-public final char[] getCurrentTokenSource() {
+public char[] getCurrentTokenSource() {
 	// Return the token REAL source (aka unicodes are precomputed)
 
 	char[] result;
@@ -489,7 +447,7 @@
 		this.startPosition, 
 		this.currentPosition - this.startPosition); 
 }
-public final char[] getCurrentTokenSourceString() {
+public char[] getCurrentTokenSourceString() {
 	//return the token REAL source (aka unicodes are precomputed).
 	//REMOVE the two " that are at the beginning and the end.
 
@@ -614,6 +572,32 @@
 		return -1;
 	}
 }
+public final int getNextCharWithBoundChecks() {
+	if (this.currentPosition >= this.eofPosition) {
+		return -1;
+	}
+	this.currentCharacter = this.source[this.currentPosition++];
+	if (this.currentPosition >= this.eofPosition) {
+		this.unicodeAsBackSlash = false;
+		if (this.withoutUnicodePtr != 0) {
+		    unicodeStore();
+		}
+		return this.currentCharacter;
+	}
+	if (this.currentCharacter == '\\' && this.source[this.currentPosition] == 'u') {
+		try {
+			getNextUnicodeChar();
+		} catch (InvalidInputException e) {
+			return -1;
+		}
+	} else {
+		this.unicodeAsBackSlash = false;
+		if (this.withoutUnicodePtr != 0) {
+		    unicodeStore();
+		}
+	}
+	return this.currentCharacter;
+}
 public final boolean getNextChar(char testedChar) {
 	//BOOLEAN
 	//handle the case of unicode.
@@ -625,7 +609,7 @@
 
 	//ALL getNextChar.... ARE OPTIMIZED COPIES 
 
-	if (this.currentPosition >= this.source.length) { // handle the obvious case upfront
+	if (this.currentPosition >= this.eofPosition) { // handle the obvious case upfront
 		this.unicodeAsBackSlash = false;
 		return false;
 	}
@@ -673,7 +657,7 @@
 	//On false, no side effect has occured.
 
 	//ALL getNextChar.... ARE OPTIMIZED COPIES 
-	if (this.currentPosition >= this.source.length) // handle the obvious case upfront
+	if (this.currentPosition >= this.eofPosition) // handle the obvious case upfront
 		return -1;
 
 	int temp = this.currentPosition;
@@ -724,7 +708,7 @@
 	//On false, no side effect has occured.
 
 	//ALL getNextChar.... ARE OPTIMIZED COPIES 
-	if (this.currentPosition >= this.source.length) // handle the obvious case upfront
+	if (this.currentPosition >= this.eofPosition) // handle the obvious case upfront
 		return false;
 
 	int temp = this.currentPosition;
@@ -732,14 +716,14 @@
 		if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
 			&& (this.source[this.currentPosition] == 'u')) {
 			getNextUnicodeChar();
-			if (!isDigit(this.currentCharacter)) {
+			if (!ScannerHelper.isDigit(this.currentCharacter)) {
 				this.currentPosition = temp;
 				this.withoutUnicodePtr--;
 				return false;
 			}
 			return true;
 		} else {
-			if (!isDigit(this.currentCharacter)) {
+			if (!ScannerHelper.isDigit(this.currentCharacter)) {
 				this.currentPosition = temp;
 				return false;
 			}
@@ -765,7 +749,7 @@
 	//On false, no side effect has occured.
 
 	//ALL getNextChar.... ARE OPTIMIZED COPIES 
-	if (this.currentPosition >= this.source.length) // handle the obvious case upfront
+	if (this.currentPosition >= this.eofPosition) // handle the obvious case upfront
 		return false;
 
 	int temp = this.currentPosition;
@@ -773,14 +757,14 @@
 		if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
 			&& (this.source[this.currentPosition] == 'u')) {
 			getNextUnicodeChar();
-			if (Character.digit(this.currentCharacter, radix) == -1) {
+			if (ScannerHelper.digit(this.currentCharacter, radix) == -1) {
 				this.currentPosition = temp;
 				this.withoutUnicodePtr--;
 				return false;
 			}
 			return true;
 		} else {
-			if (Character.digit(this.currentCharacter, radix) == -1) {
+			if (ScannerHelper.digit(this.currentCharacter, radix) == -1) {
 				this.currentPosition = temp;
 				return false;
 			}
@@ -796,6 +780,78 @@
 		return false;
 	}
 }
+public boolean getNextCharAsJavaIdentifierPartWithBoundCheck() {
+	//BOOLEAN
+	//handle the case of unicode.
+	//when a unicode appears then we must use a buffer that holds char internal values
+	//At the end of this method currentCharacter holds the new visited char
+	//and currentPosition points right next after it
+	//Both previous lines are true if the currentCharacter is a JavaIdentifierPart
+	//On false, no side effect has occured.
+
+	//ALL getNextChar.... ARE OPTIMIZED COPIES 
+	int pos = this.currentPosition;
+	if (pos >= this.eofPosition) // handle the obvious case upfront
+		return false;
+
+	int temp2 = this.withoutUnicodePtr;
+	try {
+		boolean unicode = false;
+		this.currentCharacter = this.source[this.currentPosition++];
+		if (this.currentPosition < this.eofPosition) {
+			if (this.currentCharacter == '\\' && this.source[this.currentPosition] == 'u') {
+				getNextUnicodeChar();
+				unicode = true;
+			}
+		}
+		char c = this.currentCharacter;
+		boolean isJavaIdentifierPart = false;
+		if (c >= HIGH_SURROGATE_MIN_VALUE && c <= HIGH_SURROGATE_MAX_VALUE) {
+			if (this.complianceLevel < ClassFileConstants.JDK1_5) {
+				this.currentPosition = pos;
+				this.withoutUnicodePtr = temp2;
+				return false;
+			}
+			// Unicode 4 detection
+			char low = (char) getNextCharWithBoundChecks();
+			if (low < LOW_SURROGATE_MIN_VALUE || low > LOW_SURROGATE_MAX_VALUE) {
+				// illegal low surrogate
+				this.currentPosition = pos;
+				this.withoutUnicodePtr = temp2;
+				return false;
+			}
+			isJavaIdentifierPart = ScannerHelper.isJavaIdentifierPart(c, low);
+		}
+		else if (c >= LOW_SURROGATE_MIN_VALUE && c <= LOW_SURROGATE_MAX_VALUE) {
+			this.currentPosition = pos;
+			this.withoutUnicodePtr = temp2;
+			return false;
+		} else {
+			isJavaIdentifierPart = ScannerHelper.isJavaIdentifierPart(c);
+		}
+		if (unicode) {
+			if (!isJavaIdentifierPart) {
+				this.currentPosition = pos;
+				this.withoutUnicodePtr = temp2;
+				return false;
+			}
+			return true;
+		} else {
+			if (!isJavaIdentifierPart) {
+				this.currentPosition = pos;
+				return false;
+			}
+
+			if (this.withoutUnicodePtr != 0)
+			    unicodeStore();
+			return true;
+		}
+	} catch(InvalidInputException e) {
+		this.currentPosition = pos;
+		this.withoutUnicodePtr = temp2;
+		return false;
+	}
+}
 public boolean getNextCharAsJavaIdentifierPart() {
 	//BOOLEAN
 	//handle the case of unicode.
@@ -807,7 +863,7 @@
 
 	//ALL getNextChar.... ARE OPTIMIZED COPIES 
 	int pos;
-	if ((pos = this.currentPosition) >= this.source.length) // handle the obvious case upfront
+	if ((pos = this.currentPosition) >= this.eofPosition) // handle the obvious case upfront
 		return false;
 
 	int temp2 = this.withoutUnicodePtr;
@@ -841,7 +897,7 @@
 			this.withoutUnicodePtr = temp2;
 			return false;
 		} else {
-			isJavaIdentifierPart = Character.isJavaIdentifierPart(c);
+			isJavaIdentifierPart = ScannerHelper.isJavaIdentifierPart(c);
 		}
 		if (unicode) {
 			if (!isJavaIdentifierPart) {
@@ -870,12 +926,118 @@
 		return false;
 	}
 }
+/*
+ * External API in JavaConventions.
+ * This is used to optimize the case where the scanner is used to scan a single identifier.
+ * In this case, the AIOOBE is slower to handle than a bound check
+ */
+public int scanIdentifier() throws InvalidInputException {
+	int whiteStart = 0;
+	while (true) { //loop for jumping over comments
+		this.withoutUnicodePtr = 0;
+		//start with a new token (even comment written with unicode )
+		// ---------Consume white space and handles startPosition---------
+		whiteStart = this.currentPosition;
+		boolean isWhiteSpace, hasWhiteSpaces = false;
+		int offset;
+		int unicodePtr;
+		boolean checkIfUnicode = false;
+		do {
+			unicodePtr = this.withoutUnicodePtr;
+			offset = this.currentPosition;
+			this.startPosition = this.currentPosition;
+			if (this.currentPosition < this.eofPosition) {
+				this.currentCharacter = this.source[this.currentPosition++];
+				checkIfUnicode = this.currentPosition < this.eofPosition
+						&& this.currentCharacter == '\\'
+						&& this.source[this.currentPosition] == 'u';
+			} else if (this.tokenizeWhiteSpace && (whiteStart != this.currentPosition - 1)) {
+				// reposition scanner in case we are interested by spaces as tokens
+				this.currentPosition--;
+				this.startPosition = whiteStart;
+				return TokenNameWHITESPACE;
+			} else {
+				return TokenNameEOF;
+			}
+			if (checkIfUnicode) {
+				isWhiteSpace = jumpOverUnicodeWhiteSpace();
+				offset = this.currentPosition - offset;
+			} else {
+				offset = this.currentPosition - offset;
+				// inline version of:
+				//isWhiteSpace = 
+				//	(this.currentCharacter == ' ') || ScannerHelper.isWhitespace(this.currentCharacter); 
+				switch (this.currentCharacter) {
+					case 10 : /* \ u000a: LINE FEED               */
+					case 12 : /* \ u000c: FORM FEED               */
+					case 13 : /* \ u000d: CARRIAGE RETURN         */
+					case 32 : /* \ u0020: SPACE                   */
+					case 9 : /* \ u0009: HORIZONTAL TABULATION   */
+						isWhiteSpace = true;
+						break;
+					default :
+						isWhiteSpace = false;
+				}
+			}
+			if (isWhiteSpace) {
+				hasWhiteSpaces = true;
+			}
+		} while (isWhiteSpace);
+		if (hasWhiteSpaces) {
+			if (this.tokenizeWhiteSpace) {
+				// reposition scanner in case we are interested by spaces as tokens
+				this.currentPosition-=offset;
+				this.startPosition = whiteStart;
+				if (checkIfUnicode) {
+					this.withoutUnicodePtr = unicodePtr;
+				}
+				return TokenNameWHITESPACE;
+			} else if (checkIfUnicode) {
+				this.withoutUnicodePtr = 0;
+				unicodeStore();
+			} else {
+				this.withoutUnicodePtr = 0;
+			}
+		}
+		char c = this.currentCharacter;
+		if (c < ScannerHelper.MAX_OBVIOUS) {
+			if ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] & ScannerHelper.C_IDENT_START) != 0) {
+				return scanIdentifierOrKeywordWithBoundCheck();
+			}
+			return TokenNameERROR;
+		}
+		boolean isJavaIdStart;
+		if (c >= HIGH_SURROGATE_MIN_VALUE && c <= HIGH_SURROGATE_MAX_VALUE) {
+			if (this.complianceLevel < ClassFileConstants.JDK1_5) {
+				throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
+			}
+			// Unicode 4 detection
+			char low = (char) getNextCharWithBoundChecks();
+			if (low < LOW_SURROGATE_MIN_VALUE || low > LOW_SURROGATE_MAX_VALUE) {
+				// illegal low surrogate
+				throw new InvalidInputException(INVALID_LOW_SURROGATE);
+			}
+			isJavaIdStart = ScannerHelper.isJavaIdentifierStart(c, low);
+		} else if (c >= LOW_SURROGATE_MIN_VALUE && c <= LOW_SURROGATE_MAX_VALUE) {
+			if (this.complianceLevel < ClassFileConstants.JDK1_5) {
+				throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
+			}
+			throw new InvalidInputException(INVALID_HIGH_SURROGATE);
+		} else {
+			// optimized case already checked
+			isJavaIdStart = Character.isJavaIdentifierStart(c);
+		}
+		if (isJavaIdStart)
+			return scanIdentifierOrKeywordWithBoundCheck();
+		return TokenNameERROR;
+	}
+}
 public int getNextToken() throws InvalidInputException {
 	this.wasAcr = false;
 	if (this.diet) {
 		jumpOverMethodBody();
 		this.diet = false;
-		return this.currentPosition > this.source.length ? TokenNameEOF : TokenNameRBRACE;
+		return this.currentPosition > this.eofPosition ? TokenNameEOF : TokenNameRBRACE;
 	}
 	int whiteStart = 0;
 	try {
@@ -906,7 +1068,6 @@
 					if (this.currentPosition > this.eofPosition)
 						return TokenNameEOF;
 				}
-				//little trick to get out in the middle of a source compuation
 				if (this.currentPosition > this.eofPosition)
 					return TokenNameEOF;
 				if (checkIfUnicode) {
@@ -915,16 +1076,13 @@
 				} else {
 					offset = this.currentPosition - offset;
 					if ((this.currentCharacter == '\r') || (this.currentCharacter == '\n')) {
-						checkNonExternalizedString();
 						if (this.recordLineSeparator) {
 							pushLineSeparator();
-						} else {
-							this.currentLine = null;
 						}
 					}
 					// inline version of:
 					//isWhiteSpace = 
-					//	(this.currentCharacter == ' ') || CharOperation.isWhitespace(this.currentCharacter); 
+					//	(this.currentCharacter == ' ') || ScannerHelper.isWhitespace(this.currentCharacter); 
 					switch (this.currentCharacter) {
 						case 10 : /* \ u000a: LINE FEED               */
 						case 12 : /* \ u000c: FORM FEED               */
@@ -986,22 +1144,6 @@
 					if (getNextCharAsDigit()) {
 						return scanNumber(true);
 					}
-/*					if (this.sourceLevel >= ClassFileConstants.JDK1_5) {
-						int temp = this.currentPosition;
-						if (getNextChar('.')) {
-							if (getNextChar('.')) {
-								return TokenNameELLIPSIS;
-							} else {
-								this.currentPosition = temp;
-								return TokenNameDOT;
-							}
-						} else {
-							this.currentPosition = temp;
-							return TokenNameDOT;
-						}
-					} else {
-						return TokenNameDOT;
-					}*/
 					int temp = this.currentPosition;
 					if (getNextChar('.')) {
 						if (getNextChar('.')) {
@@ -1117,7 +1259,7 @@
 						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 (this.currentPosition + lookAhead == this.source.length)
+								if (this.currentPosition + lookAhead == this.eofPosition)
 									break;
 								if (this.source[this.currentPosition + lookAhead] == '\n')
 									break;
@@ -1132,7 +1274,7 @@
 					if (getNextChar('\'')) {
 						// relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
 						for (int lookAhead = 0; lookAhead < 3; lookAhead++) {
-							if (this.currentPosition + lookAhead == this.source.length)
+							if (this.currentPosition + lookAhead == this.eofPosition)
 								break;
 							if (this.source[this.currentPosition + lookAhead] == '\n')
 								break;
@@ -1180,7 +1322,7 @@
 						return TokenNameCharacterLiteral;
 					// relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
 					for (int lookAhead = 0; lookAhead < 20; lookAhead++) {
-						if (this.currentPosition + lookAhead == this.source.length)
+						if (this.currentPosition + lookAhead == this.eofPosition)
 							break;
 						if (this.source[this.currentPosition + lookAhead] == '\n')
 							break;
@@ -1242,7 +1384,10 @@
 									this.unicodeAsBackSlash = false;
 									if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') && (this.source[this.currentPosition] == 'u')) {
 										getNextUnicodeChar();
+										isUnicode = true;
 										this.withoutUnicodePtr--;
+									} else {
+										isUnicode = false;
 									}
 								} else {
 									if (this.withoutUnicodePtr == 0) {
@@ -1262,7 +1407,9 @@
 							if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
 								&& (this.source[this.currentPosition] == 'u')) {
 								getNextUnicodeChar();
+								isUnicode = true;
 							} else {
+								isUnicode = false;
 								if (this.withoutUnicodePtr != 0) {
 									unicodeStore();
 								}
@@ -1276,7 +1423,7 @@
 						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 (this.currentPosition + lookAhead == this.source.length)
+								if (this.currentPosition + lookAhead == this.eofPosition)
 									break;
 								if (this.source[this.currentPosition + lookAhead] == '\n')
 									break;
@@ -1289,16 +1436,6 @@
 						}
 						throw e; // rethrow
 					}
-					if (this.checkNonExternalizedStringLiterals){ // check for presence of	NLS tags //$NON-NLS-?$ where ? is an int.
-						if (this.currentLine == null) {
-							this.currentLine = new NLSLine();
-						}
-						this.currentLine.add(
-							new StringLiteral(
-								getCurrentTokenSourceString(), 
-								this.startPosition, 
-								this.currentPosition - 1));
-					}
 					return TokenNameStringLiteral;
 				case '/' :
 					{
@@ -1336,7 +1473,7 @@
 								 * We need to completely consume the line break
 								 */
 								if (this.currentCharacter == '\r'
-								   && this.source.length > this.currentPosition) {
+								   && this.eofPosition > this.currentPosition) {
 								   	if (this.source[this.currentPosition] == '\n') {
 										this.currentPosition++;
 										this.currentCharacter = '\n';
@@ -1349,15 +1486,15 @@
 								recordComment(TokenNameCOMMENT_LINE);
 								if (this.taskTags != null) checkTaskTag(this.startPosition, this.currentPosition);
 								if ((this.currentCharacter == '\r') || (this.currentCharacter == '\n')) {
-									checkNonExternalizedString();
+									if (this.checkNonExternalizedStringLiterals) {
+										parseTags();
+									}
 									if (this.recordLineSeparator) {
 										if (isUnicode) {
 											pushUnicodeLineSeparator();
 										} else {
 											pushLineSeparator();
 										}
-									} else {
-										this.currentLine = null;
 									}
 								}
 								if (this.tokenizeComments) {
@@ -1367,6 +1504,9 @@
 								this.currentPosition--;
 								recordComment(TokenNameCOMMENT_LINE);
 								if (this.taskTags != null) checkTaskTag(this.startPosition, this.currentPosition);
+								if (this.checkNonExternalizedStringLiterals) {
+									parseTags();
+								}
 								if (this.tokenizeComments) {
 									return TokenNameCOMMENT_LINE;
 								} else {
@@ -1398,15 +1538,12 @@
 									star = true;
 								}
 								if ((this.currentCharacter == '\r') || (this.currentCharacter == '\n')) {
-									checkNonExternalizedString();
 									if (this.recordLineSeparator) {
 										if (isUnicode) {
 											pushUnicodeLineSeparator();
 										} else {
 											pushLineSeparator();
 										}
-									} else {
-										this.currentLine = null;
 									}
 								}
 								isUnicode = false;
@@ -1432,15 +1569,12 @@
 								int firstTag = 0;
 								while ((this.currentCharacter != '/') || (!star)) {
 									if ((this.currentCharacter == '\r') || (this.currentCharacter == '\n')) {
-										checkNonExternalizedString();
 										if (this.recordLineSeparator) {
 											if (isUnicode) {
 												pushUnicodeLineSeparator();
 											} else {
 												pushLineSeparator();
 											}
-										} else {
-											this.currentLine = null;
 										}
 									}
 									switch (this.currentCharacter) {
@@ -1498,15 +1632,15 @@
 						return TokenNameEOF;
 					//the atEnd may not be <currentPosition == source.length> if source is only some part of a real (external) stream
 					throw new InvalidInputException("Ctrl-Z"); //$NON-NLS-1$
-
 				default :
 					char c = this.currentCharacter;
-					if (c < MAX_OBVIOUS) {
-						switch (ObviousIdentCharNatures[c]) {
-							case C_LETTER :
-								return scanIdentifierOrKeyword();
-							case C_DIGIT :
+					if (c < ScannerHelper.MAX_OBVIOUS) {
+						if ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] & ScannerHelper.C_IDENT_START) != 0) {
+							return scanIdentifierOrKeyword();
+						} else if ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] & ScannerHelper.C_DIGIT) != 0) {
 								return scanNumber(false);
+						} else {
+							return TokenNameERROR;
 						}
 					}
 					boolean isJavaIdStart;
@@ -1528,11 +1662,12 @@
 						}
 						throw new InvalidInputException(INVALID_HIGH_SURROGATE);
 					} else {
+						// optimized case already checked
 						isJavaIdStart = Character.isJavaIdentifierStart(c);
 					}
 					if (isJavaIdStart)
 						return scanIdentifierOrKeyword();
-					if (isDigit(this.currentCharacter)) {
+					if (ScannerHelper.isDigit(this.currentCharacter)) {
 						return scanNumber(false);
 					}						
 					return TokenNameERROR;
@@ -1558,70 +1693,66 @@
 	//and currentPosition points right next after it
 
 	//ALL getNextChar.... ARE OPTIMIZED COPIES 
-
-	try {
-		int c1 = 0, c2 = 0, c3 = 0, c4 = 0, unicodeSize = 6;
-		this.currentPosition++;
+	int c1 = 0, c2 = 0, c3 = 0, c4 = 0, unicodeSize = 6;
+	this.currentPosition++;
+	if (this.currentPosition < this.eofPosition) {
 		while (this.source[this.currentPosition] == 'u') {
 			this.currentPosition++;
+			if (this.currentPosition >= this.eofPosition) {
+				this.currentPosition--;
+				throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
+			}
 			unicodeSize++;
 		}
-
-		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);
-		}
-		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
-		unicodeStore();
-		this.unicodeAsBackSlash = this.currentCharacter == '\\';
-	} catch (ArrayIndexOutOfBoundsException e) {
+	} else {
 		this.currentPosition--;
 		throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
 	}
-}
 
+	if ((this.currentPosition + 4) > this.eofPosition) {
+		this.currentPosition += (this.eofPosition - this.currentPosition);
+		throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
+	}
+	if ((c1 = ScannerHelper.getNumericValue(this.source[this.currentPosition++])) > 15
+    		|| c1 < 0
+    		|| (c2 = ScannerHelper.getNumericValue(this.source[this.currentPosition++])) > 15
+    		|| c2 < 0
+    		|| (c3 = ScannerHelper.getNumericValue(this.source[this.currentPosition++])) > 15
+    		|| c3 < 0
+    		|| (c4 = ScannerHelper.getNumericValue(this.source[this.currentPosition++])) > 15
+    		|| c4 < 0){
+		throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
+	}
+	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
+	unicodeStore();
+	this.unicodeAsBackSlash = this.currentCharacter == '\\';
+}
+public NLSTag[] getNLSTags() {
+	final int length = this.nlsTagsPtr;
+	if (length != 0) {
+		NLSTag[] result = new NLSTag[length];
+		System.arraycopy(this.nlsTags, 0, result, 0, length);
+		this.nlsTagsPtr = 0;
+		return result;
+	}
+	return null;
+}
 public char[] getSource(){
 	return this.source;
 }
-// TODO (philippe) should simply switch on character
-protected boolean isDigit(char c) throws InvalidInputException {
-	if (Character.isDigit(c)) {
-		switch(c) {
-			case '0' :
-			case '1' :
-			case '2' :
-			case '3' :
-			case '4' :
-			case '5' :
-			case '6' :
-			case '7' :
-			case '8' :
-			case '9' :
-				return true;
-		}
-		throw new InvalidInputException(Scanner.INVALID_DIGIT);
-	} else {
-		return false;
-	}
-}
 public final void jumpOverMethodBody() {
 
 	this.wasAcr = false;
 	int found = 1;
 	try {
 		while (true) { //loop for jumping over comments
+			this.withoutUnicodePtr = 0;
 			// ---------Consume white space and handles startPosition---------
 			boolean isWhiteSpace;
 			do {
@@ -1631,8 +1762,9 @@
 					isWhiteSpace = jumpOverUnicodeWhiteSpace();
 				} else {
 					if (this.recordLineSeparator
-						&& ((this.currentCharacter == '\r') || (this.currentCharacter == '\n')))
+							&& ((this.currentCharacter == '\r') || (this.currentCharacter == '\n'))) {
 						pushLineSeparator();
+					}
 					isWhiteSpace = CharOperation.isWhitespace(this.currentCharacter);
 				}
 			} while (isWhiteSpace);
@@ -1785,7 +1917,7 @@
 								 * We need to completely consume the line break
 								 */
 								if (this.currentCharacter == '\r'
-								   && this.source.length > this.currentPosition) {
+								   && this.eofPosition > this.currentPosition) {
 								   	if (this.source[this.currentPosition] == '\n') {
 										this.currentPosition++;
 										this.currentCharacter = '\n';
@@ -1798,16 +1930,24 @@
 								recordComment(TokenNameCOMMENT_LINE);
 								if (this.recordLineSeparator
 									&& ((this.currentCharacter == '\r') || (this.currentCharacter == '\n'))) {
-										if (isUnicode) {
-											pushUnicodeLineSeparator();
-										} else {
-											pushLineSeparator();
+										if (this.checkNonExternalizedStringLiterals) {
+											parseTags();
+										}
+										if (this.recordLineSeparator) {
+											if (isUnicode) {
+												pushUnicodeLineSeparator();
+											} else {
+												pushLineSeparator();
+											}
 										}
 									}
 							} catch (IndexOutOfBoundsException e) {
 								 //an eof will then be generated
 								this.currentPosition--;
 								recordComment(TokenNameCOMMENT_LINE);
+								if (this.checkNonExternalizedStringLiterals) {
+									parseTags();
+								}
 								if (!this.tokenizeComments) {
 									this.currentPosition++; 
 								}
@@ -1844,8 +1984,6 @@
 										} else {
 											pushLineSeparator();
 										}
-									} else {
-										this.currentLine = null;
 									}
 								}
 								isUnicode = false;
@@ -1876,8 +2014,6 @@
 											} else {
 												pushLineSeparator();
 											}
-										} else {
-											this.currentLine = null;
 										}
 									}
 									switch (this.currentCharacter) {
@@ -1920,14 +2056,15 @@
 				default :
 					try {
 						char c = this.currentCharacter;
-						if (c < MAX_OBVIOUS) {
-							switch (ObviousIdentCharNatures[c]) {
-								case C_LETTER :
-									scanIdentifierOrKeyword();
-									break NextToken;
-								case C_DIGIT :
-									scanNumber(false);
-									break NextToken;
+						if (c < ScannerHelper.MAX_OBVIOUS) {
+							if ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] & ScannerHelper.C_IDENT_START) != 0) {
+								scanIdentifierOrKeyword();
+								break NextToken;
+							} else if ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] & ScannerHelper.C_DIGIT) != 0) {
+								scanNumber(false);
+								break NextToken;
+							} else {
+								break NextToken;
 							}
 						}
 						boolean isJavaIdStart;
@@ -1939,26 +2076,23 @@
 							char low = (char) getNextChar();
 							if (low < LOW_SURROGATE_MIN_VALUE || low > LOW_SURROGATE_MAX_VALUE) {
 								// illegal low surrogate
-								throw new InvalidInputException(INVALID_LOW_SURROGATE);
+								break NextToken;
 							}
 							isJavaIdStart = ScannerHelper.isJavaIdentifierStart(c, low);
-						}
-						else if (c >= LOW_SURROGATE_MIN_VALUE && c <= LOW_SURROGATE_MAX_VALUE) {
-							if (this.complianceLevel < ClassFileConstants.JDK1_5) {
-								throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
-							}
-							throw new InvalidInputException(INVALID_HIGH_SURROGATE);
+						} else if (c >= LOW_SURROGATE_MIN_VALUE && c <= LOW_SURROGATE_MAX_VALUE) {
+							break NextToken;
 						} else {
+							// optimized case already checked
 							isJavaIdStart = Character.isJavaIdentifierStart(c);
 						}
 						if (isJavaIdStart) {
 							scanIdentifierOrKeyword();
 							break NextToken;
 						}
-						if (isDigit(this.currentCharacter)) {
-							scanNumber(false);
-							break NextToken;
-						}						
+//						if (ScannerHelper.isDigit(this.currentCharacter)) {
+//							scanNumber(false);
+//							break NextToken;
+//						}						
 					} catch (InvalidInputException ex) {
 						// ignore
 					}
@@ -1979,14 +2113,9 @@
 	//On false, the currentCharacter is filled up with a potential
 	//correct char
 
-	try {
-		this.wasAcr = false;
-		getNextUnicodeChar();
-		return CharOperation.isWhitespace(this.currentCharacter);
-	} catch (IndexOutOfBoundsException e){
-		this.currentPosition--;
-		throw new InvalidInputException(INVALID_UNICODE_ESCAPE);
-	}
+	this.wasAcr = false;
+	getNextUnicodeChar();
+	return CharOperation.isWhitespace(this.currentCharacter);
 }
 
 final char[] optimizedCurrentTokenSource1() {
@@ -2225,64 +2354,120 @@
 	return table[newEntry6 = max] = r; //(r = new char[] {c0, c1, c2, c3, c4, c5});
 }
 
-protected void parseTags(NLSLine line) {
-	String s = new String(getCurrentTokenSource());
-	int pos = s.indexOf(TAG_PREFIX);
-	int lineLength = line.size();
-	while (pos != -1) {
-		int start = pos + TAG_PREFIX_LENGTH;
-		int end = s.indexOf(TAG_POSTFIX, start);
-		if (end != -1) {
-			String index = s.substring(start, end);
-			int i = 0;
-			try {
-				i = Integer.parseInt(index) - 1; // Tags are one based not zero based.
-			} catch (NumberFormatException e) {
-				i = -1; // we don't want to consider this as a valid NLS tag
-			}
-			if (line.exists(i)) {
-				line.set(i, null);
-			}
-		}
-		pos = s.indexOf(TAG_PREFIX, start);
+private void parseTags() {
+	int position = 0;
+	final int currentStartPosition = this.startPosition;
+	final int currentLinePtr = this.linePtr;
+	if (currentLinePtr >= 0) {
+		position = this.lineEnds[currentLinePtr] + 1; 
 	}
-
-	this.nonNLSStrings = new StringLiteral[lineLength];
-	int nonNLSCounter = 0;
-	for (Iterator iterator = line.iterator(); iterator.hasNext(); ) {
-		StringLiteral literal = (StringLiteral) iterator.next();
-		if (literal != null) {
-			this.nonNLSStrings[nonNLSCounter++] = literal;
-		}
+	while (ScannerHelper.isWhitespace(this.source[position])) {
+		position++;
 	}
-	if (nonNLSCounter == 0) {
-		this.nonNLSStrings = null;
-		this.currentLine = null;
+	if (currentStartPosition == position) {
+		// the whole line is commented out
 		return;
-	} 
-	this.wasNonExternalizedStringLiteral = true;
-	if (nonNLSCounter != lineLength) {
-		System.arraycopy(this.nonNLSStrings, 0, (this.nonNLSStrings = new StringLiteral[nonNLSCounter]), 0, nonNLSCounter);
 	}
-	this.currentLine = null;
+	char[] s = null;
+	int sourceEnd = this.currentPosition;
+	int sourceStart = currentStartPosition;
+	int sourceDelta = 0;
+	if (this.withoutUnicodePtr != 0) {
+		// 0 is used as a fast test flag so the real first char is in position 1
+		System.arraycopy(
+			this.withoutUnicodeBuffer, 
+			1, 
+			s = new char[this.withoutUnicodePtr], 
+			0, 
+			this.withoutUnicodePtr);
+		sourceEnd = this.withoutUnicodePtr;
+		sourceStart = 1;
+		sourceDelta = currentStartPosition;
+	} else {
+		s = this.source;
+	}
+	int pos = CharOperation.indexOf(TAG_PREFIX, s, true, sourceStart, sourceEnd);
+	if (pos != -1) {
+		if (this.nlsTags == null) {
+			this.nlsTags = new NLSTag[10];
+			this.nlsTagsPtr = 0;
+		}
+		while (pos != -1) {
+			int start = pos + TAG_PREFIX_LENGTH;
+			int end = CharOperation.indexOf(TAG_POSTFIX, s, start, sourceEnd);
+			if (end != -1) {
+				NLSTag currentTag = null;
+				final int currentLine = currentLinePtr + 1;
+				try {
+					currentTag = new NLSTag(pos + sourceDelta, end + sourceDelta, currentLine, extractInt(s, start, end));
+				} catch (NumberFormatException e) {
+					currentTag = new NLSTag(pos + sourceDelta, end + sourceDelta, currentLine, -1);
+				}
+				if (this.nlsTagsPtr == this.nlsTags.length) {
+					// resize
+					System.arraycopy(this.nlsTags, 0, (this.nlsTags = new NLSTag[this.nlsTagsPtr + 10]), 0, this.nlsTagsPtr);
+				}
+				this.nlsTags[this.nlsTagsPtr++] = currentTag;
+			} else {
+				end = start;
+			}
+			pos = CharOperation.indexOf(TAG_PREFIX, s, true, end, sourceEnd);
+		}
+	}
 }
-
+private int extractInt(char[] array, int start, int end) {
+	int value = 0;
+	for (int i = start; i < end; i++) {
+		final char currentChar = array[i];
+		int digit = 0;
+		switch(currentChar) {
+			case '0' :
+				digit = 0;
+				break;
+			case '1' :
+				digit = 1;
+				break;
+			case '2' :
+				digit = 2;
+				break;
+			case '3' :
+				digit = 3;
+				break;
+			case '4' :
+				digit = 4;
+				break;
+			case '5' :
+				digit = 5;
+				break;
+			case '6' :
+				digit = 6;
+				break;
+			case '7' :
+				digit = 7;
+				break;
+			case '8' :
+				digit = 8;
+				break;
+			case '9' :
+				digit = 9;
+				break;
+			default :
+				throw new NumberFormatException();
+		}
+		value *= 10;
+		if (digit < 0) throw new NumberFormatException();
+		value += digit;
+	}
+	return value;
+}
 public final void pushLineSeparator() {
 	//see comment on isLineDelimiter(char) for the use of '\n' and '\r'
 	final int INCREMENT = 250;
-	
-	if (this.checkNonExternalizedStringLiterals) {
-	// reinitialize the current line for non externalize strings purpose
-		this.currentLine = null;
-	}
 	//currentCharacter is at position currentPosition-1
-
 	// cr 000D
 	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);
 		int length = this.lineEnds.length;
 		if (++this.linePtr >=  length)
 			System.arraycopy(this.lineEnds, 0, this.lineEnds = new int[length + INCREMENT], 0, length);
@@ -2308,9 +2493,7 @@
 				this.lineEnds[this.linePtr] = this.currentPosition - 1;
 			} else {
 				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);
@@ -2321,11 +2504,6 @@
 	}
 }
 public final void pushUnicodeLineSeparator() {
-	if (this.checkNonExternalizedStringLiterals) {
-	// reinitialize the current line for non externalize strings purpose
-		this.currentLine = null;
-	}
-	
 	// cr 000D
 	if (this.currentCharacter == '\r') {
 		if (this.source[this.currentPosition] == '\n') {
@@ -2420,18 +2598,18 @@
 			// OctalDigit OctalDigit
 			// ZeroToThree OctalDigit OctalDigit
 
-			int number = Character.getNumericValue(this.currentCharacter);
+			int number = ScannerHelper.getNumericValue(this.currentCharacter);
 			if (number >= 0 && number <= 7) {
 				boolean zeroToThreeNot = number > 3;
-				if (isDigit(this.currentCharacter = this.source[this.currentPosition++])) {
-					int digit = Character.getNumericValue(this.currentCharacter);
+				if (ScannerHelper.isDigit(this.currentCharacter = this.source[this.currentPosition++])) {
+					int digit = ScannerHelper.getNumericValue(this.currentCharacter);
 					if (digit >= 0 && digit <= 7) {
 						number = (number * 8) + digit;
-						if (isDigit(this.currentCharacter = this.source[this.currentPosition++])) {
+						if (ScannerHelper.isDigit(this.currentCharacter = this.source[this.currentPosition++])) {
 							if (zeroToThreeNot) {// has read \NotZeroToThree OctalDigit Digit --> ignore last character
 								this.currentPosition--;
 							} else {
-								digit = Character.getNumericValue(this.currentCharacter);
+								digit = ScannerHelper.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
@@ -2454,6 +2632,68 @@
 				throw new InvalidInputException(INVALID_ESCAPE);
 	}
 }
+public int scanIdentifierOrKeywordWithBoundCheck() {
+	//test keywords
+
+	//first dispatch on the first char.
+	//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 
+	this.useAssertAsAnIndentifier = false;
+	this.useEnumAsAnIndentifier = false;
+
+	char[] src = this.source;
+	identLoop: {
+		int pos;
+		int srcLength = this.eofPosition;
+		while (true) {
+			if ((pos = this.currentPosition) >= srcLength) // handle the obvious case upfront
+				break identLoop;
+			char c = src[pos];
+			if (c < ScannerHelper.MAX_OBVIOUS) {
+				if ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] & 
+						(ScannerHelper.C_UPPER_LETTER | ScannerHelper.C_LOWER_LETTER | ScannerHelper.C_IDENT_PART | ScannerHelper.C_DIGIT)) != 0) {
+		               if (this.withoutUnicodePtr != 0) {
+							this.currentCharacter = c;
+							unicodeStore();
+						}
+						this.currentPosition++;
+				} else if ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] & (ScannerHelper.C_SEPARATOR | ScannerHelper.C_JLS_SPACE)) != 0) {
+						this.currentCharacter = c;
+						break identLoop;
+				} else {
+					//System.out.println("slow<=128:  "+ c);						
+					while (getNextCharAsJavaIdentifierPartWithBoundCheck()){/*empty*/}
+					break identLoop;						
+				}
+			} else {
+				//System.out.println("slow>>128:  "+ c);						
+				while (getNextCharAsJavaIdentifierPartWithBoundCheck()){/*empty*/}
+				break identLoop;						
+			}
+		}
+	}
+	
+	int index, length;
+	char[] data;
+	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 = this.currentPosition - this.startPosition) == 1) {
+			return TokenNameIdentifier;
+		}
+		data = this.source;
+		index = this.startPosition;
+	} else {
+		if ((length = this.withoutUnicodePtr) == 1)
+			return TokenNameIdentifier;
+		data = this.withoutUnicodeBuffer;
+		index = 1;
+	}
+
+	return internalScanIdentifierOrKeyword(index, length, data);
+}
 public int scanIdentifierOrKeyword() {
 	//test keywords
 
@@ -2466,31 +2706,27 @@
 
 	char[] src = this.source;
 	identLoop: {
-		int pos, srcLength = this.source.length;
+		int pos;
+		int srcLength = this.eofPosition;
 		while (true) {
 			if ((pos = this.currentPosition) >= srcLength) // handle the obvious case upfront
 				break identLoop;
 			char c = src[pos];
-			if (c < MAX_OBVIOUS) {
-				switch (ObviousIdentCharNatures[c]) {
-					case C_LETTER :
-					case C_DIGIT :
+			if (c < ScannerHelper.MAX_OBVIOUS) {
+				if ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] & 
+						(ScannerHelper.C_UPPER_LETTER | ScannerHelper.C_LOWER_LETTER | ScannerHelper.C_IDENT_PART | ScannerHelper.C_DIGIT)) != 0) {
 		               if (this.withoutUnicodePtr != 0) {
 							this.currentCharacter = c;
 							unicodeStore();
 						}
 						this.currentPosition++;
-						break;						
-						
-					case C_SEPARATOR :
-					case C_SPACE :
+				} else if ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] & (ScannerHelper.C_SEPARATOR | ScannerHelper.C_JLS_SPACE)) != 0) {
 						this.currentCharacter = c;
-						break identLoop;	
-
-					default:
-						//System.out.println("slow<=128:  "+ c);						
-						while (getNextCharAsJavaIdentifierPart()){/*empty*/}
-						break identLoop;						
+						break identLoop;
+				} else {
+					//System.out.println("slow<=128:  "+ c);						
+					while (getNextCharAsJavaIdentifierPart()){/*empty*/}
+					break identLoop;						
 				}
 			} else {
 				//System.out.println("slow>>128:  "+ c);						
@@ -2502,15 +2738,13 @@
 	
 	int index, length;
 	char[] data;
-	if (this.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 = this.currentPosition - this.startPosition) == 1)
+		if ((length = this.currentPosition - this.startPosition) == 1) {
 			return TokenNameIdentifier;
+		}
 		data = this.source;
 		index = this.startPosition;
 	} else {
@@ -2520,9 +2754,11 @@
 		index = 1;
 	}
 
+	return internalScanIdentifierOrKeyword(index, length, data);
+}
 
+private int internalScanIdentifierOrKeyword(int index, int length, char[] data) {
 	switch (data[index]) {
-
 		case 'a' : 
 			switch(length) {
 				case 8: //abstract
@@ -3130,7 +3366,7 @@
 							}
 						}
 					}
-					if (!isDigit(this.currentCharacter)) {
+					if (!ScannerHelper.isDigit(this.currentCharacter)) {
 						throw new InvalidInputException(INVALID_HEXA);
 					}
 					while (getNextCharAsDigit()){/*empty*/}
@@ -3175,7 +3411,7 @@
 						}
 					}
 				}
-				if (!isDigit(this.currentCharacter))
+				if (!ScannerHelper.isDigit(this.currentCharacter))
 					throw new InvalidInputException(INVALID_FLOAT);
 				while (getNextCharAsDigit()){/*empty*/}
 				if (getNextChar('f', 'F') >= 0)
@@ -3238,7 +3474,7 @@
 							}
 						}
 					}
-					if (!isDigit(this.currentCharacter))
+					if (!ScannerHelper.isDigit(this.currentCharacter))
 						throw new InvalidInputException(INVALID_FLOAT);
 					while (getNextCharAsDigit()){/*empty*/}
 				}
@@ -3290,7 +3526,7 @@
 				}
 			}
 		}
-		if (!isDigit(this.currentCharacter))
+		if (!ScannerHelper.isDigit(this.currentCharacter))
 			throw new InvalidInputException(INVALID_FLOAT);
 		while (getNextCharAsDigit()){/*empty*/}
 	}
@@ -3304,34 +3540,14 @@
 
 	return floating ? TokenNameDoubleLiteral : TokenNameIntegerLiteral;
 }
+
 /**
  * Search the line number corresponding to a specific position
  * @param position int
  * @return int
  */
 public final int getLineNumber(int position) {
-
-	if (this.lineEnds == null)
-		return 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 < this.lineEnds[m]) {
-			d = m-1;
-		} else if (position > this.lineEnds[m]) {
-			g = m+1;
-		} else {
-			return m + 1;
-		}
-	}
-	if (position < this.lineEnds[m]) {
-		return m+1;
-	}
-	return m+2;
+	return Util.getLineNumber(position, this.lineEnds, 0, this.linePtr);
 }
 public final void setSource(char[] sourceString){
 	//the source-buffer is set to sourceString
@@ -3375,9 +3591,9 @@
 	setSource(null, compilationResult);
 }
 public String toString() {
-	if (this.startPosition == this.source.length)
+	if (this.startPosition == this.eofPosition)
 		return "EOF\n\n" + new String(this.source); //$NON-NLS-1$
-	if (this.currentPosition > this.source.length)
+	if (this.currentPosition > this.eofPosition)
 		return "behind the EOF\n\n" + new String(this.source); //$NON-NLS-1$
 
 	char front[] = new char[this.startPosition];
@@ -3397,13 +3613,13 @@
 		middle = CharOperation.NO_CHAR;
 	}
 	
-	char end[] = new char[this.source.length - (this.currentPosition - 1)];
+	char end[] = new char[this.eofPosition - (this.currentPosition - 1)];
 	System.arraycopy(
 		this.source, 
 		(this.currentPosition - 1) + 1, 
 		end, 
 		0, 
-		this.source.length - (this.currentPosition - 1) - 1);
+		this.eofPosition - (this.currentPosition - 1) - 1);
 	
 	return new String(front)
 		+ "\n===============================\nStarts here -->" //$NON-NLS-1$
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
index d490044..9cd31e7 100644
--- 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
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2002, 2004 IBM Corporation and others.
+ * Copyright (c) 2002, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,7 +10,7 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.util;
 
-import org.eclipse.jdt.core.compiler.IProblem;
+import org.eclipse.jdt.core.compiler.CategorizedProblem;
 import org.eclipse.jdt.internal.compiler.CompilationResult;
 
 /**
@@ -18,12 +18,12 @@
  * line ends or problems.
  */
 public class RecordedParsingInformation {
-	public IProblem[] problems;
+	public CategorizedProblem[] problems;
 	public int problemsCount;
 	public int[] lineEnds;
 	public int[][] commentPositions;
 	
-	public RecordedParsingInformation(IProblem[] problems, int[] lineEnds, int[][] commentPositions) {
+	public RecordedParsingInformation(CategorizedProblem[] problems, int[] lineEnds, int[][] commentPositions) {
 		this.problems = problems;
 		this.lineEnds = lineEnds;
 		this.commentPositions = commentPositions;
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 b0c5a6b..fba1212 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ResourceCompilationUnit.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ResourceCompilationUnit.java
new file mode 100755
index 0000000..0e55fff
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ResourceCompilationUnit.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core.util;
+
+import java.net.URI;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.batch.CompilationUnit;
+
+/**
+ * An ICompilationUnit that retrieves its contents using an IFile
+ */
+public class ResourceCompilationUnit extends CompilationUnit {
+	
+	private IFile file;
+	
+	public ResourceCompilationUnit(IFile file, URI location) {
+		super(null/*no contents*/, location == null ? file.getFullPath().toString() : location.getPath(), null/*encoding is used only when retrieving the contents*/);
+		this.file = file;
+	}
+
+	public char[] getContents() {
+		if (this.contents != null)
+			return this.contents;   // answer the cached source
+	
+		// otherwise retrieve it
+		try {
+			return Util.getResourceContentsAsCharArray(this.file);
+		} catch (CoreException e) {
+			return CharOperation.NO_CHAR;
+		}
+	}
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/RuntimeInvisibleAnnotationsAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/RuntimeInvisibleAnnotationsAttribute.java
index e0bb58f..2598546 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/RuntimeInvisibleAnnotationsAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/RuntimeInvisibleAnnotationsAttribute.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/RuntimeInvisibleParameterAnnotationsAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/RuntimeInvisibleParameterAnnotationsAttribute.java
index 91cd147..099a032 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/RuntimeInvisibleParameterAnnotationsAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/RuntimeInvisibleParameterAnnotationsAttribute.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/RuntimeVisibleAnnotationsAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/RuntimeVisibleAnnotationsAttribute.java
index 5360535..62af5b1 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/RuntimeVisibleAnnotationsAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/RuntimeVisibleAnnotationsAttribute.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/RuntimeVisibleParameterAnnotationsAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/RuntimeVisibleParameterAnnotationsAttribute.java
index 9e4d5ab..6f3e8d1 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/RuntimeVisibleParameterAnnotationsAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/RuntimeVisibleParameterAnnotationsAttribute.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004 IBM Corporation and others.
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/SignatureAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/SignatureAttribute.java
index fa7612e..e6e65b1 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/SignatureAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/SignatureAttribute.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 3362c19..7fb4386 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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
deleted file mode 100644
index fe7c065..0000000
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/SimpleSet.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.core.util;
-
-/**
- * A simple lookup table is a non-synchronized Hashtable, whose keys
- * and values are Objects. It also uses linear probing to resolve collisions
- * rather than a linked list of hash table entries.
- */
-public final class SimpleSet implements Cloneable {
-
-// to avoid using Enumerations, walk the individual values skipping nulls
-public Object[] values;
-public int elementSize; // number of elements in the table
-public int threshold;
-
-public SimpleSet() {
-	this(13);
-}
-
-public SimpleSet(int size) {
-	if (size < 3) size = 3;
-	this.elementSize = 0;
-	this.threshold = size + 1; // size is the expected number of elements
-	this.values = new Object[2 * size + 1];
-}
-
-public Object add(Object object) {
-	int length = values.length;
-	int index = (object.hashCode() & 0x7FFFFFFF) % length;
-	Object current;
-	while ((current = values[index]) != null) {
-		if (current.equals(object)) return values[index] = object;
-		if (++index == length) index = 0;
-	}
-	values[index] = object;
-
-	// assumes the threshold is never equal to the size of the table
-	if (++elementSize > threshold) rehash();
-	return object;
-}
-
-public void clear() {
-	for (int i = this.values.length; --i >= 0;)
-		this.values[i] = null;
-	this.elementSize = 0;
-}
-
-public Object clone() throws CloneNotSupportedException {
-	SimpleSet result = (SimpleSet) super.clone();
-	result.elementSize = this.elementSize;
-	result.threshold = this.threshold;
-
-	int length = this.values.length;
-	result.values = new Object[length];
-	System.arraycopy(this.values, 0, result.values, 0, length);
-	return result;
-}
-
-public boolean includes(Object object) {
-	int length = values.length;
-	int index = (object.hashCode() & 0x7FFFFFFF) % length;
-	Object current;
-	while ((current = values[index]) != null) {
-		if (current.equals(object)) return true;
-		if (++index == length) index = 0;
-	}
-	return false;
-}
-
-public Object remove(Object object) {
-	int length = values.length;
-	int index = (object.hashCode() & 0x7FFFFFFF) % length;
-	Object current;
-	while ((current = values[index]) != null) {
-		if (current.equals(object)) {
-			elementSize--;
-			Object oldValue = values[index];
-			values[index] = null;
-			if (values[index + 1 == length ? 0 : index + 1] != null)
-				rehash(); // only needed if a possible collision existed
-			return oldValue;
-		}
-		if (++index == length) index = 0;
-	}
-	return null;
-}
-
-private void rehash() {
-	SimpleSet newSet = new SimpleSet(elementSize * 2); // double the number of expected elements
-	Object current;
-	for (int i = values.length; --i >= 0;)
-		if ((current = values[i]) != null)
-			newSet.add(current);
-
-	this.values = newSet.values;
-	this.elementSize = newSet.elementSize;
-	this.threshold = newSet.threshold;
-}
-
-public String toString() {
-	String s = ""; //$NON-NLS-1$
-	Object object;
-	for (int i = 0, l = values.length; i < l; i++)
-		if ((object = values[i]) != null)
-			s += object.toString() + "\n"; //$NON-NLS-1$
-	return s;
-}
-}
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
index 306c5cc..a9e6197 100644
--- 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
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
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 b0cadcd..fcba33d 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/StackMapAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/StackMapAttribute.java
new file mode 100755
index 0000000..5c32a64
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/StackMapAttribute.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core.util;
+
+import org.eclipse.jdt.core.util.ClassFormatException;
+import org.eclipse.jdt.core.util.IConstantPool;
+import org.eclipse.jdt.core.util.IStackMapFrame;
+import org.eclipse.jdt.core.util.IStackMapAttribute;
+/**
+ * Default implementation of IStackMapAttribute.
+ * @see IStackMapAttribute
+ */
+public class StackMapAttribute
+	extends ClassFileAttribute
+	implements IStackMapAttribute {
+
+	private static final IStackMapFrame[] NO_FRAMES = new IStackMapFrame[0];
+	private static final byte[] NO_ENTRIES = new byte[0];
+
+	private int numberOfEntries;
+	private IStackMapFrame[] frames;
+	
+	private byte[] bytes;
+
+	/**
+	 * Constructor for LineNumberAttribute.
+	 * @param classFileBytes
+	 * @param constantPool
+	 * @param offset
+	 * @throws ClassFormatException
+	 */
+	public StackMapAttribute(
+			byte[] classFileBytes,
+			IConstantPool constantPool,
+			int offset)
+			throws ClassFormatException {
+		super(classFileBytes, constantPool, offset);
+		
+		final int length = u2At(classFileBytes, 6, offset); 
+		this.numberOfEntries = length;
+		if (length != 0) {
+			int readOffset = 8;
+			this.frames = new IStackMapFrame[length];
+			for (int i = 0; i < length; i++) {
+				DefaultStackMapFrame frame = new DefaultStackMapFrame(classFileBytes, constantPool, offset + readOffset);
+				this.frames[i] = frame;
+				readOffset += frame.sizeInBytes();
+			}
+		} else {
+			this.frames = NO_FRAMES;
+		}
+		final int byteLength = (int) u4At(classFileBytes, 2, offset);
+		
+		if (length != 0) {
+			System.arraycopy(classFileBytes, offset + 6, this.bytes = new byte[byteLength], 0, byteLength);
+		} else {
+			this.bytes = NO_ENTRIES;
+		}
+	}
+
+	public int getNumberOfEntries() {
+		return this.numberOfEntries;
+	}
+
+	public IStackMapFrame[] getStackMapFrame() {
+		return this.frames;
+	}
+	
+	/**
+	 */
+	public byte[] getBytes() {
+		return this.bytes;
+	}
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/StackMapFrame.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/StackMapFrame.java
new file mode 100755
index 0000000..3e6d060
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/StackMapFrame.java
@@ -0,0 +1,170 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core.util;
+
+import org.eclipse.jdt.core.util.ClassFormatException;
+import org.eclipse.jdt.core.util.IConstantPool;
+import org.eclipse.jdt.core.util.IStackMapFrame;
+import org.eclipse.jdt.core.util.IVerificationTypeInfo;
+
+/**
+ * Default implementation of IStackMapFrame
+ */
+public class StackMapFrame extends ClassFileStruct implements IStackMapFrame {
+	private static final IVerificationTypeInfo[] EMPTY_LOCALS_OR_STACK_ITEMS = new IVerificationTypeInfo[0];
+
+	private int readOffset;
+	private int frameType;
+	private int numberOfLocals;
+	private int numberOfStackItems;
+	private IVerificationTypeInfo[] locals;
+	private IVerificationTypeInfo[] stackItems;
+	private int offsetDelta;
+	
+	/**
+	 * Constructor for StackMapFrame.
+	 * 
+	 * @param classFileBytes
+	 * @param constantPool
+	 * @param offset
+	 * @throws ClassFormatException
+	 */
+	public StackMapFrame(
+			byte[] classFileBytes,
+			IConstantPool constantPool,
+			int offset) throws ClassFormatException {
+		
+		final int type = u1At(classFileBytes, 0, offset);
+		this.frameType = type;
+		switch(type) {
+			case 247 : // SAME_LOCALS_1_STACK_ITEM_EXTENDED
+				this.offsetDelta = u2At(classFileBytes, 1, offset);
+				this.numberOfStackItems = 1;
+				this.stackItems = new VerificationInfo[1];
+				this.readOffset = 3;
+				VerificationInfo info = new VerificationInfo(classFileBytes, constantPool, offset + this.readOffset);
+				this.stackItems[0] = info;
+				this.readOffset += info.sizeInBytes();
+				this.locals = EMPTY_LOCALS_OR_STACK_ITEMS;
+				this.numberOfLocals = 0;
+				break;
+			case 248 :
+			case 249 :
+			case 250:
+				// CHOP
+				this.offsetDelta = u2At(classFileBytes, 1, offset);
+				this.numberOfStackItems = 0;
+				this.stackItems = EMPTY_LOCALS_OR_STACK_ITEMS;
+				this.readOffset = 3;
+				this.locals = EMPTY_LOCALS_OR_STACK_ITEMS;
+				this.numberOfLocals = 0;
+				break;
+			case 251 :
+				// SAME_FRAME_EXTENDED
+				this.offsetDelta = u2At(classFileBytes, 1, offset);
+				this.numberOfStackItems = 0;
+				this.stackItems = EMPTY_LOCALS_OR_STACK_ITEMS;
+				this.readOffset = 3;
+				this.locals = EMPTY_LOCALS_OR_STACK_ITEMS;
+				this.numberOfLocals = 0;
+				break;
+			case 252 :
+			case 253 :
+			case 254 :
+				// APPEND
+				this.offsetDelta = u2At(classFileBytes, 1, offset);
+				this.numberOfStackItems = 0;
+				this.stackItems = EMPTY_LOCALS_OR_STACK_ITEMS;
+				this.readOffset = 3;
+				int diffLocals = type - 251;
+				this.numberOfLocals = diffLocals;
+				this.locals = new IVerificationTypeInfo[diffLocals];
+				for (int i = 0; i < diffLocals; i++) {
+					VerificationInfo verificationInfo = new VerificationInfo(classFileBytes, constantPool, offset + readOffset);
+					this.locals[i] = verificationInfo;
+					this.readOffset += verificationInfo.sizeInBytes();
+				}
+				break;
+			case 255 :
+				// FULL_FRAME
+				this.offsetDelta = u2At(classFileBytes, 1, offset);
+				int tempLocals = u2At(classFileBytes, 3, offset);
+				this.numberOfLocals = tempLocals;
+				this.readOffset = 5;
+				if (tempLocals != 0) {
+					this.locals = new IVerificationTypeInfo[tempLocals];
+					for (int i = 0; i < tempLocals; i++) {
+						VerificationInfo verificationInfo = new VerificationInfo(classFileBytes, constantPool, offset + this.readOffset);
+						this.locals[i] = verificationInfo;
+						this.readOffset += verificationInfo.sizeInBytes();
+					}
+				} else {
+					this.locals = EMPTY_LOCALS_OR_STACK_ITEMS;
+				}
+				int tempStackItems = u2At(classFileBytes, readOffset, offset);
+				this.readOffset += 2;
+				this.numberOfStackItems = tempStackItems;
+				if (tempStackItems != 0) {
+					this.stackItems = new IVerificationTypeInfo[tempStackItems];
+					for (int i = 0; i < tempStackItems; i++) {
+						VerificationInfo verificationInfo = new VerificationInfo(classFileBytes, constantPool, offset + this.readOffset);
+						this.stackItems[i] = verificationInfo;
+						this.readOffset += verificationInfo.sizeInBytes();
+					}
+				} else {
+					this.stackItems = EMPTY_LOCALS_OR_STACK_ITEMS;
+				}
+				break;
+			default:
+				if (type <= 63) {
+					// SAME_FRAME
+					this.offsetDelta = type;
+					this.numberOfStackItems = 0;
+					this.stackItems = EMPTY_LOCALS_OR_STACK_ITEMS;
+					this.locals = EMPTY_LOCALS_OR_STACK_ITEMS;
+					this.numberOfLocals = 0;
+					this.readOffset = 1;
+				} else if (type <= 127) {
+					// SAME_LOCALS_1_STACK_ITEM
+					this.offsetDelta = type - 64;
+					this.numberOfStackItems = 1;
+					this.stackItems = new VerificationInfo[1];
+					this.readOffset = 1;
+					info = new VerificationInfo(classFileBytes, constantPool, offset + this.readOffset);
+					this.stackItems[0] = info;
+					this.readOffset += info.sizeInBytes();
+					this.locals = EMPTY_LOCALS_OR_STACK_ITEMS;
+					this.numberOfLocals = 0;
+				}
+		}
+	}
+	int sizeInBytes() {
+		return this.readOffset;
+	}
+	public int getFrameType() {
+		return this.frameType;
+	}
+	public IVerificationTypeInfo[] getLocals() {
+		return this.locals;
+	}
+	public int getNumberOfLocals() {
+		return this.numberOfLocals;
+	}
+	public int getNumberOfStackItems() {
+		return this.numberOfStackItems;
+	}
+	public int getOffsetDelta() {
+		return this.offsetDelta;
+	}
+	public IVerificationTypeInfo[] getStackItems() {
+		return this.stackItems;
+	}
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/StackMapTableAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/StackMapTableAttribute.java
new file mode 100755
index 0000000..a184f97
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/StackMapTableAttribute.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core.util;
+
+import org.eclipse.jdt.core.util.ClassFormatException;
+import org.eclipse.jdt.core.util.IConstantPool;
+import org.eclipse.jdt.core.util.IStackMapFrame;
+import org.eclipse.jdt.core.util.IStackMapTableAttribute;
+/**
+ * Default implementation of IStackMapTableAttribute.
+ * @see IStackMapTableAttribute
+ */
+public class StackMapTableAttribute
+	extends ClassFileAttribute
+	implements IStackMapTableAttribute {
+
+	private static final IStackMapFrame[] NO_FRAMES = new IStackMapFrame[0];
+	private static final byte[] NO_ENTRIES = new byte[0];
+
+	private int numberOfEntries;
+	private IStackMapFrame[] frames;
+	
+	private byte[] bytes;
+
+	/**
+	 * Constructor for LineNumberAttribute.
+	 * @param classFileBytes
+	 * @param constantPool
+	 * @param offset
+	 * @throws ClassFormatException
+	 */
+	public StackMapTableAttribute(
+			byte[] classFileBytes,
+			IConstantPool constantPool,
+			int offset)
+			throws ClassFormatException {
+		super(classFileBytes, constantPool, offset);
+		
+		final int length = u2At(classFileBytes, 6, offset); 
+		this.numberOfEntries = length;
+		if (length != 0) {
+			int readOffset = 8;
+			this.frames = new IStackMapFrame[length];
+			for (int i = 0; i < length; i++) {
+				StackMapFrame frame = new StackMapFrame(classFileBytes, constantPool, offset + readOffset);
+				this.frames[i] = frame;
+				readOffset += frame.sizeInBytes();
+			}
+		} else {
+			this.frames = NO_FRAMES;
+		}
+		final int byteLength = (int) u4At(classFileBytes, 2, offset);
+		
+		if (length != 0) {
+			System.arraycopy(classFileBytes, offset + 6, this.bytes = new byte[byteLength], 0, byteLength);
+		} else {
+			this.bytes = NO_ENTRIES;
+		}
+	}
+
+	public int getNumberOfEntries() {
+		return this.numberOfEntries;
+	}
+
+	public IStackMapFrame[] getStackMapFrame() {
+		return this.frames;
+	}
+	
+	/**
+	 */
+	public byte[] getBytes() {
+		return this.bytes;
+	}
+}
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 c20a83b..1b711b8 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, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -32,7 +32,7 @@
 private void quickSort(int left, int right) {
 	int originalLeft = left;
 	int originalRight = right;
-	int midIndex =  (left + right) / 2;
+	int midIndex =  left + (right - left) / 2;
 	String midToString = this.sortedStrings[midIndex];
 	
 	do {
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 2bdd34f..6d80a22 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, 2005 IBM Corporation and others.
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -11,10 +11,13 @@
 package org.eclipse.jdt.internal.core.util;
 
 import java.io.*;
+import java.net.URI;
 import java.util.*;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
+import org.eclipse.core.filesystem.EFS;
+import org.eclipse.core.filesystem.IFileStore;
 import org.eclipse.core.resources.*;
 import org.eclipse.core.runtime.*;
 import org.eclipse.core.runtime.content.IContentType;
@@ -40,8 +43,9 @@
 import org.eclipse.jdt.internal.compiler.ast.TypeReference;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
+import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
-import org.eclipse.jdt.internal.core.Assert;
+import org.eclipse.jdt.internal.core.JavaElement;
 import org.eclipse.jdt.internal.core.JavaModelManager;
 import org.eclipse.jdt.internal.core.PackageFragmentRoot;
 import org.eclipse.jface.text.BadLocationException;
@@ -73,6 +77,7 @@
 	private static final String EMPTY_ARGUMENT = "   "; //$NON-NLS-1$
 	
 	private static char[][] JAVA_LIKE_EXTENSIONS;
+	public static boolean ENABLE_JAVA_LIKE_EXTENSIONS = true;
 
 	private static final char[] BOOLEAN = "boolean".toCharArray(); //$NON-NLS-1$
 	private static final char[] BYTE = "byte".toCharArray(); //$NON-NLS-1$
@@ -84,7 +89,7 @@
 	private static final char[] SHORT = "short".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 Util() {
 		// cannot be instantiated
 	}
@@ -434,7 +439,7 @@
 		// return false if any character of the end are
 		// not the same in lower case.
 		for(int i = 1 ; i <= endLength; i++){
-			if(Character.toLowerCase(end.charAt(endLength - i)) != Character.toLowerCase(str.charAt(strLength - i)))
+			if(ScannerHelper.toLowerCase(end.charAt(endLength - i)) != ScannerHelper.toLowerCase(str.charAt(strLength - i)))
 				return false;
 		}
 		
@@ -496,7 +501,9 @@
 
 		int len = a.length;
 		if (len != b.length) return false;
-		for (int i = 0; i < len; ++i) {
+		// walk array from end to beginning as this optimizes package name cases 
+		// where the first part is always the same (e.g. org.eclipse.jdt)
+		for (int i = len-1; i >= 0; i--) {
 			if (a[i] == null) {
 				if (b[i] != null) return false;
 			} else {
@@ -590,9 +597,11 @@
 		char[][] javaLikeExtensions = getJavaLikeExtensions();
 		suffixes: for (int i = 0, length = javaLikeExtensions.length; i < length; i++) {
 			char[] suffix = javaLikeExtensions[i];
-			if (stringLength + suffix.length != fileNameLength) continue;
-			for (int j = stringLength; j < fileNameLength; j++) {
-				if (fileName.charAt(j) != suffix[j-stringLength]) 
+			int extensionStart = stringLength+1;
+			if (extensionStart + suffix.length != fileNameLength) continue;
+			if (fileName.charAt(stringLength) != '.') continue;
+			for (int j = extensionStart; j < fileNameLength; j++) {
+				if (fileName.charAt(j) != suffix[j-extensionStart]) 
 					continue suffixes;
 			}
 			return true;
@@ -733,37 +742,40 @@
 		}
 		return null;
 	}
+	
 	/**
 	 * Returns the registered Java like extensions.
 	 */
 	public static char[][] getJavaLikeExtensions() {
 		if (JAVA_LIKE_EXTENSIONS == null) {
 			// TODO (jerome) reenable once JDT UI supports other file extensions (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=71460)
-			if (true)
-				JAVA_LIKE_EXTENSIONS = new char[][] {SuffixConstants.SUFFIX_java};
+			if (!ENABLE_JAVA_LIKE_EXTENSIONS)
+				JAVA_LIKE_EXTENSIONS = new char[][] {SuffixConstants.EXTENSION_java.toCharArray()};
 			else {
-				IContentType javaContentType = Platform.getContentTypeManager().getContentType(JavaModelManager.JAVA_SOURCE_CONTENT_TYPE);
-				String[] fileExtensions = javaContentType == null ? null : javaContentType.getFileSpecs(IContentType.FILE_EXTENSION_SPEC);
-				// note that file extensions contains "java" as it is defined in JDT Core's plugin.xml
-				int length = fileExtensions == null ? 0 : fileExtensions.length;
-				char[][] extensions = new char[length][];
-				SimpleWordSet knownExtensions = new SimpleWordSet(length); // used to ensure no duplicate extensions
-				extensions[0] = SuffixConstants.SUFFIX_java; // ensure that ".java" is first
-				knownExtensions.add(SuffixConstants.SUFFIX_java);
-				int index = 1;
-				for (int i = 0; i < length; i++) {
-					String fileExtension = fileExtensions[i];
-					int extensionLength = fileExtension.length() + 1;
-					char[] extension = new char[extensionLength];
-					extension[0] = '.';
-					fileExtension.getChars(0, extensionLength-1, extension, 1);
-					if (!knownExtensions.includes(extension)) {
-						extensions[index++] = extension;
-						knownExtensions.add(extension);
+				IContentType javaContentType = Platform.getContentTypeManager().getContentType(JavaCore.JAVA_SOURCE_CONTENT_TYPE);
+				HashSet fileExtensions = new HashSet();
+				// content types derived from java content type should be included (https://bugs.eclipse.org/bugs/show_bug.cgi?id=121715)
+				IContentType[] contentTypes = Platform.getContentTypeManager().getAllContentTypes();
+				for (int i = 0, length = contentTypes.length; i < length; i++) {
+					if (contentTypes[i].isKindOf(javaContentType)) { // note that javaContentType.isKindOf(javaContentType) == true
+						String[] fileExtension = contentTypes[i].getFileSpecs(IContentType.FILE_EXTENSION_SPEC);
+						for (int j = 0, length2 = fileExtension.length; j < length2; j++) {
+							fileExtensions.add(fileExtension[j]);
+						}
 					}
 				}
-				if (index != length)
-					System.arraycopy(extensions, 0, extensions = new char[index][], 0, index);
+				int length = fileExtensions.size();
+				// note that file extensions contains "java" as it is defined in JDT Core's plugin.xml
+				char[][] extensions = new char[length][];
+				extensions[0] = SuffixConstants.EXTENSION_java.toCharArray(); // ensure that "java" is first
+				int index = 1;
+				Iterator iterator = fileExtensions.iterator();
+				while (iterator.hasNext()) {
+					String fileExtension = (String) iterator.next();
+					if (SuffixConstants.EXTENSION_java.equals(fileExtension))
+						continue;
+					extensions[index++] = fileExtension.toCharArray();
+				}
 				JAVA_LIKE_EXTENSIONS = extensions;
 			}
 		}
@@ -780,48 +792,45 @@
 	 */
 	public static long getJdkLevel(Object targetLibrary) {
 		try {
-				ClassFileReader reader = null;
-				if (targetLibrary instanceof IFolder) {
-					IFile classFile = findFirstClassFile((IFolder) targetLibrary); // only internal classfolders are allowed
-					if (classFile != null) {
-						byte[] bytes = Util.getResourceContentsAsByteArray(classFile);
-						IPath location = classFile.getLocation();
-						reader = new ClassFileReader(bytes, location == null ? null : location.toString().toCharArray());
+			ClassFileReader reader = null;
+			if (targetLibrary instanceof IFolder) {
+				IFile classFile = findFirstClassFile((IFolder) targetLibrary); // only internal classfolders are allowed
+				if (classFile != null)
+					reader = Util.newClassFileReader(classFile);
+			} else {
+				// root is a jar file or a zip file
+				ZipFile jar = null;
+				try {
+					IPath path = null;
+					if (targetLibrary instanceof IResource) {
+						path = ((IResource)targetLibrary).getFullPath();
+					} else if (targetLibrary instanceof File){
+						File f = (File) targetLibrary;
+						if (!f.isDirectory()) {
+							path = new Path(((File)targetLibrary).getPath());
+						}
 					}
-				} else {
-					// root is a jar file or a zip file
-					ZipFile jar = null;
-					try {
-						IPath path = null;
-						if (targetLibrary instanceof IResource) {
-							path = ((IResource)targetLibrary).getLocation();
-						} else if (targetLibrary instanceof File){
-							File f = (File) targetLibrary;
-							if (!f.isDirectory()) {
-								path = new Path(((File)targetLibrary).getPath());
+					if (path != null) {
+						jar = JavaModelManager.getJavaModelManager().getZipFile(path);
+						for (Enumeration e= jar.entries(); e.hasMoreElements();) {
+							ZipEntry member= (ZipEntry) e.nextElement();
+							String entryName= member.getName();
+							if (org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(entryName)) {
+								reader = ClassFileReader.read(jar, entryName);
+								break;
 							}
 						}
-						if (path != null) {
-							jar = JavaModelManager.getJavaModelManager().getZipFile(path);
-							for (Enumeration e= jar.entries(); e.hasMoreElements();) {
-								ZipEntry member= (ZipEntry) e.nextElement();
-								String entryName= member.getName();
-								if (org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(entryName)) {
-									reader = ClassFileReader.read(jar, entryName);
-									break;
-								}
-							}
-						}
-					} catch (CoreException e) {
-						// ignore
-					} finally {
-						JavaModelManager.getJavaModelManager().closeZipFile(jar);
 					}
+				} catch (CoreException e) {
+					// ignore
+				} finally {
+					JavaModelManager.getJavaModelManager().closeZipFile(jar);
 				}
-				if (reader != null) {
-					return reader.getVersion();
-				}
-		} catch(JavaModelException e) {
+			}
+			if (reader != null) {
+				return reader.getVersion();
+			}
+		} catch (CoreException e) {
 			// ignore
 		} catch(ClassFormatException e) {
 			// ignore
@@ -832,10 +841,14 @@
 	}
 	
 	/**
-	 * Returns the substring of the given file name, ending at the start of a Java like extension.
+	 * Returns the substring of the given file name, ending at the start of a
+	 * Java like extension. The entire file name is returned if it doesn't end
+	 * with a Java like extension.
 	 */
 	public static String getNameWithoutJavaLikeExtension(String fileName) {
 		int index = indexOfJavaLikeExtension(fileName);
+		if (index == -1)
+			return fileName;
 		return fileName.substring(0, index);
 	}
 	
@@ -849,7 +862,7 @@
 		String lineSeparator = null;
 		
 		// line delimiter in given text
-		if (text != null) {
+		if (text != null && text.length() != 0) {
 			lineSeparator = findLineSeparator(text.toCharArray());
 			if (lineSeparator != null)
 				return lineSeparator;
@@ -989,7 +1002,7 @@
 	public static byte[] getResourceContentsAsByteArray(IFile file) throws JavaModelException {
 		InputStream stream= null;
 		try {
-			stream = new BufferedInputStream(file.getContents(true));
+			stream = file.getContents(true);
 		} catch (CoreException e) {
 			throw new JavaModelException(e);
 		}
@@ -1011,26 +1024,42 @@
 	 */
 	public static char[] getResourceContentsAsCharArray(IFile file) throws JavaModelException {
 		// Get encoding from file
-		String encoding = null;
+		String encoding;
 		try {
 			encoding = file.getCharset();
-		}
-		catch(CoreException ce) {
+		} catch(CoreException ce) {
 			// do not use any encoding
+			encoding = null;
 		}
 		return getResourceContentsAsCharArray(file, encoding);
 	}
-
-	public static char[] getResourceContentsAsCharArray(IFile file, String encoding) throws JavaModelException {
+		
+	public static char[] getResourceContentsAsCharArray(IFile file, String encoding) throws JavaModelException {		
+		// Get file length
+		// workaround https://bugs.eclipse.org/bugs/show_bug.cgi?id=130736 by using java.io.File if possible
+		IPath location = file.getLocation();
+		long length;
+		if (location == null) {
+			// non local file
+			try {
+				length = EFS.getStore(file.getLocationURI()).fetchInfo().getLength();
+			} catch (CoreException e) {
+				throw new JavaModelException(e);
+			}
+		} else {
+			// local file
+			length = location.toFile().length();
+		}
+		
 		// Get resource contents
 		InputStream stream= null;
 		try {
-			stream = new BufferedInputStream(file.getContents(true));
+			stream = file.getContents(true);
 		} catch (CoreException e) {
 			throw new JavaModelException(e, IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST);
 		}
 		try {
-			return org.eclipse.jdt.internal.compiler.util.Util.getInputStreamAsCharArray(stream, -1, encoding);
+			return org.eclipse.jdt.internal.compiler.util.Util.getInputStreamAsCharArray(stream, (int) length, encoding);
 		} catch (IOException e) {
 			throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
 		} finally {
@@ -1041,7 +1070,8 @@
 			}
 		}
 	}
-/*
+	
+	/*
 	 * Returns the signature of the given type.
 	 */
 	public static String getSignature(Type type) {
@@ -1051,6 +1081,43 @@
 	}
 	
 	/*
+	 * Returns the source attachment property for this package fragment root's path
+	 */
+	public static String getSourceAttachmentProperty(IPath path) throws JavaModelException {
+		Map rootPathToAttachments = JavaModelManager.getJavaModelManager().rootPathToAttachments;
+		String property = (String) rootPathToAttachments.get(path);
+		if (property == null) {
+			try {
+				property = ResourcesPlugin.getWorkspace().getRoot().getPersistentProperty(getSourceAttachmentPropertyName(path));
+				if (property == null) {
+					rootPathToAttachments.put(path, PackageFragmentRoot.NO_SOURCE_ATTACHMENT);
+					return null;
+				}
+				rootPathToAttachments.put(path, property);
+				return property;
+			} catch (CoreException e)  {
+				throw new JavaModelException(e);
+			}
+		} else if (property.equals(PackageFragmentRoot.NO_SOURCE_ATTACHMENT)) {
+			return null;
+		} else
+			return property;
+	}
+	
+	private static QualifiedName getSourceAttachmentPropertyName(IPath path) {
+		return new QualifiedName(JavaCore.PLUGIN_ID, "sourceattachment: " + path.toOSString()); //$NON-NLS-1$
+	}
+
+	public static void setSourceAttachmentProperty(IPath path, String property) {
+		JavaModelManager.getJavaModelManager().rootPathToAttachments.put(path, property);
+		try {
+			ResourcesPlugin.getWorkspace().getRoot().setPersistentProperty(getSourceAttachmentPropertyName(path), property);
+		} catch (CoreException e) {
+			e.printStackTrace();
+		}
+	}
+	
+	/*
 	 * Returns the declaring type signature of the element represented by the given binding key.
 	 * Returns the signature of the element if it is a type.
 	 * 
@@ -1148,6 +1215,7 @@
 	/*
 	 * Returns the index of the Java like extension of the given file name
 	 * or -1 if it doesn't end with a known Java like extension. 
+	 * Note this is the index of the '.' even if it is not considered part of the extension.
 	 */
 	public static int indexOfJavaLikeExtension(String fileName) {
 		int fileNameLength = fileName.length();
@@ -1156,12 +1224,14 @@
 			char[] extension = javaLikeExtensions[i];
 			int extensionLength = extension.length;
 			int extensionStart = fileNameLength - extensionLength;
-			if (extensionStart < 0) continue;
+			int dotIndex = extensionStart - 1;
+			if (dotIndex < 0) continue;
+			if (fileName.charAt(dotIndex) != '.') continue;
 			for (int j = 0; j < extensionLength; j++) {
 				if (fileName.charAt(extensionStart + j) != extension[j])
 					continue extensions;
 			}
-			return extensionStart;
+			return dotIndex;
 		}
 		return -1;
 	}
@@ -1188,6 +1258,36 @@
 		}
 		return -1;
 	}
+	/**
+	 * Returns whether the local file system supports accessing and modifying
+	 * the given attribute.
+	 */
+	protected static boolean isAttributeSupported(int attribute) {
+		return (EFS.getLocalFileSystem().attributes() & attribute) != 0;
+	}
+	
+	/**
+	 * Returns whether the given resource is read-only or not.
+	 * @param resource
+	 * @return <code>true</code> if the resource is read-only, <code>false</code> if it is not or
+	 * 	if the file system does not support the read-only attribute.
+	 */
+	public static boolean isReadOnly(IResource resource) {
+		if (isReadOnlySupported()) {
+			ResourceAttributes resourceAttributes = resource.getResourceAttributes();
+			if (resourceAttributes == null) return false; // not supported on this platform for this resource
+			return resourceAttributes.isReadOnly();
+		}
+		return false;
+	}
+
+	/**
+	 * Returns whether the local file system supports accessing and modifying
+	 * the read only flag.
+	 */
+	public static boolean isReadOnlySupported() {
+		return isAttributeSupported(EFS.ATTRIBUTE_READ_ONLY);
+	}
 
 	/*
 	 * Returns whether the given java element is exluded from its root's classpath.
@@ -1209,7 +1309,9 @@
 			case IJavaElement.COMPILATION_UNIT:
 				root = (PackageFragmentRoot)element.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
 				resource = element.getResource();
-				if (resource != null && isExcluded(resource, root.fullInclusionPatternChars(), root.fullExclusionPatternChars()))
+				if (resource == null) 
+					return false;
+				if (isExcluded(resource, root.fullInclusionPatternChars(), root.fullExclusionPatternChars()))
 					return true;
 				return isExcluded(element.getParent());
 				
@@ -1238,9 +1340,11 @@
 	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
-		return isExcluded(path, inclusionPatterns, exclusionPatterns, resource.getType() == IResource.FOLDER);
+		int resourceType = resource.getType();
+		return isExcluded(path, inclusionPatterns, exclusionPatterns, resourceType == IResource.FOLDER || resourceType == IResource.PROJECT);
 	}
 
+
 	/**
 	 * Validate the given .class file name.
 	 * A .class file name must obey the following rules:
@@ -1251,14 +1355,17 @@
 	 * </ul>
 	 * </p>
 	 * @param name the name of a .class file
+	 * @param sourceLevel the source level
+	 * @param complianceLevel the compliance level
 	 * @return a status object with code <code>IStatus.OK</code> if
 	 *		the given name is valid as a .class file name, otherwise a status 
 	 *		object indicating what is wrong with the name
 	 */
-	public static boolean isValidClassFileName(String name) {
-		return JavaConventions.validateClassFileName(name).getSeverity() != IStatus.ERROR;
+	public static boolean isValidClassFileName(String name, String sourceLevel, String complianceLevel) {
+		return JavaConventions.validateClassFileName(name, sourceLevel, complianceLevel).getSeverity() != IStatus.ERROR;
 	}
 
+
 	/**
 	 * Validate the given compilation unit name.
 	 * A compilation unit name must obey the following rules:
@@ -1269,20 +1376,25 @@
 	 * </ul>
 	 * </p>
 	 * @param name the name of a compilation unit
+	 * @param sourceLevel the source level
+	 * @param complianceLevel the compliance level
 	 * @return a status object with code <code>IStatus.OK</code> if
 	 *		the given name is valid as a compilation unit name, otherwise a status 
 	 *		object indicating what is wrong with the name
 	 */
-	public static boolean isValidCompilationUnitName(String name) {
-		return JavaConventions.validateCompilationUnitName(name).getSeverity() != IStatus.ERROR;
+	public static boolean isValidCompilationUnitName(String name, String sourceLevel, String complianceLevel) {
+		return JavaConventions.validateCompilationUnitName(name, sourceLevel, complianceLevel).getSeverity() != IStatus.ERROR;
 	}
-	
+
 	/**
 	 * Returns true if the given folder name is valid for a package,
 	 * false if it is not.
+	 * @param folderName the name of the folder
+	 * @param sourceLevel the source level
+	 * @param complianceLevel the compliance level
 	 */
-	public static boolean isValidFolderNameForPackage(String folderName) {
-		return JavaConventions.validateIdentifier(folderName).getSeverity() != IStatus.ERROR;
+	public static boolean isValidFolderNameForPackage(String folderName, String sourceLevel, String complianceLevel) {
+		return JavaConventions.validateIdentifier(folderName, sourceLevel, complianceLevel).getSeverity() != IStatus.ERROR;
 	}	
 
 	/**
@@ -1318,9 +1430,13 @@
 	
 	/*
 	 * Returns the simple name of a local type from the given binary type name.
-	 * The last '$' is at lastDollar. The ;last character of the type name is at end-1.
+	 * The last '$' is at lastDollar. The last character of the type name is at end-1.
 	 */
 	public static String localTypeName(String binaryTypeName, int lastDollar, int end) {
+		if (lastDollar > 0 && binaryTypeName.charAt(lastDollar-1) == '$') 
+			// local name starts with a dollar sign
+			// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=103466)
+			return binaryTypeName;
 		int nameStart = lastDollar+1;
 		while (nameStart < end && Character.isDigit(binaryTypeName.charAt(nameStart)))
 			nameStart++;
@@ -1343,8 +1459,19 @@
 			message, 
 			e); 
 		JavaCore.getPlugin().getLog().log(status);
-	}	
+	}
 	
+	public static ClassFileReader newClassFileReader(IResource resource) throws CoreException, ClassFormatException, IOException {
+		InputStream in = null;
+		try {
+			in = ((IFile) resource).getContents(true);
+			return ClassFileReader.read(in, resource.getFullPath().toString());
+		} finally {
+			if (in != null)
+				in.close();
+		}
+	}
+
 	/**
 	 * Normalizes the cariage returns in the given text.
 	 * They are all changed  to use the given buffer's line separator.
@@ -1416,12 +1543,15 @@
 	/**
 	 * Converts the given relative path into a package name.
 	 * Returns null if the path is not a valid package name.
+	 * @param pkgPath the package path
+	 * @param sourceLevel the source level
+	 * @param complianceLevel the compliance level
 	 */
-	public static String packageName(IPath pkgPath) {
+	public static String packageName(IPath pkgPath, String sourceLevel, String complianceLevel) {
 		StringBuffer pkgName = new StringBuffer(IPackageFragment.DEFAULT_PACKAGE_NAME);
 		for (int j = 0, max = pkgPath.segmentCount(); j < max; j++) {
 			String segment = pkgPath.segment(j);
-			if (!isValidFolderNameForPackage(segment)) {
+			if (!isValidFolderNameForPackage(segment, sourceLevel, complianceLevel)) {
 				return null;
 			}
 			pkgName.append(segment);
@@ -1455,7 +1585,7 @@
 	private static void quickSort(char[][] list, int left, int right) {
 		int original_left= left;
 		int original_right= right;
-		char[] mid= list[(left + right) / 2];
+		char[] mid= list[left + (right - left) / 2];
 		do {
 			while (compare(list[left], mid) < 0) {
 				left++;
@@ -1485,7 +1615,7 @@
 	private static void quickSort(Comparable[] sortedCollection, int left, int right) {
 		int original_left = left;
 		int original_right = right;
-		Comparable mid = sortedCollection[ (left + right) / 2];
+		Comparable mid = sortedCollection[ left + (right - left) / 2];
 		do {
 			while (sortedCollection[left].compareTo(mid) < 0) {
 				left++;
@@ -1511,7 +1641,7 @@
 	private static void quickSort(int[] list, int left, int right) {
 		int original_left= left;
 		int original_right= right;
-		int mid= list[(left + right) / 2];
+		int mid= list[left + (right - left) / 2];
 		do {
 			while (list[left] < mid) {
 				left++;
@@ -1541,7 +1671,7 @@
 	private static void quickSort(Object[] sortedCollection, int left, int right, Comparer comparer) {
 		int original_left = left;
 		int original_right = right;
-		Object mid = sortedCollection[ (left + right) / 2];
+		Object mid = sortedCollection[ left + (right - left) / 2];
 		do {
 			while (comparer.compare(sortedCollection[left], mid) < 0) {
 				left++;
@@ -1566,45 +1696,12 @@
 	}
 
 	/**
-	 * Sort the objects in the given collection using the given sort order.
-	 */
-	private static void quickSort(Object[] sortedCollection, int left, int right, int[] sortOrder) {
-		int original_left = left;
-		int original_right = right;
-		int mid = sortOrder[ (left + right) / 2];
-		do {
-			while (sortOrder[left] < mid) {
-				left++;
-			}
-			while (mid < sortOrder[right]) {
-				right--;
-			}
-			if (left <= right) {
-				Object tmp = sortedCollection[left];
-				sortedCollection[left] = sortedCollection[right];
-				sortedCollection[right] = tmp;
-				int tmp2 = sortOrder[left];
-				sortOrder[left] = sortOrder[right];
-				sortOrder[right] = tmp2;
-				left++;
-				right--;
-			}
-		} while (left <= right);
-		if (original_left < right) {
-			quickSort(sortedCollection, original_left, right, sortOrder);
-		}
-		if (left < original_right) {
-			quickSort(sortedCollection, left, original_right, sortOrder);
-		}
-	}
-
-	/**
 	 * Sort the strings in the given collection.
 	 */
 	private static void quickSort(String[] sortedCollection, int left, int right) {
 		int original_left = left;
 		int original_right = right;
-		String mid = sortedCollection[ (left + right) / 2];
+		String mid = sortedCollection[ left + (right - left) / 2];
 		do {
 			while (sortedCollection[left].compareTo(mid) < 0) {
 				left++;
@@ -1629,112 +1726,6 @@
 	}
 
 	/**
-	 * Sort the strings in the given collection in reverse alphabetical order.
-	 */
-	private static void quickSortReverse(String[] sortedCollection, int left, int right) {
-		int original_left = left;
-		int original_right = right;
-		String mid = sortedCollection[ (left + right) / 2];
-		do {
-			while (sortedCollection[left].compareTo(mid) > 0) {
-				left++;
-			}
-			while (mid.compareTo(sortedCollection[right]) > 0) {
-				right--;
-			}
-			if (left <= right) {
-				String tmp = sortedCollection[left];
-				sortedCollection[left] = sortedCollection[right];
-				sortedCollection[right] = tmp;
-				left++;
-				right--;
-			}
-		} while (left <= right);
-		if (original_left < right) {
-			quickSortReverse(sortedCollection, original_left, right);
-		}
-		if (left < original_right) {
-			quickSortReverse(sortedCollection, left, original_right);
-		}
-	}
-	/**
-	 * Reads in a string from the specified data input stream. The 
-	 * string has been encoded using a modified UTF-8 format. 
-	 * <p>
-	 * The first two bytes are read as if by 
-	 * <code>readUnsignedShort</code>. This value gives the number of 
-	 * following bytes that are in the encoded string, not
-	 * the length of the resulting string. The following bytes are then 
-	 * interpreted as bytes encoding characters in the UTF-8 format 
-	 * and are converted into characters. 
-	 * <p>
-	 * This method blocks until all the bytes are read, the end of the 
-	 * stream is detected, or an exception is thrown. 
-	 *
-	 * @param      in   a data input stream.
-	 * @return     a Unicode string.
-	 * @exception  EOFException            if the input stream reaches the end
-	 *               before all the bytes.
-	 * @exception  IOException             if an I/O error occurs.
-	 * @exception  UTFDataFormatException  if the bytes do not represent a
-	 *               valid UTF-8 encoding of a Unicode string.
-	 * @see        java.io.DataInputStream#readUnsignedShort()
-	 */
-	public final static char[] readUTF(DataInput in) throws IOException {
-		int utflen= in.readUnsignedShort();
-		char str[]= new char[utflen];
-		int count= 0;
-		int strlen= 0;
-		while (count < utflen) {
-			int c= in.readUnsignedByte();
-			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= in.readUnsignedByte();
-					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= in.readUnsignedByte();
-					char3= in.readUnsignedByte();
-					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;
-	}
-
-	/**
 	 * Returns the toString() of the given full path minus the first given number of segments.
 	 * The returned string is always a relative path (it has no leading slash)
 	 */
@@ -1776,6 +1767,13 @@
 		return new String(result);
 	}
 	
+	/*
+	 * Resets the list of Java-like extensions after a change in content-type.
+	 */
+	public static void resetJavaLikeExtensions() {
+		JAVA_LIKE_EXTENSIONS = null;
+	}
+	
 	/**
 	 * Return a new array which is the split of the given string using the given divider. The given end 
 	 * is exclusive and the given start is inclusive.
@@ -1824,19 +1822,24 @@
 		split[currentWord] = string.substring(last, end);
 		return split;
 	}
-	public static boolean isReadOnly(IResource resource) {
-		ResourceAttributes resourceAttributes = resource.getResourceAttributes();
-		if (resourceAttributes == null) return false; // not supported on this platform for this resource
-		return resourceAttributes.isReadOnly();
-	}
+	/**
+	 * Sets or unsets the given resource as read-only in the file system.
+	 * It's a no-op if the file system does not support the read-only attribute.
+	 * 
+	 * @param resource The resource to set as read-only
+	 * @param readOnly <code>true</code> to set it to read-only, 
+	 *		<code>false</code> to unset
+	 */
 	public static void setReadOnly(IResource resource, boolean readOnly) {
-		ResourceAttributes resourceAttributes = resource.getResourceAttributes();
-		if (resourceAttributes == null) return; // not supported on this platform for this resource
-		resourceAttributes.setReadOnly(readOnly);
-		try {
-			resource.setResourceAttributes(resourceAttributes);
-		} catch (CoreException e) {
-			// ignore
+		if (isReadOnlySupported()) {
+			ResourceAttributes resourceAttributes = resource.getResourceAttributes();
+			if (resourceAttributes == null) return; // not supported on this platform for this resource
+			resourceAttributes.setReadOnly(readOnly);
+			try {
+				resource.setResourceAttributes(resourceAttributes);
+			} catch (CoreException e) {
+				// ignore
+			}
 		}
 	}
 	public static void sort(char[][] list) {
@@ -1866,14 +1869,6 @@
 	}
 
 	/**
-	 * Sorts an array of objects in place, using the sort order given for each item.
-	 */
-	public static void sort(Object[] objects, int[] sortOrder) {
-		if (objects.length > 1)
-			quickSort(objects, 0, objects.length - 1, sortOrder);
-	}
-
-	/**
 	 * Sorts an array of strings in place using quicksort.
 	 */
 	public static void sort(String[] strings) {
@@ -1894,6 +1889,23 @@
 	}
 
 	/**
+	 * Sorts an array of Java elements based on their toStringWithAncestors(), 
+	 * returning a new array with the sorted items. 
+	 * The original array is left untouched.
+	 */
+	public static IJavaElement[] sortCopy(IJavaElement[] elements) {
+		int len = elements.length;
+		IJavaElement[] copy = new IJavaElement[len];
+		System.arraycopy(elements, 0, copy, 0, len);
+		sort(copy, new Comparer() {
+			public int compare(Object a, Object b) {
+				return ((JavaElement) a).toStringWithAncestors().compareTo(((JavaElement) b).toStringWithAncestors());
+			}
+		});
+		return copy;
+	}
+	
+	/**
 	 * Sorts an array of Strings, returning a new array
 	 * with the sorted items.  The original array is left untouched.
 	 */
@@ -1917,21 +1929,12 @@
 		return copy;
 	}
 
-	/**
-	 * Sorts an array of strings in place using quicksort
-	 * in reverse alphabetical order.
-	 */
-	public static void sortReverseOrder(String[] strings) {
-		if (strings.length > 1)
-			quickSortReverse(strings, 0, strings.length - 1);
-	}
-	
 	/*
 	 * Returns whether the given compound name starts with the given prefix.
 	 * Returns true if the n first elements of the prefix are equals and the last element of the 
 	 * prefix is a prefix of the corresponding element in the compound name.
 	 */
-	public static boolean startsWithIgnoreCase(String[] compoundName, String[] prefix) {
+	public static boolean startsWithIgnoreCase(String[] compoundName, String[] prefix, boolean partialMatch) {
 		int prefixLength = prefix.length;
 		int nameLength = compoundName.length;
 		if (prefixLength > nameLength) return false;
@@ -1939,7 +1942,31 @@
 			if (!compoundName[i].equalsIgnoreCase(prefix[i]))
 				return false;
 		}
-		return compoundName[prefixLength-1].toLowerCase().startsWith(prefix[prefixLength-1].toLowerCase());
+		return (partialMatch || prefixLength == nameLength) && compoundName[prefixLength-1].toLowerCase().startsWith(prefix[prefixLength-1].toLowerCase());
+	}
+
+	/*
+	 * Returns whether the given compound name matches the given pattern.
+	 */
+	public static boolean matchesWithIgnoreCase(String[] compoundName, String pattern) {
+		if (pattern.equals("*")) return true; //$NON-NLS-1$
+		int nameLength = compoundName.length;
+		if (pattern.length() == 0) return nameLength == 0;
+		if (nameLength == 0) return false;
+		int length = nameLength-1;
+		for (int i=0; i<nameLength; i++) {
+			length += compoundName[i].length();
+		}
+		char[] compoundChars = new char[length];
+		int pos = 0;
+		for (int i=0; i<nameLength; i++) {
+			if (pos > 0) compoundChars[pos++] = '.';
+			char[] array = compoundName[i].toCharArray();
+			int size = array.length;
+			System.arraycopy(array, 0, compoundChars, pos, size);
+			pos += size;
+		}
+		return CharOperation.match(pattern.toCharArray(), compoundChars, false);
 	}
 
 	/**
@@ -1947,6 +1974,7 @@
 	 */
 	public static char[][] toCharArrays(String[] a) {
 		int len = a.length;
+		if (len == 0) return CharOperation.NO_CHAR_CHAR;
 		char[][] result = new char[len][];
 		for (int i = 0; i < len; ++i) {
 			result[i] = a[i].toCharArray();
@@ -1977,6 +2005,19 @@
 		}
 		return segs;
 	}
+	/*
+	 * Converts the given URI to a local file. Use the existing file if the uri is on the local file system.
+	 * Otherwise fetch it.
+	 * Returns null if unable to fetch it.
+	 */
+	public static File toLocalFile(URI uri, IProgressMonitor monitor) throws CoreException {
+		IFileStore fileStore = EFS.getStore(uri);
+		File localFile = fileStore.toLocalFile(EFS.NONE, monitor);
+		if (localFile ==null)
+			// non local file system
+			localFile= fileStore.toLocalFile(EFS.CACHE, monitor);
+		return localFile;
+	}
 	/**
 	 * Converts a char[][] to String, where segments are separated by '.'.
 	 */
@@ -2021,7 +2062,7 @@
 			throw new IllegalArgumentException();
 		}
 		char c = string[start];
-		if (c != Signature.C_ARRAY) { //$NON-NLS-1$
+		if (c != Signature.C_ARRAY) {
 			throw new IllegalArgumentException();
 		}
 		
@@ -2174,7 +2215,6 @@
 			if (includeReturnType) {
 				char[] rts = Signature.getReturnType(methodSignature);
 				appendTypeSignature(rts, 0 , buffer, compact);
-				buffer.append(' ');
 			}
 		}
 		return String.valueOf(buffer);
@@ -2194,7 +2234,7 @@
 			}
 			return signatures;
 		}
-		return new String[0];
+		return CharOperation.NO_STRINGS;
 	}
 
 	/*
@@ -2235,59 +2275,6 @@
 		} while (start != 0);
 		printStream.println();
 	}
-	/**
-	 * Writes a string to the given output stream using UTF-8 
-	 * encoding in a machine-independent manner. 
-	 * <p>
-	 * First, two bytes are written to the output stream as if by the 
-	 * <code>writeShort</code> method giving the number of bytes to 
-	 * follow. This value is the number of bytes actually written out, 
-	 * not the length of the string. Following the length, each character 
-	 * of the string is output, in sequence, using the UTF-8 encoding 
-	 * 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 int writeUTF(OutputStream out, char[] str) throws IOException {
-		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 UTFDataFormatException();
-		out.write((utflen >>> 8) & 0xFF);
-		out.write((utflen >>> 0) & 0xFF);
-		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
-	}
 
 	/**
 	 * Returns true if the given name ends with one of the known java like extension.
@@ -2310,7 +2297,8 @@
 			char[] extension = javaLikeExtensions[i];
 			int extensionLength = extension.length;
 			int extensionStart = fileNameLength - extensionLength;
-			if (extensionStart < 0) continue;
+			if (extensionStart-1 < 0) continue;
+			if (fileName[extensionStart-1] != '.') continue;
 			for (int j = 0; j < extensionLength; j++) {
 				if (fileName[extensionStart + j] != extension[j])
 					continue extensions;
@@ -2421,7 +2409,7 @@
 			throw new IllegalArgumentException();
 		}
 		char c = string[start];
-		if (c != Signature.C_ARRAY) { //$NON-NLS-1$
+		if (c != Signature.C_ARRAY) {
 			throw new IllegalArgumentException();
 		}
 		
@@ -2455,7 +2443,7 @@
 			throw new IllegalArgumentException();
 		}
 		char c = string[start];
-		if (c != Signature.C_CAPTURE) { //$NON-NLS-1$
+		if (c != Signature.C_CAPTURE) {
 			throw new IllegalArgumentException();
 		}
 		return scanTypeBoundSignature(string, start + 1);
@@ -2594,8 +2582,8 @@
 				return start;
 			case Signature.C_SUPER :
 			case Signature.C_EXTENDS :
-				// need a minimum 4 chars "+Lx;"
-				if (start >= string.length - 3) {
+				// need a minimum 3 chars "+[I"
+				if (start >= string.length - 2) {
 					throw new IllegalArgumentException();
 				}
 				break;
@@ -2763,7 +2751,7 @@
 		int paramOpening = 0;
 		
 		// Scan each signature character
-		scanUniqueKey: for (int idx=0, ln = source.length; idx < ln; idx++) {
+		for (int idx=0, ln = source.length; idx < ln; idx++) {
 			switch (source[idx]) {
 				case '>':
 					paramOpening--;
@@ -2809,4 +2797,256 @@
 		}
 		return typeSignatures;
 	}
+	
+	/*
+	 * Can throw IllegalArgumentException or ArrayIndexOutOfBoundsException 
+	 */
+	public static String toAnchor(char[] methodSignature, String methodName, boolean isVarArgs) {
+		try {
+			return new String(toAnchor(methodSignature, methodName.toCharArray(), isVarArgs));
+		} catch(IllegalArgumentException e) {
+			return null;
+		}
+	}
+	private static char[] toAnchor(char[] methodSignature, char[] methodName, boolean isVargArgs) {
+		int firstParen = CharOperation.indexOf(Signature.C_PARAM_START, methodSignature);
+		if (firstParen == -1) {
+			throw new IllegalArgumentException();
+		}
+		
+		StringBuffer buffer = new StringBuffer(methodSignature.length + 10);
+
+		// selector
+		if (methodName != null) {
+			buffer.append(methodName);
+		}
+		
+		// parameters
+		buffer.append('(');
+		char[][] pts = Signature.getParameterTypes(methodSignature);
+		for (int i = 0, max = pts.length; i < max; i++) {
+			if (i == max - 1) {
+				appendTypeSignatureForAnchor(pts[i], 0 , buffer, isVargArgs);
+			} else {
+				appendTypeSignatureForAnchor(pts[i], 0 , buffer, false);
+			}
+			if (i != pts.length - 1) {
+				buffer.append(',');
+				buffer.append(' ');
+			}
+		}
+		buffer.append(')');
+		char[] result = new char[buffer.length()];
+		buffer.getChars(0, buffer.length(), result, 0);
+		return result;
+	}
+
+	private static int appendTypeSignatureForAnchor(char[] string, int start, StringBuffer buffer, boolean isVarArgs) {
+		// need a minimum 1 char
+		if (start >= string.length) {
+			throw new IllegalArgumentException();
+		}
+		char c = string[start];
+		if (isVarArgs) {
+			switch (c) {
+				case Signature.C_ARRAY :
+					return appendArrayTypeSignatureForAnchor(string, start, buffer, true);
+				case Signature.C_RESOLVED :
+				case Signature.C_TYPE_VARIABLE :
+				case Signature.C_BOOLEAN :
+				case Signature.C_BYTE :
+				case Signature.C_CHAR :
+				case Signature.C_DOUBLE :
+				case Signature.C_FLOAT :
+				case Signature.C_INT :
+				case Signature.C_LONG :
+				case Signature.C_SHORT :
+				case Signature.C_VOID :
+				case Signature.C_STAR:
+				case Signature.C_EXTENDS:
+				case Signature.C_SUPER:
+				case Signature.C_CAPTURE:
+				default:
+					throw new IllegalArgumentException(); // a var args is an array type
+			}
+		} else {
+			switch (c) {
+				case Signature.C_ARRAY :
+					return appendArrayTypeSignatureForAnchor(string, start, buffer, false);
+				case Signature.C_RESOLVED :
+					return appendClassTypeSignatureForAnchor(string, start, buffer);
+				case Signature.C_TYPE_VARIABLE :
+					int e = Util.scanTypeVariableSignature(string, start);
+					buffer.append(string, start + 1, e - start - 1);
+					return e;
+				case Signature.C_BOOLEAN :
+					buffer.append(BOOLEAN);
+					return start;
+				case Signature.C_BYTE :
+					buffer.append(BYTE);
+					return start;
+				case Signature.C_CHAR :
+					buffer.append(CHAR);
+					return start;
+				case Signature.C_DOUBLE :
+					buffer.append(DOUBLE);
+					return start;
+				case Signature.C_FLOAT :
+					buffer.append(FLOAT);
+					return start;
+				case Signature.C_INT :
+					buffer.append(INT);
+					return start;
+				case Signature.C_LONG :
+					buffer.append(LONG);
+					return start;
+				case Signature.C_SHORT :
+					buffer.append(SHORT);
+					return start;
+				case Signature.C_VOID :
+					buffer.append(VOID);
+					return start;
+				case Signature.C_CAPTURE :
+					return appendCaptureTypeSignatureForAnchor(string, start, buffer);
+				case Signature.C_STAR:
+				case Signature.C_EXTENDS:
+				case Signature.C_SUPER:
+					return appendTypeArgumentSignatureForAnchor(string, start, buffer);
+				default :
+					throw new IllegalArgumentException();
+			}
+		}
+	}
+	private static int appendTypeArgumentSignatureForAnchor(char[] string, int start, StringBuffer buffer) {
+		// need a minimum 1 char
+		if (start >= string.length) {
+			throw new IllegalArgumentException();
+		}
+		char c = string[start];
+		switch(c) {
+			case Signature.C_STAR :
+				return start;
+			case Signature.C_EXTENDS :
+				return appendTypeSignatureForAnchor(string, start + 1, buffer, false);
+			case Signature.C_SUPER :
+				return appendTypeSignatureForAnchor(string, start + 1, buffer, false);
+			default :
+				return appendTypeSignatureForAnchor(string, start, buffer, false);
+		}
+	}
+	private static int appendCaptureTypeSignatureForAnchor(char[] string, int start, StringBuffer buffer) {
+		// need a minimum 2 char
+		if (start >= string.length - 1) {
+			throw new IllegalArgumentException();
+		}
+		char c = string[start];
+		if (c != Signature.C_CAPTURE) {
+			throw new IllegalArgumentException();
+		}
+		return appendTypeArgumentSignatureForAnchor(string, start + 1, buffer);
+	}
+	private static int appendArrayTypeSignatureForAnchor(char[] string, int start, StringBuffer buffer, boolean isVarArgs) {
+		int length = string.length;
+		// need a minimum 2 char
+		if (start >= length - 1) {
+			throw new IllegalArgumentException();
+		}
+		char c = string[start];
+		if (c != Signature.C_ARRAY) {
+			throw new IllegalArgumentException();
+		}
+		
+		int index = start;
+		c = string[++index];
+		while(c == Signature.C_ARRAY) {
+			// need a minimum 2 char
+			if (index >= length - 1) {
+				throw new IllegalArgumentException();
+			}
+			c = string[++index];
+		}
+		
+		int e = appendTypeSignatureForAnchor(string, index, buffer, false);
+		
+		for(int i = 1, dims = index - start; i < dims; i++) {
+			buffer.append('[').append(']');
+		}
+		
+		if (isVarArgs) {
+			buffer.append('.').append('.').append('.');
+		} else {
+			buffer.append('[').append(']');
+		}
+		return e;
+	}
+	private static int appendClassTypeSignatureForAnchor(char[] string, int start, StringBuffer buffer) {
+		// need a minimum 3 chars "Lx;"
+		if (start >= string.length - 2) { 
+			throw new IllegalArgumentException();
+		}
+		// must start in "L" or "Q"
+		char c = string[start];
+		if (c != Signature.C_RESOLVED && c != Signature.C_UNRESOLVED) {
+			throw new IllegalArgumentException();
+		}
+		int p = start + 1;
+		while (true) {
+			if (p >= string.length) {
+				throw new IllegalArgumentException();
+			}
+			c = string[p];
+			switch(c) {
+				case Signature.C_SEMICOLON :
+					// all done
+					return p;
+				case Signature.C_GENERIC_START :
+					int e = scanGenericEnd(string, p + 1);
+					// once we hit type arguments there are no more package prefixes
+					p = e;
+					break;
+				case Signature.C_DOT :
+					buffer.append('.');
+					break;
+				 case '/' :
+					buffer.append('/');
+					break;
+				 case Signature.C_DOLLAR :
+					// once we hit "$" there are no more package prefixes
+					/**
+					 * Convert '$' in resolved type signatures into '.'.
+					 * NOTE: This assumes that the type signature is an inner type
+					 * signature. This is true in most cases, but someone can define a
+					 * non-inner type name containing a '$'.
+					 */
+					buffer.append('.');
+				 	break;
+				 default :
+					buffer.append(c);
+			}
+			p++;
+		}
+	}
+	private static int scanGenericEnd(char[] string, int start) {
+		if (string[start] == Signature.C_GENERIC_END) {
+			return start;
+		}
+		int length = string.length;
+		int balance = 1;
+		start++;
+		while (start <= length) {
+			switch(string[start]) {
+				case Signature.C_GENERIC_END :
+					balance--;
+					if (balance == 0) {
+						return start;
+					}
+					break;
+				case Signature.C_GENERIC_START :
+					balance++;
+					break;
+			}
+			start++;
+		}
+		return start;
+	}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/VerificationInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/VerificationInfo.java
new file mode 100755
index 0000000..62ab95b
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/VerificationInfo.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core.util;
+
+import org.eclipse.jdt.core.util.ClassFormatException;
+import org.eclipse.jdt.core.util.IConstantPool;
+import org.eclipse.jdt.core.util.IConstantPoolConstant;
+import org.eclipse.jdt.core.util.IConstantPoolEntry;
+import org.eclipse.jdt.core.util.IVerificationTypeInfo;
+
+public class VerificationInfo extends ClassFileStruct implements IVerificationTypeInfo {
+	
+	private int tag;
+	private int offset;
+	private int constantPoolIndex;
+	private char[] classTypeName;
+	private int readOffset;
+
+	public VerificationInfo(
+			byte[] classFileBytes,
+			IConstantPool constantPool,
+			int offset) throws ClassFormatException {
+		final int t = u1At(classFileBytes, 0, offset);
+		this.tag = t;
+		this.readOffset = 1;
+		switch(t) {
+			case IVerificationTypeInfo.ITEM_OBJECT :
+				final int constantIndex = u2At(classFileBytes, 1, offset);
+				this.constantPoolIndex = constantIndex;
+				if (constantIndex != 0) {
+					IConstantPoolEntry constantPoolEntry = constantPool.decodeEntry(constantIndex);
+					if (constantPoolEntry.getKind() != IConstantPoolConstant.CONSTANT_Class) {
+						throw new ClassFormatException(ClassFormatException.INVALID_CONSTANT_POOL_ENTRY);
+					}
+					this.classTypeName = constantPoolEntry.getClassInfoName();
+				}
+				this.readOffset += 2;
+				break;
+			case IVerificationTypeInfo.ITEM_UNINITIALIZED : 
+				this.offset = u2At(classFileBytes, 1, offset);
+				this.readOffset += 2;
+		}
+	}
+	
+	public int getTag() {
+		return this.tag;
+	}
+
+	public int getOffset() {
+		return this.offset;
+	}
+
+	public int getConstantPoolIndex() {
+		return this.constantPoolIndex;
+	}
+
+	public char[] getClassTypeName() {
+		return this.classTypeName;
+	}
+	
+	public int sizeInBytes() {
+		return this.readOffset;
+	}
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/WeakHashSet.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/WeakHashSet.java
new file mode 100755
index 0000000..8eb19b7
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/WeakHashSet.java
@@ -0,0 +1,217 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core.util;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+
+/**
+ * A hashset whose values can be garbage collected.
+ */
+public class WeakHashSet {
+	
+	public static class HashableWeakReference extends WeakReference {
+		public int hashCode;
+		public HashableWeakReference(Object referent, ReferenceQueue queue) {
+			super(referent, queue);
+			this.hashCode = referent.hashCode();
+		}
+		public boolean equals(Object obj) {
+			if (!(obj instanceof HashableWeakReference)) return false;
+			Object referent = get();
+			Object other = ((HashableWeakReference) obj).get();
+			if (referent == null) return other == null;
+			return referent.equals(other);
+		}
+		public int hashCode() {
+			return this.hashCode;
+		}
+		public String toString() {
+			Object referent = get();
+			if (referent == null) return "[hashCode=" + this.hashCode + "] <referent was garbage collected>"; //$NON-NLS-1$  //$NON-NLS-2$
+			return "[hashCode=" + this.hashCode + "] " + referent.toString(); //$NON-NLS-1$ //$NON-NLS-2$
+		}
+	}
+	
+	HashableWeakReference[] values;
+	public int elementSize; // number of elements in the table
+	int threshold;
+	ReferenceQueue referenceQueue = new ReferenceQueue();	
+	
+	public WeakHashSet() {
+		this(5);
+	}
+	
+	public WeakHashSet(int size) {
+		this.elementSize = 0;
+		this.threshold = size; // size represents the expected number of elements
+		int extraRoom = (int) (size * 1.75f);
+		if (this.threshold == extraRoom)
+			extraRoom++;
+		this.values = new HashableWeakReference[extraRoom];
+	}
+	
+	/*
+	 * Adds the given object to this set.
+	 * If an object that is equals to the given object already exists, do nothing.
+	 * Returns the existing object or the new object if not found.
+	 */
+	public Object add(Object obj) {
+		cleanupGarbageCollectedValues();
+		int valuesLength = this.values.length,
+			index = (obj.hashCode() & 0x7FFFFFFF) % valuesLength;
+		HashableWeakReference currentValue;
+		while ((currentValue = this.values[index]) != null) {
+			Object referent;
+			if (obj.equals(referent = currentValue.get())) {
+				return referent;
+			}
+			if (++index == valuesLength) {
+				index = 0;
+			}
+		}
+		this.values[index] = new HashableWeakReference(obj, this.referenceQueue);
+
+		// assumes the threshold is never equal to the size of the table
+		if (++this.elementSize > this.threshold)
+			rehash();
+		
+		return obj;
+	}
+		
+	private void addValue(HashableWeakReference value) {
+		Object obj = value.get();
+		if (obj == null) return;
+		int valuesLength = this.values.length;
+		int index = (value.hashCode & 0x7FFFFFFF) % valuesLength;
+		HashableWeakReference currentValue;
+		while ((currentValue = this.values[index]) != null) {
+			if (obj.equals(currentValue.get())) {
+				return;
+			}
+			if (++index == valuesLength) {
+				index = 0;
+			}
+		}
+		this.values[index] = value;
+
+		// assumes the threshold is never equal to the size of the table
+		if (++this.elementSize > this.threshold)
+			rehash();
+	}
+	
+	private void cleanupGarbageCollectedValues() {
+		HashableWeakReference toBeRemoved;
+		while ((toBeRemoved = (HashableWeakReference) this.referenceQueue.poll()) != null) {
+			int hashCode = toBeRemoved.hashCode;
+			int valuesLength = this.values.length;
+			int index = (hashCode & 0x7FFFFFFF) % valuesLength;
+			HashableWeakReference currentValue;
+			while ((currentValue = this.values[index]) != null) {
+				if (currentValue == toBeRemoved) {
+					// replace the value at index with the last value with the same hash
+					int sameHash = index;
+					int current;
+					while ((currentValue = this.values[current = (sameHash + 1) % valuesLength]) != null && currentValue.hashCode == hashCode)
+						sameHash = current;
+					this.values[index] = this.values[sameHash];
+					this.values[sameHash] = null;
+					this.elementSize--;
+					break;
+				}
+				if (++index == valuesLength) {
+					index = 0;
+				}
+			}
+		}
+	}
+	
+	public boolean contains(Object obj) {
+		return get(obj) != null;
+	}
+	
+	/*
+	 * Return the object that is in this set and that is equals to the given object.
+	 * Return null if not found.
+	 */
+	public Object get(Object obj) {
+		cleanupGarbageCollectedValues();
+		int valuesLength = this.values.length;
+		int index = (obj.hashCode() & 0x7FFFFFFF) % valuesLength;
+		HashableWeakReference currentValue;
+		while ((currentValue = this.values[index]) != null) {
+			Object referent;
+			if (obj.equals(referent = currentValue.get())) {
+				return referent;
+			}
+			if (++index == valuesLength) {
+				index = 0;
+			}
+		}
+		return null;
+	}
+		
+	private void rehash() {
+		WeakHashSet newHashSet = new WeakHashSet(this.elementSize * 2);		// double the number of expected elements
+		newHashSet.referenceQueue = this.referenceQueue;
+		HashableWeakReference currentValue;
+		for (int i = 0, length = this.values.length; i < length; i++)
+			if ((currentValue = this.values[i]) != null)
+				newHashSet.addValue(currentValue);
+
+		this.values = newHashSet.values;
+		this.threshold = newHashSet.threshold;
+		this.elementSize = newHashSet.elementSize;
+	}
+
+	/*
+	 * Removes the object that is in this set and that is equals to the given object.
+	 * Return the object that was in the set, or null if not found.
+	 */
+	public Object remove(Object obj) {
+		cleanupGarbageCollectedValues();
+		int valuesLength = this.values.length;
+		int index = (obj.hashCode() & 0x7FFFFFFF) % valuesLength;
+		HashableWeakReference currentValue;
+		while ((currentValue = this.values[index]) != null) {
+			Object referent;
+			if (obj.equals(referent = currentValue.get())) {
+				this.elementSize--;
+				this.values[index] = null;
+				rehash();
+				return referent;
+			}
+			if (++index == valuesLength) {
+				index = 0;
+			}
+		}
+		return null;
+	}
+
+	public int size() {
+		return this.elementSize;
+	}
+
+	public String toString() {
+		StringBuffer buffer = new StringBuffer("{"); //$NON-NLS-1$
+		for (int i = 0, length = this.values.length; i < length; i++) {
+			HashableWeakReference value = this.values[i];
+			if (value != null) {
+				Object ref = value.get();
+				if (ref != null) {
+					buffer.append(ref.toString());
+					buffer.append(", "); //$NON-NLS-1$
+				}
+			}
+		}
+		buffer.append("}"); //$NON-NLS-1$
+		return buffer.toString();
+	}
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/WeakHashSetOfCharArray.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/WeakHashSetOfCharArray.java
new file mode 100755
index 0000000..790f8f8
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/WeakHashSetOfCharArray.java
@@ -0,0 +1,220 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core.util;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+
+import org.eclipse.jdt.core.compiler.CharOperation;
+
+/**
+ * A hashset of char[] whose values can be garbage collected.
+ */
+public class WeakHashSetOfCharArray {
+	
+	public static class HashableWeakReference extends WeakReference {
+		public int hashCode;
+		public HashableWeakReference(char[] referent, ReferenceQueue queue) {
+			super(referent, queue);
+			this.hashCode = CharOperation.hashCode(referent);
+		}
+		public boolean equals(Object obj) {
+			if (!(obj instanceof HashableWeakReference)) return false;
+			char[] referent = (char[]) get();
+			char[] other = (char[]) ((HashableWeakReference) obj).get();
+			if (referent == null) return other == null;
+			return CharOperation.equals(referent, other);
+		}
+		public int hashCode() {
+			return this.hashCode;
+		}
+		public String toString() {
+			char[] referent = (char[]) get();
+			if (referent == null) return "[hashCode=" + this.hashCode + "] <referent was garbage collected>"; //$NON-NLS-1$  //$NON-NLS-2$
+			return "[hashCode=" + this.hashCode + "] \"" + new String(referent) + '\"'; //$NON-NLS-1$ //$NON-NLS-2$
+		}
+	}
+	
+	HashableWeakReference[] values;
+	public int elementSize; // number of elements in the table
+	int threshold;
+	ReferenceQueue referenceQueue = new ReferenceQueue();	
+	
+	public WeakHashSetOfCharArray() {
+		this(5);
+	}
+	
+	public WeakHashSetOfCharArray(int size) {
+		this.elementSize = 0;
+		this.threshold = size; // size represents the expected number of elements
+		int extraRoom = (int) (size * 1.75f);
+		if (this.threshold == extraRoom)
+			extraRoom++;
+		this.values = new HashableWeakReference[extraRoom];
+	}
+	
+	/*
+	 * Adds the given char array to this set.
+	 * If a char array that is equals to the given char array already exists, do nothing.
+	 * Returns the existing char array or the new char array if not found.
+	 */
+	public char[] add(char[] array) {
+		cleanupGarbageCollectedValues();
+		int valuesLength = this.values.length, 
+			index = (CharOperation.hashCode(array) & 0x7FFFFFFF) % valuesLength;
+		HashableWeakReference currentValue;
+		while ((currentValue = this.values[index]) != null) {
+			char[] referent;
+			if (CharOperation.equals(array, referent = (char[]) currentValue.get())) {
+				return referent;
+			}
+			if (++index == valuesLength) {
+				index = 0;
+			}
+		}
+		this.values[index] = new HashableWeakReference(array, this.referenceQueue);
+
+		// assumes the threshold is never equal to the size of the table
+		if (++this.elementSize > this.threshold)
+			rehash();
+		
+		return array;
+	}
+		
+	private void addValue(HashableWeakReference value) {
+		char[] array = (char[]) value.get();
+		if (array == null) return;
+		int valuesLength = this.values.length;
+		int index = (value.hashCode & 0x7FFFFFFF) % valuesLength;
+		HashableWeakReference currentValue;
+		while ((currentValue = this.values[index]) != null) {
+			if (CharOperation.equals(array, (char[]) currentValue.get())) {
+				return;
+			}
+			if (++index == valuesLength) {
+				index = 0;
+			}
+		}
+		this.values[index] = value;
+
+		// assumes the threshold is never equal to the size of the table
+		if (++this.elementSize > this.threshold)
+			rehash();
+	}
+	
+	private void cleanupGarbageCollectedValues() {
+		HashableWeakReference toBeRemoved;
+		while ((toBeRemoved = (HashableWeakReference) this.referenceQueue.poll()) != null) {
+			int hashCode = toBeRemoved.hashCode;
+			int valuesLength = this.values.length;
+			int index = (hashCode & 0x7FFFFFFF) % valuesLength;
+			HashableWeakReference currentValue;
+			while ((currentValue = this.values[index]) != null) {
+				if (currentValue == toBeRemoved) {
+					// replace the value at index with the last value with the same hash
+					int sameHash = index;
+					int current;
+					while ((currentValue = this.values[current = (sameHash + 1) % valuesLength]) != null && currentValue.hashCode == hashCode)
+						sameHash = current;
+					this.values[index] = this.values[sameHash];
+					this.values[sameHash] = null;
+					this.elementSize--;
+					break;
+				}
+				if (++index == valuesLength) {
+					index = 0;
+				}
+			}
+		}
+	}
+	
+	public boolean contains(char[] array) {
+		return get(array) != null;
+	}
+	
+	/*
+	 * Return the char array that is in this set and that is equals to the given char array.
+	 * Return null if not found.
+	 */
+	public char[] get(char[] array) {
+		cleanupGarbageCollectedValues();
+		int valuesLength = this.values.length;
+		int index = (CharOperation.hashCode(array) & 0x7FFFFFFF) % valuesLength;
+		HashableWeakReference currentValue;
+		while ((currentValue = this.values[index]) != null) {
+			char[] referent;
+			if (CharOperation.equals(array, referent = (char[]) currentValue.get())) {
+				return referent;
+			}
+			if (++index == valuesLength) {
+				index = 0;
+			}
+		}
+		return null;
+	}
+		
+	private void rehash() {
+		WeakHashSetOfCharArray newHashSet = new WeakHashSetOfCharArray(this.elementSize * 2);		// double the number of expected elements
+		newHashSet.referenceQueue = this.referenceQueue;
+		HashableWeakReference currentValue;
+		for (int i = 0, length = this.values.length; i < length; i++)
+			if ((currentValue = this.values[i]) != null)
+				newHashSet.addValue(currentValue);
+
+		this.values = newHashSet.values;
+		this.threshold = newHashSet.threshold;
+		this.elementSize = newHashSet.elementSize;
+	}
+
+	/*
+	 * Removes the char array that is in this set and that is equals to the given char array.
+	 * Return the char array that was in the set, or null if not found.
+	 */
+	public char[] remove(char[] array) {
+		cleanupGarbageCollectedValues();
+		int valuesLength = this.values.length;
+		int index = (CharOperation.hashCode(array) & 0x7FFFFFFF) % valuesLength;
+		HashableWeakReference currentValue;
+		while ((currentValue = this.values[index]) != null) {
+			char[] referent;
+			if (CharOperation.equals(array, referent = (char[]) currentValue.get())) {
+				this.elementSize--;
+				this.values[index] = null;
+				rehash();
+				return referent;
+			}
+			if (++index == valuesLength) {
+				index = 0;
+			}
+		}
+		return null;
+	}
+
+	public int size() {
+		return this.elementSize;
+	}
+
+	public String toString() {
+		StringBuffer buffer = new StringBuffer("{"); //$NON-NLS-1$
+		for (int i = 0, length = this.values.length; i < length; i++) {
+			HashableWeakReference value = this.values[i];
+			if (value != null) {
+				char[] ref = (char[]) value.get();
+				if (ref != null) {
+					buffer.append('\"');
+					buffer.append(ref);
+					buffer.append("\", "); //$NON-NLS-1$
+				}
+			}
+		}
+		buffer.append("}"); //$NON-NLS-1$
+		return buffer.toString();
+	}
+}
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 b271672..cd45c04 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, 2005 IBM Corporation and others.
+# Copyright (c) 2000, 2007 IBM Corporation and others.
 # All rights reserved. This program and the accompanying materials
 # are made available under the terms of the Eclipse Public License v1.0
 # which accompanies this distribution, and is available at
@@ -28,7 +28,6 @@
 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
@@ -57,21 +56,21 @@
 operation_deleteElementProgress = Deleting elements...
 operation_deleteResourceProgress = Deleting resources...
 operation_cannotRenameDefaultPackage = Default package cannot be renamed
-operation_pathOutsideProject = Path ''{0}'' must denote location inside project {1}
+operation_pathOutsideProject = Path ''{0}'' must denote location inside project ''{1}''
 operation_sortelements = Sorting elements...
 
 ### working copy
 workingCopy_commit = Committing working copy...
 
 ### build status messages
-build_preparingBuild = Preparing for build
-build_readStateProgress = Reading saved built state for project {0}
-build_saveStateProgress = Saving built state for project {0}
+build_preparingBuild = Preparing to build {0}
+build_readStateProgress = Reading saved build state for project {0}
+build_saveStateProgress = Saving build state for project {0}
 build_saveStateComplete = Saved in {0} ms
 build_readingDelta = Reading resource change information for {0}
 build_analyzingDeltas = Analyzing deltas
 build_analyzingSources = Analyzing sources
-build_cleaningOutput = Cleaning output folder
+build_cleaningOutput = Cleaning output folder for {0}
 build_copyingResources = Copying resources to the output folder
 build_compiling = Compiling {0}
 build_foundHeader = Found
@@ -124,47 +123,51 @@
 status_readOnly = {0} is read-only
 status_targetException = Target exception
 status_updateConflict = Update conflict
+status_cannot_retrieve_attached_javadoc = Cannot retrieve the attached javadoc for {0}{1}
+status_unknown_javadoc_format = Unknown javadoc format for {0}
 
 ### classpath
 classpath_buildPath = Build path
 classpath_cannotNestEntryInEntry = Cannot nest ''{0}'' inside ''{1}''. To enable the nesting exclude ''{2}'' from ''{1}''
+classpath_cannotNestEntryInEntryNoExclusion= Cannot nest ''{0}'' inside ''{1}''. To allow the nesting enable use of exclusion patterns in the preferences of project ''{1}'' and 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_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_illegalEntryInClasspathFile = Illegal entry in ''.classpath'' of project {0} file: {1}
-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_cannotReadClasspathFile = Unable to read ''.classpath'' file of project ''{0}''
+classpath_cannotReferToItself = Project ''{0}'' cannot reference itself
+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_illegalEntryInClasspathFile = Illegal entry in ''.classpath'' of project ''{0}'' file: {1}
+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_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_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_xmlFormatError = XML format error in ''.classpath'' file of project ''{0}'': {1}
+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
-classpath_duplicateEntryExtraAttribute = Duplicate extra attribute: ''{0}'' in classpath entry ''{1}'' for project {2}
+classpath_duplicateEntryExtraAttribute = Duplicate extra attribute: ''{0}'' in classpath entry ''{1}'' for project ''{2}''
+classpath_deprecated_variable = Classpath variable ''{0}'' in project ''{1}'' is deprecated: {2}
 
 ### miscellaneous
 file_notFound = File not found: ''{0}''
@@ -173,15 +176,29 @@
 path_mustBeAbsolute = Path must be absolute
 cache_invalidLoadFactor = Incorrect load factor
 savedState_jobName = Processing Java changes since last activation
+
+## java model initialization
 javamodel_initialization = Initializing Java tooling
+javamodel_configuring_searchengine=Configuring search engine
+javamodel_configuring_classpath_containers=Configuring classpath containers
+javamodel_getting_build_state_number=Getting build state version number
+javamodel_configuring=Configuring {0}
+javamodel_building_after_upgrade=Triggering build after upgrade
+javamodel_refreshing_external_jars=Refreshing external archives
 
 ### access restrictions
 restrictedAccess_project = The type {0} is not accessible due to restriction on required project {1}
 restrictedAccess_library = The type {0} is not accessible due to restriction on required library {1}
+restrictedAccess_constructor_project = The constructor {0} is not accessible due to restriction on required project {1}
+restrictedAccess_constructor_library = The constructor {0} is not accessible due to restriction on required library {1}
+restrictedAccess_field_project = The field {0} from the type {1} is not accessible due to restriction on required project {2}
+restrictedAccess_field_library = The field {0} from the type {1} is not accessible due to restriction on required library {2}
+restrictedAccess_method_project = The method {0} from the type {1} is not accessible due to restriction on required project {2}
+restrictedAccess_method_library = The method {0} from the type {1} is not accessible due to restriction on required library {2}
 
 ### java conventions
 convention_unit_nullName = Compilation unit name must not be null
-convention_unit_notJavaName = Compilation unit name must end with .java
+convention_unit_notJavaName = Compilation unit name must end with .java, or one of the registered Java-like extensions
 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
@@ -219,6 +236,9 @@
 dom_addNullInterface = Cannot add null interface
 dom_nullInterfaces = Illegal to set super interfaces to null
 
+### import rewrite
+importRewrite_processDescription = Updating imports
+
 ### correction
 correction_nullRequestor = Requestor cannot be null
 correction_nullUnit = Compilation unit cannot be null
@@ -226,8 +246,8 @@
 ### Eclipse Java Core Search messages.
 
 engine_searching = Searching...
-engine_searching_indexing = {0}: lookup indexes...
-engine_searching_matching = {0}: locate matches...
+engine_searching_indexing = Looking through {0} indexes...
+engine_searching_matching = Locating {0} matches...
 exception_wrongFormat = Wrong format
 process_name = Java indexing
 manager_filesToIndex = {0} files to index
@@ -257,7 +277,9 @@
 disassembler_outer_class_info_name = outer class info:
 disassembler_inner_name = inner name:
 disassembler_inner_accessflags = accessflags:\ 
-disassembler_genericattributeheader = Attribute: Name: {0} Length: {1}
+disassembler_genericattributeheader = Attribute: {0} Length: {1}
+disassembler_stackmaptableattributeheader = Stack map table: number of frames {0}
+disassembler_stackmapattributeheader =  Stack map : number of frames {0}
 disassembler_signatureattributeheader = // Signature: {0}
 disassembler_indentation = \  
 disassembler_constantpoolindex =\ #
@@ -272,12 +294,12 @@
 disassembler_constantpool_float = constant #{0} float: {1}
 disassembler_constantpool_integer = constant #{0} integer: {1}
 disassembler_constantpool_long = constant #{0} long: {1}
-disassembler_constantpool_string = constant #{0} string: #{1} {2}
+disassembler_constantpool_string = constant #{0} string: #{1} "{2}"
 disassembler_constantpool_fieldref = constant #{0} field_ref: #{1}.#{2} {3}.{4} {5}
 disassembler_constantpool_interfacemethodref = constant #{0} interface_method_ref: #{1}.#{2} {3}.{4} {5}
 disassembler_constantpool_methodref = constant #{0} method_ref: #{1}.#{2} {3}.{4} {5}
 disassembler_constantpool_name_and_type = constant #{0} name_and_type: #{1}.#{2} {3} {4}
-disassembler_constantpool_utf8 = constant #{0} utf8: {1}
+disassembler_constantpool_utf8 = constant #{0} utf8: "{1}"
 disassembler_annotationdefaultheader = Annotation Default:\ 
 disassembler_annotationdefaultvalue= {0} (constant type)
 disassembler_annotationenumvalue = {2}.{3}(enum type #{0}.#{1})
@@ -293,7 +315,19 @@
 disassembler_runtimevisibleparameterannotationsattributeheader= RuntimeVisibleParameterAnnotations:\ 
 disassembler_runtimeinvisibleparameterannotationsattributeheader= RuntimeInvisibleParameterAnnotations:\ 
 disassembler_parameterannotationentrystart=Number of annotations for parameter {0}: {1}
-
+disassembler_frame_same_locals_1_stack_item_extended=[pc: {0}, same_locals_1_stack_item_extended, stack: {1}]
+disassembler_frame_chop=[pc: {0}, chop {1} local(s)]
+disassembler_frame_same_frame_extended=[pc: {0}, same_extended]
+disassembler_frame_append=[pc: {0}, append: {1}]
+# {0} = offset delta
+# {1} = number of locals
+# {2} = locals
+# {3} = number of stack items
+# {4} = stack items
+# {5} = line separator + tabs
+disassembler_frame_full_frame=[pc: {0}, full, stack: {4}, locals: {2}]
+disassembler_frame_same_frame=[pc: {0}, same]
+disassembler_frame_same_locals_1_stack_item=[pc: {0}, same_locals_1_stack_item, stack: {1}]
 ### classfileformat decoding
 classfileformat_versiondetails =\ (version {0} : {1}.{2}, {3})
 classfileformat_methoddescriptor = // Method descriptor #{0} {1}
@@ -303,6 +337,7 @@
 classfileformat_superflagisset = super bit
 classfileformat_clinitname = '{'}
 classformat_classformatexception = Class Format Exception
+classfileformat_versionUnknown = unknown
 
 ### string displayed for each opcode
 classformat_anewarray = {0} {2} [{1}]
@@ -314,7 +349,7 @@
 classformat_ldc_w_string = {0} <String "{2}"> [{1}]
 classformat_ldc2_w_long = {0} <Long {2}> [{1}]
 classformat_ldc2_w_double = {0} <Double {2}> [{1}]
-classformat_multianewarray = {0} {2}{3} [{1}]
+classformat_multianewarray = {0} {2} [{1}]
 classformat_new = {0} {2} [{1}]
 classformat_iinc = {0} {1} {2}{3}
 classformat_invokespecial ={0} {2} [{1}]