updating to Eclipse 3.1 final version, tag v_574_R31X in the org.eclipse CVS tree.
diff --git a/org.eclipse.jdt.core/.project b/org.eclipse.jdt.core/.project
index 5e05291..7342551 100644
--- a/org.eclipse.jdt.core/.project
+++ b/org.eclipse.jdt.core/.project
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <projectDescription>
-	<name>org.eclipse.jdt.core</name>
+	<name>org.eclipse.jdt.core_shadows_HEAD</name>
 	<comment></comment>
 	<projects>
 		<project>org.eclipse.ant.core</project>
diff --git a/org.eclipse.jdt.core/META-INF/MANIFEST.MF b/org.eclipse.jdt.core/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..00dc181
--- /dev/null
+++ b/org.eclipse.jdt.core/META-INF/MANIFEST.MF
@@ -0,0 +1,58 @@
+Manifest-Version: 1.0
+Main-Class: org.eclipse.jdt.internal.compiler.batch.Main
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-SymbolicName: org.eclipse.jdt.core; singleton:=true
+Bundle-Version: 3.1.1
+Bundle-ClassPath: .
+Bundle-Activator: org.eclipse.jdt.core.JavaCore
+Bundle-Vendor: %providerName
+Bundle-Localization: plugin
+Export-Package: org.eclipse.jdt.core,
+ org.eclipse.jdt.core.compiler,
+ org.eclipse.jdt.core.dom,
+ org.eclipse.jdt.core.dom.rewrite,
+ org.eclipse.jdt.core.eval,
+ org.eclipse.jdt.core.formatter,
+ org.eclipse.jdt.core.jdom,
+ org.eclipse.jdt.core.search,
+ org.eclipse.jdt.core.util,
+ org.eclipse.jdt.internal.codeassist;x-internal:=true,
+ org.eclipse.jdt.internal.codeassist.complete;x-internal:=true,
+ org.eclipse.jdt.internal.codeassist.impl;x-internal:=true,
+ org.eclipse.jdt.internal.codeassist.select;x-internal:=true,
+ org.eclipse.jdt.internal.compiler;x-internal:=true,
+ org.eclipse.jdt.internal.compiler.ast;x-internal:=true,
+ org.eclipse.jdt.internal.compiler.batch;x-internal:=true,
+ org.eclipse.jdt.internal.compiler.classfmt;x-internal:=true,
+ org.eclipse.jdt.internal.compiler.codegen;x-internal:=true,
+ org.eclipse.jdt.internal.compiler.env;x-internal:=true,
+ org.eclipse.jdt.internal.compiler.flow;x-internal:=true,
+ org.eclipse.jdt.internal.compiler.impl;x-internal:=true,
+ org.eclipse.jdt.internal.compiler.lookup;x-internal:=true,
+ org.eclipse.jdt.internal.compiler.parser;x-internal:=true,
+ org.eclipse.jdt.internal.compiler.parser.diagnose;x-internal:=true,
+ org.eclipse.jdt.internal.compiler.problem;x-internal:=true,
+ org.eclipse.jdt.internal.compiler.util;x-internal:=true,
+ org.eclipse.jdt.internal.core;x-internal:=true,
+ org.eclipse.jdt.internal.core.builder;x-internal:=true,
+ org.eclipse.jdt.internal.core.dom.rewrite;x-internal:=true,
+ org.eclipse.jdt.internal.core.eval;x-internal:=true,
+ org.eclipse.jdt.internal.core.hierarchy;x-internal:=true,
+ org.eclipse.jdt.internal.core.index;x-internal:=true,
+ org.eclipse.jdt.internal.core.jdom;x-internal:=true,
+ org.eclipse.jdt.internal.core.search;x-internal:=true,
+ org.eclipse.jdt.internal.core.search.indexing;x-internal:=true,
+ org.eclipse.jdt.internal.core.search.matching;x-internal:=true,
+ org.eclipse.jdt.internal.core.search.processing;x-internal:=true,
+ org.eclipse.jdt.internal.core.util;x-internal:=true,
+ org.eclipse.jdt.internal.eval;x-internal:=true,
+ org.eclipse.jdt.internal.formatter;x-internal:=true,
+ org.eclipse.jdt.internal.formatter.align;x-internal:=true,
+ org.eclipse.jdt.internal.formatter.comment;x-internal:=true,
+ org.eclipse.jdt.internal.formatter.old;x-internal:=true
+Require-Bundle: org.eclipse.core.resources,
+ org.eclipse.core.runtime,
+ org.eclipse.text,
+ org.eclipse.team.core;resolution:=optional
+Eclipse-AutoStart: true
diff --git a/org.eclipse.jdt.core/antadapter/org/eclipse/jdt/core/JDTCompilerAdapter.java b/org.eclipse.jdt.core/antadapter/org/eclipse/jdt/core/JDTCompilerAdapter.java
index 2edf25f..5542abe 100644
--- a/org.eclipse.jdt.core/antadapter/org/eclipse/jdt/core/JDTCompilerAdapter.java
+++ b/org.eclipse.jdt.core/antadapter/org/eclipse/jdt/core/JDTCompilerAdapter.java
@@ -62,7 +62,7 @@
 			Method compile = c.getMethod("compile", new Class[] {String[].class}); //$NON-NLS-1$
 			Object result = compile.invoke(batchCompilerInstance, new Object[] { cmd.getArguments()});
 			final boolean resultValue = ((Boolean) result).booleanValue();
-			if (!resultValue && this.verbose) {
+			if (!resultValue && this.logFileName != null) {
 				System.out.println(AntAdapterMessages.getString("ant.jdtadapter.error.compilationFailed", this.logFileName)); //$NON-NLS-1$
 			}
 			return resultValue;
@@ -294,14 +294,19 @@
 		/*
 		 * verbose option
 		 */
-		if (this.verbose) {
-			cmd.createArgument().setValue("-verbose"); //$NON-NLS-1$
+		if (this.verbose && this.destDir != null) {
+			/*
+			 * if destDir is null, we don't generate any log.
+			 * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=97744
+			 */
+			// Fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=96605
+			// cmd.createArgument().setValue("-verbose"); //$NON-NLS-1$
 			/*
 			 * extra option allowed by the Eclipse compiler
 			 */
 			cmd.createArgument().setValue("-log"); //$NON-NLS-1$
 			this.logFileName = this.destDir.getAbsolutePath() + ".log"; //$NON-NLS-1$
-			cmd.createArgument().setValue(this.logFileName);
+			cmd.createArgument().setValue(this.logFileName);			
 		}
 
 		/*
@@ -366,7 +371,7 @@
 		 * srcdir option.
 		 */        
         logAndAddFilesToCompile(cmd);
-		return cmd;
+        return cmd;
 	}
 	
     /**
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathDirectory.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathDirectory.java
index 59a97fd..9ac9be7 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathDirectory.java
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathDirectory.java
@@ -11,13 +11,14 @@
 package org.eclipse.jdt.internal.compiler.batch;
 
 import java.io.File;
+import java.io.IOException;
 import java.util.Hashtable;
 
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
+import org.eclipse.jdt.internal.compiler.env.AccessRuleSet;
 import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
-import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
 
-public class ClasspathDirectory implements FileSystem.Classpath, SuffixConstants {
+public class ClasspathDirectory extends ClasspathLocation {
 
 String path;
 Hashtable directoryCache;
@@ -28,8 +29,14 @@
 public static final int SOURCE = 1;
 public static final int BINARY = 2;
 
-ClasspathDirectory(File directory, String encoding, int mode) {
-	this.mode = mode;
+ClasspathDirectory(File directory, String encoding, int mode, AccessRuleSet accessRuleSet) {
+	super(accessRuleSet);
+	if (mode == 0){
+		this.mode = SOURCE | BINARY;
+	}
+	else {
+	    this.mode = mode;
+	}
 	this.path = directory.getAbsolutePath();
 	if (!this.path.endsWith(File.separator))
 		this.path += File.separator;
@@ -38,9 +45,8 @@
 }
 
 ClasspathDirectory(File directory, String encoding) {
-	this(directory, encoding, SOURCE | BINARY); // by default consider both sources and binaries
+	this(directory, encoding, SOURCE | BINARY, null); // by default consider both sources and binaries
 }
-
 String[] directoryList(String qualifiedPackageName) {
 	String[] dirList = (String[]) this.directoryCache.get(qualifiedPackageName);
 	if (dirList == this.missingPackageHolder) return null; // package exists in another classpath directory or jar
@@ -90,24 +96,34 @@
 	if (sourceExists) {
 		String fullSourcePath = this.path + qualifiedBinaryFileName.substring(0, qualifiedBinaryFileName.length() - 6)  + SUFFIX_STRING_java;
 		if (!binaryExists)
-			return new NameEnvironmentAnswer(new CompilationUnit(null, fullSourcePath, this.encoding), null/* TODO no access restriction*/);
-
+			return new NameEnvironmentAnswer(new CompilationUnit(null,
+					fullSourcePath, this.encoding),
+					fetchAccessRestriction(qualifiedBinaryFileName));
 		String fullBinaryPath = this.path + qualifiedBinaryFileName;
 		long binaryModified = new File(fullBinaryPath).lastModified();
 		long sourceModified = new File(fullSourcePath).lastModified();
 		if (sourceModified > binaryModified)
-			return new NameEnvironmentAnswer(new CompilationUnit(null, fullSourcePath, this.encoding), null/* TODO no access restriction*/);
+			return new NameEnvironmentAnswer(new CompilationUnit(null,
+					fullSourcePath, this.encoding),
+					fetchAccessRestriction(qualifiedBinaryFileName));
 	}
 	if (binaryExists) {
 		try {
-			ClassFileReader reader = ClassFileReader.read(this.path + qualifiedBinaryFileName);
-			if (reader != null) return new NameEnvironmentAnswer(reader, null/* TODO no access restriction*/);
-		} catch (Exception e) { 
+			ClassFileReader reader = ClassFileReader.read(this.path
+					+ qualifiedBinaryFileName);
+			if (reader != null)
+				return new NameEnvironmentAnswer(
+						reader,
+						fetchAccessRestriction(qualifiedBinaryFileName));
+		} catch (Exception e) {
 			// treat as if file is missing
 		}
 	}
 	return null;
 }
+public void initialize() throws IOException {
+	// nothing to do
+}
 public boolean isPackage(String qualifiedPackageName) {
 	return directoryList(qualifiedPackageName) != null;
 }
@@ -117,4 +133,10 @@
 public String toString() {
 	return "ClasspathDirectory " + this.path; //$NON-NLS-1$
 }
+public String normalizedPath() {
+	return this.path;
+}
+public String getPath() {
+	return this.path;
+}
 }
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJar.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJar.java
index 56b037a..5697cee 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJar.java
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJar.java
@@ -18,34 +18,41 @@
 import java.util.zip.ZipFile;
 
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
+import org.eclipse.jdt.internal.compiler.env.AccessRuleSet;
 import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
 
-public class ClasspathJar implements FileSystem.Classpath {
+public class ClasspathJar extends ClasspathLocation {
 	
-ZipFile zipFile;
-Hashtable packageCache;
-boolean closeZipFileAtEnd;
+private File file;
+private ZipFile zipFile;
+private boolean closeZipFileAtEnd;
+private Hashtable packageCache;
 
 public ClasspathJar(File file) throws IOException {
-	this(new ZipFile(file), true);
+	this(file, true, null);
 }
-public ClasspathJar(ZipFile zipFile, boolean closeZipFileAtEnd) {
-	this.zipFile = zipFile;
-	this.packageCache = null;
+public ClasspathJar(File file, boolean closeZipFileAtEnd, AccessRuleSet accessRuleSet) {
+	super(accessRuleSet);
+	this.file = file;
 	this.closeZipFileAtEnd = closeZipFileAtEnd;
-}	
+}
+
 public NameEnvironmentAnswer findClass(char[] typeName, String qualifiedPackageName, String qualifiedBinaryFileName) {
 	if (!isPackage(qualifiedPackageName)) 
 		return null; // most common case
 
 	try {
 		ClassFileReader reader = ClassFileReader.read(this.zipFile, qualifiedBinaryFileName);
-		if (reader != null) return new NameEnvironmentAnswer(reader, null /*no access restriction*/);
+		if (reader != null) return new NameEnvironmentAnswer(reader, 
+				fetchAccessRestriction(qualifiedBinaryFileName));
 	} catch (Exception e) {
 		// treat as if class file is missing
 	}
 	return null;
 }
+public void initialize() throws IOException {
+	this.zipFile = new ZipFile(this.file);
+}
 public boolean isPackage(String qualifiedPackageName) {
 	if (this.packageCache != null)
 		return this.packageCache.containsKey(qualifiedPackageName);
@@ -72,14 +79,22 @@
 public void reset() {
 	if (this.zipFile != null && this.closeZipFileAtEnd) {
 		try { 
-			this.zipFile.close(); 
+			this.zipFile.close();
 		} catch(IOException e) {
 			// ignore
 		}
+		this.zipFile = null;
 	}
 	this.packageCache = null;
 }
 public String toString() {
-	return "Classpath for jar file " + this.zipFile.getName(); //$NON-NLS-1$
+	return "Classpath for jar file " + this.file.getPath(); //$NON-NLS-1$
+}
+public String normalizedPath(){
+	String rawName = this.file.getPath();
+	return rawName.substring(0, rawName.lastIndexOf('.'));
+}
+public String getPath(){
+	return this.file.getPath();
 }
 }
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathLocation.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathLocation.java
new file mode 100644
index 0000000..a0219b7
--- /dev/null
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathLocation.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * 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.compiler.batch;
+
+import org.eclipse.jdt.internal.compiler.env.AccessRestriction;
+import org.eclipse.jdt.internal.compiler.env.AccessRuleSet;
+import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
+
+public abstract class ClasspathLocation implements FileSystem.Classpath,
+		SuffixConstants {
+
+	private AccessRuleSet accessRuleSet;
+
+	public ClasspathLocation(AccessRuleSet accessRuleSet) {
+		this.accessRuleSet = accessRuleSet;
+	}
+
+	/**
+	 * Return the first access rule which is violated when accessing a given
+	 * type, or null if no 'non accessible' access rule applies.
+	 * 
+	 * @param qualifiedBinaryFileName
+	 *            tested type specification, formed as:
+	 *            "org/eclipse/jdt/core/JavaCore.class"
+	 * @return the first access rule which is violated when accessing a given
+	 *         type, or null if none applies
+	 */
+	AccessRestriction fetchAccessRestriction(String qualifiedBinaryFileName) {
+		if (this.accessRuleSet == null)
+			return null;
+		return this.accessRuleSet
+					.getViolatedRestriction(
+						qualifiedBinaryFileName.substring(0, qualifiedBinaryFileName.length() - SUFFIX_CLASS.length)
+						.toCharArray());
+	}
+}
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java
index a98b0e7..81cef77 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java
@@ -12,9 +12,9 @@
 
 import java.io.File;
 import java.io.IOException;
-import java.util.zip.ZipFile;
 
 import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.env.AccessRuleSet;
 import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
 import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
@@ -31,6 +31,24 @@
 		 * a new name environment without creating a new object.
 		 */
 		void reset();
+		/**
+		 * Return a normalized path for file based classpath entries. This is an absolute path
+		 * ending with a file separator for directories, an absolute path deprived from the '.jar'
+		 * (resp. '.zip') extension for jar (resp. zip) files.
+		 * @return a normalized path for file based classpath entries
+		 */
+		String normalizedPath();
+		/**
+		 * Return the path for file based classpath entries. This is an absolute path
+		 * ending with a file separator for directories, an absolute path including from the '.jar'
+		 * (resp. '.zip') extension for jar (resp. zip) files.
+		 * @return the path for file based classpath entries
+		 */
+		String getPath();
+		/**
+		 * Initialize the entry
+		 */
+		void initialize() throws IOException;
 	}
 /*
 	classPathNames is a collection is Strings representing the full path of each class path
@@ -41,49 +59,64 @@
 	this(classpathNames, initialFileNames, encoding, null);
 }
 public FileSystem(String[] classpathNames, String[] initialFileNames, String encoding, int[] classpathDirectoryModes) {
-	int classpathSize = classpathNames.length;
+	final int classpathSize = classpathNames.length;
 	this.classpaths = new Classpath[classpathSize];
-	String[] pathNames = new String[classpathSize];
-	int problemsOccured = 0;
+	int counter = 0;
 	for (int i = 0; i < classpathSize; i++) {
+		Classpath classpath = getClasspath(classpathNames[i], encoding,
+					classpathDirectoryModes == null ? 0
+							: classpathDirectoryModes[i], null);
 		try {
-			File file = new File(convertPathSeparators(classpathNames[i]));
-			if (file.isDirectory()) {
-				if (file.exists()) {
-					if (classpathDirectoryModes == null){
-						this.classpaths[i] = new ClasspathDirectory(file, encoding);
-					} else {
-						this.classpaths[i] = new ClasspathDirectory(file, encoding, classpathDirectoryModes[i]);
-					}
-					pathNames[i] = ((ClasspathDirectory) this.classpaths[i]).path;
-				}
-			} else {
-				String lowercaseClasspathName = classpathNames[i].toLowerCase();
-				if (lowercaseClasspathName.endsWith(SUFFIX_STRING_jar)
-					  || lowercaseClasspathName.endsWith(SUFFIX_STRING_zip)) {
-					this.classpaths[i] = this.getClasspathJar(file); // will throw an IOException if file does not exist
-					pathNames[i] = classpathNames[i].substring(0, classpathNames[i].lastIndexOf('.'));
-				}
-			}
+			classpath.initialize();
+			this.classpaths[counter++] = classpath;
 		} catch (IOException e) {
-			this.classpaths[i] = null;
+			// ignore
 		}
-		if (this.classpaths[i] == null)
-			problemsOccured++;
 	}
-	if (problemsOccured > 0) {
-		Classpath[] newPaths = new Classpath[classpathSize - problemsOccured];
-		String[] newNames = new String[classpathSize - problemsOccured];
-		for (int i = 0, current = 0; i < classpathSize; i++)
-			if (this.classpaths[i] != null) {
-				newPaths[current] = this.classpaths[i];
-				newNames[current++] = pathNames[i];
-			}
-		classpathSize = newPaths.length;
-		this.classpaths = newPaths;
-		pathNames = newNames;
+	if (counter != classpathSize) {
+		System.arraycopy(this.classpaths, 0, (this.classpaths = new Classpath[counter]), 0, counter);
 	}
-
+	initializeKnownFileNames(initialFileNames);
+}
+FileSystem(Classpath[] paths, String[] initialFileNames) {
+	final int length = paths.length;
+	int counter = 0;
+	this.classpaths = new FileSystem.Classpath[length];
+	for (int i = 0; i < length; i++) {
+		final Classpath classpath = paths[i];
+		try {
+			classpath.initialize();
+			this.classpaths[counter++] = classpath;
+		} catch(IOException exception) {
+			// ignore
+		}
+	}
+	if (counter != length) {
+		// should not happen
+		System.arraycopy(this.classpaths, 0, (this.classpaths = new FileSystem.Classpath[counter]), 0, counter);
+	}
+	initializeKnownFileNames(initialFileNames);
+}
+static Classpath getClasspath(String classpathName, String encoding,
+		int classpathDirectoryMode, AccessRuleSet accessRuleSet) {
+	Classpath result = null;
+	File file = new File(convertPathSeparators(classpathName));
+	if (file.isDirectory()) {
+		if (file.exists()) {
+			result = new ClasspathDirectory(file, encoding,
+					classpathDirectoryMode, accessRuleSet);
+		}
+	} else {
+		String lowercaseClasspathName = classpathName.toLowerCase();
+		if (lowercaseClasspathName.endsWith(SUFFIX_STRING_jar)
+				|| lowercaseClasspathName.endsWith(SUFFIX_STRING_zip)) {
+			result = new ClasspathJar(file, true, accessRuleSet);
+			// will throw an IOException if file does not exist
+		}
+	}
+	return result;
+}
+private void initializeKnownFileNames(String[] initialFileNames) {
 	this.knownFileNames = new String[initialFileNames.length];
 	for (int i = initialFileNames.length; --i >= 0;) {
 		String fileName = initialFileNames[i];
@@ -92,20 +125,26 @@
 			fileName = fileName.substring(0, fileName.lastIndexOf('.')); // remove trailing ".java"
 
 		fileName = convertPathSeparators(fileName);
-		for (int j = 0; j < classpathSize; j++)
-			if (fileName.startsWith(pathNames[j]))
-				matchingPathName = pathNames[j];
+		for (int j = 0; j < classpaths.length; j++){
+			String matchCandidate = this.classpaths[j].normalizedPath();
+			if (this.classpaths[j] instanceof  ClasspathDirectory && 
+					fileName.startsWith(matchCandidate) && 
+					(matchingPathName == null || 
+							matchCandidate.length() < matchingPathName.length()))
+				matchingPathName = matchCandidate;
+		}
 		if (matchingPathName == null)
 			this.knownFileNames[i] = fileName; // leave as is...
 		else
 			this.knownFileNames[i] = fileName.substring(matchingPathName.length());
+		matchingPathName = null;
 	}
 }
 public void cleanup() {
 	for (int i = 0, max = this.classpaths.length; i < max; i++)
 		this.classpaths[i].reset();
 }
-private String convertPathSeparators(String path) {
+private static String convertPathSeparators(String path) {
 	return File.separatorChar == '/'
 		? path.replace('\\', '/')
 		 : path.replace('/', '\\');
@@ -153,7 +192,7 @@
 	return null;
 }
 public ClasspathJar getClasspathJar(File file) throws IOException {
-	return new ClasspathJar(new ZipFile(file), true);
+	return new ClasspathJar(file, true, null);
 }
 public boolean isPackage(char[][] compoundName, char[] packageName) {
 	String qualifiedPackageName = new String(CharOperation.concatWith(compoundName, packageName, '/'));
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java
index 19ed7a8..87588d8 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java
@@ -23,8 +23,11 @@
 import java.io.UnsupportedEncodingException;
 import java.lang.reflect.Field;
 import java.text.MessageFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.Date;
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -45,6 +48,8 @@
 import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
 import org.eclipse.jdt.internal.compiler.IProblemFactory;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.env.AccessRule;
+import org.eclipse.jdt.internal.compiler.env.AccessRuleSet;
 import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
 import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
@@ -311,7 +316,7 @@
 					String.valueOf(time),
 					String.valueOf(((int) (lineCount * 10000.0 / time)) / 10.0) }));
 		}
-		public void logClasspath(String[] classpaths) {
+		public void logClasspath(FileSystem.Classpath[] classpaths) {
 			if (classpaths == null) return;
 			if (this.isXml) {
 				final int length = classpaths.length;
@@ -320,7 +325,7 @@
 					this.printTag(CLASSPATHS, null, true, false);
 					for (int i = 0; i < length; i++) {
 						this.parameters.clear();
-						String classpath = classpaths[i];
+						String classpath = classpaths[i].getPath();
 						parameters.put(PATH, classpath);
 						File f = new File(classpath);
 						String id = null;
@@ -379,7 +384,7 @@
 				} catch (IOException e) {
 					this.logNoClassFileCreated(fileName);
 				}
-			}			
+			}	
 		}
 		
 		public void logCommandLineArguments(String[] commandLineArguments) {
@@ -726,7 +731,7 @@
 					Main.bind("compiler.version"), //$NON-NLS-1$
 					Main.bind("compiler.copyright") //$NON-NLS-1$
 				}
-			)); //$NON-NLS-1$
+			));
 		}
 
 		/**
@@ -816,6 +821,11 @@
 
 		private void printlnOut(String s) {
 			this.out.println(s);
+			if (!this.isXml) {
+				if (this.log != null) {
+					this.log.println(s);
+				}
+			}
 		}
 
 		/**
@@ -857,13 +867,17 @@
 		}
 
 		public void setLog(String logFileName) throws InvalidInputException {
+			final Date date = new Date();
+			final SimpleDateFormat dateFormat = new SimpleDateFormat("d MMM yyyy HH:mm:ss", Locale.getDefault());//$NON-NLS-1$
 			try {
 				this.log = new PrintWriter(new FileOutputStream(logFileName, false));
 				int index = logFileName.lastIndexOf('.');
-				if (index != 0) {
+				if (index != -1) {
 					if (logFileName.substring(index).toLowerCase().equals(".xml")) { //$NON-NLS-1$
 						this.isXml = true;
 						this.log.println(XML_HEADER);
+						// insert time stamp as comment
+						this.log.println("<!-- " + dateFormat.format(date) + " -->");//$NON-NLS-1$//$NON-NLS-2$
 						this.log.println(XML_DTD_DECLARATION);
 						this.tab = 0;
 						parameters.clear();
@@ -871,7 +885,11 @@
 						parameters.put(COMPILER_VERSION, Main.bind("compiler.version")); //$NON-NLS-1$//$NON-NLS-2$
 						parameters.put(COMPILER_COPYRIGHT, Main.bind("compiler.copyright")); //$NON-NLS-1$//$NON-NLS-2$
 						this.printTag(COMPILER, parameters, true, false);
+					} else {
+						this.log.println("# " + dateFormat.format(date));//$NON-NLS-1$//$NON-NLS-2$
 					}
+				} else {
+					this.log.println("# " + dateFormat.format(date));//$NON-NLS-1$//$NON-NLS-2$
 				}
 			} catch (FileNotFoundException e) {
 				throw new InvalidInputException(Main.bind("configure.cannotOpenLog")); //$NON-NLS-1$
@@ -925,7 +943,7 @@
 	public final static String bundleName =
 		"org.eclipse.jdt.internal.compiler.batch.messages"; 	//$NON-NLS-1$
 
-	public String[] classpaths;
+	FileSystem.Classpath[] checkedClasspaths;
 	public String destinationPath;
 	public String[] encodings;
 	public Logger logger;
@@ -1184,11 +1202,18 @@
 		final int InsideDefaultEncoding = 64;
 		final int InsideBootClasspath = 128;
 		final int InsideMaxProblems = 256;
+		final int InsideExtdirs = 512;
+		final int InsideSourcepath = 1024;
+
 		final int Default = 0;
-		String[] bootclasspaths = null;
 		int DEFAULT_SIZE_CLASSPATH = 4;
-		int pathCount = 0;
-		int bootclasspathCount = 0;
+		ArrayList bootclasspaths = new ArrayList(DEFAULT_SIZE_CLASSPATH),
+			extdirsClasspaths = new ArrayList(DEFAULT_SIZE_CLASSPATH),
+			extdirsNames = new ArrayList(DEFAULT_SIZE_CLASSPATH),
+			sourcepathClasspaths = new ArrayList(DEFAULT_SIZE_CLASSPATH),
+			classpaths = new ArrayList(DEFAULT_SIZE_CLASSPATH);
+		String currentClasspathName = null;
+		ArrayList currentRuleSpecs = new ArrayList(DEFAULT_SIZE_CLASSPATH);
 		int index = -1, filesCount = 0, argCount = argv.length;
 		int mode = Default;
 		this.repetitions = 0;
@@ -1264,7 +1289,8 @@
 			currentArg = newCommandLineArgs[index];
 
 			customEncoding = null;
-			if (currentArg.endsWith("]")) { //$NON-NLS-1$ 
+			if (currentArg.endsWith("]") && !(mode == InsideBootClasspath || mode == InsideClasspath || //$NON-NLS-1$ 
+					mode == InsideSourcepath) ) {
 				// look for encoding specification
 				int encodingStart = currentArg.indexOf('[') + 1;
 				int encodingEnd = currentArg.length() - 1;
@@ -1376,20 +1402,30 @@
 			}
 			if (currentArg.equals("-classpath") //$NON-NLS-1$
 				|| currentArg.equals("-cp")) { //$NON-NLS-1$ //$NON-NLS-2$
-				if (pathCount == 0) {
-					this.classpaths = new String[DEFAULT_SIZE_CLASSPATH];
-				}
 				mode = InsideClasspath;
 				continue;
 			}
 			if (currentArg.equals("-bootclasspath")) {//$NON-NLS-1$
-				if (bootclasspathCount > 0)
+				if (bootclasspaths.size() > 0)
 					throw new InvalidInputException(
 						Main.bind("configure.duplicateBootClasspath", currentArg)); //$NON-NLS-1$
-				bootclasspaths = new String[DEFAULT_SIZE_CLASSPATH];
 				mode = InsideBootClasspath;
 				continue;
 			}
+			if (currentArg.equals("-sourcepath")) {//$NON-NLS-1$
+				if (sourcepathClasspaths.size() > 0)
+					throw new InvalidInputException(
+						Main.bind("configure.duplicateSourcepath", currentArg)); //$NON-NLS-1$
+				mode = InsideSourcepath;
+				continue;
+			}
+			if (currentArg.equals("-extdirs")) {//$NON-NLS-1$
+				if (extdirsNames.size() > 0)
+					throw new InvalidInputException(
+						Main.bind("configure.duplicateExtdirs", currentArg)); //$NON-NLS-1$
+				mode = InsideExtdirs;
+				continue;
+			}
 			if (currentArg.equals("-progress")) { //$NON-NLS-1$
 				mode = Default;
 				this.showProgress = true;
@@ -1608,7 +1644,8 @@
 						this.options.put(
 							CompilerOptions.OPTION_ReportPossibleAccidentalBooleanAssignment,
 							isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
-   					} else if (token.equals("syntheticAccess")) { //$NON-NLS-1$
+   					} else if (token.equals("syntheticAccess") //$NON-NLS-1$
+   							|| token.equals("synthetic-access")) { //$NON-NLS-1$
 						this.options.put(
 							CompilerOptions.OPTION_ReportSyntheticAccessEmulation,
 							isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
@@ -1660,6 +1697,14 @@
 						this.options.put(
 							CompilerOptions.OPTION_ReportFinalParameterBound,
 							isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
+					} else if (token.equals("suppress")) {//$NON-NLS-1$ 
+						this.options.put(
+							CompilerOptions.OPTION_SuppressWarnings,
+							isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
+					} else if (token.equals("warningToken")) {//$NON-NLS-1$ 
+						this.options.put(
+							CompilerOptions.OPTION_ReportUnhandledWarningToken,
+							isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
 					} else if (token.equals("unnecessaryElse")) {//$NON-NLS-1$ 
 						this.options.put(
 							CompilerOptions.OPTION_ReportUnnecessaryElse,
@@ -1751,7 +1796,8 @@
 						this.options.put(
 							CompilerOptions.OPTION_ReportUnusedDeclaredThrownException,
 							isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
-					} else if (token.equals("unqualifiedField")) { //$NON-NLS-1$
+					} else if (token.equals("unqualifiedField") //$NON-NLS-1$
+							|| token.equals("unqualified-field-access")) { //$NON-NLS-1$
 						this.options.put(
 							CompilerOptions.OPTION_ReportUnqualifiedFieldAccess,
 							isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
@@ -1771,11 +1817,11 @@
 						this.options.put(
 							CompilerOptions.OPTION_ReportAutoboxing,
 							isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);						
-					} else if (token.equals("Override")) { //$NON-NLS-1$
+					} else if (token.equals("over-ann")) { //$NON-NLS-1$
 						this.options.put(
 							CompilerOptions.OPTION_ReportMissingOverrideAnnotation,
 							isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);						
-					} else if (token.equals("Deprecated")) { //$NON-NLS-1$
+					} else if (token.equals("dep-ann")) { //$NON-NLS-1$
 						this.options.put(
 							CompilerOptions.OPTION_ReportMissingDeprecatedAnnotation,
 							isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);						
@@ -1783,10 +1829,47 @@
 						this.options.put(
 							CompilerOptions.OPTION_ReportAnnotationSuperInterface,
 							isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);						
-					} else if (token.equals("enumSwitch")) { //$NON-NLS-1$
+					} else if (token.equals("enumSwitch") //$NON-NLS-1$
+							|| token.equals("incomplete-switch")) { //$NON-NLS-1$
 						this.options.put(
 							CompilerOptions.OPTION_ReportIncompleteEnumSwitch,
 							isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);						
+					} else if (token.equals("hiding")) { //$NON-NLS-1$
+						this.options.put(
+							CompilerOptions.OPTION_ReportHiddenCatchBlock,
+							isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
+						this.options.put(
+							CompilerOptions.OPTION_ReportLocalVariableHiding,
+							isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
+						this.options.put(
+							CompilerOptions.OPTION_ReportFieldHiding,
+							isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
+						this.options.put(
+							CompilerOptions.OPTION_ReportTypeParameterHiding,
+							isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
+					} else if (token.equals("static-access")) { //$NON-NLS-1$
+						this.options.put(
+							CompilerOptions.OPTION_ReportNonStaticAccessToStatic,
+							isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
+						this.options.put(
+							CompilerOptions.OPTION_ReportIndirectStaticAccess,
+							isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
+					} else if (token.equals("unused")) { //$NON-NLS-1$
+						this.options.put(
+							CompilerOptions.OPTION_ReportUnusedLocal, 
+							isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
+						this.options.put(
+							CompilerOptions.OPTION_ReportUnusedParameter,
+							isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
+						this.options.put(
+							CompilerOptions.OPTION_ReportUnusedImport,
+							isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
+						this.options.put(
+							CompilerOptions.OPTION_ReportUnusedPrivateMember,
+							isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
+						this.options.put(
+							CompilerOptions.OPTION_ReportUnusedDeclaredThrownException,
+							isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
 					} else {
 						throw new InvalidInputException(Main.bind("configure.invalidWarning", token)); //$NON-NLS-1$
 					}
@@ -1814,6 +1897,35 @@
 				useEnableJavadoc = true;
 				continue;
 			}
+			// tolerated javac options - quietly filtered out
+			if (currentArg.startsWith("-X")) { //$NON-NLS-1$
+				mode = Default;
+				continue;
+			}
+			if (currentArg.startsWith("-J")) { //$NON-NLS-1$
+				mode = Default;
+				continue;
+			}
+			if (currentArg.equals("-O")) { //$NON-NLS-1$
+				mode = Default;
+				continue;
+			}
+			
+			if (currentArg.equals("-sourcepath")) {//$NON-NLS-1$
+				if (sourcepathClasspaths.size() > 0)
+					throw new InvalidInputException(
+						Main.bind("configure.duplicateSourcepath", currentArg)); //$NON-NLS-1$
+				mode = InsideSourcepath;
+				continue;
+			}
+			if (currentArg.equals("-extdirs")) {//$NON-NLS-1$
+				if (extdirsNames.size() > 0)
+					throw new InvalidInputException(
+						Main.bind("configure.duplicateExtdirs", currentArg)); //$NON-NLS-1$
+				mode = InsideExtdirs;
+				continue;
+			}
+
 			if (mode == TargetSetting) {
 				if (didSpecifyTarget) {
 					throw new InvalidInputException(
@@ -1913,40 +2025,100 @@
 				mode = Default;
 				continue;
 			}
-			if (mode == InsideClasspath) {
-				StringTokenizer tokenizer = new StringTokenizer(currentArg, File.pathSeparator);
+			if (mode == InsideClasspath || mode == InsideBootClasspath || mode == InsideSourcepath) {
+				StringTokenizer tokenizer = new StringTokenizer(currentArg,
+						File.pathSeparator + "[]", true); //$NON-NLS-1$
+				// state machine
+				final int start = 0; 
+				final int readyToClose = 1;
+				// 'path' 'path1[rule];path2'
+				final int readyToCloseEndingWithRules = 2;
+				// 'path[rule]' 'path1;path2[rule]'
+				final int readyToCloseOrOtherEntry = 3;
+				// 'path[rule];' 'path;' 'path1;path2;'
+				final int rulesNeedAnotherRule = 4;
+				// 'path[rule1;'
+				final int rulesStart = 5;
+				// 'path[' 'path1;path2['
+				final int rulesReadyToClose = 6;
+				// 'path[rule' 'path[rule1;rule2'
+				final int error = 99;
+				int state = start;
+				String token = null;
 				while (tokenizer.hasMoreTokens()) {
-					int length;
-					if ((length = this.classpaths.length) <= pathCount) {
-						System.arraycopy(
-							this.classpaths,
-							0,
-							(this.classpaths = new String[length * 2]),
-							0,
-							length);
+					token = tokenizer.nextToken();
+					if (token.equals(File.pathSeparator)) {
+						switch (state) {
+						case readyToClose:
+						case readyToCloseEndingWithRules:
+						case readyToCloseOrOtherEntry:
+							state = readyToCloseOrOtherEntry;
+							addNewEntry(InsideClasspath, InsideSourcepath, bootclasspaths, classpaths, sourcepathClasspaths, currentClasspathName, currentRuleSpecs, mode, customEncoding);
+							break;
+						case rulesReadyToClose:
+							state = rulesNeedAnotherRule;
+							break;
+						default:
+							state = error;
+						}
+					} else if (token.equals("[")) { //$NON-NLS-1$
+						switch (state) {
+						case readyToClose:
+							state = rulesStart;
+							break;
+						default:
+							state = error;
+						}
+					} else if (token.equals("]")) { //$NON-NLS-1$
+						switch (state) {
+						case rulesReadyToClose:
+							state = readyToCloseEndingWithRules;
+							break;
+						default:
+							state = error;
+						}
+
+					} else {
+						// regular word
+						switch (state) {
+						case start:
+						case readyToCloseOrOtherEntry:
+							state = readyToClose;
+							currentClasspathName = token;
+							break;
+						case rulesNeedAnotherRule:
+						case rulesStart:
+							state = rulesReadyToClose;
+							currentRuleSpecs.add(token);
+							break;
+						default:
+							state = error;
+						}
 					}
-					this.classpaths[pathCount++] = tokenizer.nextToken();
+				}
+				switch(state) {
+					case readyToClose :
+					case readyToCloseEndingWithRules :
+					case readyToCloseOrOtherEntry :
+						addNewEntry(InsideClasspath, InsideSourcepath, bootclasspaths, classpaths, sourcepathClasspaths, currentClasspathName, currentRuleSpecs, mode, customEncoding);
+						break;
+					default :
+						// we go on anyway
+						this.logger.logIncorrectClasspath(currentArg);
 				}
 				mode = Default;
 				continue;
 			}
-			if (mode == InsideBootClasspath) {
-				StringTokenizer tokenizer = new StringTokenizer(currentArg, File.pathSeparator);
-				while (tokenizer.hasMoreTokens()) {
-					int length;
-					if ((length = bootclasspaths.length) <= bootclasspathCount) {
-						System.arraycopy(
-							bootclasspaths,
-							0,
-							(bootclasspaths = new String[length * 2]),
-							0,
-							length);
-					}
-					bootclasspaths[bootclasspathCount++] = tokenizer.nextToken();
-				}
+			if (mode == InsideExtdirs) {
+				StringTokenizer tokenizer = new StringTokenizer(currentArg,	File.pathSeparator, false);
+				while (tokenizer.hasMoreTokens())
+					extdirsNames.add(tokenizer.nextToken());
+				if (extdirsNames.size() == 0) // empty entry
+					extdirsNames.add(""); //$NON-NLS-1$
 				mode = Default;
 				continue;
-			}			
+			}
+
 			//default is input directory
 			currentArg = currentArg.replace('/', File.separatorChar);
 			if (currentArg.endsWith(File.separator))
@@ -1996,6 +2168,14 @@
 			mode = Default;
 			continue;
 		}
+		
+
+		if (this.log != null) {
+			this.logger.setLog(this.log);
+		} else {
+			this.showProgress = false;
+		}
+		
 		if (printUsageRequired || filesCount == 0) {
 			printUsage();
 			this.proceed = false;
@@ -2012,22 +2192,30 @@
 				(this.filenames = new String[filesCount]),
 				0,
 				filesCount);
-		if (pathCount == 0) {
+		if (classpaths.size() == 0) {
 			// no user classpath specified.
 			String classProp = System.getProperty("java.class.path"); //$NON-NLS-1$
 			if ((classProp == null) || (classProp.length() == 0)) {
 				this.logger.logNoClasspath(); //$NON-NLS-1$
-				classProp = System.getProperty("user.dir"); //$NON-NLS-1$
 			}
-			StringTokenizer tokenizer = new StringTokenizer(classProp, File.pathSeparator);
-			this.classpaths = new String[tokenizer.countTokens() + 1];
-			while (tokenizer.hasMoreTokens()) {
-				this.classpaths[pathCount++] = tokenizer.nextToken();
+			else {
+				StringTokenizer tokenizer = new StringTokenizer(classProp, File.pathSeparator);
+				String token;
+				while (tokenizer.hasMoreTokens()) {
+					token = tokenizer.nextToken();
+					FileSystem.Classpath currentClasspath = FileSystem
+							.getClasspath(token, customEncoding, 0, null);
+					if (currentClasspath != null) {
+						classpaths.add(currentClasspath);
+					} else {
+						this.logger.logIncorrectClasspath(token);
+						// should not happen - we go on anyway
+					}
+				}
 			}
-			this.classpaths[pathCount++] = System.getProperty("user.dir");//$NON-NLS-1$
 		}
 		
-		if (bootclasspathCount == 0) {
+	 	 if (bootclasspaths.size() == 0) {
 			/* no bootclasspath specified
 			 * we can try to retrieve the default librairies of the VM used to run
 			 * the batch compiler
@@ -2042,74 +2230,89 @@
 		 	/*
 		 	 * Handle >= JDK 1.2.2 settings: retrieve rt.jar
 		 	 */
-		 	 String javaHome = System.getProperty("java.home");//$NON-NLS-1$
-		 	 if (javaHome != null) {
-		 	 	File javaHomeFile = new File(javaHome);
-		 	 	if (javaHomeFile.exists()) {
-					try {
-						javaHomeFile = new File(javaHomeFile.getCanonicalPath());
-						// add all jars in the lib subdirectory
-						File[] directoriesToCheck = new File[] { new File(javaHomeFile, "lib"), new File(javaHomeFile, "lib/ext")};//$NON-NLS-1$//$NON-NLS-2$
-						File[][] systemLibrariesJars = getLibrariesFiles(directoriesToCheck);
-						if (systemLibrariesJars != null) {
-							int length = getLength(systemLibrariesJars);
-							bootclasspaths = new String[length];
-							for (int i = 0, max = systemLibrariesJars.length; i < max; i++) {
-								File[] current = systemLibrariesJars[i];
-								if (current != null) {
-									for (int j = 0, max2 = current.length; j < max2; j++) {
-										bootclasspaths[bootclasspathCount++] = current[j].getAbsolutePath();
-									}
+		 	 if (getJavaHome() != null) {
+				File[] directoriesToCheck = new File[] { 
+						new File(getJavaHome(), "lib") //$NON-NLS-1$
+						};
+				File[][] systemLibrariesJars = getLibrariesFiles(directoriesToCheck);
+				if (systemLibrariesJars != null) {
+					for (int i = 0, max = systemLibrariesJars.length; i < max; i++) {
+						File[] current = systemLibrariesJars[i];
+						if (current != null) {
+							for (int j = 0, max2 = current.length; j < max2; j++) {
+								FileSystem.Classpath classpath = 
+									FileSystem.getClasspath(
+											current[j].getAbsolutePath(),
+											null, 0, null); 
+								if (classpath != null) {
+									bootclasspaths.add(classpath);
 								}
 							}
 						}
-					} catch (IOException e) {
-						// cannot retrieve libraries
 					}
-		 	 	}
-		 	 }
-		}
-
-		if (this.log != null) {
-			this.logger.setLog(this.log);
-		} else {
-			this.showProgress = false;
-		}
-
-		if (this.classpaths == null) {
-			this.classpaths = new String[0];
-		}
-		/* 
-		 * We put the bootclasspath at the beginning of the classpath entries
+				}
+	 		}
+	 	 }
+		
+		/*
+		 * Feed extdirsNames according to:
+		 * - -extdirs first if present;
+		 * - else java.ext.dirs if defined;
+		 * - else default extensions directory for the platform.
 		 */
-		String[] newclasspaths = null;
-		if ((pathCount + bootclasspathCount) != this.classpaths.length) {
-			newclasspaths = new String[pathCount + bootclasspathCount];
-		} else {
-			newclasspaths = this.classpaths;
-		}
-		System.arraycopy(
-			this.classpaths,
-			0,
-			newclasspaths,
-			bootclasspathCount,
-			pathCount);
-
-		if (bootclasspathCount != 0) {
-			System.arraycopy(
-				bootclasspaths,
-				0,
-				newclasspaths,
-				0,
-				bootclasspathCount);
-		}
-		this.classpaths = newclasspaths;
-		for (int i = 0, max = this.classpaths.length; i < max; i++) {
-			File file = new File(this.classpaths[i]);
-			if (!file.exists()) { // signal missing classpath entry file
-				this.logger.logIncorrectClasspath(this.classpaths[i]); //$NON-NLS-1$
+		if (extdirsNames.size() == 0) {
+			String extdirsStr = System.getProperty("java.ext.dirs"); //$NON-NLS-1$
+			if (extdirsStr == null) {
+				extdirsNames.add(getJavaHome().getAbsolutePath() + "/lib/ext"); //$NON-NLS-1$
+			}
+			else {
+				StringTokenizer tokenizer = new StringTokenizer(extdirsStr, File.pathSeparator);
+				while (tokenizer.hasMoreTokens()) 
+					extdirsNames.add(tokenizer.nextToken());
 			}
 		}
+		
+		/*
+		 * Feed extdirsClasspath with the entries found into the directories listed by
+		 * extdirsNames.
+		 */
+		if (extdirsNames.size() != 0) {
+			File[] directoriesToCheck = new File[extdirsNames.size()];
+			for (int i = 0; i < directoriesToCheck.length; i++) 
+				directoriesToCheck[i] = new File((String) extdirsNames.get(i));
+			File[][] extdirsJars = getLibrariesFiles(directoriesToCheck);
+			if (extdirsJars != null) {
+				for (int i = 0, max = extdirsJars.length; i < max; i++) {
+					File[] current = extdirsJars[i];
+					if (current != null) {
+						for (int j = 0, max2 = current.length; j < max2; j++) {
+							FileSystem.Classpath classpath = 
+								FileSystem.getClasspath(
+										current[j].getAbsolutePath(),
+										null, 0, null); 
+							if (classpath != null) {
+								extdirsClasspaths.add(classpath);
+							}
+						}
+					}
+				}
+			}
+		}
+
+		/* 
+		 * Concatenate classpath entries
+		 * We put the bootclasspath at the beginning of the classpath
+		 * entries, followed by the extension libraries, followed by
+		 * the sourcepath followed by the classpath.  All classpath
+		 * entries are searched for both sources and binaries except
+		 * the sourcepath entries which are searched for sources only.
+		 */
+		bootclasspaths.addAll(extdirsClasspaths);
+		bootclasspaths.addAll(sourcepathClasspaths);
+		bootclasspaths.addAll(classpaths);
+		classpaths = bootclasspaths;
+		this.checkedClasspaths = new FileSystem.Classpath[classpaths.size()];
+		classpaths.toArray(this.checkedClasspaths);
 		if (this.destinationPath == null) {
 			this.generatePackagesStructure = false;
 		} else if ("none".equals(this.destinationPath)) { //$NON-NLS-1$
@@ -2190,7 +2393,7 @@
 		}
 		this.logger.logCommandLineArguments(newCommandLineArgs);
 		this.logger.logOptions(this.options);
-		this.logger.logClasspath(this.classpaths);
+		this.logger.logClasspath(this.checkedClasspaths);
 		if (this.repetitions == 0) {
 			this.repetitions = 1;
 		}
@@ -2200,6 +2403,83 @@
 		}
 	}
 
+	private void addNewEntry(final int InsideClasspath, final int InsideSourcepath, ArrayList bootclasspaths, ArrayList classpaths,ArrayList sourcepathClasspaths, String currentClasspathName, ArrayList currentRuleSpecs, int mode, String customEncoding) {
+		AccessRule[] accessRules = new AccessRule[currentRuleSpecs
+				.size()];
+		boolean rulesOK = true;
+		Iterator i = currentRuleSpecs.iterator();
+		int j = 0;
+		while (i.hasNext()) {
+			String ruleSpec = (String) i.next();
+			char key = ruleSpec.charAt(0);
+			String pattern = ruleSpec.substring(1);
+			if (pattern.length() > 0) {
+				switch (key) {
+				case '+':
+					accessRules[j++] = new AccessRule(pattern
+							.toCharArray(), -1);
+					break;
+				case '~':
+					accessRules[j++] = new AccessRule(pattern
+							.toCharArray(),
+							IProblem.DiscouragedReference);
+					break;
+				case '-':
+					accessRules[j++] = new AccessRule(pattern
+							.toCharArray(),
+							IProblem.ForbiddenReference);
+					break;
+				default:
+					rulesOK = false;
+				}
+			} else {
+				rulesOK = false;
+			}
+		}
+		if (rulesOK) {
+			AccessRuleSet accessRuleSet = new AccessRuleSet(
+					accessRules, "{0}"); //$NON-NLS-1$
+			FileSystem.Classpath currentClasspath = FileSystem
+					.getClasspath(currentClasspathName,
+							customEncoding, 0, accessRuleSet);
+			if (currentClasspath != null) {
+				if (mode == InsideClasspath) {
+					classpaths.add(currentClasspath);
+				} else if (mode == InsideSourcepath) {
+					if (currentClasspath instanceof ClasspathDirectory) {
+						((ClasspathDirectory) currentClasspath).mode = 
+							ClasspathDirectory.SOURCE; 
+						// TODO may consider adding this attribute to other classpath natures
+					}
+					sourcepathClasspaths.add(currentClasspath);
+				} else { // inside bootclasspath
+					bootclasspaths.add(currentClasspath);
+				}
+			} else {
+				this.logger.logIncorrectClasspath(currentClasspathName);
+				// we go on anyway
+			}
+		} else {
+			this.logger.logIncorrectClasspath(currentClasspathName);
+			// we go on anyway
+		}
+	}
+
+	private File javaHomeCache;
+	private boolean javaHomeChecked;
+	private File getJavaHome() {
+		if (!javaHomeChecked) {
+			javaHomeChecked = true;
+			String javaHome = System.getProperty("java.home");//$NON-NLS-1$
+			if (javaHome != null) {
+				javaHomeCache = new File(javaHome);
+				if (!javaHomeCache.exists())
+					javaHomeCache = null;
+			}
+		}
+		return javaHomeCache;
+	}
+	
 	private void disableWarnings() {
 		Object[] entries = this.options.entrySet().toArray();
 		for (int i = 0, max = entries.length; i < max; i++) {
@@ -2250,6 +2530,7 @@
 					// exit?
 					if (Main.this.systemExitWhenFinished && !Main.this.proceedOnError && (localErrorCount > 0)) {
 						Main.this.logger.endLoggingSource();
+						Main.this.logger.endLoggingSources();
 						Main.this.logger.printStats(Main.this);
 						Main.this.logger.flush();
 						Main.this.logger.close();
@@ -2311,18 +2592,6 @@
 		return result;
 	}
 	
-	private int getLength(File[][] libraries) {
-		int sum = 0;
-		if (libraries != null) {
-			for (int i = 0, max = libraries.length; i < max; i++) {
-				final File[] currentFiles = libraries[i];
-				if (currentFiles != null) {
-					sum+= currentFiles.length;
-				}
-			}
-		}
-		return sum;
-	}
 	/*
 	 *  Low-level API performing the actual compilation
 	 */
@@ -2342,8 +2611,8 @@
 
 		String defaultEncoding = (String) this.options.get(CompilerOptions.OPTION_Encoding);
 		if ("".equals(defaultEncoding)) //$NON-NLS-1$
-			defaultEncoding = null; //$NON-NLS-1$	
-		return new FileSystem(this.classpaths, this.filenames, defaultEncoding);
+			defaultEncoding = null;	
+		return new FileSystem(this.checkedClasspaths, this.filenames);
 	}
 	/*
 	 *  Low-level API performing the actual compilation
@@ -2355,14 +2624,14 @@
 
 	public void outputClassFiles(CompilationResult unitResult) {
 		if (!((unitResult == null) || (unitResult.hasErrors() && !this.proceedOnError))) {
-			Enumeration classFiles = unitResult.compiledTypes.elements();
+			ClassFile[] classFiles = unitResult.getClassFiles();
 			if (!this.generatePackagesStructure) {
 				this.destinationPath = extractDestinationPathFromSourceFile(unitResult);
 			}
 			if (this.destinationPath != null) {
-				while (classFiles.hasMoreElements()) {
+				for (int i = 0, fileCount = classFiles.length; i < fileCount; i++) {
 					// retrieve the key and the corresponding classfile
-					ClassFile classFile = (ClassFile) classFiles.nextElement();
+					ClassFile classFile = classFiles[i];
 					char[] filename = classFile.fileName();
 					int length = filename.length;
 					char[] relativeName = new char[length + 6];
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties
index 22b7234..7e5dad9 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties
@@ -14,7 +14,7 @@
 #Format: compiler.name = word1 word2 word3
 compiler.name = Eclipse Java Compiler
 #Format: compiler.version = 0.XXX[, other words (don't forget the comma if adding other words)]
-compiler.version = 0.553, pre-3.1.0 milestone-7
+compiler.version = v_574_R31x, pre-3.1.1 release
 compiler.copyright = Copyright IBM Corp 2000, 2005. All rights reserved.
 
 ### scanning
@@ -49,6 +49,8 @@
 configure.source = source level should be comprised in between ''1.3'' and ''1.5'' (or ''5'' or ''5.0''): {0}
 configure.duplicateOutputPath = duplicate output path specification: {0}
 configure.duplicateBootClasspath = duplicate bootclasspath specification: {0}
+configure.duplicateExtdirs = duplicate extdirs specification: {0}
+configure.duplicateSourcepath = duplicate sourcepath specification: {0}
 configure.invalidDebugOption = invalid debug option: {0}
 configure.invalidWarningConfiguration = invalid warning configuration: {0}
 configure.invalidWarning = invalid warning: {0}
@@ -92,9 +94,19 @@
 \ \n\
 \ Classpath options:\n\
 \    -cp -classpath <directories and zip/jar files separated by {0}>\n\
-\                       specify location for application classes and sources\n\
+\                       specify location for application classes and sources. Each\n\
+\                       directory or file can specify access rules for types between\n\
+\                       ''['' and '']'' (e.g. [-X.java] to deny access to type X)\n\
 \    -bootclasspath <directories and zip/jar files separated by {0}>\n\
-\                       specify location for system classes\n\
+\                       specify location for system classes. Each directory or file can\n\
+\                       specify access rules for types between ''['' and '']'' (e.g. [-X.java]\n\
+\                       to deny access to type X)\n\
+\    -sourcepath <directories separated by {0}>\n\
+\                       specify location for application sources. Each directory can\n\
+\                       specify access rules for types between ''['' and '']'' (e.g. [-X.java]\n\
+\                       to deny access to type X)\n\
+\    -extdirs <directories separated by {0}>\n\
+\                       specify location for extension zip/jar files\n\
 \    -d <dir>           destination directory (if omitted, no directory is created)\n\
 \    -d none            generate no .class files\n\
 \    -encoding <enc>    specify custom encoding for all sources. Each file/directory can override it\n\
@@ -121,13 +133,15 @@
 \      charConcat         + char[] in String concat\n\
 \      conditionAssign      possible accidental boolean assignment\n\
 \      constructorName    + method with constructor name\n\
+\      dep-ann              missing @Deprecated annotation\n\
 \      deprecation        + deprecation outside deprecated code\n\
-\      Deprecated           missing @Deprecated annotation\n\
 \      emptyBlock           undocumented empty block\n\
 \      enumSwitch           incomplete enum switch\n\
 \      fieldHiding          field hiding another variable\n\
 \      finalBound           type parameter with final bound\n\
 \      finally            + finally block not completing normally\n\
+\      hiding               macro for fieldHiding, localHiding, typeHiding and maskedCatchBlock\n\
+\      incomplete-switch    same as enumSwitch\n\
 \      indirectStatic       indirect reference to static member\n\
 \      intfAnnotation     + annotation type used as super interface\n\
 \      intfNonInherited   + interface non-inherited method compatibility\n\
@@ -136,27 +150,32 @@
 \      maskedCatchBlock   + hidden catch block\n\
 \      nls                  string literal lacking non-nls tag //$NON-NLS-<n>$\n\
 \      noEffectAssign     + assignment without effect\n\
-\      nullCheck          + missing or redundant null check\n\
-\      Override             missing @Override annotation\n\
+\      null                 missing or redundant null check\n\
+\      over-ann             missing @Override annotation\n\
 \      pkgDefaultMethod   + attempt to override package-default method\n\
 \      semicolon            unnecessary semicolon, empty statement\n\
 \      serial             + missing serialVersionUID\n\
-\      unqualifiedField     unqualified reference to field\n\
-\      unchecked          + unchecked type operation\n\
-\      unusedArgument       unread method parameter\n\
-\      unusedImport       + unused import declaration\n\
-\      unusedLocal          unread local variable\n\
-\      unusedPrivate        unused private member declaration\n\
-\      unusedThrown         unused declared thrown exception\n\
-\      unnecessaryElse      unnecessary else clause\n\
-\      uselessTypeCheck     unnecessary cast/instanceof operation\n\
 \      specialParamHiding   constructor or setter parameter hiding another field\n\
+\      static-access        macro for indirectStatic and staticReceiver\n\
 \      staticReceiver     + non-static reference to static member\n\
+\      suppress           + enable @SuppressWarnings\n\
+\      synthetic-access     same as syntheticAccess\n\
 \      syntheticAccess      synthetic access for innerclass\n\
 \      tasks(<tags separated by |>) tasks identified by tags inside comments\n\
 \      typeHiding         + type parameter hiding another type\n\
+\      unchecked          + unchecked type operation\n\
+\      unnecessaryElse      unnecessary else clause\n\
+\      unqualified-field-access same as unQualifiedField\n\
+\      unqualifiedField     unqualified reference to field\n\
+\      unused               macro for unusedArgument, unusedImport, unusedLocal, unusedPrivate and unusedThrown\n\
+\      unusedArgument       unread method parameter\n\
+\      unusedImport       + unused import declaration\n\
+\      unusedLocal        + unread local variable\n\
+\      unusedPrivate      + unused private member declaration\n\
+\      unusedThrown         unused declared thrown exception\n\
+\      uselessTypeCheck     unnecessary cast/instanceof operation\n\
 \      varargsCast        + varargs argument need explicit cast\n\
-\
+\      warningToken       + unhandled warning token in @SuppressWarnings\n\
 \ \n\
 \ Debug options:\n\
 \    -g[:lines,vars,source] custom debug info\n\
@@ -165,10 +184,17 @@
 \    -g:none            no debug info\n\
 \    -preserveAllLocals preserve unused local vars for debug purpose\n\
 \ \n\
+\ Ignored options:\n\
+\    -J<option>         pass option to virtual machine (ignored)\n\
+\    -X<option>         specify non-standard option (ignored)\n\
+\    -X                 print non-standard options and exit (ignored)\n\
+\    -O                 optimize for execution time (ignored)\n\
+\ \n\
 \ Advanced options:\n\
 \    @<file>            read command line arguments from file\n\
 \    -maxProblems <n>   max number of problems per compilation unit (100 by default)\n\
-\    -log <file>        log to a file\n\
+\    -log <file>        log to a file. If the file extension is ''.xml'', then the log\n\
+\                       will be a xml file.\n\
 \    -proceedOnError    do not stop at first error, dumping class files with problem methods\n\
 \    -verbose           enable verbose output\n\
 \    -referenceInfo     compute reference info\n\
diff --git a/org.eclipse.jdt.core/build.ajproperties b/org.eclipse.jdt.core/build.ajproperties
new file mode 100644
index 0000000..debfb00
--- /dev/null
+++ b/org.eclipse.jdt.core/build.ajproperties
@@ -0,0 +1,10 @@
+src.includes = antadapter/,\
+               aspectj/,\
+               batch/,\
+               codeassist/,\
+               compiler/,\
+               dom/,\
+               eval/,\
+               formatter/,\
+               model/,\
+               search/
diff --git a/org.eclipse.jdt.core/build.properties b/org.eclipse.jdt.core/build.properties
index ba3b548..c47d1ad 100644
--- a/org.eclipse.jdt.core/build.properties
+++ b/org.eclipse.jdt.core/build.properties
@@ -35,5 +35,4 @@
 jars.compile.order=.,jdtCompilerAdapter.jar
 jars.extra.classpath=platform:/plugin/org.apache.ant/lib/ant.jar
 src.includes = about.html,\
-               schema/,\
-               component.xml
+               schema/
diff --git a/org.eclipse.jdt.core/buildnotes_jdt-core.html b/org.eclipse.jdt.core/buildnotes_jdt-core.html
index 97faf17..6355afc 100644
--- a/org.eclipse.jdt.core/buildnotes_jdt-core.html
+++ b/org.eclipse.jdt.core/buildnotes_jdt-core.html
@@ -3,7 +3,7 @@
 <head>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
    <meta name="Author" content="IBM">
-   <title>JDT/Core Release Notes</title>
+   <title>JDT/Core Release Notes 3.1</title>
    <link rel="stylesheet" href="jdt_core_style.css" charset="iso-8859-1" type="text/css">
 </head>
 <body text="#000000" bgcolor="#FFFFFF">
@@ -36,21 +36,1400 @@
 	</td>
   </tr>
 </table>
-
-<a name="v_553"></a>
+<a name="v_574_R31x"></a>
 <p><hr><h1>
-Eclipse Platform Build Notes&nbsp;<br>
+Eclipse Platform Build Notes<br>
 Java Development Tooling Core</h1>
-Eclipse SDK 3.1M7 - 2?th April 2005
-<br>Project org.eclipse.jdt.core v_553
-(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_553">cvs</a>).
+Eclipse SDK 3.1.1 - 16th August 2005 <!-- - 3.1.1 RELEASE (R3_1_1) -->
+<br>Project org.eclipse.jdt.core v_574_R31x
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_574_R31x">cvs</a>).
 <h2>
 What's new in this drop</h2>
 <ul>
 </ul>
 
 <h3>Problem Reports Fixed</h3>
-<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=92059">92059</a>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=106964">106964</a>
+[1.5][search] AIOBE in MethodLocator.matchOverriddenMethod
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=99903">99903</a>
+[1.5][search] range wrong for package-info
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=99662">99662</a>
+[1.5] JavaModel returns inexistent IType for package-info ICompilationUnits
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=106936">106936</a>
+[1.5][compiler] Unoptimal lub computation
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=106865">106865</a>
+[1.5][compiler] capture conversion doesn't handle array types
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=105284">105284</a>
+[1.5][compiler] Autoboxing: Type mismatch
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=106106">106106</a>
+[1.5][compiler] Compiler error with Arrays.asList in Java 5 mode?
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=105531">105531</a>
+[1.5][compiler] ecj from CVS generates spurious incomprehensible error
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=106514">106514</a>
+[1.5][compiler] Improve diagnostic on bound mismatch for GenericTypeTests.test79
+
+
+<a name="v_573_R31x"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.1.1 - 11th August 2005
+<br>Project org.eclipse.jdt.core v_573_R31x
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_573_R31x">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+<li>Plug-in version ID got promoted to "3.1.1".
+</li>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=106403">106403</a>
+PublicScanner returns EOF late
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=105635">105635</a>
+incorrect parsing of field declarations with generic types
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=106297">106297</a>
+[1.5][compiler] new A&lt;X&gt;().new B(){}
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=104780">104780</a>
+TVT 3.1: TCT 386 - wrong description for option FORMATTER_INSERT_NEW_LINE_AFTER_ANNOTATION
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=100041">100041</a>
+[javadoc][dom] Wrong positions when javadoc comment inside method declaration
+
+
+<a name="v_572_R31x"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.1.1 - 3rd August 2005
+<br>Project org.eclipse.jdt.core v_572_R31x
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_572_R31x">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=104664">104664</a>
+[compiler] repeat mode is broken in the batch compiler
+
+<a name="v_571a_R31x"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.1.1 - 27th July 2005
+<br>Project org.eclipse.jdt.core v_571a_R31x
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_571a_R31x">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=104738">104738</a>
+[1.5][compiler] Enclosing method attribute is generated for member type of a local type
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=104649">104649</a>
+[1.5][compiler] method type variable: inference broken for null
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=104655">104655</a>
+[1.5] inconsistent compiler behavior in generic methods
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=104551">104551</a>
+[1.5][compiler] Method override checks fail with raw subtype and type variable as type bound
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=104492">104492</a>
+[AST]java.lang.ClassCastException: org.eclipse.jdt.core.dom.PrimitiveType
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=103485">103485</a>
+[1.5][compiler] compiler: wrongfully accepted method call
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=103994">103994</a>
+[1.5][compiler] Internal compiler error while overriding bootstrap class
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=103528">103528</a>
+[1.5][compiler] compiler allows invalid assignment with method type parameter and nested wildcards
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=104082">104082</a>
+[1.5][compiler] 1.5 source code gets internal eclipse null pointer error
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=104167">104167</a>
+[1.5][compiler] incorrect 'unread field' diagnosis
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=103320">103320</a>
+Method-local subtype with instance initializer break JDOM
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=103636">103636</a>
+JDT compiler produces invalid XML
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=103227">103227</a>
+[1.5][compiler] VerifyError in case of a parametrized anonymous class inside a static inner class
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=103472">103472</a>
+[1.5][compiler] Should detect incompatible super interfaces
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=102650">102650</a>
+[ast rewrite] Removing all TYPE_PARAMETERS_PROPERTY values in a derived type gives incompilable code
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=103148">103148</a>
+[1.5][assist] Code completion breaks if using static method generics ( Class.&lt;T&gt;staticMethod(params) )
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=91426">91426</a>
+[Markers] Java task tags in Task View don't have configured priority
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=100772">100772</a>
+[1.5][search] Search for declarations in hierarchy reports to many matches
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=100695">100695</a>
+[1.5][search] Renaming a field of generic array type has no effect
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=103023">103023</a>
+[1.5][compiler] StackOverflow inferring type arguments
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=102778">102778</a>
+Scrapbook page doesn't work with enhanced for statement
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=101283">101283</a>
+[1.5][javadoc] Javadoc validation raises missing implementation in compiler
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=100868">100868</a>
+Code assist does not recommend methods in anonymous enum subclass
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=101456">101456</a>
+Proposals and Open Declaration fail with NPE
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=101387">101387</a>
+[1.5][compiler] Incorrect Cycle detected in type hierarchy error
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97326">97326</a>
+[dom] ITypeBinding#isFromSource() is always false for type variables, wildcards, and capture types
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=100153">100153</a>
+[1.5][compiler] Bound check failure on recursive formal bound
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=100808">100808</a>
+[assist] Wrong replace range for package proposals if there is no line termination
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=98532">98532</a>
+[1.5][compiler] Spurious 'type parameter T is hiding the type T' warning for static nested classes
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=100797">100797</a>
+editor general failure
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=100043">100043</a>
+[1.5][compiler] false compiler error on ?: ternary operator with boxing
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=102181">102181</a>
+[1.5][compiler] Generic varargs are built with incorrect array type
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=102305">102305</a>
+Error in JDT Core during reconcile
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=102213">102213</a>
+[1.5][compiler] enum constants cannot be referenced inside enum constants initializer
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=101955">101955</a>
+NullPointerException after invoking extract method
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97220">97220</a>
+Should not issue nls warning for annotation
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=101885">101885</a>
+[mode] sort operation doesn't set the RELATIVE_ORDER for enum constants
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=101247">101247</a>
+[formatter] Fails to format some labelled statements
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=101713">101713</a>
+[1.5][compiler] Access to static fields within enum constructors inconsistent with javac
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=101779">101779</a>
+[1.5][compiler] VerifyError using -- operator on unboxed generic Integer type
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=101208">101208</a>
+[compiler] instanceof check cannot be unnecessary on null values
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=100619">100619</a>
+[1.5][compiler] Incorrect duplicate bound diagnosis
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=94759">94759</a>
+[1.5][compiler] @Override doesn't report an error inside interface when specified for clone() method
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=98538">98538</a>
+[1.5][compiler] Inference broken for subtypes of subtypes of F-bounded types
+
+<a name="v_570"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.1RC4 - 27th June 2005 - 3.1 RELEASE (R3_1)
+<br>Project org.eclipse.jdt.core v_570
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_570">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=101453">101453</a>
+java.lang.UnsupportedOperationException: Operation only supported in JLS2 AST
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=101794">101794</a>
+[1.5][compiler] Compiling Classpath classes results in bad class file
+
+
+<a name="v_569"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.1RC4 - 24th June 2005 - 3.1 RELEASE (R3_1)
+<br>Project org.eclipse.jdt.core v_569
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_569">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=101613">101613</a>
+Performance regressions in Open Type Hierarchy performance test
+	
+
+<a name="v_568"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.1RC4 - 23rd June 2005
+<br>Project org.eclipse.jdt.core v_568
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_568">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=101426">101426</a>
+[search] Search doesn't work with imported plugin
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=101120">101120</a>
+Cannot generate an executable of the batch compiler using gcj 3.4.4
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=100631">100631</a>
+Internal compiler error in 3.1RC2
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=101230">101230</a>
+[compiler] Internal compiler error when labeled statement processing
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=101022">101022</a>
+[search] JUnit Test Runner on folder runs tests outside directory
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=101019">101019</a>
+RC3: Type Hierarchy does not find implementers/extenders of inner class/interface in other project 	
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=100009">100009</a>
+[assist] Content assist uses generic parameter name arg0 instead of real name
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=100584">100584</a>
+[1.5][dom] NPE when selecting a faulty member type following a generic type reference
+
+<a name="v_567"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.1RC3 - 17th June 2005 - 3.1 RELEASE CANDIDATE 3
+<br>Project org.eclipse.jdt.core v_567
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_567">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=100519">100519</a>
+[1.5][compiler] generic parameter and qualified access seems to confuse each other
+
+
+<a name="v_566"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.1RC3 - 16th June 2005
+<br>Project org.eclipse.jdt.core v_566
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_566">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=100421">100421</a>
+[1.5][compiler] chain of generics-extends confuse compiler
+
+
+<a name="v_565"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.1RC3 - 16th June 2005
+<br>Project org.eclipse.jdt.core v_565
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_565">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=99654">99654</a>
+[5.0] JavaModel returns both IClassFile and ICompilationUnit for package-info.java
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=100393">100393</a>
+Defaults for compiler errors/warnings settings
+
+<a name="v_564"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.1RC3 - 16th June 2005
+<br>Project org.eclipse.jdt.core v_564
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_564">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+<li>Fix for <a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=99606">bug 99606</a> required the index version to be incremented. 
+     Indexes will be automatically regenerated upon subsequent search queries (accounting for indexing notification in search progress dialogs).
+</li>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=100302">100302</a>
+StackOverflowError during completion
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=99606">99606</a>
+Subtype not found if parameterized on inner class
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=100293">100293</a>
+1.5 compiler - Methods using non-generic inner types of concreted generic classes generate wrong signatures
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=98322">98322</a>
+[compiler] ParameterizedTypeBinding should not have AccGenericSignature set when no type arguments
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=99978">99978</a>
+MalformedTreeException on Inline Method
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=100128">100128</a>
+[1.5][compiler] StackOverflow compiling GNU Classpath generics branch
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=100142">100142</a>
+CCE when calling ITypeBinding#getJavaElement() on char[][]
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=100147">100147</a>
+[1.5][compiler] NPE when reporting an error on an unsafe type conversion
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=100062">100062</a>
+[formatting] Code formatter is broken on test case from bug 99999
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=100162">100162</a>
+java.lang.VerifyError is produced by Eclipse Java compiler
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=99428">99428</a>
+[1.5][compiler] enum classes created without final accessFlag
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=99999">99999</a>
+[1.5][compiler] AIOOBE with generics + nested classes + arrays
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=99686">99686</a>
+IAE in Util#scanTypeBoundSignature
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=100149">100149</a>
+[1.5][compiler] Raw type upper bounds should be raw types
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=99927">99927</a>
+NPE in ParameterizedTypeBinding.initialize
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=100138">100138</a>
+[doc] Confusing documentation in Project Configuration tutorial
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=99915">99915</a>
+[search] Open Type: not yet saved types not found if case-sensitve name is entered
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=100007">100007</a>
+[1.5][compiler] ClassCastException using array object as generic type
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=99600">99600</a>
+[search] Java model exception on "Move to new file" on inner type with inner type
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=99982">99982</a>
+[DOM] Wrong positions for boolean[] type
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=99811">99811</a>
+NPE during content assist
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=99629">99629</a>
+Error while entering expression in change variable value dialog
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=99922">99922</a>
+[1.5][compiler] NPE in compiler for Arrays.asList(3, 3.1);
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=98378">98378</a>
+[search] Can't find declarations in hierarchy of interface.
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97614">97614</a>
+[1.5][search] Refactoring: renaming of field of a (complex) parametrized type does not replace all occurrences
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97547">97547</a>
+[search] Package search does not find references in member types import clause
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=96950">96950</a>
+[search] Code assist proposes non accessible types into completion
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=99510">99510</a>
+isCastCompatible seems to need capture bindings now to answer correct results
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=99608">99608</a>
+IMethodBinding#overrides returns false on overridden method
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=99901">99901</a>
+[select]  AIOOBE when selecting package reference in import statement
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=99282">99282</a>
+[1.5][compiler] Enum / Switch method is not initialized in a thread safe way
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=52921">52921</a>
+[formatting] Javadoc formatting: extra newline with [pre]
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=99507">99507</a>
+[javadoc] Infinit loop in DocCommentParser
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=99397">99397</a>
+Typo in CompletionProposal#isConstructor()
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=99553">99553</a>
+[1.5][compiler] Parameterized class nested statically inside another parameterized type causes compile errors when used in method signatures
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=99355">99355</a>
+extract method trips up with generics and final variables
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=99469">99469</a>
+[1.5][compiler] NPE compiling code with unknown annotations
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=99375">99375</a>
+Compiler error using Annotations
+
+<a name="v_563"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.1RC2 - 10th June 2005 - 3.1 RELEASE CANDIDATE 2
+<br>Project org.eclipse.jdt.core v_563
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_563">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=99260">99260</a>
+[1.5][compiler] Bad bytecode generated with varargs + generics
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=98331">98331</a>
+[1.5][compiler] Casting Conversion needs to check all supertypes for conflicts
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=99106">99106</a>
+[1.5][compiler] Ambiguous method error because methods don't override in eclipse
+
+
+<a name="v_562"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.1RC2 - 9th June 2005
+<br>Project org.eclipse.jdt.core v_562
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_562">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97487">97487</a>
+[call hierarchy] Call Hierarchy Fails in mounted classes with attached src files
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97524">97524</a>
+[prefs] Importing preferences with user library doesn't recreate jar entries
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=99142">99142</a>
+Exception when shutting down quickly after starting
+
+<a name="v_561"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.1RC2 - 9th June 2005
+<br>Project org.eclipse.jdt.core v_561
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_561">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+<li>The build state version number has changed. A full build of all projects in the workspace will be triggered upon
+      startup if autobuild is on, or on the next build if autobuild is off.</li>
+<li>The new list of supported warning tokens for the @SuppressWarnings annotation is:
+<ul>
+<li><b><font color="red">all</font></b> : any warning</li>
+<li><b>boxing</b> : autoboxing conversion</li>
+<li><b><font color="red">dep-ann</font></b> : missing @Deprecated annotation</li>
+<li><b><font color="red">deprecation</font></b> : deprecation outside deprecated code</li>
+<li><b>incomplete-switch</b> : incomplete enum switch (<i>enumSwitch</i>)</li>
+<li><b>hiding</b> : 
+<ol><li>field hiding another variable (<i>fieldHiding</i>)</li>
+<li>local variable hiding another variable (<i>localHiding</i>)</li>
+<li>type parameter hiding another type (<i>typeHiding</i>)</li>
+<li>hidden catch block (<i>maskedCatchBlock</i>)</li>
+</ol>
+</li>
+<li><b><font color="red">finally</font></b> : finally block not completing normally</li>
+<li><b>static-access</b> :
+<ol>
+<li>indirect reference to static member (<i>indirectStatic</i>)</li>
+<li>non-static reference to static member (<i>staticReceiver</i>)</li>
+</ol>
+</li>
+<li><b>nls</b> : string literal lacking non-nls tag //$NON-NLS-&lt;n&gt;$</li>
+<li><b><font color="red">serial</font></b> : missing serialVersionUID</li>
+<li><b>unqualified-field-access </b>: unqualified reference to field (<i>unQualifiedField</i>)</li>
+<li><b><font color="red">unchecked</font></b> : unchecked type operation</li>
+<li><b>unused</b> :
+<ol>
+<li>unread method parameter (<i>unusedArgument</i>)</li>
+<li>unread local variable (<i>unusedLocal</i>)</li>
+<li>unused private member declaration (<i>unusedPrivate</i>)</li>
+<li>unused declared thrown exception (<i>unusedThrown</i>)</li>
+</ol>
+</li>
+<li><b>synthetic-access</b> : synthetic access for innerclass (<i>syntheticAccess</i>)</li>
+</ul>
+<p>NOTE: <blockquote>All other warning tokens are not longer supported by @SuppressWarnings;
+considering that for some diagnosis, it is simpler to just fix the code than silence some warning.
+In <i>Italic</i> the old warning token is specified.
+<br>Warning tokens also supported by javac are in <font color="red">red</font> (also see <a href="http://www.javac.info/doc?n=JavaCompiler.WarningTokens">declared warning tokens</a>).
+</blockquote></p>
+</li>
+<li>CodeAssist: added a new API CompletionProposal#isConstructor() to distinguish method and constructor proposal</li>
+<li>Access rules file patterns have been changed to ignore the file extension. This allow easy switching from a source project
+     to a binary project. Thus <code>"com/test/X.java"</code> is now an invalid access rule pattern, and 
+     <code>"com/test/X"</code> is a valid access rule pattern.</li>
+<li>
+Following batch compiler options default value have been changed from "ignore" to "warning":
+<ul>
+<li>unusedLocal (unread local variable)</li>
+<li>unusedPrivate (unused private member declaration)</li>
+<li>fieldHiding (field hiding another variable)</li>
+<li>localHiding (local variable hiding another variable)</li>
+</ul>
+(see bug <a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=76530">76530</a>)
+</li>
+<li>Compiler optional diagnosis for unused private members got generalized to also flag unused
+members of local types.
+</li>
+<li>Compiler no longer reports as unchecked the situation where a method of a raw type is invoked,
+and only the return type got altered by raw conversion (also see bug <a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=85815">85815</a>). 
+This change is motivated to better match the language spec 3rd edition.</li>
+<li>Fix for <a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97087">bug 97087</a> required the index version to be incremented. 
+     Indexes will be automatically regenerated upon subsequent search queries (accounting for indexing notification in search progress dialogs).
+</li>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=99138">99138</a>
+NPE in RawTypeBinding.computeUniqueKey(..) for raw type inside anonymous parameterized type
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93975">93975</a>
+[1.5][syntax] Poor recovery when extra semicolon in annotation
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93208">93208</a>
+[dom] CompilationUnit.rewrite throws AssertionFailedException with legal AST (bug in recoding ast modifications)
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97440">97440</a>
+[1.5][compiler] StackOverflow compiling heavily generic code
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=99104">99104</a>
+Startup job displayed as "Initializing the Java d...ent tooling"
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=99084">99084</a>
+Formatter error when generic method has an argument
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=98892">98892</a>
+[compiler] Eclipse compiler generates code that calls the finally block twice
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=98969">98969</a>
+Builder didn't find state for prereq project
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=96586">96586</a>
+[1.5][compiler] Invalid cycle detected
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=98954">98954</a>
+Javadoc of ITypeBinding#getErasure() is wrong for array types
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=98504">98504</a>
+[1.5][compiler] Compiler difference between javac and jdt?
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=96763">96763</a>
+[1.5][search] Search for method declarations does not find overridden method with different signature
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=96761">96761</a>
+[1.5][search] Search for declarations of generic method finds non-overriding method
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=98228">98228</a>
+[1.5][compiler] regression - incorrect handling of generics
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=98720">98720</a>
+[preferences] classpath variables are not exported if the session is closed and restored
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=98906">98906</a>
+No rebuild after upgrade
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=98711">98711</a>
+no way to distinguish constructor from method proposals
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=98434">98434</a>
+A non-1.5 project with 1.5 projects in the classpath does not show methods with generics
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=98750">98750</a>
+[dom] Java DOM Parser finding syntax Problems when parsing Annotations
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=90619">90619</a>
+[1.5][compiler] Cannot implement generified interface with erased method
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=98500">98500</a>
+[1.5] Internal compiler error
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=98488">98488</a>
+NPE while computing a key for a paramterized type binding
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97087">97087</a>
+[1.5][search] Can't find reference of generic class's constructor.
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93668">93668</a>
+Search indexes not rebuild
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=98473">98473</a>
+AST binding: type variable reports as 'isTopLevel'
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=98364">98364</a>
+[1.5][compiler] Compiler allowing invalid generic interface inheritance
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=85815">85815</a>
+[1.5] warn when raw iterator is used
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93377">93377</a>
+[1.5][compiler] Multiple auto-build failures when using generics
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=79309">79309</a>
+Nested interfaces aren't resolved correctly in import (with "Open Declaration" / F3)
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=96765">96765</a>
+Code completion does not work in enum constants
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=98483">98483</a>
+IMethodBinding.override does not compare method names
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=98115">98115</a>
+Field completion failed to propose a field declared into an innerclass
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93789">93789</a>
+[1.5][compiler] Compiler incorrectly allows static declarations in enum constants.
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=98396">98396</a>
+[1.5][compiler] Casting Conversion ignores second bound of Type Variables
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=98383">98383</a>
+[1.5][compiler] ClassCastException attempting to cast from intersection type
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97322">97322</a>
+[search] Search for method references sometimes reports potential match with differing argument count
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=94160">94160</a>
+[1.5][search] Generic method in superclass does not exist
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=91061">91061</a>
+[1.5][compiler] Static reference to outer type variable should not be allowed
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97108">97108</a>
+[1.5][compiler] NullPointerException encountered while running Java Builder
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=98259">98259</a>
+NPE computing ITypeBinding#getKey()
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93536">93536</a>
+[1.5] Internal compiler generating error on code that javac accepts
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97606">97606</a>
+[1.5][search] Raw type reference is reported as exact match for qualified names
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=96424">96424</a>
+[search] SearchParticipant sets containerPath to documentPath
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97542">97542</a>
+ASTParser#createASTs does not correctly resolve bindings in working copies
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=94898">94898</a>
+[1.5] errors in ambiguous method invocation detection
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=94754">94754</a>
+[1.5][compiler] Ambiguous method call is not detected
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=84035">84035</a>
+[1.5][compiler] Ambiguous method call
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=76530">76530</a>
+[options] Warn about unused local variables and private members
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=98091">98091</a>
+[1.5][compiler] @SuppressWarnings("assertIdentifier") cannot be applied
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=94907">94907</a>
+[assist] missing keyword completions for generic signatures
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=84001">84001</a>
+[select] Renaming of class with internal classes fails.
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=94641">94641</a>
+Code assist does not display parameters for constructor with type parameters
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=96991">96991</a>
+[1.5][compiler] Annotation attribute should be able to reference field
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=96713">96713</a>
+[1.5][compiler] Inconsistency with Sun JDK
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=95684">95684</a>
+[1.5][compiler] Type handling on concrete inner class of super class is incorrect
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97273">97273</a>
+Illegal argument exception in Signature#getTypeSignatureKind
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=98165">98165</a>
+Wrong source range for ConditionalExpression with casted target in FieldAccess as expression
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=96085">96085</a>
+[1.5][compiler] problems with inner classes and generics
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=98139">98139</a>
+Java Code Formatter is severely confused by following code
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=98079">98079</a>
+[1.5][compiler] incorrect Bound mismatch compilation error
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97860">97860</a>
+[1.5][assist] All current proposals while completing after a type parameter results in a compiler error
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=82560">82560</a>
+[assist] Completion fails on parameterized generic method call
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=98086">98086</a>
+[1.5][dom] CU still have problems even with @SuppressWarnings("all")
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=98037">98037</a>
+[Java Editor Templates] Templates with multiple lines are inlined when used
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=96258">96258</a>
+Bogus build path errors caused by multiple project import
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97902">97902</a>
+NPE on Open Declaration on reference to generic type
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=80432">80432</a>
+Code Assist box exhibits strange behavior in an endless for loop
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=96944">96944</a>
+[1.5][assist] shoud not suggest type parameters after new
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97801">97801</a>
+[1.5][codeassist] The type of the class literal must be parameterized
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=85384">85384</a>
+[1.5][assist] "extends" not proposed when writing method declarations
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97219">97219</a>
+[1.5] eclipse does not detect ambiguous method invocation errors
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97744">97744</a>
+[compiler][ant adapter] NPE when verbose = true and destDir not specified
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97480">97480</a>
+[1.5][compiler] incorrect error on some calls to raw Map.Entry.setValue
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97809">97809</a>
+Ambiguous method reference wrongly reported
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97814">97814</a>
+Incorrect resolved information on hover
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97841">97841</a>
+[1.5][dom] null binding for ClassInstanceCreation
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=90916">90916</a>
+CCE in SourceTypeConverter
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97466">97466</a>
+NPE in SourceTypeConverter
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97307">97307</a>
+[5.0][typing] completion for "import static" deletes all source before
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97459">97459</a>
+CCE during reconcile and AST creation
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97800">97800</a>
+[1.5][compiler] Cast type shouldn't be used in generic method argument inference
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=95349">95349</a>
+Access rule pattern matching should ignore file extension
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97161">97161</a>
+[1.5][compiler] Internal compiler error java.lang.NullPointerException
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97303">97303</a>
+[1.5][compiler] Cannot convert when inferring list of inner parameterized type
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97272">97272</a>
+Export preferences offers "all" button, does not export classpath variables
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=96794">96794</a>
+Polishing disassembler output
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97275">97275</a>
+method reference should not contain type variable anymore
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97187">97187</a>
+[rendering] Shows Single Char for primitve Types
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=96918">96918</a>
+Code Assist - suggest extends and super in the context of a wildcard type argument
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97190">97190</a>
+Incorrect handling of large long values
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97247">97247</a>
+ArrayIndexOutOfBoundsException in ClassFile.addSyntheticSwitchTable
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=76155">76155</a>
+[options] Unused code warning for unused methods in anonymous inner classes
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97224">97224</a>
+[polish][compiler] Inconsistent error message for non-visible field
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=95481">95481</a>
+[1.5] NPE in TypeVariableBinding.checkBounds
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=65748">65748</a>
+[type hierarchy] Hierarchy view fails to pick up class modifier change
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=96633">96633</a>
+getJavaElement returns null for Object[] array binding
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=96605">96605</a>
+JDTCompilerAdapter should allow a log without all verbose information
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=96858">96858</a>
+IllegalArgumentException in Signature
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97164">97164</a>
+classpath variables lost when upgrading from M7 to RC1
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=97139">97139</a>
+eclipse 3.1RC1 compiler crash for project
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=96974">96974</a>
+[5.0] @SuppressWarnings({"nls"}) does not work for unexternalized strings
+
+<a name="v_560"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.1RC1 - 26th May 2005 - 3.1 RELEASE CANDIDATE 1
+<br>Project org.eclipse.jdt.core v_560
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_560">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=96646">96646</a>
+[1.5][compiler] VerifyError - Generics and Interfaces - "Wrong return type in function"
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=96631">96631</a>
+NPE in Annotation on empty ArrayInitializer
+
+
+<a name="v_559"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.1RC1 - 26th May 2005
+<br>Project org.eclipse.jdt.core v_559
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_559">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=95638">95638</a>
+[1.5][compiler] Possibly incorrect Bounds Mismatch errors for complicated bounds
+
+
+<a name="v_558"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.1RC1 - 26th May 2005
+<br>Project org.eclipse.jdt.core v_558
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_558">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+<li>The Code Assist option CODEASSIST_HIDE_RESTRICTED_REFERENCES is replaced by
+CODEASSIST_FORBIDDEN_REFERENCE_CHECK and CODEASSIST_DISCOURAGED_REFERENCE_CHECK
+(see bug <a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=94403">94403</a>).
+</li>
+<li> Code Assist suggest all member types when completion token is a single name.
+<pre>
+Y&lt;complete here&gt; // p.q.X.Y is proposed.
+</pre>
+As all member types are proposed, code assist does not propose types of the wrong kind.
+Only classes are proposed inside an extends clause, only interfaces inside an implements clause
+and only annotations in annotation reference (It was necessary before to be able to propose
+a top level type which contains these types).<br>
+Note: To re-enabled quickly the old behaviors, change the value of Completion.PROPOSE_MEMBER_TYPES.
+</li>
+<li>Added API <code>JavaCore#initializeAfterLoad(IProgressMonitor)</code> to allow
+	 a client to force the initialization of internal structures.
+</li>
+<li>Default value for <code>COMPILER_PB_MISSING_JAVADOC_COMMENTS_OVERRIDING</code> and
+	<code>COMPILER_PB_MISSING_JAVADOC_TAGS_OVERRIDING</code> JavaCore options have been changed from "enabled" to "disabled".<br>
+	(see bug <a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=96270">96270</a>).
+</li>
+<li>Fix for <a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=75816">bug 75816</a> required the index version to be incremented. 
+     Indexes will be automatically regenerated upon subsequent search queries (accounting for indexing notification in search progress dialogs).
+</li>
+<li>
+Duplicate names are not allowed in classpath entry extra attributes.<br>
+Javadoc comment of each <code>JavaCore.new*Entry</code> method have been updated to clearly specify this behavior:
+<pre>
+ * The <code>extraAttributes</code> list contains name/value pairs that must be persisted with
+ * this entry. If no extra attributes are provided, an empty array must be passed in.
+ * Note that this list should not contain any duplicate name.
+</pre>
+<code>JavaConventions.validateClasspathEntry(IJavaProject,IClasspathEntry,boolean,boolean)</code> has been modified
+to verify this point. It now returns an invalid status (<code>new IJavaStatus(IJavaModelStatusConstants.NAME_COLLISION,...)</code>)
+when duplicate names are found in extra attributes.
+</li>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93119">93119</a>
+code assist: proposals for wildcard types
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=95505">95505</a>
+Can not use code completion
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=96698">96698</a>
+org.eclipse.jdt.core.dom.VariableBinding.getUnresolvedJavaElement produce ClassCastException
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=88364">88364</a>
+compiler options
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=94267">94267</a>
+[1.5][select] Selecting type parameter in binary answer match on line 0
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=96642">96642</a>
+CCE in SourceMapper.computeAllRootPaths(..)
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=87362">87362</a>
+BindingKey#internalToSignature() should return the field's type signature
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=94404">94404</a>
+[model] Disallow classpath attributes with same key
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=92398">92398</a>
+[compiler] Leverage access rule support in batch compiler
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=96588">96588</a>
+Rename Signature#removeCaptureFromMethod(...) to removeCaptureFrom(..)
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=96410">96410</a>
+Incorrect information in selection resolved key
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=75816">75816</a>
+[search] Call Hierarchy does not find calls to the constructor of java.util.HashMap.Entry [call hierarchy]
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=95167">95167</a>
+[content assist] Spurious "Access restriction" error during code assist
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=95580">95580</a>
+CreateField on IType doesn't work if the type is an enum type that has enum constants
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=95963">95963</a>
+(3.1M7) Compiler error when parameterizing with missing inner type.
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=96134">96134</a>
+Internal error for odd (probably illegal) class declaration
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=96464">96464</a>
+[assist] JavaCorePreferenceInitializer does not initialized CODEASSIST_DISCOURAGED_REFERENCE_CHECK
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=96414">96414</a>
+Javadoc of ASTParser#setCompilerOptions(..): mention that setProject(..) resets options
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=95933">95933</a>
+Refining a generic method causes AbstractMethodError
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=94897">94897</a>
+[1.5] Compiler does not reject class with two erasure-equivalent methods
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=96213">96213</a>
+Eclipse 3.1M7 - Field completion stack overflow
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=96401">96401</a>
+jdt.core tests pass, but fill the .log
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=96439">96439</a>
+Hierarchy not refreshed if adding a dependent project
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=82852">82852</a>
+"Searching for errors in &lt;project&gt;" running unit tests from package
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=95154">95154</a>
+Missing package.html files for API packages
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=96387">96387</a>
+Schemas for extension points are inaccurate
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93249">93249</a>
+Code assist doesn't propose full method stub
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=94878">94878</a>
+Configuration details is large, containing many prefs for PDE and JDT classpath containers
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=96270">96270</a>
+[javadoc] Missing Javadoc comment: 'check overriding..' should be 'off' by default
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=96300">96300</a>
+Use the line separator platform preference for new files
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=94303">94303</a>
+import static adds annoying semicolon
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=83716">83716</a>
+[search] refs to 2-arg constructor on Action found unexpected matches
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=96071">96071</a>
+Javadoc for IJavaProject.findType(String ) is not consistant
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=94903">94903</a>
+Error setting method breakpoint in 1.5 project
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=88395">88395</a>
+[1.5][compiler] Binary compat problem with enum/switch codegen
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=95727">95727</a>
+ITypeBinding#getJavaElement() returns a ResolvedSourceField for an anonymous class
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=95909">95909</a>
+Error with static import
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=95794">95794</a>
+[1.5][search] Search for all occurrences does not find references in static imports
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=95911">95911</a>
+[5.0][dom] Wrong node range for variable declaration fragment containing anonymous class declaration
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93941">93941</a>
+Classpath initialization on shutdown
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93731">93731</a>
+JDT core job still running after shutdown.
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=89849">89849</a>
+[1.5][assist] Completion in switch proposes already written enum constants
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=91670">91670</a>
+package-info.java is not being correctly compiled
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93880">93880</a>
+[1.5][javadoc] Source range of PackageDeclaration does not include Javadoc child
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93254">93254</a>
+[assist] ClassCastException when complete annotation type ref
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=95760">95760</a>
+[1.5][search] MatchLocator does not compile against 5.0 JRE
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93668">93668</a>
+Search indexes not rebuild
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=95748">95748</a>
+SourceMapper should not write timing info to stdout
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=92555">92555</a>
+Code assist in Annotations suggests non-annotations
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=92733">92733</a>
+[assist] Classes suggested in implements clause
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=94965">94965</a>
+[assist] code assist should suggest inner types
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=92937">92937</a>
+Need API: JavaCore#initializeAfterLoad()
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=90215">90215</a>
+[1.5] Enums implementing generic interfaces can compile incorrectly.
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=95244">95244</a>
+performance optimization in SourceMapper.computeAllRootPaths
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=91615">91615</a>
+Wrong class opened by debugger/"Open Type"
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=39856">39856</a>
+External jar's timestamps should be persisted accross sessions
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=89632">89632</a>
+Exception when trying to evaluate in Snippet Editor
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=95538">95538</a>
+Operation not supported in JLS2 AST from resolving MethodBinding
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=95521">95521</a>
+[1.5][javadoc] validation with @see tag not working for generic method
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=95286">95286</a>
+[1.5][javadoc] package-info.java incorrectly flags "Missing comment for public declaration"
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=95388">95388</a>
+[code manipulation] NPE sorting members
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=94150">94150</a>
+[1.5][javadoc][enum] javadoc is always null for EnumConstantDeclaration
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=94653">94653</a>
+[1.5][select] Selection on invalid raw member type should still surface raw type
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=94092">94092</a>
+ASTParser#createASTs(..) restores wrong bindings from capture keys
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=88719">88719</a>
+UserLibrary.serialize /createFromString need support for access restriction / attributes
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=89937">89937</a>
+[1.5][compiler] Annotation attribute should not be able to reference field
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93891">93891</a>
+Restricted UIPlugin is in my code assist
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93905">93905</a>
+Batch compiler - add a timestamp to log files
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=95262">95262</a>
+ASTParser fails with K_CLASS_BODY_DECLARATIONS
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=95211">95211</a>
+[api] stale J2SE5 comment in IDOMImport
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=95431">95431</a>
+Code formatter fails to format this code
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=95394">95394</a>
+Problem resolving types for Assignment ("+=") on 3.1M7
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=83034">83034</a>
+[1.5][compiler] method on A&lt;D,?&gt; not applicable for argument &lt;?&gt;
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=87550">87550</a>
+[1.5] [compiler] The method in the type is not applicable for the arguments
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=95021">95021</a>
+[1.5][compiler] incorrectly inferred method type parameters bug in 3.1M6?
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=91588">91588</a>
+Delete CVS project and then add as source project leads to duplicate Open Type entries
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=73969">73969</a>
+Full build on startup
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=80118">80118</a>
+[search] OutOfMemoryError while searching for Test class
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=87749">87749</a>
+different IMethodBindings of generic method have equal getKey()
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=94398">94398</a>
+Error attempting to find References
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93408">93408</a>
+ITypeBinding#isEqualTo(..) does not resolve type variables
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=94389">94389</a>
+[search] InvocationTargetException on Rename
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=79990">79990</a>
+[1.5][search] Search for method declaration doesn't find method with instantiated type parameters
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=95066">95066</a>
+[1.5][compiler] Wrong Cast Allowed
+
+
+<a name="v_557"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.1M7 - 12th May 2005 - 3.1 MILESTONE 7 / 3.1 RELEASE CANDIDATE 0
+<br>Project org.eclipse.jdt.core v_557
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_557">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=94308">94308</a>
+[1.5][compiler] @SuppressWarnings("deprecation") does not suppress warnings from javadoc
+
+
+<a name="v_556"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.1M7 - 12th May 2005
+<br>Project org.eclipse.jdt.core v_556
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_556">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+<li> Enabled by default the optional compiler diagnosis to signal unhandled warning tokens in <code>@SuppressWarnings</code> annotations.
+Note that this warning can itself be turned off using @SuppressWarnings("warningToken").
+<pre>
+* COMPILER / Reporting Unhandled Warning Token for @SuppressWarnings
+*    When enabled, the compiler will issue an error or a warning when encountering a token
+*    it cannot handle inside a @SuppressWarnings annotation.
+*     - option id:         "org.eclipse.jdt.core.compiler.problem.unhandledWarningToken"
+*     - possible values:   { "error", "warning", "ignore" }
+*     - default:           "warning"
+</pre>
+</li>
+<li>Fix for <a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=94718">bug 94718</a> required the index version to be incremented. 
+     Indexes will be automatically regenerated upon subsequent search queries (accounting for indexing notification in search progress dialogs).
+</li>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=94928">94928</a>
+[1.5][compiler] NPE in ParameterizedGenericMethodBinding generated by making method generic
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93727">93727</a>
+Code Formatter fails with Method Parameter Annotations
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93075">93075</a>
+Invalid source ranges for nested ParameterizedTypes
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=92360">92360</a>
+type binding with isWildcardType() == true should not have isClass() == true
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=94168">94168</a>
+Java annotation is missing in EnumConstantDeclaration
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=94867">94867</a>
+[1.5][compiler] Annotation method should tolerate empty array default value
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=94747">94747</a>
+[1.5][compiler] Error message is not optimal
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=94718">94718</a>
+[1.5][search][annot] Find references in workspace breaks on an annotation
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=94644">94644</a>
+[1.5][compiler] Non-static member type of raw type should be raw
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=94206">94206</a>
+CCE in BindingKeyResolver when restoring array type of method type parameter
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=94260">94260</a>
+[Preferences] preference option missing in Compiler Settings
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=94262">94262</a>
+[1.5] non static class must not be visible through static import
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93904">93904</a>
+Batch compiler -log option broken for some values
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=87627">87627</a>
+[1.5][search] references to type variable yield non-existent elements in search view
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93588">93588</a>
+[compiler] java.lang.VerifyError: Looks similar to 60040 but is happening on current release
+
+
+<a name="v_555"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.1M7 - 9th May 2005
+<br>Project org.eclipse.jdt.core v_555
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_555">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+<li> Code Assist provide the enclosing type reference when cursor is inside a type argument
+and the completion token is empty (in the same way as method calls).
+<pre>
+p.q.X&lt;&lt;complete here&gt;&gt; // p.q.X&lt;T,U&gt; is proposed.
+p.q.X&lt;Object, &lt;complete here&gt;&gt; //p.q.X&lt;T,U&gt; is proposed
+</pre>
+</li>
+<li> Code Assist provide the enclosing annotation reference when completion is inside an annotation argument
+and the completion token is empty (in the same way as method calls).
+<pre>
+@Annot(&lt;complete here&gt;) // p.Annot is proposed.
+@Annot(foo1=0, &lt;complete here&gt;) // p.Annot is proposed.
+</pre>
+</li>
+<li> In 5.0 compliant mode, changed local inner type naming convention to reflect JLS 13.1 (3rd edition).
+As a consequence, instead of generating a file named <code>X$1$A.class</code>, it will simply be <code>X$1A.class"</code>.
+</li>
+<li> Added optional compiler diagnosis to signal unhandled warning tokens in <code>@SuppressWarnings</code> annotations.
+Note that this warning can itself be turned off using @SuppressWarnings("warningToken").
+<pre>
+* COMPILER / Reporting Unhandled Warning Token for @SuppressWarnings
+*    When enabled, the compiler will issue an error or a warning when encountering a token
+*    it cannot handle inside a @SuppressWarnings annotation.
+*     - option id:         "org.eclipse.jdt.core.compiler.problem.unhandledWarningToken"
+*     - possible values:   { "error", "warning", "ignore" }
+*     - default:           "ignore"
+</pre>
+</li>
+<li> Added compiler option to control whether @SuppressWarning annotations are active or not.
+By disabling them, one can quickly revive all hidden warnings.
+<pre>
+* COMPILER / Determine whether @SuppressWarnings is effective
+*    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" }
+*     - default:           "enabled"
+</pre>
+</li>
+<li> Added API on <code>CorrectionEngine</code> for computing the warning token corresponding to an optional warning ID.
+<pre>
+/**
+ * Returns a token which can be used to suppress a given warning using 
+ * <code>@SuppressWarnings</code> annotation, for a given problem ID 
+ * ({@link IProblem }). If a particular problem is not suppressable, 
+ * <code>null</code> will be returned. 
+ * 
+ * Note: <code>@SuppressWarnings</code> can only suppress warnings, 
+ * which means that if some problems got promoted to ERROR using custom compiler 
+ * settings ({@link IJavaProject#setOption(String, String)}), the 
+ * <code>@SuppressWarnings</code> annotation will be ineffective.
+ * 
+ * Note: <code>@SuppressWarnings</code> can be argumented with 
+ * <code>"all"</code> so as to suppress all possible warnings at once.
+ * 
+ * Note: The tokens returned are not necessarily standardized across Java 
+ * compilers. If you were to use one of these tokens in an @SuppressWarnings 
+ * annotation in the Java source code, the effects (if any) may vary from 
+ * compiler to compiler.
+ * 
+ * @param problemID
+ *         the ID of a given warning to suppress
+ * @return a String which can be used in <code>@SuppressWarnings</code> annotation, 
+ * or <code>null</code> if unable to suppress this warning.
+ * @since 3.1
+ */
+public static String getWarningToken(int problemID)
+</pre>
+</li>
+<li>More warning tokens are now recognized by <code>@SuppressWarnings</code>, see list below. Note that
+these are subject to changing in the near future.
+  <ul>
+     <li>all : any warning</li>
+     <li>boxing : autoboxing conversion</li>
+     <li>charConcat : char[] in String concat</li>
+     <li>conditionAssign : possible accidental boolean assignment</li>
+     <li>constructorName : method with constructor name</li>
+     <li>dep-ann : missing @Deprecated annotation</li>
+     <li>deprecation : deprecation outside deprecated code</li>
+     <li>emptyBlock : undocumented empty block</li>
+     <li>enumSwitch : incomplete enum switch</li>
+     <li>fieldHiding : field hiding another variable</li>
+     <li>finalBound : type parameter with final bound</li>
+     <li>finally : finally block not completing normally</li>
+     <li>indirectStatic : indirect reference to static member</li>
+     <li>intfAnnotation : annotation type used as super interface</li>
+     <li>intfNonInherited : interface non-inherited method compatibility</li>
+     <li>javadoc : invalid javadoc</li>
+     <li>localHiding : local variable hiding another variable</li>
+     <li>maskedCatchBlock : hidden catch block</li>
+     <li>nls : string literal lacking non-nls tag //$NON-NLS-&lt;n&gt;$</li>
+     <li>noEffectAssign : assignment without effect</li>
+     <li>over-ann : missing @Override annotation</li>
+     <li>pkgDefaultMethod : attempt to override package-default method</li>
+     <li>semicolon : unnecessary semicolon, empty statement</li>
+     <li>serial : missing serialVersionUID</li>
+     <li>unqualifiedField : unqualified reference to field</li>
+     <li>unchecked : unchecked type operation</li>
+     <li>unusedArgument : unread method parameter</li>
+     <li>unusedImport : unused import declaration</li>
+     <li>unusedLocal : unread local variable</li>
+     <li>unusedPrivate : unused private member declaration</li>
+     <li>unusedThrown : unused declared thrown exception</li>
+     <li>unnecessaryElse : unnecessary else clause</li>
+     <li>uselessTypeCheck : unnecessary cast/instanceof operation</li>
+     <li>specialParamHiding : constructor or setter parameter hiding another field</li>
+     <li>staticReceiver : non-static reference to static member</li>
+     <li>syntheticAccess : synthetic access for innerclass</li>
+     <li>typeHiding : type parameter hiding another type</li>
+     <li>varargsCast : varargs argument need explicit cast</li>
+     <li>warningToken : unhandled warning token</li>
+  </ul>
+</li>
+<li>
+SearchMatch now has a implicit field which shows whether the associated element is implicit or not
+(see bug <a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=94062">94062</a>).<br>
+Added new API methods to access this field:
+<ul>
+<li><code>SearchMatch#isImplicit()</code><br></li>
+<li><code>SearchMatch#setImplicit(boolean)</code></li>
+</ul>
+</li>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=94053">94053</a>
+[javadoc] Unknown references are not warned for string or href in @see/@link tags
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=94111">94111</a>
+[assist] provide parameter hints for template instantiations
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=94062">94062</a>
+[1.5][search][annot] search for annotation elements incorrect match range
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93392">93392</a>
+[1.5][search] Reference to implicit annotation element "value" has wrong offset
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=84968">84968</a>
+[1.5][generics] Exception type handling broken in latest milestone
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=75885">75885</a>
+[1.5][compiler] Naming convention for local innerclasses
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=89426">89426</a>
+provide Java class file content type
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93826">93826</a>
+ArrayIndexOutOfBoundsException when opening type hierarchy
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=83739">83739</a>
+[1.5] support @SuppressWarnings
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=89850">89850</a>
+Duplicate strings of VM path
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=83750">83750</a>
+[perf] Excessive File.isFile calls for clients of JavaModel.getTarget(...)
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=92210">92210</a>
+[search] Search for method declaration in working set (source folder) searches in whole project
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93913">93913</a>
+wrong resolved type caused by a static import
+
+
+<a name="v_554"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.1M7 - 6th May 2005
+<br>Project org.eclipse.jdt.core v_554
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_554">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+<li>Code Assist doesn't propose anymore type completion when completion token is empty.<br>
+Note: the code to propose completion when token is empty is not removed.
+Change the value of Completion.NO_TYPE_COMPLETION_ON_EMPTY_TOKEN to re-enabled this behavior.
+</li>
+<li>@SuppressWarnings is now supported. Recognized warning names are: <code>"all"</code>, <code>"deprecation"</code>,
+<code>"serial"</code>, <code>"unchecked"</code>, <code>"finally"</code>.
+</li>
+<li>Changed Code Assist options.<br>
+    CODEASSIST_FORBIDDEN_REFERENCE_CHECK and CODEASSIST_DISCOURAGED_REFERENCE_CHECK are replaced by CODEASSIST_HIDE_RESTRICTED_REFERENCES.<br>
+    <pre>
+/*
+ *  CODEASSIST / Hide Proposals for Restricted Completions
+ *    When value is "never", never hide proposals for restricted completions.
+ *    When value is "error", hide proposals for restricted completions if insertion of these completions would create a compile error.
+ *    When value is "warning", hide proposals for restricted completions if insertion of these completions would create a compile error or warning.
+ *    To configure the severity of restrictions, "org.eclipse.jdt.core.compiler.problem.forbiddenReference"
+ *    option must be used for forbidden reference and "org.eclipse.jdt.core.compiler.problem.discouragedReference"
+ *    option must be used for discouraged reference.
+ *     - option id:         "org.eclipse.jdt.core.codeComplete.restrictionsCheck"
+ *     - possible values:   { "never", "error", "warning" }
+ *     - default:           "error"
+ */
+ public static final String CODEASSIST_HIDE_RESTRICTED_REFERENCES;
+    </pre></li>
+<li>Removed 3.1 APIs <code>BindingKey#getDeclaringTypeSignature()</code> and
+    <code>BindingKey#toSignature()</code> as they were found error prone. See <a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93105">bug 93105</a>
+    for details.</li>
+<li>Added support for 'capture' inside Code Assist. Delaring type of a completion proposal is captured for qualified completion.</li>
+<li>Added APIs to replace a range of moved nodes (<code>ListRewrite#createMoveTarget(first, last, replacingNode, editGroup)</code>). 
+    See <a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=91938">bug 91938</a> for details.
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93854">93854</a>
+IAE in Util.scanTypeSignature when scanning a signature retrieved from a binding key
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93662">93662</a>
+Singature#getTypeParameters returns strange signature string
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93113">93113</a>
+Opening the Type Hierarchy of Object uses 400M of heap
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=92071">92071</a>
+Duplicate entry on classpath with -promiscuous mode
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93486">93486</a>
+[compiler] Wrong compile errors reported
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93487">93487</a>
+IType#findMethods fails on vararg methods
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=90186">90186</a>
+resolved key of methods should contain parametrized types
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=88082">88082</a>
+ASTParser#createASTs(..) does not use the given progress monitor
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=90612">90612</a>
+Forbidden types must not be available in Code Assist
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93105">93105</a>
+Remove unnecessary APIs on BindingKey
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93396">93396</a>
+[1.5] problem with recovery and enum constant body
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=92899">92899</a>
+Empty extra attributes list should not appear in .classpath
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93275">93275</a>
+Need ITypeBinding#getDeclaringClass() for capture types
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93298">93298</a>
+[1.5][compiler] nested statics and templates compilation error
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=92477">92477</a>
+[1.5][compiler] Internal compiler error: NullPointerException in ReferenceBinding.findSuperTypeErasingTo
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=83083">83083</a>
+[1.5][compiler] NPE while checking bounds of type variable
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93204">93204</a>
+[1.5][compiler] EnumSet.of within generic class
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=90775">90775</a>
+[1.5][compiler] Missing unchecked warning
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=88202">88202</a>
+Javadoc: clarify ITypeBinding#getTypeBounds()
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93093">93093</a>
+[1.5][dom] Capture binding "? extends Number[]" has bound Object instead of Number[]
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93102">93102</a>
+[1.5] Cannot restore capture binding from binding key
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=93082">93082</a>
+[1.5][compiler] Eclipse accepts assignment between captures with array-type bounds
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=91467">91467</a>
+[1.5][compiler] Eclipse asks for and then complains about unnecessary cast
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=92982">92982</a>
+[1.5][compiler] Bounds and erasure of capture and type variable bindings
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=84690">84690</a>
+[assist] CompletionProposal.getDeclarationSignature returns null for array types
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=92821">92821</a>
+[javadoc] Organize Imports - M6 - incorrectly retains import when only referered to in javadoc
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=91542">91542</a>
+[1.5][search] JavaModelException on ResolvedSourceMethod during refactoring
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=92981">92981</a>
+Content Assist overrides wrong method
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=91619">91619</a>
+Extraneous exported package
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=92872">92872</a>
+[api] API constants renamed in IProblem
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=92888">92888</a>
+ITypeBinding#isEqualTo(..) is wrong for capture bindings
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=84224">84224</a>
+Need advice for finding duplicate Types
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=92944">92944</a>
+[1.5][search] SearchEngine#searchAllTypeNames doesn't honor enum or annotation element kind
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=91078">91078</a>
+[search] Java search for package reference wrongly identifies inner class as package
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=92005">92005</a>
+AIOBE during content assist
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=67139">67139</a>
+[classpath] n^2 classpath computations
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=80063">80063</a>
+code assist allows overriding super class' private method
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=82208">82208</a>
+[search] BasicSearchEngine#searchAllTypeNames doc
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=3336">3336</a>
+SearchEngine doesn't support CLASS and INTERFACE (1GIEPRK)
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=90160">90160</a>
+[search] SearchEngine.createJavaSearchScope swallows problems
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=88174">88174</a>
+[1.5][search][enum] method declarations not found in anonymous enum
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=91938">91938</a>
+[ast rewrite] new API: move range of nodes and replace
+
+<a name="v_553"></a>
+<p><hr><h1>
+Eclipse Platform Build Notes&nbsp;<br>
+Java Development Tooling Core</h1>
+Eclipse SDK 3.1M7 - 26th April 2005
+<br>Project org.eclipse.jdt.core v_553
+(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_553">cvs</a>).
+<h2>
+What's new in this drop</h2>
+<ul>
+<li>Removed the need to load <code>java.lang.RuntimeException</code> and <code>java.lang.Error</code> eagerly
+during compilation when assessing unchecked exception diagnosis. This allows Java class library developpers to be 
+more minimalistic.
+</li>
+<li>Fix for <a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=83230">bug 83230</a> required the index version to be incremented. 
+     Indexes will be automatically regenerated upon subsequent search queries (accounting for indexing notification in search progress dialogs).
+</li>
+<li>Added support for Javadoc in package-info.java. Compiler now verifies package comment tags
+syntax and references for this compilation unit. See bug <a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=83804">83804</a> for 
+further details.</li>
+</ul>
+
+<h3>Problem Reports Fixed</h3>
+<a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=91761">91761</a>
+[1.5][compiler] Return statements ignored in anonymous inner classes used as enum constant constructor parameters.
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=84049">84049</a>
+[javadoc][dom] Extended ranges wrong for method name without return type
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=82673">82673</a>
+[search] Refactor->Rename on local class also renames references to different local classes with same name
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=81062">81062</a>
+[builder] Build is aborted even when no errors are occuring (incomplete build path == warning)
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=83012">83012</a>
+[1.5][search][annot] Search for annotations misses references in default and values constructs
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=92588">92588</a>
+Full build in reaction to beginRule failure
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=92451">92451</a>
+code assist failure: new+cast+arrays
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=92373">92373</a>
+[1.5] Can't distinguish capture ITypeBindings by #getKey() or #isEqualTo()
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=92370">92370</a>
+[1.5] IAE in Signature.getParameterCount(..) for method proposal on capture type receiver
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=92361">92361</a>
+[1.5] NPE in ITypeBinding#getJavaElement() for capture binding
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=92315">92315</a>
+[search] NPE in MethodLocator.matchReportReference
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=86380">86380</a>
+[1.5][search][annot] Add support to find references inside annotations on a package declaration
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=83804">83804</a>
+[1.5][javadoc] Missing Javadoc node for package declaration
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=83501">83501</a>
+IBinding#getJavaElement needs better specification
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=83230">83230</a>
+[1.5][search][annot] search for annotation elements does not seem to be implemented yet
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=89624">89624</a>
+Open on selection proposes twice the same entry
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=92237">92237</a>
+IType resolved key: key.toSignature has wrong format
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=91804">91804</a>
+JavaProject.isOnClasspath(IJavaElement) should avoid resolving classpath
+<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=92059">92059</a>
 IVariableBinding#getJavaElement() thows NPE for array's 'length' field
 <br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=84551">84551</a>
 [1.5][compiler] compiler must not allow implicit static reference to outer type
@@ -65,11 +1444,11 @@
 <br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=89274">89274</a>
 [1.5][compiler] Enums in hierarchies with generics produces unnecessary warnings and errors
 <br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=90137">90137</a>
-[1.5][compiler] Collections.sort (List<Comparable>) compile error
+[1.5][compiler] Collections.sort (List&lt;Comparable&gt;) compile error
 <br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=90879">90879</a>
 [1.5][compiler] Cannot sort a raw Comparable
 <br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=85281">85281</a>
-[1.5][compiler]  A<++Element> should not be assignable a  A<+Element>
+[1.5][compiler]  A&lt;++Element&gt; should not be assignable a  A&lt;+Element&gt;
 <br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=91091">91091</a>
 [quick assist] Cannot rename type name in file
 <br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=90881">90881</a>
@@ -991,8 +2370,6 @@
 [DOM] AbortCompilation should not abort the creation of the tree
 <br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=86463">86463</a>
 [1.5][compiler] Compiler-Bug using generics
-<br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=85815">85815</a>
-[1.5] warn when raw iterator is used
 <br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=86611">86611</a>
 [1.4] 1.5 power double causes compiler internal failure
 <br><a href="http://bugs.eclipse.org/bugs/show_bug.cgi?id=86531">86531</a>
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java
index b6fb7f7..0e2892b 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java
@@ -19,6 +19,7 @@
 import org.eclipse.jdt.core.Flags;
 import org.eclipse.jdt.core.IAccessRule;
 import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IMethod;
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.Signature;
@@ -68,6 +69,10 @@
 	public static boolean DEBUG = false;
 	public static boolean PERF = false;
 	
+	// temporary constants to quickly disabled polish features if necessary
+	public final static boolean NO_TYPE_COMPLETION_ON_EMPTY_TOKEN = true;
+	public final static boolean PROPOSE_MEMBER_TYPES = true;
+	
 	private final static char[] ERROR_PATTERN = "*error*".toCharArray();  //$NON-NLS-1$
 	private final static char[] EXCEPTION_PATTERN = "*exception*".toCharArray();  //$NON-NLS-1$
 	private final static char[] SEMICOLON = new char[] { ';' };
@@ -77,6 +82,8 @@
 	private final static char[] INT = "int".toCharArray();  //$NON-NLS-1$
 	private final static char[] INT_SIGNATURE = new char[]{Signature.C_INT};
 	private final static char[] VALUE = "value".toCharArray();  //$NON-NLS-1$
+	private final static char[] EXTENDS = "extends".toCharArray();  //$NON-NLS-1$
+	private final static char[] SUPER = "super".toCharArray();  //$NON-NLS-1$
 	
 	private final static int SUPERTYPE = 1;
 	private final static int SUBTYPE = 2;
@@ -98,6 +105,7 @@
 	boolean assistNodeIsException;
 	boolean assistNodeIsInterface;
 	boolean assistNodeIsAnnotation;
+	boolean assistNodeIsConstructor;
 	
 	IJavaProject javaProject;
 	CompletionParser parser;
@@ -107,9 +115,11 @@
 	char[] completionToken;
 	char[] qualifiedCompletionToken;
 	boolean resolvingImports = false;
+	boolean resolvingStaticImports = false;
 	boolean insideQualifiedReference = false;
 	boolean noProposal = true;
 	IProblem problem = null;
+	char[] fileName = null;
 	int startPosition, actualCompletionPosition, endPosition, offset;
 	HashtableOfObject knownPkgs = new HashtableOfObject(10);
 	HashtableOfObject knownTypes = new HashtableOfObject(10);
@@ -168,6 +178,44 @@
 		public int sourceStart() { return 0; 	}
 		public int sourceEnd() { return 0; 	}
 	};
+	
+	private class AcceptedType {
+		public AcceptedType(
+			char[] packageName,
+			char[] simpleTypeName,
+			char[][] enclosingTypeNames,
+			int modifiers,
+			int accessibility) {
+			this.packageName = packageName;
+			this.simpleTypeName = simpleTypeName;
+			this.enclosingTypeNames = enclosingTypeNames;
+			this.modifiers = modifiers;
+			this.accessibility = accessibility;
+		}
+		public char[] packageName;
+		public char[] simpleTypeName;
+		public char[][] enclosingTypeNames;
+		public int modifiers;
+		public int accessibility;
+		
+		public boolean mustBeQualified = false;
+		public char[] fullyQualifiedName = null;
+		public char[] qualifiedTypeName = null;
+		
+		public String toString() {
+			StringBuffer buffer = new StringBuffer();
+			buffer.append('{');
+			buffer.append(packageName);
+			buffer.append(',');
+			buffer.append(simpleTypeName);
+			buffer.append(',');
+			buffer.append(CharOperation.concatWith(enclosingTypeNames, '.'));
+			buffer.append('}');
+			return buffer.toString();
+		}
+	}
+	
+	private ObjectVector acceptedTypes;
 
 	/**
 	 * The CompletionEngine is responsible for computing source completions.
@@ -222,11 +270,11 @@
 							start,
 							end,
 							lineNumber);
-						// TODO (david) problems could be detected in other units which got requested (see CompilationUnitProblemFinder)
 						if(CompletionEngine.this.actualCompletionPosition > start
 							&& this.lastErrorStart < start
 							&& pb.isError()
-							&& (pb.getID() & IProblem.Syntax) == 0) {
+							&& (pb.getID() & IProblem.Syntax) == 0
+							&& (CompletionEngine.this.fileName == null || CharOperation.equals(CompletionEngine.this.fileName, originatingFileName))) {
 								
 							CompletionEngine.this.problem = pb;
 							this.lastErrorStart = start;
@@ -261,69 +309,270 @@
 	 */
 	public void acceptType(
 		char[] packageName,
-		char[] typeName,
+		char[] simpleTypeName,
+		char[][] enclosingTypeNames,
 		int modifiers,
 		AccessRestriction accessRestriction) {
 
-		char[] fullyQualifiedName = CharOperation.concat(packageName, typeName, '.');
-		char[] completionName = fullyQualifiedName;
-
-		if (this.knownTypes.containsKey(completionName)) return;
-
-		this.knownTypes.put(completionName, this);
-
+		if (this.options.checkVisibility) {
+			if((modifiers & IConstants.AccPublic) == 0) {
+				if((modifiers & IConstants.AccPrivate) != 0) return;
+				
+				char[] currentPackage = CharOperation.concatWith(this.unitScope.fPackage.compoundName, '.');
+				if(!CharOperation.equals(packageName, currentPackage)) return;
+			}
+		}
+		
 		int accessibility = IAccessRule.K_ACCESSIBLE;
 		if(accessRestriction != null) {
 			switch (accessRestriction.getProblemId()) {
 				case IProblem.ForbiddenReference:
-					if(this.options.checkForbiddenReference) return;
+					if (this.options.checkForbiddenReference) {
+						return;
+					}
 					accessibility = IAccessRule.K_NON_ACCESSIBLE;
 					break;
 				case IProblem.DiscouragedReference:
-					if(this.options.checkDiscouragedReference) return;
+					if (this.options.checkDiscouragedReference) {
+						return;
+					}
 					accessibility = IAccessRule.K_DISCOURAGED;
 					break;
 			}
 		}
 		
-		boolean isQualified = true;
+		if(acceptedTypes == null) {
+			acceptedTypes = new ObjectVector();
+		}
+		acceptedTypes.add(new AcceptedType(packageName, simpleTypeName, enclosingTypeNames, modifiers, accessibility));
+	}
+	
+	private void acceptTypes() {
+		if(this.acceptedTypes == null) return;
+		
+		int length = this.acceptedTypes.size();
+		
+		if(length == 0) return;
+		
+		HashtableOfObject onDemandFound = new HashtableOfObject();
+		
+		next : for (int i = 0; i < length; i++) {
+			AcceptedType acceptedType = (AcceptedType)this.acceptedTypes.elementAt(i);
+			char[] packageName = acceptedType.packageName;
+			char[] simpleTypeName = acceptedType.simpleTypeName;
+			char[][] enclosingTypeNames = acceptedType.enclosingTypeNames;
+			int modifiers = acceptedType.modifiers;
+			int accessibility = acceptedType.accessibility;
+			
+			char[] typeName;
+			char[] flatEnclosingTypeNames;
+			if(enclosingTypeNames == null || enclosingTypeNames.length == 0) {
+				flatEnclosingTypeNames = null;
+				typeName = simpleTypeName;
+			} else {
+				flatEnclosingTypeNames = CharOperation.concatWith(acceptedType.enclosingTypeNames, '.');
+				typeName = CharOperation.concat(flatEnclosingTypeNames, simpleTypeName, '.');
+			}
+			char[] fullyQualifiedName = CharOperation.concat(packageName, typeName, '.');
+			
+			if (this.knownTypes.containsKey(fullyQualifiedName)) continue next;
+	
+			this.knownTypes.put(fullyQualifiedName, this);
+			
+			if (this.resolvingImports) {
+				char[] completionName;
+				
+				if(this.resolvingStaticImports) {
+					if(enclosingTypeNames == null || enclosingTypeNames.length == 0) {
+						completionName = CharOperation.concat(fullyQualifiedName, new char[] { '.' });
+					} else if ((modifiers & IConstants.AccStatic) == 0) {
+						continue next;
+					} else {
+						completionName = CharOperation.concat(fullyQualifiedName, new char[] { ';' });
+					}
+				} else {
+					completionName = CharOperation.concat(fullyQualifiedName, new char[] { ';' });
+				}
+				
+				int relevance = computeBaseRelevance();
+				relevance += computeRelevanceForInterestingProposal();
+				relevance += computeRelevanceForRestrictions(accessibility);
+				if(insideQualifiedReference) {
+					relevance += computeRelevanceForCaseMatching(this.completionToken, fullyQualifiedName);
+				} else {
+					relevance += computeRelevanceForCaseMatching(this.completionToken, simpleTypeName);
+				}
+				
+				this.noProposal = false;
+				if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
+					CompletionProposal proposal = this.createProposal(CompletionProposal.TYPE_REF, this.actualCompletionPosition);
+					proposal.setDeclarationSignature(packageName);
+					proposal.setSignature(createNonGenericTypeSignature(packageName, typeName));
+					proposal.setPackageName(packageName);
+					proposal.setTypeName(typeName);
+					proposal.setCompletion(completionName);
+					proposal.setFlags(modifiers);
+					proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
+					proposal.setRelevance(relevance);
+					proposal.setAccessibility(accessibility);
+					this.requestor.accept(proposal);
+					if(DEBUG) {
+						this.printDebug(proposal);
+					}
+				}
+			} else {
+				if(!this.importCachesInitialized) {
+					this.initializeImportCaches();
+				}
+			
+				found : for (int j = 0; j < this.importCacheCount; j++) {
+					char[][] importName = this.importsCache[j];
+					if(CharOperation.equals(typeName, importName[0])) {
+						proposeType(
+								packageName,
+								simpleTypeName,
+								modifiers,
+								accessibility,
+								typeName,
+								fullyQualifiedName,
+								!CharOperation.equals(fullyQualifiedName, importName[1]));
+						continue next;
+					}
+				}
+				
+				
+				if ((enclosingTypeNames == null || enclosingTypeNames.length == 0 ) && CharOperation.equals(this.currentPackageName, packageName)) {
+					proposeType(
+							packageName,
+							simpleTypeName,
+							modifiers,
+							accessibility,
+							typeName,
+							fullyQualifiedName,
+							false);
+					continue next;
+				} else {
+					char[] fullyQualifiedEnclosingTypeOrPackageName = null;
+			
+					AcceptedType foundType = null;
+					if((foundType = (AcceptedType)onDemandFound.get(simpleTypeName)) == null) {
+						for (int j = 0; j < this.onDemandImportCacheCount; j++) {
+							ImportBinding importBinding = this.onDemandImportsCache[j];
+
+							char[][] importName = importBinding.compoundName;
+							char[] importFlatName = CharOperation.concatWith(importName, '.');
+						
+							if(fullyQualifiedEnclosingTypeOrPackageName == null) {
+								if(enclosingTypeNames != null && enclosingTypeNames.length != 0) {
+									fullyQualifiedEnclosingTypeOrPackageName =
+										CharOperation.concat(
+												packageName,
+												flatEnclosingTypeNames,
+												'.');
+								} else {
+									fullyQualifiedEnclosingTypeOrPackageName =
+										packageName;
+								}
+							}
+							if(CharOperation.equals(fullyQualifiedEnclosingTypeOrPackageName, importFlatName)) {
+								if(importBinding.isStatic()) {
+									if((modifiers & IConstants.AccStatic) != 0) {
+										acceptedType.qualifiedTypeName = typeName;
+										acceptedType.fullyQualifiedName = fullyQualifiedName;
+										onDemandFound.put(
+												simpleTypeName,
+												acceptedType);
+										continue next;
+									}
+								} else {
+									acceptedType.qualifiedTypeName = typeName;
+									acceptedType.fullyQualifiedName = fullyQualifiedName;
+									onDemandFound.put(
+											simpleTypeName,
+											acceptedType);
+									continue next;
+								}
+							}
+						}
+					} else {
+						foundType.mustBeQualified = true;
+					}
+					proposeType(
+							packageName,
+							simpleTypeName,
+							modifiers,
+							accessibility,
+							typeName,
+							fullyQualifiedName,
+							true);
+				}
+			}
+		}
+		char[][] keys = onDemandFound.keyTable;
+		Object[] values = onDemandFound.valueTable;
+		int max = keys.length;
+		for (int i = 0; i < max; i++) {
+			if(keys[i] != null) {
+				AcceptedType value = (AcceptedType) values[i];
+				if(value != null) {
+					proposeType(
+							value.packageName,
+							value.simpleTypeName,
+							value.modifiers,
+							value.accessibility,
+							value.qualifiedTypeName,
+							value.fullyQualifiedName,
+							value.mustBeQualified);
+				}
+			}
+		}
+		this.acceptedTypes = null; // reset
+	}
+
+	private void proposeType(char[] packageName, char[] simpleTypeName, int modifiers, int accessibility, char[] typeName, char[] fullyQualifiedName, boolean isQualified) {
+		if(PROPOSE_MEMBER_TYPES) {
+			if(this.assistNodeIsClass) {
+				if((modifiers & (IConstants.AccInterface | IConstants.AccAnnotation | IConstants.AccEnum)) != 0 ) return;
+			} else if(this.assistNodeIsInterface) {
+				if((modifiers & (IConstants.AccInterface | IConstants.AccAnnotation)) == 0) return;
+			} else if (this.assistNodeIsAnnotation) {
+				if((modifiers & IConstants.AccAnnotation) == 0) return;
+			}
+		}
+		
+		char[] completionName = fullyQualifiedName;
+		if(isQualified) {
+			if (packageName == null || packageName.length == 0)
+				if (this.unitScope != null && this.unitScope.fPackage.compoundName != CharOperation.NO_CHAR_CHAR)
+					return; // ignore types from the default package from outside it
+		} else {
+			completionName = simpleTypeName;
+		}
+		
 		int relevance = computeBaseRelevance();
 		relevance += computeRelevanceForInterestingProposal();
 		relevance += computeRelevanceForRestrictions(accessibility);
-		if (this.resolvingImports) {
-			completionName = CharOperation.concat(completionName, new char[] { ';' });
-			relevance += computeRelevanceForCaseMatching(this.completionToken, fullyQualifiedName);
-		} else {
-			if (mustQualifyType(packageName, typeName)) {
-				if (packageName == null || packageName.length == 0)
-					if (this.unitScope != null && this.unitScope.fPackage.compoundName != CharOperation.NO_CHAR_CHAR)
-						return; // ignore types from the default package from outside it
-			} else {
-				completionName = typeName;
-				isQualified = false;
-			}
-			relevance += computeRelevanceForCaseMatching(this.completionToken, typeName);
-			relevance += computeRelevanceForExpectingType(packageName, typeName);
-			relevance += computeRelevanceForQualification(isQualified);
-			
-			int kind = modifiers & (IConstants.AccInterface | IConstants.AccEnum | IConstants.AccAnnotation);
-			switch (kind) {
-				case IConstants.AccAnnotation:
-				case IConstants.AccAnnotation | IConstants.AccInterface:
-					relevance += computeRelevanceForAnnotation();
-					relevance += computeRelevanceForInterface();
-					break;
-				case IConstants.AccEnum:
-					relevance += computeRelevanceForEnum();
-					break;
-				case IConstants.AccInterface:
-					relevance += computeRelevanceForInterface();
-					break;
-				default:
-					relevance += computeRelevanceForClass();
-					relevance += computeRelevanceForException(typeName);
-					break;
-			}
+		relevance += computeRelevanceForCaseMatching(this.completionToken, simpleTypeName);
+		relevance += computeRelevanceForExpectingType(packageName, simpleTypeName);
+		relevance += computeRelevanceForQualification(isQualified);
+		
+		int kind = modifiers & (IConstants.AccInterface | IConstants.AccEnum | IConstants.AccAnnotation);
+		switch (kind) {
+			case IConstants.AccAnnotation:
+			case IConstants.AccAnnotation | IConstants.AccInterface:
+				relevance += computeRelevanceForAnnotation();
+				relevance += computeRelevanceForInterface();
+				break;
+			case IConstants.AccEnum:
+				relevance += computeRelevanceForEnum();
+				break;
+			case IConstants.AccInterface:
+				relevance += computeRelevanceForInterface();
+				break;
+			default:
+				relevance += computeRelevanceForClass();
+				relevance += computeRelevanceForException(simpleTypeName);
+				break;
 		}
 		
 		this.noProposal = false;
@@ -361,7 +610,9 @@
 		int relevance = computeBaseRelevance();
 		relevance += computeRelevanceForInterestingProposal();
 		relevance += computeRelevanceForCaseMatching(this.qualifiedCompletionToken == null ? this.completionToken : this.qualifiedCompletionToken, packageName);
-		relevance += computeRelevanceForQualification(true);
+		if(!this.resolvingImports) {
+			relevance += computeRelevanceForQualification(true);
+		}
 		relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE);
 		
 		this.noProposal = false;
@@ -401,14 +652,14 @@
 		this.requestor.acceptContext(context);
 	}
 	
-	private void complete(ASTNode astNode, ASTNode astNodeParent, Binding qualifiedBinding, Scope scope, boolean insideTypeAnnotation) {
+	private boolean complete(ASTNode astNode, ASTNode astNodeParent, Binding qualifiedBinding, Scope scope, boolean insideTypeAnnotation) {
 
 		setSourceRange(astNode.sourceStart, astNode.sourceEnd);
 		
 		scope = computeForbiddenBindings(astNode, astNodeParent, scope);
 		computeUninterestingBindings(astNodeParent, scope);
 		if(astNodeParent != null) {
-			if(!isValidParent(astNodeParent, astNode, scope)) return;
+			if(!isValidParent(astNodeParent, astNode, scope)) return false;
 			computeExpectedTypes(astNodeParent, astNode, scope);
 		}
 		
@@ -464,6 +715,7 @@
 							&& switchStatement.expression.resolvedType != null
 							&& switchStatement.expression.resolvedType.isEnum()) {
 						if(!this.requestor.isIgnored(CompletionProposal.FIELD_REF)) {
+							this.assistNodeIsEnum = true;
 							this.findEnumConstant(this.completionToken, (SwitchStatement) astNodeParent);
 						}
 					} else {
@@ -481,7 +733,7 @@
 							findTypesAndPackages(this.completionToken, scope);
 							if(!this.requestor.isIgnored(CompletionProposal.KEYWORD)) {
 								if(this.completionToken != null && this.completionToken.length != 0) {
-									findKeywords(this.completionToken, singleNameReference.possibleKeywords);
+									findKeywords(this.completionToken, singleNameReference.possibleKeywords, false);
 								} else {
 									findTrueOrFalseKeywords(singleNameReference.possibleKeywords);
 								}
@@ -504,23 +756,35 @@
 						this.completionToken = ((CompletionOnSingleTypeReference) astNode).token;
 						
 						this.assistNodeIsClass = astNode instanceof CompletionOnClassReference;
-						this.assistNodeIsEnum = this.assistNodeIsClass;
 						this.assistNodeIsException = astNode instanceof CompletionOnExceptionReference;
 						this.assistNodeIsInterface = astNode instanceof CompletionOnInterfaceReference;
-	
+						this.assistNodeIsConstructor = ((CompletionOnSingleTypeReference) astNode).isConstructorType;
+						
 						// can be the start of a qualified type name
 						if (qualifiedBinding == null) {
-							findTypesAndPackages(this.completionToken, scope);
-							} else {
-								if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
-									findMemberTypes(
-									this.completionToken,
-									(ReferenceBinding) qualifiedBinding,
-									scope,
-									scope.enclosingSourceType(),
-									false,
-									new ObjectVector());
-								}
+							if(this.completionToken.length == 0 &&
+									(astNodeParent instanceof ParameterizedSingleTypeReference ||
+											astNodeParent instanceof ParameterizedQualifiedTypeReference)) {
+								this.setSourceRange(astNode.sourceStart, astNode.sourceStart - 1, false);
+								
+								findParameterizedType((TypeReference)astNodeParent);
+							} else { 
+								findTypesAndPackages(this.completionToken, scope);
+							}
+						} else {
+							if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
+								findMemberTypes(
+								this.completionToken,
+								(ReferenceBinding) qualifiedBinding,
+								scope,
+								scope.enclosingSourceType(),
+								false,
+								false,
+								false,
+								!this.assistNodeIsConstructor,
+								null,
+								new ObjectVector());
+							}
 						}
 					} else {
 						
@@ -537,18 +801,25 @@
 								setSourceRange((int) (completionPosition >>> 32), (int) completionPosition);
 								TypeBinding receiverType = ((VariableBinding) qualifiedBinding).type;
 								if (receiverType != null) {
-									findFieldsAndMethods(this.completionToken, receiverType, scope, ref, scope,false,false);
+									findFieldsAndMethods(this.completionToken, receiverType.capture(scope, ref.sourceEnd), scope, ref, scope,false,false);
 								}
 	
 							} else {
 	
-								if (qualifiedBinding instanceof ReferenceBinding) {
+								if (qualifiedBinding instanceof ReferenceBinding &&
+										!(qualifiedBinding instanceof TypeVariableBinding)) {
 									boolean isInsideAnnotationAttribute = ref.isInsideAnnotationAttribute;
 									ReferenceBinding receiverType = (ReferenceBinding) qualifiedBinding;
 									setSourceRange((int) (completionPosition >>> 32), (int) completionPosition);
 	
 									if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
-										findMemberTypes(this.completionToken, receiverType, scope, scope.enclosingSourceType(), false, new ObjectVector());
+										findMemberTypes(
+												this.completionToken,
+												receiverType,
+												scope,
+												scope.enclosingSourceType(),
+												false,
+												new ObjectVector());
 									}
 									if(!this.requestor.isIgnored(CompletionProposal.FIELD_REF)) {
 										findClassField(this.completionToken, (TypeBinding) qualifiedBinding, scope);
@@ -560,7 +831,7 @@
 											((scope instanceof MethodScope && !((MethodScope)scope).isStatic)
 											|| ((methodScope = scope.enclosingMethodScope()) != null && !methodScope.isStatic))) {
 										if(this.completionToken.length > 0) {
-											findKeywords(this.completionToken, new char[][]{Keywords.THIS});
+											findKeywords(this.completionToken, new char[][]{Keywords.THIS}, false);
 										} else {
 											int relevance = computeBaseRelevance();
 											relevance += computeRelevanceForInterestingProposal();
@@ -630,7 +901,6 @@
 								this.insideQualifiedReference = true;
 								
 								this.assistNodeIsClass = astNode instanceof CompletionOnQualifiedClassReference;
-								this.assistNodeIsEnum = this.assistNodeIsClass;
 								this.assistNodeIsException = astNode instanceof CompletionOnQualifiedExceptionReference;
 								this.assistNodeIsInterface = astNode instanceof CompletionOnQualifiedInterfaceReference;
 								
@@ -640,7 +910,8 @@
 								long completionPosition = ref.sourcePositions[ref.tokens.length];
 	
 								// get the source positions of the completion identifier
-								if (qualifiedBinding instanceof ReferenceBinding) {
+								if (qualifiedBinding instanceof ReferenceBinding &&
+										!(qualifiedBinding instanceof TypeVariableBinding)) {
 									if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
 										setSourceRange((int) (completionPosition >>> 32), (int) completionPosition);
 										findMemberTypes(
@@ -673,12 +944,12 @@
 									this.completionToken = access.token;
 									
 									if(!this.requestor.isIgnored(CompletionProposal.KEYWORD)) {
-										findKeywords(this.completionToken, new char[][]{Keywords.NEW});
+										findKeywords(this.completionToken, new char[][]{Keywords.NEW}, false);
 									}
 									
 									findFieldsAndMethods(
 										this.completionToken,
-										(TypeBinding) qualifiedBinding,
+										((TypeBinding) qualifiedBinding).capture(scope, access.receiver.sourceEnd),
 										scope,
 										access,
 										scope,
@@ -703,7 +974,7 @@
 												findMethods(
 													this.completionToken,
 													argTypes,
-													(ReferenceBinding) qualifiedBinding,
+													(ReferenceBinding)((ReferenceBinding) qualifiedBinding).capture(scope, messageSend.receiver.sourceEnd),
 													scope,
 													new ObjectVector(),
 													false,
@@ -837,7 +1108,7 @@
 																if(astNode instanceof CompletionOnKeyword) {
 																	if(!this.requestor.isIgnored(CompletionProposal.KEYWORD)) {
 																		CompletionOnKeyword keyword = (CompletionOnKeyword)astNode;
-																		findKeywords(keyword.getToken(), keyword.getPossibleKeywords());
+																		findKeywords(keyword.getToken(), keyword.getPossibleKeywords(), keyword.canCompleteEmptyToken());
 																	}
 																} else if(astNode instanceof CompletionOnParameterizedQualifiedTypeReference) {
 																	if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
@@ -871,18 +1142,27 @@
 																		
 																		findTypesAndPackages(this.completionToken, scope);
 																	} else if(annot.type instanceof CompletionOnQualifiedTypeReference) {
+																		this.insideQualifiedReference = true;
+																		
 																		CompletionOnQualifiedTypeReference type = (CompletionOnQualifiedTypeReference) annot.type;
 																		this.completionToken = type.completionIdentifier;
 																		long completionPosition = type.sourcePositions[type.tokens.length];
-																		setSourceRange((int) (completionPosition >>> 32), (int) completionPosition);
-										
-																		findMemberTypes(
-																			this.completionToken,
-																			(ReferenceBinding) qualifiedBinding,
-																			scope,
-																			scope.enclosingSourceType(),
-																			false,
-																			new ObjectVector());
+																		if (qualifiedBinding instanceof PackageBinding) {
+	
+																			setSourceRange(astNode.sourceStart, (int) completionPosition);
+																			// replace to the end of the completion identifier
+																			findTypesAndSubpackages(this.completionToken, (PackageBinding) qualifiedBinding);
+																		} else {
+																			setSourceRange((int) (completionPosition >>> 32), (int) completionPosition);
+											
+																			findMemberTypes(
+																				this.completionToken,
+																				(ReferenceBinding) qualifiedBinding,
+																				scope,
+																				scope.enclosingSourceType(),
+																				false,
+																				new ObjectVector());
+																		}
 																	}
 																} else if (astNode instanceof CompletionOnMemberValueName) {
 																	if(!this.requestor.isIgnored(CompletionProposal.ANNOTATION_ATTRIBUTE_REF)) {
@@ -891,31 +1171,36 @@
 																		
 																		this.completionToken = memberValuePair.name;
 																		
-																		MemberValuePair[] memberValuePairs = annotation.memberValuePairs();
-																		this.findAnnotationAttributes(this.completionToken, annotation.memberValuePairs(), (ReferenceBinding)annotation.resolvedType);
-																		if(memberValuePairs == null || memberValuePairs.length == 0) {
-																			if(annotation.resolvedType instanceof ReferenceBinding) {
-																				MethodBinding[] methodBindings =
-																					((ReferenceBinding)annotation.resolvedType).availableMethods();
-																				if(methodBindings != null &&
-																						methodBindings.length == 1 &&
-																						CharOperation.equals(methodBindings[0].selector, VALUE)) {
-																					if(this.expectedTypesPtr > -1 && this.expectedTypes[0].isAnnotationType()) {
-																						findTypesAndPackages(this.completionToken, scope);
-																					} else {
-																						findVariablesAndMethods(
-																							this.completionToken,
-																							scope,
-																							FakeInvocationSite,
-																							scope,
-																							insideTypeAnnotation,
-																							true);
-																						// can be the start of a qualified type name
-																						findTypesAndPackages(this.completionToken, scope);
+																		if(this.completionToken.length == 0) {
+																			this.setSourceRange(astNode.sourceStart, astNode.sourceStart - 1, false);
+								
+																			findAnnotationReference(annotation.type);
+																		} else {
+																			MemberValuePair[] memberValuePairs = annotation.memberValuePairs();
+																			this.findAnnotationAttributes(this.completionToken, annotation.memberValuePairs(), (ReferenceBinding)annotation.resolvedType);
+																			if(memberValuePairs == null || memberValuePairs.length == 0) {
+																				if(annotation.resolvedType instanceof ReferenceBinding) {
+																					MethodBinding[] methodBindings =
+																						((ReferenceBinding)annotation.resolvedType).availableMethods();
+																					if(methodBindings != null &&
+																							methodBindings.length == 1 &&
+																							CharOperation.equals(methodBindings[0].selector, VALUE)) {
+																						if(this.expectedTypesPtr > -1 && this.expectedTypes[0].isAnnotationType()) {
+																							findTypesAndPackages(this.completionToken, scope);
+																						} else {
+																							findVariablesAndMethods(
+																								this.completionToken,
+																								scope,
+																								FakeInvocationSite,
+																								scope,
+																								insideTypeAnnotation,
+																								true);
+																							// can be the start of a qualified type name
+																							findTypesAndPackages(this.completionToken, scope);
+																						}
 																					}
 																				}
 																			}
-																			
 																		}
 																	}
 																}
@@ -933,6 +1218,7 @@
 				}
 			}
 		}
+		return true;
 	}
 	
 	public void complete(IType type, char[] snippet, int position, char[][] localVariableTypeNames, char[][] localVariableNames, int[] localVariableModifiers, boolean isStatic){	
@@ -945,7 +1231,8 @@
 			topLevelType = topLevelType.getDeclaringType();
 		}
 		
-		CompilationResult compilationResult = new CompilationResult(topLevelType.getParent().getElementName().toCharArray(), 1, 1, this.compilerOptions.maxProblemsPerUnit);
+		this.fileName = topLevelType.getParent().getElementName().toCharArray();
+		CompilationResult compilationResult = new CompilationResult(this.fileName, 1, 1, this.compilerOptions.maxProblemsPerUnit);
 	
 		CompilationUnitDeclaration compilationUnit = null;
 	
@@ -1003,9 +1290,8 @@
 					} catch (CompletionNodeFound e) {
 						//					completionNodeFound = true;
 						if (e.astNode != null) {
-							contextAccepted = true;
 							// if null then we found a problem in the completion node
-							complete(e.astNode, this.parser.assistNodeParent, e.qualifiedBinding, e.scope, e.insideTypeAnnotation);
+							contextAccepted = complete(e.astNode, this.parser.assistNodeParent, e.qualifiedBinding, e.scope, e.insideTypeAnnotation);
 						}
 					}
 				}
@@ -1020,6 +1306,26 @@
 					}
 				}
 			}
+		}  catch (IndexOutOfBoundsException e) { // work-around internal failure - 1GEMF6D (added with fix of 99629)
+			if(DEBUG) {
+				System.out.println("Exception caught by CompletionEngine:"); //$NON-NLS-1$
+				e.printStackTrace(System.out);
+			}
+		} catch (InvalidCursorLocation e) { // may eventually report a usefull error (added to fix 99629)
+			if(DEBUG) {
+				System.out.println("Exception caught by CompletionEngine:"); //$NON-NLS-1$
+				e.printStackTrace(System.out);
+			}
+		} catch (AbortCompilation e) { // ignore this exception for now since it typically means we cannot find java.lang.Object (added with fix of 99629)
+			if(DEBUG) {
+				System.out.println("Exception caught by CompletionEngine:"); //$NON-NLS-1$
+				e.printStackTrace(System.out);
+			}
+		} catch (CompletionNodeFound e){ // internal failure - bugs 5618 (added with fix of 99629)
+			if(DEBUG) {
+				System.out.println("Exception caught by CompletionEngine:"); //$NON-NLS-1$
+				e.printStackTrace(System.out);
+			}
 		} catch(JavaModelException e) {
 			// Do nothing
 		}
@@ -1095,6 +1401,7 @@
 		this.requestor.beginReporting();
 		boolean contextAccepted = false;
 		try {
+			this.fileName = sourceUnit.getFileName();
 			this.actualCompletionPosition = completionPosition - 1;
 			this.offset = pos;
 			// for now until we can change the UI.
@@ -1129,35 +1436,50 @@
 					for (int i = 0, length = imports.length; i < length; i++) {
 						ImportReference importReference = imports[i];
 						if (importReference instanceof CompletionOnImportReference) {
-							contextAccepted = true;
-							this.requestor.acceptContext(new CompletionContext());
-							findImports((CompletionOnImportReference) importReference);
-							if(this.noProposal && this.problem != null) {
-								this.requestor.completionFailure(this.problem);
-								if(DEBUG) {
-									this.printDebug(this.problem);
-								}
-							}
-							if(importReference.isStatic()) {
-								this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/);
-								if ((this.unitScope = parsedUnit.scope) != null) {
-									char[][] oldTokens = importReference.tokens;
-									int tokenCount = oldTokens.length;
+							this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/);
+							if ((this.unitScope = parsedUnit.scope) != null) {
+								contextAccepted = true;
+								this.requestor.acceptContext(new CompletionContext());
+								
+								setSourceRange(
+									importReference.sourceStart,
+									importReference.declarationSourceEnd);
+								
+								char[][] oldTokens = importReference.tokens;
+								int tokenCount = oldTokens.length;
+								if (tokenCount == 1) {
+									findImports((CompletionOnImportReference)importReference, true);
+								} else if(tokenCount > 1){
+									this.insideQualifiedReference = true;
+									
 									char[] lastToken = oldTokens[tokenCount - 1];
 									char[][] qualifierTokens = CharOperation.subarray(oldTokens, 0, tokenCount - 1);
 									
 									Binding binding = this.unitScope.getTypeOrPackage(qualifierTokens);
-									if(binding != null && binding instanceof ReferenceBinding) {
-										ReferenceBinding ref = (ReferenceBinding) binding;
-										if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
-											this.findImportsOfMemberTypes(lastToken, ref);
+									if(binding != null) {
+										if(binding instanceof PackageBinding) {
+											findImports((CompletionOnImportReference)importReference, false);
+										} else {
+											ReferenceBinding ref = (ReferenceBinding) binding;
+											if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
+												this.findImportsOfMemberTypes(lastToken, ref, importReference.isStatic());
+											}
+											if(importReference.isStatic()) {
+												if(!this.requestor.isIgnored(CompletionProposal.FIELD_REF)) {
+													this.findImportsOfStaticFields(lastToken, ref);
+												}
+												if(!this.requestor.isIgnored(CompletionProposal.METHOD_NAME_REFERENCE)) {
+													this.findImportsOfStaticMethdods(lastToken, ref);
+												}
+											}
 										}
-										if(!this.requestor.isIgnored(CompletionProposal.FIELD_REF)) {
-											this.findImportsOfStaticFields(lastToken, ref);
-										}
-										if(!this.requestor.isIgnored(CompletionProposal.METHOD_NAME_REFERENCE)) {
-											this.findImportsOfStaticMethdods(lastToken, ref);
-										}
+									}
+								}
+								
+								if(this.noProposal && this.problem != null) {
+									this.requestor.completionFailure(this.problem);
+									if(DEBUG) {
+										this.printDebug(this.problem);
 									}
 								}
 							}
@@ -1168,7 +1490,7 @@
 							if(!this.requestor.isIgnored(CompletionProposal.KEYWORD)) {
 								setSourceRange(importReference.sourceStart, importReference.sourceEnd);
 								CompletionOnKeyword keyword = (CompletionOnKeyword)importReference;
-								findKeywords(keyword.getToken(), keyword.getPossibleKeywords());
+								findKeywords(keyword.getToken(), keyword.getPossibleKeywords(), false);
 							}
 							if(this.noProposal && this.problem != null) {
 								this.requestor.completionFailure(this.problem);
@@ -1207,9 +1529,8 @@
 									System.out.println(this.parser.assistNodeParent);
 								}
 							}
-							contextAccepted = true;
 							// if null then we found a problem in the completion node
-							complete(e.astNode, this.parser.assistNodeParent, e.qualifiedBinding, e.scope, e.insideTypeAnnotation);
+							contextAccepted = complete(e.astNode, this.parser.assistNodeParent, e.qualifiedBinding, e.scope, e.insideTypeAnnotation);
 						}
 					}
 				}
@@ -1313,6 +1634,58 @@
 			}
 		}
 	}
+	private void findAnnotationReference(TypeReference ref) {
+		ReferenceBinding refBinding = (ReferenceBinding) ref.resolvedType;
+		if(refBinding != null) {
+			char[] packageName = refBinding.qualifiedPackageName();
+			char[] typeName = refBinding.qualifiedSourceName();
+			
+			int accessibility = IAccessRule.K_ACCESSIBLE;
+			if(refBinding.hasRestrictedAccess()) {
+				AccessRestriction accessRestriction = lookupEnvironment.getAccessRestriction(refBinding);
+				if(accessRestriction != null) {
+					switch (accessRestriction.getProblemId()) {
+						case IProblem.ForbiddenReference:
+							if (this.options.checkForbiddenReference) {
+								return;
+							}
+							accessibility = IAccessRule.K_NON_ACCESSIBLE;
+							break;
+						case IProblem.DiscouragedReference:
+							if (this.options.checkDiscouragedReference) {
+								return;
+							}
+							accessibility = IAccessRule.K_DISCOURAGED;
+							break;
+					}
+				}
+			}
+
+			int relevance = computeBaseRelevance();
+			relevance += computeRelevanceForInterestingProposal();
+			relevance += computeRelevanceForCaseMatching(refBinding.sourceName, refBinding.sourceName);
+			relevance += computeRelevanceForExpectingType(refBinding);
+			relevance += computeRelevanceForQualification(false);
+			relevance += computeRelevanceForRestrictions(accessibility); // no access restriction for type in the current unit
+			
+			if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
+				CompletionProposal proposal = this.createProposal(CompletionProposal.TYPE_REF, this.actualCompletionPosition);
+				proposal.setDeclarationSignature(packageName);
+				proposal.setSignature(getSignature(refBinding));
+				proposal.setPackageName(packageName);
+				proposal.setTypeName(typeName);
+				proposal.setCompletion(CharOperation.NO_CHAR);
+				proposal.setFlags(refBinding.modifiers);
+				proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
+				proposal.setRelevance(relevance);
+				proposal.setAccessibility(accessibility);
+				this.requestor.accept(proposal);
+				if(DEBUG) {
+					this.printDebug(proposal);
+				}
+			}
+		}
+	}
 	private void findAnonymousType(
 		ReferenceBinding currentType,
 		TypeBinding[] argTypes,
@@ -1341,6 +1714,7 @@
 								CharOperation.NO_CHAR_CHAR,
 								CharOperation.NO_CHAR,
 								CharOperation.NO_CHAR));
+				//proposal.setOriginalSignature(null);
 				//proposal.setUniqueKey(null);
 				proposal.setDeclarationPackageName(currentType.qualifiedPackageName());
 				proposal.setDeclarationTypeName(currentType.qualifiedSourceName());
@@ -1385,10 +1759,23 @@
 			if(!this.requestor.isIgnored(CompletionProposal.FIELD_REF)) {
 				CompletionProposal proposal = this.createProposal(CompletionProposal.FIELD_REF, this.actualCompletionPosition);
 				//proposal.setDeclarationSignature(null);
-				proposal.setSignature(
-						createNonGenericTypeSignature(
-								CharOperation.concatWith(JAVA_LANG, '.'),
-								CLASS));
+				char[] signature = 
+					createNonGenericTypeSignature(
+						CharOperation.concatWith(JAVA_LANG, '.'),
+						CLASS);
+				if (this.compilerOptions.sourceLevel > ClassFileConstants.JDK1_4) {
+					// add type argument
+					char[] typeArgument = getTypeSignature(receiverType);
+					int oldLength = signature.length;
+					int argumentLength = typeArgument.length;
+					int newLength = oldLength + argumentLength + 2;
+					System.arraycopy(signature, 0, signature = new char[newLength], 0, oldLength - 1);
+					signature[oldLength - 1] = '<';
+					System.arraycopy(typeArgument, 0, signature, oldLength , argumentLength);
+					signature[newLength - 2] = '>';
+					signature[newLength - 1] = ';';
+				}
+				proposal.setSignature(signature);
 				//proposal.setDeclarationPackageName(null);
 				//proposal.setDeclarationTypeName(null);
 				proposal.setPackageName(CharOperation.concatWith(JAVA_LANG, '.'));
@@ -1410,6 +1797,16 @@
 		if(expressionType != null && expressionType.isEnum()) {
 			ReferenceBinding enumType = (ReferenceBinding) expressionType;
 			
+			CaseStatement[] cases = switchStatement.cases;
+			
+			char[][] alreadyUsedConstants = new char[switchStatement.caseCount][];
+			int alreadyUsedConstantCount = 0;
+			for (int i = 0; i < switchStatement.caseCount; i++) {
+				if(cases[i].isEnumConstant) {
+					alreadyUsedConstants[alreadyUsedConstantCount++] = ((SingleNameReference)cases[i].constantExpression).token;
+				}
+			}
+			
 			FieldBinding[] fields = enumType.fields();
 			
 			int enumConstantLength = enumConstantName.length;
@@ -1425,10 +1822,14 @@
 				if (!CharOperation.prefixEquals(enumConstantName, field.name, false /* ignore case */))	continue next;
 				
 				char[] completion = field.name;
+				
+				for (int i = 0; i < alreadyUsedConstantCount; i++) {
+					if(CharOperation.equals(alreadyUsedConstants[i], completion)) continue next;
+				}
 
 				int relevance = computeBaseRelevance();
 				relevance += computeRelevanceForInterestingProposal(field);
-				relevance += R_ENUM_CONSTANT;
+				relevance += computeRelevanceForEnum();
 				relevance += computeRelevanceForCaseMatching(enumConstantName, field.name);
 				relevance += computeRelevanceForExpectingType(field.type);
 				relevance += computeRelevanceForQualification(false);
@@ -1507,6 +1908,10 @@
 						CompletionProposal proposal = this.createProposal(CompletionProposal.METHOD_REF, this.actualCompletionPosition);
 						proposal.setDeclarationSignature(getSignature(currentType));
 						proposal.setSignature(getSignature(constructor));
+						MethodBinding original = constructor.original();
+						if(original != constructor) {
+							proposal.setOriginalSignature(getSignature(original));
+						}
 						proposal.setDeclarationPackageName(currentType.qualifiedPackageName());
 						proposal.setDeclarationTypeName(currentType.qualifiedSourceName());
 						proposal.setParameterPackageNames(parameterPackageNames);
@@ -1514,6 +1919,7 @@
 						//proposal.setPackageName(null);
 						//proposal.setTypeName(null);
 						proposal.setName(name);
+						proposal.setIsContructor(true);
 						proposal.setCompletion(completion);
 						proposal.setFlags(constructor.modifiers);
 						proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
@@ -1587,6 +1993,10 @@
 							proposal.setDeclarationSignature(getSignature(currentType));
 							proposal.setDeclarationKey(currentType.computeUniqueKey());
 							proposal.setSignature(getSignature(constructor));
+							MethodBinding original = constructor.original();
+							if(original != constructor) {
+								proposal.setOriginalSignature(getSignature(original));
+							}
 							proposal.setKey(constructor.computeUniqueKey());
 							proposal.setDeclarationPackageName(currentType.qualifiedPackageName());
 							proposal.setDeclarationTypeName(currentType.qualifiedSourceName());
@@ -1614,6 +2024,10 @@
 							CompletionProposal proposal = this.createProposal(CompletionProposal.METHOD_REF, this.actualCompletionPosition);
 							proposal.setDeclarationSignature(getSignature(currentType));
 							proposal.setSignature(getSignature(constructor));
+							MethodBinding original = constructor.original();
+							if(original != constructor) {
+								proposal.setOriginalSignature(getSignature(original));
+							}
 							proposal.setDeclarationPackageName(currentType.qualifiedPackageName());
 							proposal.setDeclarationTypeName(currentType.qualifiedSourceName());
 							proposal.setParameterPackageNames(parameterPackageNames);
@@ -1621,6 +2035,7 @@
 							//proposal.setPackageName(null);
 							//proposal.setTypeName(null);
 							proposal.setName(currentType.sourceName());
+							proposal.setIsContructor(true);
 							proposal.setCompletion(completion);
 							proposal.setFlags(constructor.modifiers);
 							proposal.setReplaceRange(this.endPosition - this.offset, this.endPosition - this.offset);
@@ -1895,7 +2310,7 @@
 				this.noProposal = false;
 				if(!this.requestor.isIgnored(CompletionProposal.FIELD_REF)) {
 					CompletionProposal proposal = this.createProposal(CompletionProposal.FIELD_REF, this.actualCompletionPosition);
-					//proposal.setDeclarationSignature(null);
+					proposal.setDeclarationSignature(getSignature(receiverType));
 					proposal.setSignature(INT_SIGNATURE);
 					//proposal.setDeclarationPackageName(null);
 					//proposal.setDeclarationTypeName(null);
@@ -1937,13 +2352,14 @@
 				this.noProposal = false;
 				if(!this.requestor.isIgnored(CompletionProposal.METHOD_REF)) {
 					CompletionProposal proposal = this.createProposal(CompletionProposal.METHOD_REF, this.actualCompletionPosition);
-					//proposal.setDeclarationSignature(null);
+					proposal.setDeclarationSignature(getSignature(receiverType));
 					proposal.setSignature(
 							createMethodSignature(
 									CharOperation.NO_CHAR_CHAR,
 									CharOperation.NO_CHAR_CHAR,
 									CharOperation.concatWith(JAVA_LANG, '.'),
 									OBJECT));
+					//proposal.setOriginalSignature(null);
 					//proposal.setDeclarationPackageName(null);
 					//proposal.setDeclarationTypeName(null);
 					//proposal.setParameterPackageNames(null);
@@ -1998,7 +2414,7 @@
 		}
 	}
 
-	private void findImports(CompletionOnImportReference importReference) {
+	private void findImports(CompletionOnImportReference importReference, boolean findMembers) {
 		char[][] tokens = importReference.tokens;
 			
 		char[] importName = CharOperation.concatWith(tokens, '.');
@@ -2011,9 +2427,7 @@
 			importName = CharOperation.concat(importName, new char[]{'.'});
 
 		this.resolvingImports = true;
-		setSourceRange(
-			importReference.sourceStart,
-			importReference.declarationSourceEnd);
+		this.resolvingStaticImports = importReference.isStatic();
 			
 		this.completionToken =  importName;
 		// want to replace the existing .*;
@@ -2021,11 +2435,12 @@
 			this.nameEnvironment.findPackages(importName, this);
 		}
 		if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
-			this.nameEnvironment.findTypes(importName, this);
+			this.nameEnvironment.findTypes(importName, findMembers && PROPOSE_MEMBER_TYPES, this);
+			acceptTypes();
 		}
 	}
 	
-	private void findImportsOfMemberTypes(char[] typeName,	ReferenceBinding ref) {
+	private void findImportsOfMemberTypes(char[] typeName,	ReferenceBinding ref, boolean onlyStatic) {
 		ReferenceBinding[] memberTypes = ref.memberTypes();
 		
 		int typeLength = typeName.length;
@@ -2034,6 +2449,9 @@
 			//		if (!wantClasses && memberType.isClass()) continue next;
 			//		if (!wantInterfaces && memberType.isInterface()) continue next;
 			
+			if (onlyStatic && !memberType.isStatic())
+				continue next;
+			
 			if (typeLength > memberType.sourceName.length)
 				continue next;
 
@@ -2224,11 +2642,11 @@
 	
 	// what about onDemand types? Ignore them since it does not happen!
 	// import p1.p2.A.*;
-	private void findKeywords(char[] keyword, char[][] choices) {
+	private void findKeywords(char[] keyword, char[][] choices, boolean canCompleteEmptyToken) {
 		if(choices == null || choices.length == 0) return;
 		
 		int length = keyword.length;
-		if (length > 0)
+		if (canCompleteEmptyToken || length > 0)
 			for (int i = 0; i < choices.length; i++)
 				if (length <= choices[i].length
 					&& CharOperation.prefixEquals(keyword, choices[i], false /* ignore case */
@@ -2376,7 +2794,7 @@
 		}
 		System.arraycopy(keywords, 0, keywords = new char[count][], 0, count);
 		
-		findKeywords(token, keywords);
+		findKeywords(token, keywords, false);
 	}
 
 	// Helper method for findMemberTypes(char[], ReferenceBinding, Scope)
@@ -2386,7 +2804,9 @@
 		ObjectVector typesFound,
 		ReferenceBinding receiverType,
 		SourceTypeBinding invocationType,
-		boolean staticOnly) {
+		boolean staticOnly,
+		boolean fromStaticImport,
+		boolean checkQualification) {
 
 		// Inherited member types which are hidden by subclasses are filtered out
 		// No visibility checks can be performed without the scope & invocationSite
@@ -2441,11 +2861,47 @@
 
 			typesFound.add(memberType);
 
+			if(!this.insideQualifiedReference && PROPOSE_MEMBER_TYPES) {
+				if(this.assistNodeIsClass) {
+					if(!memberType.isClass()) continue next;
+				} else if(this.assistNodeIsInterface) {
+					if(!memberType.isInterface() && !memberType.isAnnotationType()) continue next;
+				} else if (this.assistNodeIsAnnotation) {
+					if(!memberType.isAnnotationType()) continue next;
+				}
+			}
+			
+			char[] completionName = memberType.sourceName();
+			
+			boolean isQualified = false;
+			if(checkQualification && !fromStaticImport) {
+				char[] memberPackageName = memberType.qualifiedPackageName();
+				char[] memberTypeName = memberType.sourceName();
+				char[] memberEnclosingTypeNames = memberType.enclosingType().qualifiedSourceName();
+				if (mustQualifyType(memberPackageName, memberTypeName, memberEnclosingTypeNames, memberType.modifiers)) {
+					if (memberPackageName == null || memberPackageName.length == 0)
+						if (this.unitScope != null && this.unitScope.fPackage.compoundName != CharOperation.NO_CHAR_CHAR)
+							break next; // ignore types from the default package from outside it
+					isQualified = true;
+					completionName =
+						CharOperation.concat(
+								memberPackageName,
+								CharOperation.concat(
+										memberEnclosingTypeNames,
+										memberTypeName,
+										'.'),
+								'.');
+				}
+			}
+			
 			int relevance = computeBaseRelevance();
 			relevance += computeRelevanceForInterestingProposal();
 			relevance += computeRelevanceForCaseMatching(typeName, memberType.sourceName);
 			relevance += computeRelevanceForExpectingType(memberType);
 			relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE);
+			if(!insideQualifiedReference) {
+				relevance += computeRelevanceForQualification(isQualified);
+			}
 
 			if (memberType.isClass()) {
 				relevance += computeRelevanceForClass();
@@ -2463,7 +2919,7 @@
 				proposal.setSignature(getSignature(memberType));
 				proposal.setPackageName(memberType.qualifiedPackageName());
 				proposal.setTypeName(memberType.qualifiedSourceName());
-				proposal.setCompletion(memberType.sourceName());
+				proposal.setCompletion(completionName);
 				proposal.setFlags(memberType.modifiers);
 				proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
 				proposal.setRelevance(relevance);
@@ -2481,6 +2937,29 @@
 		Scope scope,
 		SourceTypeBinding typeInvocation,
 		boolean staticOnly,
+		ObjectVector typesFound)  {
+		findMemberTypes(
+				typeName,
+				receiverType,
+				scope,
+				typeInvocation,
+				staticOnly,
+				false,
+				false,
+				false,
+				null,
+				typesFound);
+	}
+	private void findMemberTypes(
+		char[] typeName,
+		ReferenceBinding receiverType,
+		Scope scope,
+		SourceTypeBinding typeInvocation,
+		boolean staticOnly,
+		boolean fromStaticImport,
+		boolean checkQualification,
+		boolean proposeAllMemberTypes,
+		SourceTypeBinding typeToIgnore,
 		ObjectVector typesFound) {
 
 		ReferenceBinding currentType = receiverType;
@@ -2499,7 +2978,9 @@
 				typesFound,
 				receiverType,
 				typeInvocation,
-				staticOnly);
+				staticOnly,
+				fromStaticImport,
+				checkQualification);
 			return;
 		}
 
@@ -2523,17 +3004,37 @@
 						lastPosition);
 				interfacesToVisit[lastPosition] = itsInterfaces;
 			}
-
+			
 			findMemberTypes(
 				typeName,
 				currentType.memberTypes(),
 				typesFound,
 				receiverType,
 				typeInvocation,
-				staticOnly);
+				staticOnly,
+				fromStaticImport,
+				checkQualification);
+			
 			currentType = currentType.superclass();
 
 		} while (currentType != null);
+		
+		
+		if(proposeAllMemberTypes) {
+			ReferenceBinding[] memberTypes = receiverType.memberTypes();
+			for (int i = 0; i < memberTypes.length; i++) {
+				if(memberTypes[i] != typeToIgnore) {
+					findSubMemberTypes(
+						typeName,
+						memberTypes[i],
+						scope,
+						typeInvocation,
+						staticOnly,
+						fromStaticImport,
+						typesFound);
+				}
+			}
+		}
 
 		if (interfacesToVisit != null) {
 			for (int i = 0; i <= lastPosition; i++) {
@@ -2544,15 +3045,17 @@
 					if ((anInterface.tagBits & TagBits.InterfaceVisited) == 0) {
 						// if interface as not already been visited
 						anInterface.tagBits |= TagBits.InterfaceVisited;
-
+						
 						findMemberTypes(
 							typeName,
 							anInterface.memberTypes(),
 							typesFound,
 							receiverType,
 							typeInvocation,
-							staticOnly);
-
+							staticOnly,
+							fromStaticImport,
+							checkQualification);
+								
 						ReferenceBinding[] itsInterfaces = anInterface.superInterfaces();
 						if (itsInterfaces != NoSuperInterfaces) {
 
@@ -2577,6 +3080,52 @@
 			}
 		}
 	}
+	
+	private void findSubMemberTypes(
+		char[] typeName,
+		ReferenceBinding receiverType,
+		Scope scope,
+		SourceTypeBinding typeInvocation,
+		boolean staticOnly,
+		boolean fromStaticImport,
+		ObjectVector typesFound) {
+
+		ReferenceBinding currentType = receiverType;
+		if (typeName == null || typeName.length == 0)
+			return;
+
+		if (currentType.superInterfaces() == null)
+			return; // we're trying to find a supertype
+		
+		findMemberTypes(
+				typeName,
+				currentType.memberTypes(),
+				typesFound,
+				receiverType,
+				typeInvocation,
+				staticOnly,
+				fromStaticImport,
+				true);
+		
+		ReferenceBinding[] memberTypes = receiverType.memberTypes();
+		next : for (int i = 0; i < memberTypes.length; i++) {
+			if (this.options.checkVisibility) {
+				if (typeInvocation != null && !memberTypes[i].canBeSeenBy(receiverType, typeInvocation)) {
+					continue next;
+				} else if(typeInvocation == null && !memberTypes[i].canBeSeenBy(this.unitScope.fPackage)) {
+					continue next;
+				}
+			}
+			findSubMemberTypes(
+				typeName,
+				memberTypes[i],
+				scope,
+				typeInvocation,
+				staticOnly,
+				fromStaticImport,
+				typesFound);
+		}
+	}
 
 	private void findIntefacesMethods(
 		char[] selector,
@@ -2889,6 +3438,10 @@
 				CompletionProposal proposal = this.createProposal(CompletionProposal.METHOD_REF, this.actualCompletionPosition);
 				proposal.setDeclarationSignature(getSignature(method.declaringClass));
 				proposal.setSignature(getSignature(method));
+				MethodBinding original = method.original();
+				if(original != method) {
+					proposal.setOriginalSignature(getSignature(original));
+				}
 				proposal.setDeclarationPackageName(method.declaringClass.qualifiedPackageName());
 				proposal.setDeclarationTypeName(method.declaringClass.qualifiedSourceName());
 				proposal.setParameterPackageNames(parameterPackageNames);
@@ -2974,6 +3527,10 @@
 				CompletionProposal proposal = this.createProposal(CompletionProposal.METHOD_REF, this.actualCompletionPosition);
 				proposal.setDeclarationSignature(getSignature(method.declaringClass));
 				proposal.setSignature(getSignature(method));
+				MethodBinding original = method.original();
+				if(original != method) {
+					proposal.setOriginalSignature(getSignature(original));
+				}
 				proposal.setDeclarationPackageName(method.declaringClass.qualifiedPackageName());
 				proposal.setDeclarationTypeName(method.declaringClass.qualifiedSourceName());
 				proposal.setParameterPackageNames(parameterPackageNames);
@@ -3070,17 +3627,18 @@
 	private int computeRelevanceForExpectingType(TypeBinding proposalType){
 		if(this.expectedTypes != null && proposalType != null) {
 			for (int i = 0; i <= this.expectedTypesPtr; i++) {
+                int relevance = R_EXPECTED_TYPE;
 				if(CharOperation.equals(this.expectedTypes[i].qualifiedPackageName(), proposalType.qualifiedPackageName()) &&
 					CharOperation.equals(this.expectedTypes[i].qualifiedSourceName(), proposalType.qualifiedSourceName())) {
-					return R_EXACT_EXPECTED_TYPE;
+                    relevance = R_EXACT_EXPECTED_TYPE;
 				}
 				if((this.expectedTypesFilter & SUBTYPE) != 0
 					&& proposalType.isCompatibleWith(this.expectedTypes[i])) {
-						return R_EXPECTED_TYPE;
+						return relevance;
 				}
 				if((this.expectedTypesFilter & SUPERTYPE) != 0
 					&& this.expectedTypes[i].isCompatibleWith(proposalType)) {
-					return R_EXPECTED_TYPE;
+					return relevance;
 				}
 			}
 		} 
@@ -3141,7 +3699,10 @@
 			
 			if (method.isConstructor()) continue next;
 				
-			if (method.isFinal()) continue next;
+			if (method.isFinal()) {
+                newMethodsFound.add(method);
+                continue next;
+            }
 
 			//		if (noVoidReturnType && method.returnType == BaseTypes.VoidBinding) continue next;
 			if(method.isStatic()) {
@@ -3154,8 +3715,7 @@
 				if(onlyStaticMethods) continue next;
 			}
 
-			if (this.options.checkVisibility
-				&& !method.canBeSeenBy(receiverType, FakeInvocationSite , scope)) continue next;
+			if (!method.canBeSeenBy(receiverType, FakeInvocationSite , scope)) continue next;
 
 			if (exactMatch) {
 				if (!CharOperation.equals(methodName, method.selector, false /* ignore case */
@@ -3188,76 +3748,19 @@
 			
 			int length = method.parameters.length;
 			char[][] parameterPackageNames = new char[length][];
-			char[][] parameterTypeNames = new char[length][];
+			char[][] parameterFullTypeNames = new char[length][];
 			
 			for (int i = 0; i < length; i++) {
 				TypeBinding type = method.parameters[i];
 				parameterPackageNames[i] = type.qualifiedPackageName();
-				parameterTypeNames[i] = type.qualifiedSourceName();
+				parameterFullTypeNames[i] = type.qualifiedSourceName();
 			}
 
-			char[][] parameterNames = findMethodParameterNames(method,parameterTypeNames);
+			char[][] parameterNames = findMethodParameterNames(method, parameterFullTypeNames);
 			
 			StringBuffer completion = new StringBuffer(10);
-			// flush uninteresting modifiers
-			int insertedModifiers = method.modifiers & ~(IConstants.AccNative | IConstants.AccAbstract);
-
 			if (!exactMatch) {
-				if(insertedModifiers != CompilerModifiers.AccDefault){
-					ASTNode.printModifiers(insertedModifiers, completion);
-				}
-				char[] returnPackageName = method.returnType.qualifiedPackageName();
-				char[] returnTypeName = method.returnType.qualifiedSourceName();
-				if(mustQualifyType(returnPackageName, returnTypeName)) {
-					completion.append(CharOperation.concat(returnPackageName, returnTypeName,'.'));
-				} else {
-					completion.append(method.returnType.sourceName());
-				}
-				completion.append(' ');
-				completion.append(method.selector);
-				completion.append('(');
-
-				for(int i = 0; i < length ; i++){
-					if(mustQualifyType(parameterPackageNames[i], parameterTypeNames[i])){
-						completion.append(CharOperation.concat(parameterPackageNames[i], parameterTypeNames[i], '.'));
-					} else {
-						completion.append(parameterTypeNames[i]);
-					}
-					completion.append(' ');
-					if(parameterNames != null){
-						completion.append(parameterNames[i]);
-					} else {
-						completion.append('%');
-					}
-					if(i != (length - 1))
-						completion.append(',');	
-				}
-				completion.append(')');
-				
-				ReferenceBinding[] exceptions = method.thrownExceptions;
-				
-				if (exceptions != null && exceptions.length > 0){
-					completion.append(' ');
-					completion.append(THROWS);
-					completion.append(' ');
-					for(int i = 0; i < exceptions.length ; i++){
-						ReferenceBinding exception = exceptions[i];
-
-						char[] exceptionPackageName = exception.qualifiedPackageName();
-						char[] exceptionTypeName = exception.qualifiedSourceName();
-						
-						if(i != 0){
-							completion.append(',');
-							completion.append(' ');
-						}
-						
-						if(mustQualifyType(exceptionPackageName, exceptionTypeName)){
-							completion.append(CharOperation.concat(exceptionPackageName, exceptionTypeName, '.'));
-						} else {
-							completion.append(exception.sourceName());
-						}
-					}
-				}
+				createMethod(method, parameterPackageNames, parameterFullTypeNames, parameterNames, completion);
 			}
 
 			int relevance = computeBaseRelevance();
@@ -3273,11 +3776,15 @@
 				proposal.setDeclarationSignature(getSignature(method.declaringClass));
 				proposal.setDeclarationKey(method.declaringClass.computeUniqueKey());
 				proposal.setSignature(getSignature(method));
+				MethodBinding original = method.original();
+				if(original != method) {
+					proposal.setOriginalSignature(getSignature(original));
+				}
 				proposal.setKey(method.computeUniqueKey());
 				proposal.setDeclarationPackageName(method.declaringClass.qualifiedPackageName());
 				proposal.setDeclarationTypeName(method.declaringClass.qualifiedSourceName());
 				proposal.setParameterPackageNames(parameterPackageNames);
-				proposal.setParameterTypeNames(parameterTypeNames);
+				proposal.setParameterTypeNames(parameterFullTypeNames);
 				proposal.setPackageName(method.returnType.qualifiedPackageName());
 				proposal.setTypeName(method.returnType.qualifiedSourceName());
 				proposal.setCompletion(completion.toString().toCharArray());
@@ -3294,6 +3801,170 @@
 		}
 		methodsFound.addAll(newMethodsFound);
 	}
+	private void createTypeVariable(TypeVariableBinding typeVariable, StringBuffer completion) {
+		completion.append(typeVariable.sourceName);
+		
+		if (typeVariable.superclass != null && typeVariable.firstBound == typeVariable.superclass) {
+		    completion.append(' ');
+		    completion.append(EXTENDS);
+		    completion.append(' ');
+		    createType(typeVariable.superclass, completion);
+		}
+		if (typeVariable.superInterfaces != null && typeVariable.superInterfaces != NoSuperInterfaces) {
+		   if (typeVariable.firstBound != typeVariable.superclass) {
+			   completion.append(' ');
+			   completion.append(EXTENDS);
+			   completion.append(' ');
+		   }
+		   for (int i = 0, length = typeVariable.superInterfaces.length; i < length; i++) {
+			   if (i > 0 || typeVariable.firstBound == typeVariable.superclass) {
+				   completion.append(' ');
+				   completion.append(EXTENDS);
+				   completion.append(' ');
+			   }
+			   createType(typeVariable.superInterfaces[i], completion);
+		   }
+		}
+	}
+	
+	private void createType(TypeBinding type, StringBuffer completion) {
+		if (type.isBaseType()) {
+			completion.append(type.sourceName());
+		} else if (type.isTypeVariable()) {
+			completion.append(type.sourceName());
+		} else if (type.isWildcard()) {
+			WildcardBinding wildcardBinding = (WildcardBinding) type;
+			completion.append('?');
+			switch (wildcardBinding.boundKind) {
+				case Wildcard.EXTENDS:
+					completion.append(' ');
+					completion.append(EXTENDS);
+					completion.append(' ');
+					createType(wildcardBinding.bound, completion);
+					if(wildcardBinding.otherBounds != null) {
+						
+						int length = wildcardBinding.otherBounds.length;
+						for (int i = 0; i < length; i++) {
+							completion.append(' ');
+							completion.append('&');
+							completion.append(' ');
+							createType(wildcardBinding.otherBounds[i], completion);
+						}
+					}
+					break;
+				case Wildcard.SUPER:
+					completion.append(' ');
+					completion.append(SUPER);
+					completion.append(' ');
+					createType(wildcardBinding.bound, completion);
+					break;
+			}
+		} else if (type.isArrayType()) {
+			createType(type.leafComponentType(), completion);
+			int dim = type.dimensions();
+			for (int i = 0; i < dim; i++) {
+				completion.append('[');
+				completion.append(']');
+			}
+		} else if (type.isParameterizedType()) {
+			ParameterizedTypeBinding parameterizedType = (ParameterizedTypeBinding) type;
+			if (type.isMemberType()) {
+				createType(parameterizedType.enclosingType(), completion);
+				completion.append('.');
+				completion.append(parameterizedType.sourceName);
+			} else {
+				completion.append(CharOperation.concatWith(parameterizedType.type.compoundName, '.'));
+			}	    
+			if (parameterizedType.arguments != null) {
+				completion.append('<');
+			    for (int i = 0, length = parameterizedType.arguments.length; i < length; i++) {
+			        if (i != 0) completion.append(',');
+			        createType(parameterizedType.arguments[i], completion);
+			    }
+			    completion.append('>');
+			}
+		} else {
+			char[] packageName = type.qualifiedPackageName();
+			char[] typeName = type.qualifiedSourceName();
+			if(mustQualifyType(
+					packageName,
+					type.sourceName(),
+					type.isMemberType() ? type.enclosingType().qualifiedSourceName() : null,
+					((ReferenceBinding)type).modifiers)) {
+				completion.append(CharOperation.concat(packageName, typeName,'.'));
+			} else {
+				completion.append(type.sourceName());
+			}
+		}
+	}
+	private void createMethod(MethodBinding method, char[][] parameterPackageNames, char[][] parameterTypeNames, char[][] parameterNames, StringBuffer completion) {
+		//// Modifiers
+		// flush uninteresting modifiers
+		int insertedModifiers = method.modifiers & ~(IConstants.AccNative | IConstants.AccAbstract);	
+		if(insertedModifiers != CompilerModifiers.AccDefault){
+			ASTNode.printModifiers(insertedModifiers, completion);
+		}
+		
+		//// Type parameters
+		
+		TypeVariableBinding[] typeVariableBindings = method.typeVariables;
+		if(typeVariableBindings != null && typeVariableBindings.length != 0) {
+			completion.append('<');
+			for (int i = 0; i < typeVariableBindings.length; i++) {
+				if(i != 0) {
+					completion.append(',');
+					completion.append(' ');
+				}
+				createTypeVariable(typeVariableBindings[i], completion);
+			}
+			completion.append('>');
+			completion.append(' ');
+		}
+		
+		//// Return type
+		createType(method.returnType, completion);
+		completion.append(' ');
+		
+		//// Selector
+		completion.append(method.selector);
+		
+		completion.append('(');
+
+		////Parameters
+		TypeBinding[] parameterTypes = method.parameters;
+		int length = parameterTypes.length;
+		for (int i = 0; i < length; i++) {
+			if(i != 0) {
+				completion.append(',');
+				completion.append(' ');
+			}
+			createType(parameterTypes[i], completion);
+			completion.append(' ');
+			if(parameterNames != null){
+				completion.append(parameterNames[i]);
+			} else {
+				completion.append('%');
+			}
+		}
+		
+		completion.append(')');
+		
+		//// Exceptions
+		ReferenceBinding[] exceptions = method.thrownExceptions;
+		
+		if (exceptions != null && exceptions.length > 0){
+			completion.append(' ');
+			completion.append(THROWS);
+			completion.append(' ');
+			for(int i = 0; i < exceptions.length ; i++){
+				if(i != 0) {
+					completion.append(' ');
+					completion.append(',');
+				}
+				createType(exceptions[i], completion);
+			}
+		}
+	}
 	private void findMethods(
 		char[] selector,
 		TypeBinding[] argTypes,
@@ -3435,7 +4106,8 @@
 		}
 	}
 	private char[][] findMethodParameterNames(MethodBinding method, char[][] parameterTypeNames){
-		ReferenceBinding bindingType = method.declaringClass;
+		TypeBinding erasure =  method.declaringClass.erasure();
+		if(!(erasure instanceof ReferenceBinding)) return null;
 
 		char[][] parameterNames = null;
 		
@@ -3445,8 +4117,8 @@
 			return CharOperation.NO_CHAR_CHAR;
 		}
 		// look into the corresponding unit if it is available
-		if (bindingType instanceof SourceTypeBinding){
-			SourceTypeBinding sourceType = (SourceTypeBinding) bindingType;
+		if (erasure instanceof SourceTypeBinding){
+			SourceTypeBinding sourceType = (SourceTypeBinding) erasure;
 
 			if (sourceType.scope != null){
 				TypeDeclaration parsedType;
@@ -3467,6 +4139,9 @@
 		}
 		// look into the model		
 		if(parameterNames == null){
+			
+			ReferenceBinding bindingType = (ReferenceBinding)erasure;
+			
 			char[] compoundName = CharOperation.concatWith(bindingType.compoundName, '.');
 			Object type = this.typeCache.get(compoundName);
 			
@@ -3484,18 +4159,21 @@
 			}
 			
 			if(sourceType != null) {
-				SourceMethod[] sourceMethods = ((SourceTypeElementInfo) sourceType).getMethodHandles();
-				int len = sourceMethods.length;
-				for(int i = 0; i < len ; i++){
-					SourceMethod sourceMethod = sourceMethods[i];
-					String[] argTypeSignatures = sourceMethod.getParameterTypes();
-
-					if(argTypeSignatures != null &&
-						CharOperation.equals(method.selector,sourceMethod.getElementName().toCharArray()) &&
-						equalSignatures(parameterTypeNames, argTypeSignatures)){
+				IType typeHandle = ((SourceTypeElementInfo) sourceType).getHandle();
+				
+				String[] parameterTypeSignatures = new String[length];
+				for (int i = 0; i < length; i++) {
+					parameterTypeSignatures[i] = Signature.createTypeSignature(parameterTypeNames[i], false);
+				}
+				IMethod searchedMethod = typeHandle.getMethod(String.valueOf(method.selector), parameterTypeSignatures);
+				IMethod[] foundMethods = typeHandle.findMethods(searchedMethod);
+				
+				if(foundMethods != null) {
+					int len = foundMethods.length;
+					if(len == 1) {
 						try {
+							SourceMethod sourceMethod = (SourceMethod) foundMethods[0];
 							parameterNames = ((SourceMethodElementInfo) sourceMethod.getElementInfo()).getArgumentNames();
-							break;
 						} catch (JavaModelException e) {
 							// method doesn't exist: ignore
 						}
@@ -3506,28 +4184,18 @@
 		return parameterNames;
 	}
 	
-	private boolean equalSignatures(char[][] typeNames, String[] typeSignatures) {
-		if (typeNames == null || typeSignatures == null)
-			return false;
-		if (typeNames.length != typeSignatures.length)
-			return false;
-
-		for (int i = typeNames.length; --i >= 0;)
-			if (!CharOperation.equals(typeNames[i], Signature.toCharArray(typeSignatures[i].toCharArray())))
-				return false;
-		return true;
-	}
-	
 	private void findNestedTypes(
 		char[] typeName,
 		SourceTypeBinding currentType,
 		Scope scope,
+		boolean proposeAllMemberTypes,
 		ObjectVector typesFound) {
 		if (typeName == null)
 			return;
 
 		int typeLength = typeName.length;
 
+		SourceTypeBinding nextTypeToIgnore = null;
 		while (scope != null) { // done when a COMPILATION_UNIT_SCOPE is found
 
 			switch (scope.kind) {
@@ -3545,12 +4213,23 @@
 							if (!localType.isAnonymousType()) {
 								if (this.isForbidden(localType))
 									continue next;
+								
 								if (typeLength > localType.sourceName.length)
 									continue next;
 								if (!CharOperation.prefixEquals(typeName, localType.sourceName, false
 									/* ignore case */
 									))
 									continue next;
+								
+								if(PROPOSE_MEMBER_TYPES) {
+									if(this.assistNodeIsClass) {
+										if(!localType.isClass()) continue next;
+									} else if(this.assistNodeIsInterface) {
+										if(!localType.isInterface() && !localType.isAnnotationType()) continue next;
+									} else if (this.assistNodeIsAnnotation) {
+										if(!localType.isAnnotationType()) continue next;
+									}
+								}
 
 								int relevance = computeBaseRelevance();
 								relevance += computeRelevanceForInterestingProposal();
@@ -3583,7 +4262,9 @@
 					break;
 
 				case Scope.CLASS_SCOPE :
-					findMemberTypes(typeName, scope.enclosingSourceType(), scope, currentType, false, typesFound);
+					SourceTypeBinding enclosingSourceType = scope.enclosingSourceType();
+					findMemberTypes(typeName, enclosingSourceType, scope, currentType, false, false, false, proposeAllMemberTypes, nextTypeToIgnore, typesFound);
+					nextTypeToIgnore = enclosingSourceType;
 					if (typeLength == 0)
 						return; // do not search outside the class scope if no prefix was provided
 					break;
@@ -3605,6 +4286,58 @@
 		this.nameEnvironment.findPackages(CharOperation.toLowerCase(this.completionToken), this);
 	}
 
+	private void findParameterizedType(TypeReference ref) {
+		ReferenceBinding refBinding = (ReferenceBinding) ref.resolvedType;
+		if(refBinding != null) {
+			char[] packageName = refBinding.qualifiedPackageName();
+			char[] typeName = refBinding.qualifiedSourceName();
+			
+			int accessibility = IAccessRule.K_ACCESSIBLE;
+			if(refBinding.hasRestrictedAccess()) {
+				AccessRestriction accessRestriction = lookupEnvironment.getAccessRestriction(refBinding);
+				if(accessRestriction != null) {
+					switch (accessRestriction.getProblemId()) {
+						case IProblem.ForbiddenReference:
+							if (this.options.checkForbiddenReference) {
+								return;
+							}
+							accessibility = IAccessRule.K_NON_ACCESSIBLE;
+							break;
+						case IProblem.DiscouragedReference:
+							if (this.options.checkDiscouragedReference) {
+								return;
+							}
+							accessibility = IAccessRule.K_DISCOURAGED;
+							break;
+					}
+				}
+			}
+
+			int relevance = computeBaseRelevance();
+			relevance += computeRelevanceForInterestingProposal();
+			relevance += computeRelevanceForCaseMatching(refBinding.sourceName, refBinding.sourceName);
+			relevance += computeRelevanceForExpectingType(refBinding);
+			relevance += computeRelevanceForQualification(false);
+			relevance += computeRelevanceForRestrictions(accessibility); // no access restriction for type in the current unit
+			
+			if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
+				CompletionProposal proposal = this.createProposal(CompletionProposal.TYPE_REF, this.actualCompletionPosition);
+				proposal.setDeclarationSignature(packageName);
+				proposal.setSignature(getSignature(refBinding));
+				proposal.setPackageName(packageName);
+				proposal.setTypeName(typeName);
+				proposal.setCompletion(CharOperation.NO_CHAR);
+				proposal.setFlags(refBinding.modifiers);
+				proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
+				proposal.setRelevance(relevance);
+				proposal.setAccessibility(accessibility);
+				this.requestor.accept(proposal);
+				if(DEBUG) {
+					this.printDebug(proposal);
+				}
+			}
+		}
+	}
 	private void findTypeParameters(char[] token, Scope scope) {
 		if (this.compilerOptions.sourceLevel < ClassFileConstants.JDK1_5) return;
 		
@@ -3675,22 +4408,60 @@
 		if (token == null)
 			return;
 		
+		// do not propose type if completion token is empty
+		boolean skip = false;
+		if (token.length == 0 && NO_TYPE_COMPLETION_ON_EMPTY_TOKEN) {
+			if(!assistNodeIsConstructor) {
+				return;
+			}
+			skip = true;
+		}
+		
 		boolean proposeType = !this.requestor.isIgnored(CompletionProposal.TYPE_REF);
 		
+		boolean proposeAllMemberTypes = !this.assistNodeIsConstructor && PROPOSE_MEMBER_TYPES;
+		
 		ObjectVector typesFound = new ObjectVector();
 		
-		if (proposeType && scope.enclosingSourceType() != null) {
-			findNestedTypes(token, scope.enclosingSourceType(), scope, typesFound);
-			findTypeParameters(token, scope);
+		if (!skip && proposeType && scope.enclosingSourceType() != null) {
+			findNestedTypes(token, scope.enclosingSourceType(), scope, proposeAllMemberTypes, typesFound);
+			if(!assistNodeIsConstructor) {
+				// don't propose type parmaters if the completion is a constructor ('new |')
+				findTypeParameters(token, scope);
+			}
 		}
 
-		if (proposeType && this.unitScope != null) {
+		if (!skip && proposeType && this.unitScope != null) {
+			ReferenceBinding outerInvocationType = scope.enclosingSourceType();
+			if(outerInvocationType != null) {
+				ReferenceBinding temp = outerInvocationType.enclosingType();
+				while(temp != null) {
+					outerInvocationType = temp;
+					temp = temp.enclosingType();
+				}
+			}
+			
 			int typeLength = token.length;
 			SourceTypeBinding[] types = this.unitScope.topLevelTypes;
 
 			for (int i = 0, length = types.length; i < length; i++) {
 				SourceTypeBinding sourceType = types[i]; 
 				
+				if(isForbidden(sourceType)) continue;
+				
+				if(proposeAllMemberTypes &&
+					sourceType != outerInvocationType &&
+					PROPOSE_MEMBER_TYPES) {
+					findSubMemberTypes(
+							token,
+							sourceType,
+							scope,
+							scope.enclosingSourceType(),
+							false,
+							false,
+							typesFound);
+				}
+				
 				if (sourceType.sourceName == CompletionParser.FAKE_TYPE_NAME) continue;
 				if (sourceType.sourceName == TypeConstants.PACKAGE_INFO_NAME) continue;
 
@@ -3699,9 +4470,17 @@
 				if (!CharOperation.prefixEquals(token, sourceType.sourceName, false))	continue;
 				
 				this.knownTypes.put(CharOperation.concat(sourceType.qualifiedPackageName(), sourceType.sourceName(), '.'), this);
-
-				if(isForbidden(sourceType)) continue;
-					
+				
+				if(PROPOSE_MEMBER_TYPES) {
+					if(this.assistNodeIsClass) {
+						if(!sourceType.isClass()) continue;
+					} else if(this.assistNodeIsInterface) {
+						if(!sourceType.isInterface() && !sourceType.isAnnotationType()) continue;
+					} else if (this.assistNodeIsAnnotation) {
+						if(!sourceType.isAnnotationType()) continue;
+					}
+				}
+				
 				int relevance = computeBaseRelevance();
 				relevance += computeRelevanceForInterestingProposal();
 				relevance += computeRelevanceForCaseMatching(token, sourceType.sourceName);
@@ -3713,7 +4492,7 @@
 					relevance += computeRelevanceForAnnotation();
 				} else if (sourceType.isInterface()) {
 					relevance += computeRelevanceForInterface();
-				} else {
+				} else if(sourceType.isClass()){
 					relevance += computeRelevanceForClass();
 					relevance += computeRelevanceForException(sourceType.sourceName);
 				}
@@ -3736,8 +4515,8 @@
 			}
 		}
 		
-		if(proposeType) {
-			this.findTypesFromStaticImports(token, scope, typesFound);
+		if(!skip && proposeType) {
+			this.findTypesFromStaticImports(token, scope, proposeAllMemberTypes, typesFound);
 		}
 		
 		if (token.length == 0) {
@@ -3746,17 +4525,26 @@
 					if(this.expectedTypes[i] instanceof ReferenceBinding) {
 						ReferenceBinding refBinding = (ReferenceBinding)this.expectedTypes[i];
 						
+						if(refBinding.isTypeVariable() && assistNodeIsConstructor) {
+							// don't propose type variable if the completion is a constructor ('new |')
+							continue next;
+						}
+						
 						int accessibility = IAccessRule.K_ACCESSIBLE;
 						if(refBinding.hasRestrictedAccess()) {
 							AccessRestriction accessRestriction = lookupEnvironment.getAccessRestriction(refBinding);
 							if(accessRestriction != null) {
 								switch (accessRestriction.getProblemId()) {
 									case IProblem.ForbiddenReference:
-										if(this.options.checkForbiddenReference) return;
+										if (this.options.checkForbiddenReference) {
+											continue next;
+										}
 										accessibility = IAccessRule.K_NON_ACCESSIBLE;
 										break;
 									case IProblem.DiscouragedReference:
-										if(this.options.checkDiscouragedReference) return;
+										if (this.options.checkDiscouragedReference) {
+											continue next;
+										}
 										accessibility = IAccessRule.K_DISCOURAGED;
 										break;
 								}
@@ -3766,14 +4554,14 @@
 						boolean inSameUnit = this.unitScope.isDefinedInSameUnit(refBinding);
 						
 						// top level types of the current unit are already proposed.
-						if(!inSameUnit || (inSameUnit && refBinding.isMemberType())) {
+						if(skip || !inSameUnit || (inSameUnit && refBinding.isMemberType())) {
 							char[] packageName = refBinding.qualifiedPackageName();
 							char[] typeName = refBinding.sourceName();
 							char[] completionName = typeName;
 							
 							boolean isQualified = false;
 							if (!this.insideQualifiedReference && !refBinding.isMemberType()) {
-								if (mustQualifyType(packageName, typeName)) {
+								if (mustQualifyType(packageName, typeName, null, refBinding.modifiers)) {
 									if (packageName == null || packageName.length == 0)
 										if (this.unitScope != null && this.unitScope.fPackage.compoundName != CharOperation.NO_CHAR_CHAR)
 											continue next; // ignore types from the default package from outside it
@@ -3782,6 +4570,16 @@
 								}
 							}
 							
+							if(PROPOSE_MEMBER_TYPES) {
+								if(this.assistNodeIsClass) {
+									if(!refBinding.isClass()) continue next;
+								} else if(this.assistNodeIsInterface) {
+									if(!refBinding.isInterface() && !refBinding.isAnnotationType()) continue next;
+								} else if (this.assistNodeIsAnnotation) {
+									if(!refBinding.isAnnotationType()) continue next;
+								}
+							}
+							
 							int relevance = computeBaseRelevance();
 							relevance += computeRelevanceForInterestingProposal();
 							relevance += computeRelevanceForCaseMatching(token, typeName);
@@ -3820,10 +4618,21 @@
 			} 
 		} else {
 			if(!this.requestor.isIgnored(CompletionProposal.KEYWORD)) {
-				findKeywords(token, baseTypes);
+				findKeywords(token, baseTypes, false);
 			}
 			if(proposeType) {
-				this.nameEnvironment.findTypes(token, this);
+				int l = typesFound.size();
+				for (int i = 0; i < l; i++) {
+					ReferenceBinding typeFound = (ReferenceBinding) typesFound.elementAt(i);
+					char[] fullyQualifiedTypeName =
+						CharOperation.concat(
+								typeFound.qualifiedPackageName(),
+								typeFound.qualifiedSourceName(), 
+								'.');
+					this.knownTypes.put(fullyQualifiedTypeName, this);
+				}
+				this.nameEnvironment.findTypes(token, proposeAllMemberTypes, this);
+				acceptTypes();
 			}
 			if(!this.requestor.isIgnored(CompletionProposal.PACKAGE_REF)) {
 				this.nameEnvironment.findPackages(token, this);
@@ -3874,11 +4683,15 @@
 					if(accessRestriction != null) {
 						switch (accessRestriction.getProblemId()) {
 							case IProblem.ForbiddenReference:
-								if(this.options.checkForbiddenReference) return;
+								if (this.options.checkForbiddenReference) {
+									continue;
+								}
 								accessibility = IAccessRule.K_NON_ACCESSIBLE;
 								break;
 							case IProblem.DiscouragedReference:
-								if(this.options.checkDiscouragedReference) return;
+								if (this.options.checkDiscouragedReference) {
+									continue;
+								}
 								accessibility = IAccessRule.K_DISCOURAGED;
 								break;
 						}
@@ -3898,7 +4711,7 @@
 					relevance += computeRelevanceForAnnotation();
 				} else if (sourceType.isInterface()) {
 					relevance += computeRelevanceForInterface();
-				} else {
+				} else if (sourceType.isClass()) {
 					relevance += computeRelevanceForClass();
 					relevance += computeRelevanceForException(sourceType.sourceName);
 				}
@@ -3923,14 +4736,15 @@
 		}
 		
 		if(proposeType) {
-			this.nameEnvironment.findTypes(qualifiedName, this);
+			this.nameEnvironment.findTypes(qualifiedName, false, this);
+			acceptTypes();
 		}
 		if(!this.requestor.isIgnored(CompletionProposal.PACKAGE_REF)) {
 			this.nameEnvironment.findPackages(qualifiedName, this);
 		}
 	}
 
-	private void findTypesFromStaticImports(char[] token, Scope scope, ObjectVector typesFound) {
+	private void findTypesFromStaticImports(char[] token, Scope scope, boolean proposeAllMemberTypes, ObjectVector typesFound) {
 		ImportBinding[] importBindings = scope.compilationUnitScope().imports;
 		for (int i = 0; i < importBindings.length; i++) {
 			ImportBinding importBinding = importBindings[i];
@@ -3945,6 +4759,10 @@
 									scope,
 									scope.enclosingSourceType(),
 									true,
+									true,
+									true,
+									proposeAllMemberTypes,
+									null,
 									typesFound);
 						}
 					} else {
@@ -3962,10 +4780,21 @@
 							
 							typesFound.add(typeBinding);
 							
+							if(PROPOSE_MEMBER_TYPES) {
+								if(this.assistNodeIsClass) {
+									if(!typeBinding.isClass()) continue;
+								} else if(this.assistNodeIsInterface) {
+									if(!typeBinding.isInterface() && !typeBinding.isAnnotationType()) continue;
+								} else if (this.assistNodeIsAnnotation) {
+									if(!typeBinding.isAnnotationType()) continue;
+								}
+							}
+							
 							int relevance = computeBaseRelevance();
 							relevance += computeRelevanceForInterestingProposal();
 							relevance += computeRelevanceForCaseMatching(token, typeBinding.sourceName);
 							relevance += computeRelevanceForExpectingType(typeBinding);
+							relevance += computeRelevanceForQualification(false);
 							relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE);
 							
 							if (typeBinding.isClass()) {
@@ -4420,7 +5249,7 @@
 				}
 			}
 		} else if(parent instanceof Assignment) {
-			TypeBinding binding = ((Assignment)parent).resolvedType;
+			TypeBinding binding = ((Assignment)parent).lhs.resolvedType;
 			if(binding != null) {
 				addExpectedType(binding);
 			}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/ISearchRequestor.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/ISearchRequestor.java
index f242334..0d8f71e 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/ISearchRequestor.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/ISearchRequestor.java
@@ -28,7 +28,7 @@
 	 *    Nested type names are in the qualified form "A.I".
 	 *    The default package is represented by an empty array.
 	 */
-	public void acceptType(char[] packageName, char[] typeName, int modifiers, AccessRestriction accessRestriction);
+	public void acceptType(char[] packageName, char[] typeName, char[][] enclosingTypeNames, int modifiers, AccessRestriction accessRestriction);
 
 //	/**
 //	 * One result of the search consists of a new annotation.
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/InternalCompletionProposal.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/InternalCompletionProposal.java
index f16a7b1..39b98f0 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/InternalCompletionProposal.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/InternalCompletionProposal.java
@@ -14,7 +14,6 @@
 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.core.BinaryType;
 import org.eclipse.jdt.internal.core.NameLookup;
@@ -46,15 +45,46 @@
 	protected char[][] parameterPackageNames;
 	protected char[][] parameterTypeNames;
 	
+	protected char[] originalSignature;
+	
 	protected int accessibility = IAccessRule.K_ACCESSIBLE;
 	
-	protected char[][] findMethodParameterNames(char[] signatureType, char[] selector, char[][] paramTypeNames){
-		if(signatureType == null) return null;
+	protected boolean isConstructor = false;
+	
+	protected char[][] createDefaultParameterNames(int length) {
+		char[][] parameterNames;
+		switch (length) {
+			case 0 :
+				parameterNames = new char[length][];
+				break;
+			case 1 :
+				parameterNames = ARGS1;
+				break;
+			case 2 :
+				parameterNames = ARGS2;
+				break;
+			case 3 :
+				parameterNames = ARGS3;
+				break;
+			case 4 :
+				parameterNames = ARGS4;
+				break;
+			default :
+				parameterNames = new char[length][];
+				for (int i = 0; i < length; i++) {
+					parameterNames[i] = CharOperation.concat(ARG, String.valueOf(i).toCharArray());
+				}
+				break;
+		}
+		return parameterNames;
+	}
+	protected char[][] findMethodParameterNames(char[] declaringTypePackageName, char[] declaringTypeName, char[] selector, char[][] paramTypeNames){
+		if(paramTypeNames == null || declaringTypeName == null) return null;
 		
-		char[] tName = Signature.toCharArray(signatureType);
 		char[][] parameterNames = null;
 		int length = paramTypeNames.length;
 		
+		char[] tName = CharOperation.concat(declaringTypePackageName,declaringTypeName,'.');
 		Object cachedType = this.completionEngine.typeCache.get(tName);
 		
 		IType type = null;
@@ -94,32 +124,9 @@
 			}
 		}
 		
-//		 default parameters name
+		// default parameters name
 		if(parameterNames == null) {
-			switch (length) {
-				case 0 :
-					parameterNames = new char[length][];
-					break;
-				case 1 :
-					parameterNames = ARGS1;
-					break;
-				case 2 :
-					parameterNames = ARGS2;
-					break;
-				case 3 :
-					parameterNames = ARGS3;
-					break;
-				case 4 :
-					parameterNames = ARGS4;
-					break;
-				default :
-					parameterNames = new char[length][];
-					for (int i = 0; i < length; i++) {
-						parameterNames[i] = CharOperation.concat(ARG, String.valueOf(i).toCharArray());
-					}
-					break;
-			}
-			
+			parameterNames = createDefaultParameterNames(length);
 		}
 		
 		return parameterNames;
@@ -150,82 +157,6 @@
 		return this.parameterTypeNames;
 	}
 	
-	protected char[][] findMethodParameterNames(char[] declaringTypePackageName, char[] declaringTypeName, char[] selector, char[][] paramPackageNames, char[][] paramTypeNames){
-		if(paramTypeNames == null) return null;
-		
-		char[][] parameterNames = null;
-		int length = paramTypeNames.length;
-		
-		char[] tName = CharOperation.concat(declaringTypePackageName,declaringTypeName,'.');
-		Object cachedType = this.completionEngine.typeCache.get(tName);
-		
-		IType type = null;
-		if(cachedType != null) {
-			if(cachedType != NO_ATTACHED_SOURCE && cachedType instanceof BinaryType) {
-				type = (BinaryType)cachedType;
-			}
-		} else { 
-			// TODO (david) shouldn't it be NameLookup.ACCEPT_ALL ?
-			type = this.nameLookup.findType(new String(tName), false, NameLookup.ACCEPT_CLASSES & NameLookup.ACCEPT_INTERFACES);
-			if(type instanceof BinaryType){
-				if(((BinaryType)type).getSourceMapper() != null) {
-					this.completionEngine.typeCache.put(tName, type);
-				} else {
-					this.completionEngine.typeCache.put(tName, NO_ATTACHED_SOURCE);
-					type = null;
-				}
-			} else {
-				type = null;
-			}
-		}
-		
-		if(type != null) {
-			String[] args = new String[length];
-			for(int i = 0;	i< length ; i++){
-				char[] parameterType = CharOperation.concat(paramPackageNames[i],paramTypeNames[i],'.');
-				args[i] = Signature.createTypeSignature(parameterType,true);
-			}
-			IMethod method = type.getMethod(new String(selector),args);
-			try{
-				parameterNames = new char[length][];
-				String[] params = method.getParameterNames();
-				for(int i = 0;	i< length ; i++){
-					parameterNames[i] = params[i].toCharArray();
-				}
-			} catch(JavaModelException e){
-				parameterNames = null;
-			}
-		}
-		// default parameters name
-		if(parameterNames == null) {
-			switch (length) {
-				case 0 :
-					parameterNames = new char[length][];
-					break;
-				case 1 :
-					parameterNames = ARGS1;
-					break;
-				case 2 :
-					parameterNames = ARGS2;
-					break;
-				case 3 :
-					parameterNames = ARGS3;
-					break;
-				case 4 :
-					parameterNames = ARGS4;
-					break;
-				default :
-					parameterNames = new char[length][];
-					for (int i = 0; i < length; i++) {
-						parameterNames[i] = CharOperation.concat(ARG, String.valueOf(i).toCharArray());
-					}
-					break;
-			}
-			
-		}
-		return parameterNames;
-	}
-	
 	protected void setDeclarationPackageName(char[] declarationPackageName) {
 		this.declarationPackageName = declarationPackageName;
 	}
@@ -253,4 +184,11 @@
 	protected void setAccessibility(int kind) {
 		this.accessibility = kind;
 	}
+	
+	protected void setIsContructor(boolean isConstructor) {
+		this.isConstructor = isConstructor;
+	}
+	public void setOriginalSignature(char[] originalSignature) {
+		this.originalSignature = originalSignature;
+	}
 }
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/SelectionEngine.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/SelectionEngine.java
index 610fe4c..739943b 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/SelectionEngine.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/SelectionEngine.java
@@ -131,9 +131,20 @@
 		this.parser = new SelectionParser(problemReporter);
 	}
 
-	public void acceptType(char[] packageName, char[] typeName, int modifiers, AccessRestriction accessRestriction) {
-		if (CharOperation.equals(typeName, this.selectedIdentifier)) {
-			if(mustQualifyType(packageName, typeName)) {
+	public void acceptType(char[] packageName, char[] simpleTypeName, char[][] enclosingTypeNames, int modifiers, AccessRestriction accessRestriction) {
+		char[] typeName = enclosingTypeNames == null ?
+				simpleTypeName :
+					CharOperation.concat(
+						CharOperation.concatWith(enclosingTypeNames, '.'),
+						simpleTypeName,
+						'.');
+		
+		if (CharOperation.equals(simpleTypeName, this.selectedIdentifier)) {
+			char[] flatEnclosingTypeNames =
+				enclosingTypeNames == null || enclosingTypeNames.length == 0 ?
+						null :
+							CharOperation.concatWith(enclosingTypeNames, '.');
+			if(mustQualifyType(packageName, simpleTypeName, flatEnclosingTypeNames, modifiers)) {
 				int length = 0;
 				int kind = modifiers & (IConstants.AccInterface | IConstants.AccEnum | IConstants.AccAnnotation);
 				switch (kind) {
@@ -601,20 +612,23 @@
 							char[][] tokens = ((SelectionOnImportReference) importReference).tokens;
 							this.noProposal = false;
 							this.requestor.acceptPackage(CharOperation.concatWith(tokens, '.'));
-							this.nameEnvironment.findTypes(CharOperation.concatWith(tokens, '.'), this);
+							this.nameEnvironment.findTypes(CharOperation.concatWith(tokens, '.'), false, this);
 							
-							if(importReference.isStatic()) {
-								this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/);
-								if ((this.unitScope = parsedUnit.scope) != null) {
-									int tokenCount = tokens.length;
-									char[] lastToken = tokens[tokenCount - 1];
-									char[][] qualifierTokens = CharOperation.subarray(tokens, 0, tokenCount - 1);
-									
+							this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/);
+							if ((this.unitScope = parsedUnit.scope) != null) {
+								int tokenCount = tokens.length;
+								char[] lastToken = tokens[tokenCount - 1];
+								char[][] qualifierTokens = CharOperation.subarray(tokens, 0, tokenCount - 1);
+								
+								if(qualifierTokens != null && qualifierTokens.length > 0) {
 									Binding binding = this.unitScope.getTypeOrPackage(qualifierTokens);
 									if(binding != null && binding instanceof ReferenceBinding) {
 										ReferenceBinding ref = (ReferenceBinding) binding;
-										selectStaticFieldFromStaticImport(parsedUnit, lastToken, ref);
-										selectStaticMethodFromStaticImport(parsedUnit, lastToken, ref);
+										selectMemberTypeFromImport(parsedUnit, lastToken, ref, importReference.isStatic());
+										if(importReference.isStatic()) {
+											selectStaticFieldFromStaticImport(parsedUnit, lastToken, ref);
+											selectStaticMethodFromStaticImport(parsedUnit, lastToken, ref);
+										}
 									}
 								}
 							}
@@ -623,7 +637,7 @@
 							if(!this.acceptedAnswer) {
 								acceptQualifiedTypes();
 								if (!this.acceptedAnswer) {
-									this.nameEnvironment.findTypes(this.selectedIdentifier, this);
+									this.nameEnvironment.findTypes(this.selectedIdentifier, false, this);
 									// try with simple type name
 									if(!this.acceptedAnswer) {
 										acceptQualifiedTypes();
@@ -637,7 +651,7 @@
 						}
 					}
 				}
-				if (parsedUnit.types != null) {
+				if (parsedUnit.types != null || parsedUnit.isPackageInfo()) {
 					if(selectDeclaration(parsedUnit))
 						return;
 					this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/);
@@ -645,7 +659,9 @@
 						try {
 							this.lookupEnvironment.completeTypeBindings(parsedUnit, true);
 							parsedUnit.scope.faultInTypes();
-							ASTNode node = parseBlockStatements(parsedUnit, selectionSourceStart);
+							ASTNode node = null;
+							if (parsedUnit.types != null)
+								node = parseBlockStatements(parsedUnit, selectionSourceStart);
 							if(DEBUG) {
 								System.out.println("SELECTION - AST :"); //$NON-NLS-1$
 								System.out.println(parsedUnit.toString());
@@ -670,7 +686,7 @@
 			// only reaches here if no selection could be derived from the parsed tree
 			// thus use the selected source and perform a textual type search
 			if (!this.acceptedAnswer) {
-				this.nameEnvironment.findTypes(this.selectedIdentifier, this);
+				this.nameEnvironment.findTypes(this.selectedIdentifier, false, this);
 				
 				// accept qualified types only if no unqualified type was accepted
 				if(!this.acceptedAnswer) {
@@ -695,6 +711,25 @@
 		}
 	}
 
+	private void selectMemberTypeFromImport(CompilationUnitDeclaration parsedUnit, char[] lastToken, ReferenceBinding ref, boolean staticOnly) {
+		int fieldLength = lastToken.length;
+		ReferenceBinding[] memberTypes = ref.memberTypes();
+		next : for (int j = 0; j < memberTypes.length; j++) {
+			ReferenceBinding memberType = memberTypes[j];
+			
+			if (fieldLength > memberType.sourceName.length)
+				continue next;
+
+			if (staticOnly && !memberType.isStatic())
+				continue next;
+
+			if (!CharOperation.equals(lastToken, memberType.sourceName, true))
+				continue next;
+			
+			this.selectFrom(memberType, parsedUnit, false);
+		}
+	}
+	
 	private void selectStaticFieldFromStaticImport(CompilationUnitDeclaration parsedUnit, char[] lastToken, ReferenceBinding ref) {
 		int fieldLength = lastToken.length;
 		FieldBinding[] fields = ref.fields();
@@ -777,7 +812,7 @@
 			ReferenceBinding typeBinding = (ReferenceBinding) binding;
 			
 			if(typeBinding instanceof ProblemReferenceBinding) {
-				typeBinding = ((ProblemReferenceBinding) typeBinding).original;
+				typeBinding = ((ProblemReferenceBinding) typeBinding).closestMatch;
 			}
 			if (typeBinding == null) return;
 			if (isLocal(typeBinding) && this.requestor instanceof SelectionRequestor) {
@@ -963,6 +998,13 @@
 	public void selectType(ISourceType sourceType, char[] typeName, SourceTypeElementInfo[] topLevelTypes, boolean searchInEnvironment) {
 		try {
 			this.acceptedAnswer = false;
+			
+			// only the type erasure are returned by IType.resolvedType(...)
+			if (CharOperation.indexOf('<', typeName) != -1) {
+				char[] typeSig = Signature.createCharArrayTypeSignature(typeName, false/*not resolved*/);
+				typeSig = Signature.getTypeErasure(typeSig);
+				typeName = Signature.toCharArray(typeSig);
+			}
 
 			// find the outer most type
 			ISourceType outerType = sourceType;
@@ -1045,7 +1087,7 @@
 			// thus use the selected source and perform a textual type search
 			if (!this.acceptedAnswer && searchInEnvironment) {
 				if (this.selectedIdentifier != null) {
-					this.nameEnvironment.findTypes(typeName, this);
+					this.nameEnvironment.findTypes(typeName, false, this);
 					
 					// accept qualified types only if no unqualified type was accepted
 					if(!this.acceptedAnswer) {
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnKeyword.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnKeyword.java
index dda5b60..fb3e117 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnKeyword.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnKeyword.java
@@ -14,4 +14,5 @@
 	
 	char[] getToken();
 	char[][] getPossibleKeywords();
+	boolean canCompleteEmptyToken();
 }
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnKeyword1.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnKeyword1.java
index 22fd7a2..4124ceb 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnKeyword1.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnKeyword1.java
@@ -16,6 +16,8 @@
 
 public class CompletionOnKeyword1 extends SingleTypeReference implements CompletionOnKeyword {
 	private char[][] possibleKeywords;
+	public boolean canCompleteEmptyToken;
+	
 	public CompletionOnKeyword1(char[] token, long pos, char[] possibleKeyword) {
 		this(token, pos, new char[][]{possibleKeyword});
 	}
@@ -23,6 +25,9 @@
 		super(token, pos);
 		this.possibleKeywords = possibleKeywords;
 	}
+	public boolean canCompleteEmptyToken() {
+		return this.canCompleteEmptyToken;
+	}
 	public char[] getToken() {
 		return token;
 	}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnKeyword2.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnKeyword2.java
index fbb03f7..41c6e65 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnKeyword2.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnKeyword2.java
@@ -20,6 +20,9 @@
 		this.token = token;
 		this.possibleKeywords = possibleKeywords;
 	}
+	public boolean canCompleteEmptyToken() {
+		return false;
+	}
 	public char[] getToken() {
 		return token;
 	}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnKeyword3.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnKeyword3.java
index 20a0716..da672e1 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnKeyword3.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnKeyword3.java
@@ -24,6 +24,9 @@
 		this.token = token;
 		this.possibleKeywords = possibleKeywords;
 	}
+	public boolean canCompleteEmptyToken() {
+		return false;
+	}
 	public char[] getToken() {
 		return token;
 	}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnMessageSend.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnMessageSend.java
index d40546b..0654ac1 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnMessageSend.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnMessageSend.java
@@ -60,6 +60,16 @@
 
 		output.append("<CompleteOnMessageSend:"); //$NON-NLS-1$
 		if (!receiver.isImplicitThis()) receiver.printExpression(0, output).append('.'); //$NON-NLS-1$
+		if (this.typeArguments != null) {
+			output.append('<');//$NON-NLS-1$
+			int max = typeArguments.length - 1;
+			for (int j = 0; j < max; j++) {
+				typeArguments[j].print(0, output);
+				output.append(", ");//$NON-NLS-1$
+			}
+			typeArguments[max].print(0, output);
+			output.append('>');
+		}
 		output.append(selector).append('('); //$NON-NLS-1$
 		if (arguments != null) {
 			for (int i = 0; i < arguments.length; i++) {
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnSingleTypeReference.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnSingleTypeReference.java
index 7d40ec9..a7f415d 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnSingleTypeReference.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnSingleTypeReference.java
@@ -29,6 +29,7 @@
 
 public class CompletionOnSingleTypeReference extends SingleTypeReference {
 public boolean isCompletionNode;
+public boolean isConstructorType;
 public CompletionOnFieldType fieldTypeCompletionNode;
 
 public CompletionOnSingleTypeReference(char[] source, long pos) {
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java
index 2038322..383cb95 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java
@@ -299,6 +299,14 @@
 		}
 	}
 	
+	if(this.genericsPtr > -1) {
+		ASTNode node = this.genericsStack[this.genericsPtr];
+		if(node instanceof Wildcard && ((Wildcard)node).bound == this.assistNode){
+			buildMoreGenericsCompletionContext(node);
+			return;
+		}
+	}
+	
 	if(this.currentElement instanceof RecoveredType || this.currentElement instanceof RecoveredMethod) {
 		if(this.currentElement instanceof RecoveredType) {
 			RecoveredType recoveredType = (RecoveredType)this.currentElement;
@@ -375,8 +383,7 @@
 					return;
 				}
 			}
-			if(node == this.assistNode ||
-					((Wildcard)node).bound == this.assistNode){
+			if(node == this.assistNode){
 				buildMoreGenericsCompletionContext(node);
 			}
 		}
@@ -510,7 +517,7 @@
 					int length = expressionLengthStack[expressionLengthPtr];
 					
 					// search previous arguments if missing
-					if(expressionLengthPtr > 0 && length == 1) {
+					if(this.expressionPtr > 0 && this.expressionLengthPtr > 0 && length == 1) {
 						int start = (int) (identifierPositionStack[selector] >>> 32);
 						if(this.expressionStack[expressionPtr-1] != null && this.expressionStack[expressionPtr-1].sourceStart > start) {
 							length += expressionLengthStack[expressionLengthPtr-1];
@@ -544,9 +551,19 @@
 								
 								// remove selector 
 								this.identifierPtr--; 
-								this.identifierLengthStack[this.identifierLengthPtr]--;
+								if(this.genericsPtr > -1 && this.genericsLengthPtr > -1 && this.genericsLengthStack[this.genericsLengthPtr] > 0) {
+									// is inside a paremeterized method: bar.<X>.foo
+									this.identifierLengthPtr--;
+								} else {
+									this.identifierLengthStack[this.identifierLengthPtr]--;
+								}
 								// consume the receiver
-								messageSend.receiver = this.getUnspecifiedReference();
+								int identifierLength = this.identifierLengthStack[this.identifierLengthPtr];
+								if(this.identifierPtr > -1 && identifierLength > 0 && this.identifierPtr + 1 >= identifierLength) {
+									messageSend.receiver = this.getUnspecifiedReference();
+								} else {
+									messageSend = null;
+								}
 								break;
 							case SUPER_RECEIVER:
 								messageSend.receiver = new SuperReference(0, 0);
@@ -841,7 +858,11 @@
 						if(prevKind == K_PARAMETERIZED_CAST) {
 							ref = computeQualifiedGenericsFromRightSide(ref, 0);
 						}
-						currentElement = currentElement.add(ref, 0);
+						if(currentElement instanceof RecoveredType) {
+							currentElement = currentElement.add(new CompletionOnFieldType(ref, false), 0);
+						} else {
+							currentElement = currentElement.add(ref, 0);
+						}
 					} else if (currentElement.enclosingMethod().methodDeclaration.isConstructor()) {
 						currentElement = currentElement.add((TypeReference)node, 0);
 					}
@@ -900,6 +921,9 @@
 			} else {
 				type = getTypeReference(0);
 			}
+			if(type instanceof CompletionOnSingleTypeReference) {
+				((CompletionOnSingleTypeReference)type).isConstructorType = true;
+			}
 			allocExpr.type = type;
 			allocExpr.sourceStart = type.sourceStart;
 			allocExpr.sourceEnd = type.sourceEnd;
@@ -1144,7 +1168,12 @@
 				
 					// remove selector 
 					this.identifierPtr--; 
-					this.identifierLengthStack[this.identifierLengthPtr]--;
+					if(this.genericsPtr > -1 && this.genericsLengthPtr > -1 && this.genericsLengthStack[this.genericsLengthPtr] > 0) {
+						// is inside a paremeterized method: bar.<X>.foo
+						this.identifierLengthPtr--;
+					} else {
+						this.identifierLengthStack[this.identifierLengthPtr]--;
+					}
 					// consume the receiver
 					messageSend.receiver = this.getUnspecifiedReference();
 					break;
@@ -1197,8 +1226,10 @@
 				// creates an allocation expression 
 				CompletionOnQualifiedAllocationExpression allocExpr = new CompletionOnQualifiedAllocationExpression();
 				allocExpr.arguments = arguments;
-				pushOnGenericsLengthStack(0);
-				pushOnGenericsIdentifiersLengthStack(identifierLengthStack[identifierLengthPtr]);
+				if(this.genericsLengthPtr < 0) {
+					pushOnGenericsLengthStack(0);
+					pushOnGenericsIdentifiersLengthStack(identifierLengthStack[identifierLengthPtr]);
+				}
 				allocExpr.type = super.getTypeReference(0); // we don't want a completion node here, so call super
 				if (invocType == QUALIFIED_ALLOCATION) {
 					allocExpr.enclosingInstance = this.expressionStack[qualifierExprPtr];
@@ -1372,6 +1403,62 @@
 	}
 	return false;
 }
+private void classHeaderExtendsOrImplements(boolean isInterface) {
+	if (currentElement != null
+			&& currentToken == TokenNameIdentifier
+			&& this.cursorLocation+1 >= scanner.startPosition
+			&& this.cursorLocation < scanner.currentPosition){
+			this.pushIdentifier();
+		int index = -1;
+		/* check if current awaiting identifier is the completion identifier */
+		if ((index = this.indexOfAssistIdentifier()) > -1) {
+			int ptr = this.identifierPtr - this.identifierLengthStack[this.identifierLengthPtr] + index + 1;
+			RecoveredType recoveredType = (RecoveredType)currentElement;
+			/* filter out cases where scanner is still inside type header */
+			if (!recoveredType.foundOpeningBrace) {
+				TypeDeclaration type = recoveredType.typeDeclaration;
+				if(!isInterface) {
+					char[][] keywords = new char[Keywords.COUNT][];
+					int count = 0;
+					
+					
+					if(type.superInterfaces == null) {
+						if(type.superclass == null) {
+							keywords[count++] = Keywords.EXTENDS;
+						}
+						keywords[count++] = Keywords.IMPLEMENTS;
+					}
+					
+					System.arraycopy(keywords, 0, keywords = new char[count][], 0, count);
+					
+					if(count > 0) {
+						CompletionOnKeyword1 completionOnKeyword = new CompletionOnKeyword1(
+							identifierStack[ptr],
+							identifierPositionStack[ptr],
+							keywords);
+						completionOnKeyword.canCompleteEmptyToken = true;
+						type.superclass = completionOnKeyword;
+						type.superclass.bits |= ASTNode.IsSuperType;
+						this.assistNode = completionOnKeyword;
+						this.lastCheckPoint = completionOnKeyword.sourceEnd + 1;
+					}
+				} else {
+					if(type.superInterfaces == null) {
+						CompletionOnKeyword1 completionOnKeyword = new CompletionOnKeyword1(
+							identifierStack[ptr],
+							identifierPositionStack[ptr],
+							Keywords.EXTENDS);
+						completionOnKeyword.canCompleteEmptyToken = true;
+						type.superInterfaces = new TypeReference[]{completionOnKeyword};
+						type.superInterfaces[0].bits |= ASTNode.IsSuperType;
+						this.assistNode = completionOnKeyword;
+						this.lastCheckPoint = completionOnKeyword.sourceEnd + 1;
+					}
+				}
+			}
+		}
+	}
+}
 /* 
  * Check whether about to shift beyond the completion token.
  * If so, depending on the context, a special node might need to be created
@@ -1537,45 +1624,9 @@
 protected void consumeClassHeaderName1() {
 	super.consumeClassHeaderName1();
 
-	if (currentElement != null
-		&& currentToken == TokenNameIdentifier
-		&& this.cursorLocation+1 >= scanner.startPosition
-		&& this.cursorLocation < scanner.currentPosition){
-		this.pushIdentifier();
-
-		int index = -1;
-		/* check if current awaiting identifier is the completion identifier */
-		if ((index = this.indexOfAssistIdentifier()) > -1) {
-			int ptr = this.identifierPtr - this.identifierLengthStack[this.identifierLengthPtr] + index + 1;
-			RecoveredType recoveredType = (RecoveredType)currentElement;
-			/* filter out cases where scanner is still inside type header */
-			if (!recoveredType.foundOpeningBrace) {
-				char[][] keywords = new char[Keywords.COUNT][];
-				int count = 0;
-				
-				TypeDeclaration type = recoveredType.typeDeclaration;
-				if(type.superInterfaces == null) {
-					if(type.superclass == null) {
-						keywords[count++] = Keywords.EXTENDS;
-					}
-					keywords[count++] = Keywords.IMPLEMENTS;
-				}
-				
-				System.arraycopy(keywords, 0, keywords = new char[count][], 0, count);
-				
-				if(count > 0) {
-					type.superclass = new CompletionOnKeyword1(
-						identifierStack[ptr],
-						identifierPositionStack[ptr],
-						keywords);
-					type.superclass.bits |= ASTNode.IsSuperType;
-					this.assistNode = type.superclass;
-					this.lastCheckPoint = type.superclass.sourceEnd + 1;
-				}
-			}
-		}
-	}
+	classHeaderExtendsOrImplements(false);
 }
+
 protected void consumeClassHeaderExtends() {
 	pushOnElementStack(K_NEXT_TYPEREF_IS_CLASS);
 	super.consumeClassHeaderExtends();
@@ -1847,13 +1898,23 @@
 }
 protected void consumeInsideCastExpression() {
 	int end = intStack[intPtr--];
-	if(this.identifierLengthStack[this.identifierLengthPtr] > 0) {
-		pushOnGenericsIdentifiersLengthStack(this.identifierLengthStack[this.identifierLengthPtr]);
-		if(this.genericsLengthPtr < 0) {
+	boolean isParameterized =(topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_PARAMETERIZED_CAST);
+	if(isParameterized) {
+		popElement(K_PARAMETERIZED_CAST);
+		
+		if(this.identifierLengthStack[this.identifierLengthPtr] > 0) {
+			pushOnGenericsIdentifiersLengthStack(this.identifierLengthStack[this.identifierLengthPtr]);
+		}
+	} else {
+		if(this.identifierLengthStack[this.identifierLengthPtr] > 0) {
+			pushOnGenericsIdentifiersLengthStack(this.identifierLengthStack[this.identifierLengthPtr]);
 			pushOnGenericsLengthStack(0);
 		}
 	}
 	Expression castType = getTypeReference(intStack[intPtr--]);
+	if(isParameterized) {
+		intPtr--;
+	}
 	castType.sourceEnd = end - 1;
 	castType.sourceStart = intStack[intPtr--] + 1;
 	pushOnExpressionStack(castType);
@@ -1861,10 +1922,15 @@
 	pushOnElementStack(K_CAST_STATEMENT);
 }
 protected void consumeInsideCastExpressionLL1() {
+	if(topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_PARAMETERIZED_CAST) {
+		popElement(K_PARAMETERIZED_CAST);
+	}
 	super.consumeInsideCastExpressionLL1();
 	pushOnElementStack(K_CAST_STATEMENT);
 }
 protected void consumeInsideCastExpressionWithQualifiedGenerics() {
+	popElement(K_PARAMETERIZED_CAST);
+	
 	Expression castType;
 	int end = this.intStack[this.intPtr--];
 
@@ -1872,6 +1938,7 @@
 	TypeReference rightSide = getTypeReference(0);
 
 	castType = computeQualifiedGenericsFromRightSide(rightSide, dim);
+	this.intPtr--;
 	castType.sourceEnd = end - 1;
 	castType.sourceStart = this.intStack[this.intPtr--] + 1;
 	pushOnExpressionStack(castType);
@@ -1899,33 +1966,7 @@
 protected void consumeInterfaceHeaderName1() {
 	super.consumeInterfaceHeaderName1();
 	
-	if (currentElement != null
-		&& currentToken == TokenNameIdentifier
-		&& this.cursorLocation+1 >= scanner.startPosition
-		&& this.cursorLocation < scanner.currentPosition){
-		this.pushIdentifier();
-		
-		int index = -1;
-		/* check if current awaiting identifier is the completion identifier */
-		if ((index = this.indexOfAssistIdentifier()) > -1) {
-			int ptr = this.identifierPtr - this.identifierLengthStack[this.identifierLengthPtr] + index + 1;
-			RecoveredType recoveredType = (RecoveredType)currentElement;
-			/* filter out cases where scanner is still inside type header */
-			if (!recoveredType.foundOpeningBrace) {
-				TypeDeclaration type = recoveredType.typeDeclaration;
-				if(type.superInterfaces == null) {
-					CompletionOnKeyword1 completionOnKeyword = new CompletionOnKeyword1(
-						identifierStack[ptr],
-						identifierPositionStack[ptr],
-						Keywords.EXTENDS);
-					type.superInterfaces = new TypeReference[]{completionOnKeyword};
-					type.superInterfaces[0].bits |= ASTNode.IsSuperType;
-					this.assistNode = completionOnKeyword;
-					this.lastCheckPoint = completionOnKeyword.sourceEnd + 1;
-				}
-			}
-		}
-	}
+	classHeaderExtendsOrImplements(true);
 }
 protected void consumeInterfaceHeaderExtends() {
 	super.consumeInterfaceHeaderExtends();
@@ -1941,16 +1982,31 @@
 	popElement(K_SELECTOR_INVOCATION_TYPE);
 	super.consumeMethodInvocationName();
 }
+protected void consumeMethodInvocationNameWithTypeArguments() {
+	popElement(K_SELECTOR_QUALIFIER);
+	popElement(K_SELECTOR_INVOCATION_TYPE);
+	super.consumeMethodInvocationNameWithTypeArguments();
+}
 protected void consumeMethodInvocationPrimary() {
 	popElement(K_SELECTOR_QUALIFIER);
 	popElement(K_SELECTOR_INVOCATION_TYPE);
 	super.consumeMethodInvocationPrimary();
 }
+protected void consumeMethodInvocationPrimaryWithTypeArguments() {
+	popElement(K_SELECTOR_QUALIFIER);
+	popElement(K_SELECTOR_INVOCATION_TYPE);
+	super.consumeMethodInvocationPrimaryWithTypeArguments();
+}
 protected void consumeMethodInvocationSuper() {
 	popElement(K_SELECTOR_QUALIFIER);
 	popElement(K_SELECTOR_INVOCATION_TYPE);
 	super.consumeMethodInvocationSuper();
 }
+protected void consumeMethodInvocationSuperWithTypeArguments() {
+	popElement(K_SELECTOR_QUALIFIER);
+	popElement(K_SELECTOR_INVOCATION_TYPE);
+	super.consumeMethodInvocationSuperWithTypeArguments();
+}
 protected void consumeMethodHeaderName(boolean isAnnotationMethod) {
 	if(this.indexOfAssistIdentifier() < 0) {
 		identifierPtr--;
@@ -2287,6 +2343,20 @@
 	
 	super.consumePrimaryNoNewArrayName();
 }
+protected void consumePrimaryNoNewArrayNameSuper() {
+	// this is class literal access, so reset potential receiver
+	this.invocationType = NO_RECEIVER;
+	this.qualifier = -1;
+	
+	super.consumePrimaryNoNewArrayNameSuper();
+}
+protected void consumePrimaryNoNewArrayNameThis() {
+	// this is class literal access, so reset potential receiver
+	this.invocationType = NO_RECEIVER;
+	this.qualifier = -1;
+	
+	super.consumePrimaryNoNewArrayNameThis();
+}
 protected void consumePushPosition() {
 	super.consumePushPosition();
 	if(topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_BINARY_OPERATOR) {
@@ -2444,6 +2514,16 @@
 						this.qualifier = -1;
 						this.invocationType = NO_RECEIVER;
 						break;
+					case TokenNameGREATER: // explicit constructor invocation, eg. Fred<X>[(]1, 2)
+					case TokenNameRIGHT_SHIFT: // or fred<X<X>>[(]1, 2) 
+					case TokenNameUNSIGNED_RIGHT_SHIFT: //or Fred<X<X<X>>>[(]1, 2)
+						if (topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_SELECTOR) {
+							this.pushOnElementStack(K_SELECTOR_INVOCATION_TYPE, (this.invocationType == QUALIFIED_ALLOCATION) ? QUALIFIED_ALLOCATION : ALLOCATION);
+							this.pushOnElementStack(K_SELECTOR_QUALIFIER, this.qualifier);
+						}
+						this.qualifier = -1;
+						this.invocationType = NO_RECEIVER;
+						break;
 				}
 				break;
 			case TokenNameLBRACE:
@@ -2728,9 +2808,6 @@
 }
 protected void consumeRightParen() {
 	super.consumeRightParen();
-	if(topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_PARAMETERIZED_CAST) {
-		popElement(K_PARAMETERIZED_CAST);
-	}
 }
 protected void consumeReferenceType1() {
 	super.consumeReferenceType1();
@@ -2756,10 +2833,46 @@
 	super.consumeTypeArguments();
 	popElement(K_BINARY_OPERATOR);
 }
+protected void consumeTypeHeaderNameWithTypeParameters() {
+	super.consumeTypeHeaderNameWithTypeParameters();
+	
+	TypeDeclaration typeDecl = (TypeDeclaration)this.astStack[this.astPtr];
+	classHeaderExtendsOrImplements((typeDecl.modifiers & AccInterface) != 0);
+}
 protected void consumeTypeParameters() {
 	super.consumeTypeParameters();
 	popElement(K_BINARY_OPERATOR);
 }
+protected void consumeTypeParameterHeader() {
+	super.consumeTypeParameterHeader();
+	TypeParameter typeParameter = (TypeParameter) this.genericsStack[this.genericsPtr];
+	if(typeParameter.type != null || (typeParameter.bounds != null && typeParameter.bounds.length > 0)) return;
+	
+	if (assistIdentifier() == null && this.currentToken == TokenNameIdentifier) { // Test below copied from CompletionScanner.getCurrentIdentifierSource()
+		if (cursorLocation < this.scanner.startPosition && this.scanner.currentPosition == this.scanner.startPosition){ // fake empty identifier got issued
+			this.pushIdentifier();					
+		} else if (cursorLocation+1 >= this.scanner.startPosition && cursorLocation < this.scanner.currentPosition){
+			this.pushIdentifier();
+		} else {
+			return;
+		}
+	} else {
+		return;
+	}
+
+	CompletionOnKeyword1 keyword = new CompletionOnKeyword1(
+		identifierStack[this.identifierPtr],
+		identifierPositionStack[this.identifierPtr],
+		Keywords.EXTENDS);
+	keyword.canCompleteEmptyToken = true;
+	typeParameter.type = keyword;
+	
+	this.identifierPtr--;
+	this.identifierLengthPtr--;
+	
+	this.assistNode = typeParameter.type;
+	this.lastCheckPoint = typeParameter.type.sourceEnd + 1;
+}
 protected void consumeTypeParameters1() {
 	super.consumeTypeParameter1();
 	popElement(K_BINARY_OPERATOR);
@@ -2780,6 +2893,34 @@
 	super.consumeTypeParameter1WithExtendsAndBounds();
 	popElement(K_EXTENDS_KEYWORD);
 }
+protected void consumeWildcard() {
+	super.consumeWildcard();
+	if (assistIdentifier() == null && this.currentToken == TokenNameIdentifier) { // Test below copied from CompletionScanner.getCurrentIdentifierSource()
+		if (cursorLocation < this.scanner.startPosition && this.scanner.currentPosition == this.scanner.startPosition){ // fake empty identifier got issued
+			this.pushIdentifier();					
+		} else if (cursorLocation+1 >= this.scanner.startPosition && cursorLocation < this.scanner.currentPosition){
+			this.pushIdentifier();
+		} else {
+			return;
+		}
+	} else {
+		return;
+	}
+	Wildcard wildcard = (Wildcard) this.genericsStack[this.genericsPtr];
+	CompletionOnKeyword1 keyword = new CompletionOnKeyword1(
+		identifierStack[this.identifierPtr],
+		identifierPositionStack[this.identifierPtr],
+		new char[][]{Keywords.EXTENDS, Keywords.SUPER} );
+	keyword.canCompleteEmptyToken = true;
+	wildcard.kind = Wildcard.EXTENDS;
+	wildcard.bound = keyword;
+	
+	this.identifierPtr--;
+	this.identifierLengthPtr--;
+	
+	this.assistNode = wildcard.bound;
+	this.lastCheckPoint = wildcard.bound.sourceEnd + 1;
+}
 protected void consumeWildcard1() {
 	super.consumeWildcard1();
 	popElement(K_BINARY_OPERATOR);
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionScanner.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionScanner.java
index 7523889..7f8f80f 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionScanner.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionScanner.java
@@ -118,11 +118,6 @@
 						/* might be completing at eof (e.g. behind a dot) */
 						if (this.completionIdentifier == null && 
 							this.startPosition == this.cursorLocation + 1){
-							// compute end of empty identifier.
-							// if the empty identifier is at the start of a next token the end of
-							// empty identifier is the end of the next token (eg. "<empty token>next").
-						 	while(getNextCharAsJavaIdentifierPart()){/*empty*/}
-						 	this.endOfEmptyToken = this.currentPosition - 1;
 							this.currentPosition = this.startPosition; // for being detected as empty free identifier
 							return TokenNameIdentifier;
 						}	
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistOptions.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistOptions.java
index 4771072..5e8d5ec 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistOptions.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistOptions.java
@@ -39,13 +39,13 @@
 	public static final String OPTION_ArgumentSuffixes =
 		"org.eclipse.jdt.core.codeComplete.argumentSuffixes"; 	//$NON-NLS-1$
 	public static final String OPTION_PerformForbiddenReferenceCheck =
-		"org.eclipse.jdt.core.codeComplete.restrictionsCheck"; 	//$NON-NLS-1$
+		"org.eclipse.jdt.core.codeComplete.forbiddenReferenceCheck"; 	//$NON-NLS-1$
 	public static final String OPTION_PerformDiscouragedReferenceCheck =
 		"org.eclipse.jdt.core.codeComplete.discouragedReferenceCheck"; 	//$NON-NLS-1$
 	
 	public static final String ENABLED = "enabled"; //$NON-NLS-1$
 	public static final String DISABLED = "disabled"; //$NON-NLS-1$
-
+	
 	public boolean checkVisibility = false;
 	public boolean checkForbiddenReference = false;
 	public boolean checkDiscouragedReference = false;
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistParser.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistParser.java
index eebf89a..469e37e 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistParser.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistParser.java
@@ -74,11 +74,16 @@
 	protected static final int K_METHOD_DELIMITER = ASSIST_PARSER + 3; // whether we are inside a method declaration
 	protected static final int K_FIELD_INITIALIZER_DELIMITER = ASSIST_PARSER + 4; // whether we are inside a field initializer
 	protected static final int K_ATTRIBUTE_VALUE_DELIMITER = ASSIST_PARSER + 5; // whether we are inside a annotation attribute valuer
+	protected static final int K_ENUM_CONSTANT_DELIMITER = ASSIST_PARSER + 6; // whether we are inside a field initializer
 	
 	// selector constants
 	protected static final int THIS_CONSTRUCTOR = -1;
 	protected static final int SUPER_CONSTRUCTOR = -2;
 	
+	// enum constant constants
+	protected static final int NO_BODY = 0;
+	protected static final int WITH_BODY = 1;
+	
 	protected boolean isFirst = false;
 
 public AssistParser(ProblemReporter problemReporter) {
@@ -279,6 +284,29 @@
 	super.consumeEnterMemberValue();
 	pushOnElementStack(K_ATTRIBUTE_VALUE_DELIMITER, this.identifierPtr);
 }
+protected void consumeEnumConstantHeader() {
+	if(this.currentToken == TokenNameLBRACE) {
+		popElement(K_ENUM_CONSTANT_DELIMITER);
+		pushOnElementStack(K_ENUM_CONSTANT_DELIMITER, WITH_BODY);
+		pushOnElementStack(K_FIELD_INITIALIZER_DELIMITER);
+		pushOnElementStack(K_TYPE_DELIMITER);
+	}
+	super.consumeEnumConstantHeader();
+}
+protected void consumeEnumConstantHeaderName() {
+	super.consumeEnumConstantHeaderName();
+	pushOnElementStack(K_ENUM_CONSTANT_DELIMITER);
+}
+protected void consumeEnumConstantWithClassBody() {
+	popElement(K_TYPE_DELIMITER);
+	popElement(K_FIELD_INITIALIZER_DELIMITER);
+	popElement(K_ENUM_CONSTANT_DELIMITER);
+	super.consumeEnumConstantWithClassBody();
+}
+protected void consumeEnumConstantNoClassBody() {
+	popElement(K_ENUM_CONSTANT_DELIMITER);
+	super.consumeEnumConstantNoClassBody();
+}
 protected void consumeEnumHeader() {
 	super.consumeEnumHeader();
 	pushOnElementStack(K_TYPE_DELIMITER);
@@ -296,31 +324,23 @@
 	// if we are not in a method (ie. we are not in a local variable initializer)
 	// then we are entering a field initializer
 	if (!isInsideMethod()) {
-		pushOnElementStack(K_FIELD_INITIALIZER_DELIMITER);
+		if(topKnownElementKind(ASSIST_PARSER) != K_ENUM_CONSTANT_DELIMITER) {
+			if(topKnownElementKind(ASSIST_PARSER, 2) != K_ENUM_CONSTANT_DELIMITER) {
+				pushOnElementStack(K_FIELD_INITIALIZER_DELIMITER);
+			}
+		} else {
+			int info = topKnownElementInfo(ASSIST_PARSER);
+			if(info != NO_BODY) {
+				pushOnElementStack(K_FIELD_INITIALIZER_DELIMITER);
+			}
+		}
+		
 	}
 }
 protected void consumeInterfaceHeader() {
 	super.consumeInterfaceHeader();
 	pushOnElementStack(K_TYPE_DELIMITER);
 }
-protected void consumeInternalCompilationUnit() {
-	// InternalCompilationUnit ::= PackageDeclaration
-	// InternalCompilationUnit ::= PackageDeclaration ImportDeclarations ReduceImports
-	// InternalCompilationUnit ::= ImportDeclarations ReduceImports
-}
-protected void consumeInternalCompilationUnitWithTypes() {
-	// InternalCompilationUnit ::= PackageDeclaration ImportDeclarations ReduceImports TypeDeclarations
-	// InternalCompilationUnit ::= PackageDeclaration TypeDeclarations
-	// InternalCompilationUnit ::= TypeDeclarations
-	// InternalCompilationUnit ::= ImportDeclarations ReduceImports TypeDeclarations
-	// consume type declarations
-	int length;
-	if ((length = this.astLengthStack[this.astLengthPtr--]) != 0) {
-		this.compilationUnit.types = new TypeDeclaration[length];
-		this.astPtr -= length;
-		System.arraycopy(this.astStack, this.astPtr + 1, this.compilationUnit.types, 0, length);
-	}
-}
 protected void consumeMethodBody() {
 	super.consumeMethodBody();
 	popElement(K_METHOD_DELIMITER);
@@ -693,6 +713,13 @@
 					case TokenNamesuper: // explicit constructor invocation, eg. super(1, 2)
 						this.pushOnElementStack(K_SELECTOR, SUPER_CONSTRUCTOR);
 						break;
+					case TokenNameGREATER: // explicit constructor invocation, eg. Fred<X>[(]1, 2)
+					case TokenNameRIGHT_SHIFT: // or fred<X<X>>[(]1, 2) 
+					case TokenNameUNSIGNED_RIGHT_SHIFT: //or Fred<X<X<X>>>[(]1, 2)
+						if(this.identifierPtr > -1) {
+							this.pushOnElementStack(K_SELECTOR, this.identifierPtr);
+						}
+						break;
 				}
 				break;
 		}
@@ -1436,7 +1463,8 @@
 			if(currentElement != oldElement && !isInsideAttributeValue()) {
 				if(oldElement instanceof RecoveredInitializer
 					|| oldElement instanceof RecoveredMethod
-					|| (oldElement instanceof RecoveredBlock && oldElement.parent instanceof RecoveredInitializer)) {
+					|| (oldElement instanceof RecoveredBlock && oldElement.parent instanceof RecoveredInitializer)
+					|| (oldElement instanceof RecoveredBlock && oldElement.parent instanceof RecoveredMethod)) {
 					popUntilElement(K_METHOD_DELIMITER);
 					popElement(K_METHOD_DELIMITER);
 				} else if(oldElement instanceof RecoveredType) {
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/Engine.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/Engine.java
index 1cf0837..b3d6ae4 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/Engine.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/Engine.java
@@ -19,7 +19,9 @@
 import org.eclipse.jdt.internal.compiler.ast.*;
 import org.eclipse.jdt.internal.compiler.lookup.*;
 import org.eclipse.jdt.internal.compiler.parser.*;
+import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
 import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.core.NameLookup;
 import org.eclipse.jdt.internal.core.SearchableEnvironment;
 
 public abstract class Engine implements ITypeRequestor {
@@ -31,10 +33,23 @@
 
 	public AssistOptions options;
 	public CompilerOptions compilerOptions; 
+	public boolean forbiddenReferenceIsError;
+	public boolean discouragedReferenceIsError;
+	
+	public boolean importCachesInitialized = false;
+	public char[][][] importsCache;
+	public ImportBinding[] onDemandImportsCache;
+	public int importCacheCount = 0;
+	public int onDemandImportCacheCount = 0;
+	public char[] currentPackageName = null;
 	
 	public Engine(Map settings){
 		this.options = new AssistOptions(settings);
 		this.compilerOptions = new CompilerOptions(settings);
+		this.forbiddenReferenceIsError =
+			this.compilerOptions.getSeverity(CompilerOptions.ForbiddenReference) == ProblemSeverities.Error;
+		this.discouragedReferenceIsError =
+			this.compilerOptions.getSeverity(CompilerOptions.DiscouragedReference) == ProblemSeverities.Error;
 	}
 	
 	/**
@@ -80,47 +95,144 @@
 
 	public abstract AssistParser getParser();
 	
+	public void initializeImportCaches() {
+		ImportBinding[] importBindings = this.unitScope.imports;
+		int length = importBindings == null ? 0 : importBindings.length;
+		
+		this.currentPackageName = CharOperation.concatWith(unitScope.fPackage.compoundName, '.');
+		
+		for (int i = 0; i < length; i++) {
+			ImportBinding importBinding = importBindings[i];
+			if(importBinding.onDemand) {
+				if(this.onDemandImportsCache == null) {
+					this.onDemandImportsCache = new ImportBinding[length - i];
+				}
+				this.onDemandImportsCache[this.onDemandImportCacheCount++] = 
+					importBinding;
+			} else {
+				if(!(importBinding.resolvedImport instanceof MethodBinding) ||
+						importBinding instanceof ImportConflictBinding) {
+					if(this.importsCache == null) {
+						this.importsCache = new char[length - i][][];
+					}
+					this.importsCache[this.importCacheCount++] = new char[][]{
+							importBinding.compoundName[importBinding.compoundName.length - 1],
+							CharOperation.concatWith(importBinding.compoundName, '.')
+						};
+				}
+			}
+		}
+		
+		this.importCachesInitialized = true;
+	}
+	
 	protected boolean mustQualifyType(
 		char[] packageName,
-		char[] typeName) {
+		char[] typeName,
+		char[] enclosingTypeNames,
+		int modifiers) {
 
 		// If there are no types defined into the current CU yet.
 		if (unitScope == null)
 			return true;
-			
-		char[][] compoundPackageName = CharOperation.splitOn('.', packageName);
-		char[] readableTypeName = CharOperation.concat(packageName, typeName, '.');
-
-		if (CharOperation.equals(unitScope.fPackage.compoundName, compoundPackageName))
+		
+		if(!this.importCachesInitialized) {
+			this.initializeImportCaches();
+		}
+		
+		char[] fullyQualifiedTypeName = null;
+		
+		for (int i = 0; i < this.importCacheCount; i++) {
+			char[][] importName = this.importsCache[i];
+			if(CharOperation.equals(typeName, importName[0])) {
+				if (fullyQualifiedTypeName == null) {
+					fullyQualifiedTypeName =
+						enclosingTypeNames == null || enclosingTypeNames.length == 0
+								? CharOperation.concat(
+										packageName,
+										typeName,
+										'.')
+								: CharOperation.concat(
+										CharOperation.concat(
+											packageName,
+											enclosingTypeNames,
+											'.'),
+										typeName,
+										'.');
+				}
+				return !CharOperation.equals(fullyQualifiedTypeName, importName[1]);
+			}
+		}
+		
+		if ((enclosingTypeNames == null || enclosingTypeNames.length == 0 ) && CharOperation.equals(this.currentPackageName, packageName))
 			return false;
-
-		ImportBinding[] imports = unitScope.imports;
-		if (imports != null){
-			for (int i = 0, length = imports.length; i < length; i++) {
-				if (imports[i].onDemand) {
-					if (CharOperation.equals(imports[i].compoundName, compoundPackageName)) {
-						for (int j = 0; j < imports.length; j++) {
-							if(i != j){
-								if(imports[j].onDemand) {
-									if(nameEnvironment.findType(typeName, imports[j].compoundName) != null){
-										return true;
-									}
-								} else {
-									if(CharOperation.equals(CharOperation.lastSegment(imports[j].readableName(), '.'), typeName)
-										&& !CharOperation.equals(imports[j].compoundName, CharOperation.splitOn('.', readableTypeName))) {
-										return true;	
-									}
-								}
+		
+		char[] fullyQualifiedEnclosingTypeName = null;
+		
+		for (int i = 0; i < this.onDemandImportCacheCount; i++) {
+			ImportBinding importBinding = this.onDemandImportsCache[i];
+			Binding resolvedImport = importBinding.resolvedImport;
+			
+			char[][] importName = importBinding.compoundName;
+			char[] importFlatName = CharOperation.concatWith(importName, '.');
+			
+			boolean isFound = false;
+			// resolvedImport is a ReferenceBindng or a PackageBinding
+			if(resolvedImport instanceof ReferenceBinding) {
+				if(enclosingTypeNames != null && enclosingTypeNames.length != 0) {
+					if(fullyQualifiedEnclosingTypeName == null) {
+						fullyQualifiedEnclosingTypeName =
+							CharOperation.concat(
+									packageName,
+									enclosingTypeNames,
+									'.');
+					}
+					if(CharOperation.equals(fullyQualifiedEnclosingTypeName, importFlatName)) {
+						if(importBinding.isStatic()) {
+							isFound = (modifiers & IConstants.AccStatic) != 0;
+						} else {
+							isFound = true;
+						}
+					}
+				}
+			} else {
+				if(enclosingTypeNames == null || enclosingTypeNames.length == 0) {
+					if(CharOperation.equals(packageName, importFlatName)) {
+						if(importBinding.isStatic()) {
+							isFound = (modifiers & IConstants.AccStatic) != 0;
+						} else {
+							isFound = true;
+						}
+					}
+				}
+			}
+			
+			// find potential conflict with another import
+			if(isFound) {
+				for (int j = 0; j < this.onDemandImportCacheCount; j++) {
+					if(i != j) {
+						ImportBinding conflictingImportBinding = this.onDemandImportsCache[j];
+						if(conflictingImportBinding.resolvedImport instanceof ReferenceBinding) {
+							ReferenceBinding refBinding =
+								(ReferenceBinding) conflictingImportBinding.resolvedImport;
+							if (refBinding.getMemberType(typeName) != null) {
+								return true;
+							}
+						} else {
+							char[] conflictingImportName =
+								CharOperation.concatWith(conflictingImportBinding.compoundName, '.');
+							
+							if (this.nameEnvironment.nameLookup.findType(
+									String.valueOf(typeName),
+									String.valueOf(conflictingImportName),
+									false,
+									NameLookup.ACCEPT_ALL) != null) {
+								return true;
 							}
 						}
-						return false; // how do you match p1.p2.A.* ?
 					}
-	
-				} else
-	
-					if (CharOperation.equals(imports[i].readableName(), readableTypeName)) {
-						return false;
-					}
+				}
+				return false;
 			}
 		}
 		return true;
@@ -203,6 +315,17 @@
 		lookupEnvironment.reset();
 	}
 	
+	public static char[] getTypeSignature(TypeBinding typeBinding) {
+		if(typeBinding.isLocalType()) {
+			LocalTypeBinding localTypeBinding = (LocalTypeBinding)typeBinding;
+			if(localTypeBinding.isAnonymousType()) {
+				typeBinding = localTypeBinding.superclass();
+			} else {
+				localTypeBinding.setConstantPoolName(typeBinding.sourceName());
+			}
+		}
+		return typeBinding.signature();
+	}
 	public static char[] getSignature(Binding binding) {
 		char[] result = null;
 		if ((binding.kind() & Binding.TYPE) != 0) {
@@ -212,6 +335,7 @@
 				if(localTypeBinding.isAnonymousType()) {
 					typeBinding = localTypeBinding.superclass();
 				} else {
+					// TODO (david) this code is not necessary any longer (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=99686)
 					localTypeBinding.setConstantPoolName(typeBinding.sourceName());
 				}
 			}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionJavadoc.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionJavadoc.java
index 1054de3..f23a87d 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionJavadoc.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionJavadoc.java
@@ -69,9 +69,16 @@
 	 * 
 	 * @throws SelectionNodeFound
 	 */
-	public void resolve(ClassScope scope) {
+	private void internalResolve(Scope scope) {
 		if (this.selectedNode != null) {
-			this.selectedNode.resolveType(scope);
+			switch (scope.kind) {
+				case Scope.CLASS_SCOPE:
+					this.selectedNode.resolveType((ClassScope)scope);
+					break;
+				case Scope.METHOD_SCOPE:
+					this.selectedNode.resolveType((MethodScope)scope);
+					break;
+			}
 			Binding binding = null;
 			if (this.selectedNode instanceof JavadocFieldReference) {
 				JavadocFieldReference fieldRef = (JavadocFieldReference) this.selectedNode;
@@ -108,37 +115,28 @@
 	 * 
 	 * @throws SelectionNodeFound
 	 */
+	public void resolve(ClassScope scope) {
+		internalResolve(scope);
+	}
+
+	/**
+	 * Resolve selected node if not null and throw exception to let clients know
+	 * that it has been found.
+	 * 
+	 * @throws SelectionNodeFound
+	 */
+	public void resolve(CompilationUnitScope scope) {
+		internalResolve(scope);
+	}
+
+	/**
+	 * Resolve selected node if not null and throw exception to let clients know
+	 * that it has been found.
+	 * 
+	 * @throws SelectionNodeFound
+	 */
 	public void resolve(MethodScope scope) {
-		if (this.selectedNode != null) {
-			this.selectedNode.resolveType(scope);
-			Binding binding = null;
-			if (this.selectedNode instanceof JavadocFieldReference) {
-				JavadocFieldReference fieldRef = (JavadocFieldReference) this.selectedNode;
-				binding = fieldRef.binding;
-				if (binding == null && fieldRef.methodBinding != null) {
-					binding = fieldRef.methodBinding;
-				}
-			} else if (this.selectedNode instanceof JavadocMessageSend) {
-				binding = ((JavadocMessageSend) this.selectedNode).binding;
-			} else if (this.selectedNode instanceof JavadocAllocationExpression) {
-				binding = ((JavadocAllocationExpression) this.selectedNode).binding;
-			} else if (this.selectedNode instanceof JavadocSingleNameReference) {
-				binding = ((JavadocSingleNameReference) this.selectedNode).binding;
-			} else if (this.selectedNode instanceof JavadocSingleTypeReference) {
-				JavadocSingleTypeReference typeRef = (JavadocSingleTypeReference) this.selectedNode;
-				if (typeRef.packageBinding == null) {
-					binding = typeRef.resolvedType;
-				}
-			} else if (this.selectedNode instanceof JavadocQualifiedTypeReference) {
-				JavadocQualifiedTypeReference typeRef = (JavadocQualifiedTypeReference) this.selectedNode;
-				if (typeRef.packageBinding == null) {
-					binding = typeRef.resolvedType;
-				}
-			} else {
-				binding = this.selectedNode.resolvedType;
-			}
-			throw new SelectionNodeFound(binding);
-		}
+		internalResolve(scope);
 	}
 
 }
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnParameterizedQualifiedTypeReference.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnParameterizedQualifiedTypeReference.java
index 2818d6d..ed34c72 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnParameterizedQualifiedTypeReference.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnParameterizedQualifiedTypeReference.java
@@ -15,8 +15,6 @@
 import org.eclipse.jdt.internal.compiler.ast.TypeReference;
 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
 import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
-import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
-import org.eclipse.jdt.internal.compiler.lookup.RawTypeBinding;
 import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
 
 public class SelectionOnParameterizedQualifiedTypeReference extends ParameterizedQualifiedTypeReference {
@@ -33,19 +31,21 @@
 	
 	public TypeBinding resolveType(BlockScope scope, boolean checkBounds) {
 		super.resolveType(scope, checkBounds);
-		if(this.resolvedType != null && this.resolvedType.isRawType()) {
-			ParameterizedTypeBinding parameterizedTypeBinding = scope.createParameterizedType(((RawTypeBinding)this.resolvedType).type, new TypeBinding[0], this.resolvedType.enclosingType());
-			throw new SelectionNodeFound(parameterizedTypeBinding);
-		}
+		//// removed unnecessary code to solve bug 94653
+		//if(this.resolvedType != null && this.resolvedType.isRawType()) {
+		//	ParameterizedTypeBinding parameterizedTypeBinding = scope.createParameterizedType(((RawTypeBinding)this.resolvedType).type, new TypeBinding[0], this.resolvedType.enclosingType());
+		//	throw new SelectionNodeFound(parameterizedTypeBinding);
+		//}
 		throw new SelectionNodeFound(this.resolvedType);
 	}
 	
 	public TypeBinding resolveType(ClassScope scope) {
 		super.resolveType(scope);
-		if(this.resolvedType != null && this.resolvedType.isRawType()) {
-			ParameterizedTypeBinding parameterizedTypeBinding = scope.createParameterizedType(((RawTypeBinding)this.resolvedType).type, new TypeBinding[0], this.resolvedType.enclosingType());
-			throw new SelectionNodeFound(parameterizedTypeBinding);
-		}
+		//// removed unnecessary code to solve bug 94653
+		//if(this.resolvedType != null && this.resolvedType.isRawType()) {
+		//	ParameterizedTypeBinding parameterizedTypeBinding = scope.createParameterizedType(((RawTypeBinding)this.resolvedType).type, new TypeBinding[0], this.resolvedType.enclosingType());
+		//	throw new SelectionNodeFound(parameterizedTypeBinding);
+		//}
 		throw new SelectionNodeFound(this.resolvedType);
 	}
 	
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionParser.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionParser.java
index 3597a0d..ae20ae6 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionParser.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionParser.java
@@ -154,11 +154,17 @@
 	// ClassBodyopt produces a null item on the astStak if it produces NO class body
 	// An empty class body produces a 0 on the length stack.....
 
-	int length;
-	if (((length = astLengthStack[astLengthPtr]) == 1)
+	
+	if ((astLengthStack[astLengthPtr] == 1)
 		&& (astStack[astPtr] == null)) {
 
-		if (this.indexOfAssistIdentifier() < 0) {
+		
+		int index;
+		if ((index = this.indexOfAssistIdentifier()) < 0) {
+			super.classInstanceCreation(hasClassBody);
+			return;
+		} else if(this.identifierLengthPtr > -1 &&
+					(this.identifierLengthStack[this.identifierLengthPtr] - 1) != index) {
 			super.classInstanceCreation(hasClassBody);
 			return;
 		}
@@ -168,6 +174,7 @@
 		alloc = new SelectionOnQualifiedAllocationExpression();
 		alloc.sourceEnd = endPosition; //the position has been stored explicitly
 
+		int length;
 		if ((length = expressionLengthStack[expressionLengthPtr--]) != 0) {
 			expressionPtr -= length;
 			System.arraycopy(
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/CharOperation.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/CharOperation.java
index 6f0b3ac..3b55772 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/CharOperation.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/CharOperation.java
@@ -1346,17 +1346,15 @@
 	 * @throws NullPointerException if array is null
 	 */
 	public static final int hashCode(char[] array) {
-		int hash = 0;
-		int offset = 0;
 		int length = array.length;
-		if (length < 16) {
-			for (int i = length; i > 0; i--)
-				hash = (hash * 37) + array[offset++];
+		int hash = length == 0 ? 31 : array[0];
+		if (length < 8) {
+			for (int i = length; --i > 0;)
+				hash = (hash * 31) + array[i];
 		} else {
-			// only sample some characters
-			int skip = length / 8;
-			for (int i = length; i > 0; i -= skip, offset += skip)
-				hash = (hash * 39) + array[offset];
+			// 8 characters is enough to compute a decent hash code, don't waste time examining every character
+			for (int i = length - 1, last = i > 16 ? i - 16 : 0; i > last; i -= 2)
+				hash = (hash * 31) + array[i];
 		}
 		return hash & 0x7FFFFFFF;
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
index c12ee08..8b04d09 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
@@ -521,8 +521,8 @@
 	int InvalidDigit = Syntax + Internal + 262;	
 	/** @since 3.1 */
 	int InvalidLowSurrogate = Syntax + Internal + 263;
+	/** @since 3.1 */
 	int InvalidHighSurrogate = Syntax + Internal + 264;
-	
 
 	// type related problems
 	/** @since 3.1 */
@@ -699,7 +699,7 @@
 	int IncompatibleReturnTypeForNonInheritedInterfaceMethod = MethodRelated + 413;
 	/** @since 2.1 */
 	int IncompatibleExceptionInThrowsClauseForNonInheritedInterfaceMethod = MethodRelated + 414;
-	/** @since 3.0 */
+	/** @since 3.1 */
 	int IllegalVararg = MethodRelated + 415;
 
 	// code snippet support
@@ -762,9 +762,9 @@
 	/** @since 3.0 */
 	int JavadocInvalidThrowsClassName = Javadoc + Internal + 481;
 	/** @since 3.0 */
-	int JavadocMissingReference = Javadoc + Internal + 482;
+	int JavadocMissingSeeReference = Javadoc + Internal + 482;
 	/** @since 3.0 */
-	int JavadocInvalidReference = Javadoc + Internal + 483;
+	int JavadocInvalidSeeReference = Javadoc + Internal + 483;
 	/** @since 3.0 */
 	int JavadocInvalidSeeHref = Javadoc + Internal + 484;
 	/** @since 3.0 */
@@ -836,21 +836,21 @@
 	/** @since 3.0 */
 	int JavadocUnterminatedInlineTag = Javadoc + Internal + 512;
 	/** @since 3.0 */
-	int JavadocMissingHashCharacter = Javadoc + Internal + 513;
+	int JavadocMalformedSeeReference = Javadoc + Internal + 513;
 	/** @since 3.0 */
-	int JavadocMalformedSeeReference = Javadoc + Internal + 514;
-	/** @since 3.0 */
-	int JavadocEmptyReturnTag = Javadoc + Internal + 515;
+	int JavadocMessagePrefix = Internal + 514;
 	/** @since 3.1 */
-	int JavadocInvalidValueReference = Javadoc + Internal + 516;
+	int JavadocMissingHashCharacter = Javadoc + Internal + 515;
 	/** @since 3.1 */
-	int JavadocUnexpectedText = Javadoc + Internal + 517;
+	int JavadocEmptyReturnTag = Javadoc + Internal + 516;
 	/** @since 3.1 */
-	int JavadocInvalidParamTagName = Javadoc + Internal + 518;
+	int JavadocInvalidValueReference = Javadoc + Internal + 517;
+	/** @since 3.1 */
+	int JavadocUnexpectedText = Javadoc + Internal + 518;
+	/** @since 3.1 */
+	int JavadocInvalidParamTagName = Javadoc + Internal + 519;
 	/** @since 3.1 */
 	int JavadocInvalidParamTagTypeParameter = Javadoc + Internal + 469;
-	/** @since 3.0 */
-	int JavadocMessagePrefix = Internal + 519;
 
 	/**
 	 * Generics
@@ -860,7 +860,7 @@
 	/** @since 3.1 */
 	int IllegalTypeVariableSuperReference = Internal + 521;
 	/** @since 3.1 */
-	int TypeVariableReferenceFromStaticContext = Internal + 522;
+	int NonStaticTypeFromStaticInvocation = Internal + 522;
 	/** @since 3.1 */
 	int ObjectCannotBeGeneric = Internal + 523;
 	/** @since 3.1 */
@@ -1053,6 +1053,8 @@
 	int MethodMissingDeprecatedAnnotation = Internal + 629;
 	/** @since 3.1 */
 	int TypeMissingDeprecatedAnnotation = Internal + 630;
+	/** @since 3.1 */
+	int UnhandledWarningToken = Internal + 631;
 	
 	/**
 	 * Corrupted binaries
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java
index 168b33d..523d309 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java
@@ -356,7 +356,7 @@
 		header[headerOffset++] = (byte) (0xCAFEBABEL >> 8);
 		header[headerOffset++] = (byte) (0xCAFEBABEL >> 0);
 		
-		final CompilerOptions options = aType.scope.environment().options;
+		final CompilerOptions options = aType.scope.compilerOptions();
 		this.targetJDK = options.targetJDK;
 		header[headerOffset++] = (byte) (this.targetJDK >> 8); // minor high
 		header[headerOffset++] = (byte) (this.targetJDK >> 0); // minor low
@@ -603,7 +603,8 @@
 			attributeNumber++;
 		}
 		if (targetJDK >= ClassFileConstants.JDK1_5
-				&& (this.referenceBinding.isAnonymousType() || this.referenceBinding.isLocalType())) {
+				&& this.referenceBinding.isNestedType()
+				&& !this.referenceBinding.isMemberType()) {
 			// add enclosing method attribute (1.5 mode only)
 			if (contentsOffset + 10 >= contents.length) {
 				resizeContents(10);
@@ -1237,6 +1238,9 @@
 						// generate a method info to define <enum>#valueOf(String)
 						addSyntheticEnumValueOfMethod(syntheticMethod);
 						break;
+					case SyntheticMethodBinding.SwitchTable :
+						// generate a method info to define the switch table synthetic method
+						addSyntheticSwitchTable(syntheticMethod);
 				}
 			}
 		}
@@ -1250,11 +1254,12 @@
 	 */
 	public void addSyntheticConstructorAccessMethod(SyntheticMethodBinding methodBinding) {
 		generateMethodInfoHeader(methodBinding);
-		// We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
-		contents[contentsOffset++] = 0;
-		contents[contentsOffset++] = 2;
+		int methodAttributeOffset = this.contentsOffset;
+		// this will add exception attribute, synthetic attribute, deprecated attribute,...
+		int attributeNumber = generateMethodInfoAttribute(methodBinding);
 		// Code attribute
 		int codeAttributeOffset = contentsOffset;
+		attributeNumber++; // add code attribute
 		generateCodeAttributeHeader();
 		codeStream.init(this);
 		codeStream.generateSyntheticBodyForConstructorAccess(methodBinding);
@@ -1266,16 +1271,9 @@
 				.referenceCompilationUnit()
 				.compilationResult
 				.lineSeparatorPositions);
-		// add the synthetic attribute
-		int syntheticAttributeNameIndex =
-			constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
-		contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
-		contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
-		// the length of a synthetic attribute is equals to 0
-		contents[contentsOffset++] = 0;
-		contents[contentsOffset++] = 0;
-		contents[contentsOffset++] = 0;
-		contents[contentsOffset++] = 0;
+		// update the number of attributes
+		contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8);
+		contents[methodAttributeOffset] = (byte) attributeNumber;
 	}
 
 	/**
@@ -1285,13 +1283,13 @@
 	 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
 	 */	
 	public void addSyntheticEnumValueOfMethod(SyntheticMethodBinding methodBinding) {
-
 		generateMethodInfoHeader(methodBinding);
-		// We know that we won't get more than 1 attribute: the code attribute 
-		contents[contentsOffset++] = 0;
-		contents[contentsOffset++] = 1;
+		int methodAttributeOffset = this.contentsOffset;
+		// this will add exception attribute, synthetic attribute, deprecated attribute,...
+		int attributeNumber = generateMethodInfoAttribute(methodBinding);
 		// Code attribute
 		int codeAttributeOffset = contentsOffset;
+		attributeNumber++; // add code attribute
 		generateCodeAttributeHeader();
 		codeStream.init(this);
 		codeStream.generateSyntheticBodyForEnumValueOf(methodBinding);
@@ -1303,19 +1301,35 @@
 				.referenceCompilationUnit()
 				.compilationResult
 				.lineSeparatorPositions);
-//		// add the synthetic attribute
-//		int syntheticAttributeNameIndex =
-//			constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
-//		contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
-//		contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
-//		// the length of a synthetic attribute is equals to 0
-//		contents[contentsOffset++] = 0;
-//		contents[contentsOffset++] = 0;
-//		contents[contentsOffset++] = 0;
-//		contents[contentsOffset++] = 0;
-			
+		// update the number of attributes
+		contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8);
+		contents[methodAttributeOffset] = (byte) attributeNumber;			
 	}
 
+	public void addSyntheticSwitchTable(SyntheticMethodBinding methodBinding) {
+		generateMethodInfoHeader(methodBinding);
+		int methodAttributeOffset = this.contentsOffset;
+		// this will add exception attribute, synthetic attribute, deprecated attribute,...
+		int attributeNumber = generateMethodInfoAttribute(methodBinding);
+		// Code attribute
+		int codeAttributeOffset = contentsOffset;
+		attributeNumber++; // add code attribute
+		generateCodeAttributeHeader();
+		codeStream.init(this);
+		codeStream.generateSyntheticBodyForSwitchTable(methodBinding);
+		completeCodeAttributeForSyntheticMethod(
+			true,
+			methodBinding,
+			codeAttributeOffset,
+			((SourceTypeBinding) methodBinding.declaringClass)
+				.scope
+				.referenceCompilationUnit()
+				.compilationResult
+				.lineSeparatorPositions);
+		// update the number of attributes
+		contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8);
+		contents[methodAttributeOffset] = (byte) attributeNumber;
+	}
 	/**
 	 * INTERNAL USE-ONLY
 	 *  Generate the bytes for a synthetic method that implements Enum#values() for a given enum type
@@ -1323,13 +1337,13 @@
 	 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
 	 */	
 	public void addSyntheticEnumValuesMethod(SyntheticMethodBinding methodBinding) {
-
 		generateMethodInfoHeader(methodBinding);
-		// We know that we won't get more than 1 attribute: the code attribute 
-		contents[contentsOffset++] = 0;
-		contents[contentsOffset++] = 1;
+		int methodAttributeOffset = this.contentsOffset;
+		// this will add exception attribute, synthetic attribute, deprecated attribute,...
+		int attributeNumber = generateMethodInfoAttribute(methodBinding);
 		// Code attribute
 		int codeAttributeOffset = contentsOffset;
+		attributeNumber++; // add code attribute
 		generateCodeAttributeHeader();
 		codeStream.init(this);
 		codeStream.generateSyntheticBodyForEnumValues(methodBinding);
@@ -1341,17 +1355,9 @@
 				.referenceCompilationUnit()
 				.compilationResult
 				.lineSeparatorPositions);
-//		// add the synthetic attribute
-//		int syntheticAttributeNameIndex =
-//			constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
-//		contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
-//		contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
-//		// the length of a synthetic attribute is equals to 0
-//		contents[contentsOffset++] = 0;
-//		contents[contentsOffset++] = 0;
-//		contents[contentsOffset++] = 0;
-//		contents[contentsOffset++] = 0;
-			
+		// update the number of attributes
+		contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8);
+		contents[methodAttributeOffset] = (byte) attributeNumber;		
 	}
 
 	/**
@@ -1363,11 +1369,12 @@
 	 */
 	public void addSyntheticFieldReadAccessMethod(SyntheticMethodBinding methodBinding) {
 		generateMethodInfoHeader(methodBinding);
-		// We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
-		contents[contentsOffset++] = 0;
-		contents[contentsOffset++] = 2;
+		int methodAttributeOffset = this.contentsOffset;
+		// this will add exception attribute, synthetic attribute, deprecated attribute,...
+		int attributeNumber = generateMethodInfoAttribute(methodBinding);
 		// Code attribute
 		int codeAttributeOffset = contentsOffset;
+		attributeNumber++; // add code attribute
 		generateCodeAttributeHeader();
 		codeStream.init(this);
 		codeStream.generateSyntheticBodyForFieldReadAccess(methodBinding);
@@ -1379,16 +1386,9 @@
 				.referenceCompilationUnit()
 				.compilationResult
 				.lineSeparatorPositions);
-		// add the synthetic attribute
-		int syntheticAttributeNameIndex =
-			constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
-		contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
-		contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
-		// the length of a synthetic attribute is equals to 0
-		contents[contentsOffset++] = 0;
-		contents[contentsOffset++] = 0;
-		contents[contentsOffset++] = 0;
-		contents[contentsOffset++] = 0;
+		// update the number of attributes
+		contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8);
+		contents[methodAttributeOffset] = (byte) attributeNumber;
 	}
 
 	/**
@@ -1400,11 +1400,12 @@
 	 */
 	public void addSyntheticFieldWriteAccessMethod(SyntheticMethodBinding methodBinding) {
 		generateMethodInfoHeader(methodBinding);
-		// We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
-		contents[contentsOffset++] = 0;
-		contents[contentsOffset++] = 2;
+		int methodAttributeOffset = this.contentsOffset;
+		// this will add exception attribute, synthetic attribute, deprecated attribute,...
+		int attributeNumber = generateMethodInfoAttribute(methodBinding);
 		// Code attribute
 		int codeAttributeOffset = contentsOffset;
+		attributeNumber++; // add code attribute
 		generateCodeAttributeHeader();
 		codeStream.init(this);
 		codeStream.generateSyntheticBodyForFieldWriteAccess(methodBinding);
@@ -1416,16 +1417,9 @@
 				.referenceCompilationUnit()
 				.compilationResult
 				.lineSeparatorPositions);
-		// add the synthetic attribute
-		int syntheticAttributeNameIndex =
-			constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
-		contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
-		contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
-		// the length of a synthetic attribute is equals to 0
-		contents[contentsOffset++] = 0;
-		contents[contentsOffset++] = 0;
-		contents[contentsOffset++] = 0;
-		contents[contentsOffset++] = 0;
+		// update the number of attributes
+		contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8);
+		contents[methodAttributeOffset] = (byte) attributeNumber;
 	}
 
 	/**
@@ -1436,11 +1430,12 @@
 	 */
 	public void addSyntheticMethodAccessMethod(SyntheticMethodBinding methodBinding) {
 		generateMethodInfoHeader(methodBinding);
-		// We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
-		contents[contentsOffset++] = 0;
-		contents[contentsOffset++] = 2;
+		int methodAttributeOffset = this.contentsOffset;
+		// this will add exception attribute, synthetic attribute, deprecated attribute,...
+		int attributeNumber = generateMethodInfoAttribute(methodBinding);
 		// Code attribute
 		int codeAttributeOffset = contentsOffset;
+		attributeNumber++; // add code attribute
 		generateCodeAttributeHeader();
 		codeStream.init(this);
 		codeStream.generateSyntheticBodyForMethodAccess(methodBinding);
@@ -1452,16 +1447,9 @@
 				.referenceCompilationUnit()
 				.compilationResult
 				.lineSeparatorPositions);
-		// add the synthetic attribute
-		int syntheticAttributeNameIndex =
-			constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
-		contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
-		contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
-		// the length of a synthetic attribute is equals to 0
-		contents[contentsOffset++] = 0;
-		contents[contentsOffset++] = 0;
-		contents[contentsOffset++] = 0;
-		contents[contentsOffset++] = 0;
+		// update the number of attributes
+		contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8);
+		contents[methodAttributeOffset] = (byte) attributeNumber;
 	}
 
 	/**
@@ -2200,6 +2188,9 @@
 		localContentsOffset += 2; // first we handle the linenumber attribute
 
 		if (codeStream.generateLineNumberAttributes) {
+			if (localContentsOffset + 12 >= this.contents.length) {
+				resizeContents(12);
+			}
 			/* Create and add the line number attribute (used for debugging) 
 			    * Build the pairs of:
 			    * (bytecodePC lineNumber)
@@ -2575,6 +2566,32 @@
 		SyntheticMethodBinding binding,
 		int codeAttributeOffset,
 		int[] startLineIndexes) {
+		
+		this.completeCodeAttributeForSyntheticMethod(
+				false,
+				binding,
+				codeAttributeOffset,
+				startLineIndexes);
+	}
+
+	/**
+	 * INTERNAL USE-ONLY
+	 * That method completes the creation of the code attribute by setting
+	 * - the attribute_length
+	 * - max_stack
+	 * - max_locals
+	 * - code_length
+	 * - exception table
+	 * - and debug attributes if necessary.
+	 *
+	 * @param binding org.eclipse.jdt.internal.compiler.lookup.SyntheticAccessMethodBinding
+	 * @param codeAttributeOffset <CODE>int</CODE>
+	 */
+	public void completeCodeAttributeForSyntheticMethod(
+		boolean hasExceptionHandlers,
+		SyntheticMethodBinding binding,
+		int codeAttributeOffset,
+		int[] startLineIndexes) {
 		// reinitialize the contents with the byte modified by the code stream
 		this.contents = codeStream.bCodeStream;
 		int localContentsOffset = codeStream.classFileOffset;
@@ -2596,10 +2613,60 @@
 		if ((localContentsOffset + 40) >= this.contents.length) {
 			resizeContents(40);
 		}
-		// there is no exception table, so we need to offset by 2 the current offset and move 
-		// on the attribute generation
-		contents[localContentsOffset++] = 0;
-		contents[localContentsOffset++] = 0;
+		
+		if (hasExceptionHandlers) {
+			// write the exception table
+			int exceptionHandlersNumber = codeStream.exceptionHandlersCounter;
+			ExceptionLabel[] exceptionHandlers = codeStream.exceptionHandlers;
+			int exSize = exceptionHandlersNumber * 8 + 2;
+			if (exSize + localContentsOffset >= this.contents.length) {
+				resizeContents(exSize);
+			}
+			// there is no exception table, so we need to offset by 2 the current offset and move 
+			// on the attribute generation
+			this.contents[localContentsOffset++] = (byte) (exceptionHandlersNumber >> 8);
+			this.contents[localContentsOffset++] = (byte) exceptionHandlersNumber;
+			for (int i = 0, max = codeStream.exceptionHandlersIndex; i < max; i++) {
+				ExceptionLabel exceptionHandler = exceptionHandlers[i];
+				if (exceptionHandler != null) {
+					int start = exceptionHandler.start;
+					this.contents[localContentsOffset++] = (byte) (start >> 8);
+					this.contents[localContentsOffset++] = (byte) start;
+					int end = exceptionHandler.end;
+					this.contents[localContentsOffset++] = (byte) (end >> 8);
+					this.contents[localContentsOffset++] = (byte) end;
+					int handlerPC = exceptionHandler.position;
+					this.contents[localContentsOffset++] = (byte) (handlerPC >> 8);
+					this.contents[localContentsOffset++] = (byte) handlerPC;
+					if (exceptionHandler.exceptionType == null) {
+						// any exception handler
+						this.contents[localContentsOffset++] = 0;
+						this.contents[localContentsOffset++] = 0;
+					} else {
+						int nameIndex;
+						switch(exceptionHandler.exceptionType.id) {
+							case T_null :
+								/* represents ClassNotFoundException, see class literal access*/
+								nameIndex = constantPool.literalIndexForType(ConstantPool.JavaLangClassNotFoundExceptionConstantPoolName);
+								break;
+							case T_long :
+								/* represents NoSuchFieldError, see switch table generation*/
+								nameIndex = constantPool.literalIndexForType(ConstantPool.JavaLangNoSuchFieldErrorConstantPoolName);
+								break;
+							default:
+								nameIndex = constantPool.literalIndexForType(exceptionHandler.exceptionType.constantPoolName());
+						}
+						this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
+						this.contents[localContentsOffset++] = (byte) nameIndex;
+					}
+				}
+			}
+		} else {
+			// there is no exception table, so we need to offset by 2 the current offset and move 
+			// on the attribute generation
+			contents[localContentsOffset++] = 0;
+			contents[localContentsOffset++] = 0;
+		}
 		// debug attributes
 		int codeAttributeAttributeOffset = localContentsOffset;
 		int attributeNumber = 0;
@@ -2608,6 +2675,9 @@
 
 		// first we handle the linenumber attribute
 		if (codeStream.generateLineNumberAttributes) {
+			if (localContentsOffset + 12 >= this.contents.length) {
+				resizeContents(12);
+			}		
 			int index = 0;
 			int lineNumberNameIndex =
 				constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
@@ -2769,7 +2839,7 @@
 		contents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
 		contentsOffset = localContentsOffset;
 	}
-
+	
 	/**
 	 * INTERNAL USE-ONLY
 	 * Complete the creation of a method info by setting up the number of attributes at the right offset.
@@ -2844,7 +2914,7 @@
 			final int elementNameIndex = constantPool.literalIndex(VALUE);
 			contents[contentsOffset++] = (byte) (elementNameIndex >> 8);
 			contents[contentsOffset++] = (byte) elementNameIndex;
-			MethodBinding methodBinding = singleMemberAnnotation.singlePair.binding;
+			MethodBinding methodBinding = singleMemberAnnotation.memberValuePairs()[0].binding;
 			if (methodBinding == null) {
 				contentsOffset = attributeOffset;
 			} else {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/CompilationResult.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/CompilationResult.java
index ed266fc..a1c163f 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/CompilationResult.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/CompilationResult.java
@@ -30,14 +30,19 @@
  * specific fields and methods which were referenced, but does contain their 
  * declaring types and any other types used to locate such fields or methods.
  */
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
 
-import org.eclipse.jdt.core.compiler.*;
+import org.eclipse.jdt.core.compiler.IProblem;
 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
-import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
 import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
 import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
-
-import java.util.*;
+import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
 
 public class CompilationResult {
 	
@@ -47,17 +52,21 @@
 	public int taskCount;
 	public ICompilationUnit compilationUnit;
 	private Map problemsMap;
-	private Map firstErrorsMap;
+	private Set firstErrors;
 	private int maxProblemPerUnit;
 	public char[][][] qualifiedReferences;
 	public char[][] simpleNameReferences;
 
 	public int lineSeparatorPositions[];
-	public Hashtable compiledTypes = new Hashtable(11);
+	public Map compiledTypes = new Hashtable(11);
 	public int unitIndex, totalUnitsKnown;
 	public boolean hasBeenAccepted = false;
 	public char[] fileName;
 	public boolean hasInconsistentToplevelHierarchies = false; // record the fact some toplevel types have inconsistent hierarchies
+	public boolean hasSyntaxError = false;
+	long[] suppressWarningIrritants;  // irritant for suppressed warnings
+	long[] suppressWarningScopePositions; // (start << 32) + end 
+	int suppressWarningsCount;
 	
 	public CompilationResult(
 		char[] fileName,
@@ -104,17 +113,57 @@
 					priority += P_STATIC;
 				}
 			} else {
-			priority += P_OUTSIDE_METHOD;
+				priority += P_OUTSIDE_METHOD;
 			}
 		} else {
 			priority += P_OUTSIDE_METHOD;
 		}
-		if (firstErrorsMap.containsKey(problem)){
+		if (firstErrors.contains(problem)){
 			priority += P_FIRST_ERROR;
 		}
 		return priority;
 	}
 
+	public void discardSuppressedWarnings() {
+
+		if (this.suppressWarningsCount == 0) return;
+		int removed = 0;
+		nextProblem: for (int i = 0, length = this.problemCount; i < length; i++) {
+			IProblem problem = this.problems[i];
+			if (!problem.isWarning()) 
+				continue nextProblem;
+			int start = problem.getSourceStart();
+			int end = problem.getSourceEnd();
+			int problemID = problem.getID();
+			nextSuppress: for (int j = 0, max = this.suppressWarningsCount; j < max; j++) {
+				long position = this.suppressWarningScopePositions[j];
+				int startSuppress = (int) (position >>> 32);
+				int endSuppress = (int) position;
+				if (start < startSuppress) continue nextSuppress;
+				if (end > endSuppress) continue nextSuppress;
+				if ((ProblemReporter.getIrritant(problemID) & this.suppressWarningIrritants[j]) == 0)
+					continue nextSuppress;
+				// discard suppressed warning
+				removed++;
+				problems[i] = null;
+				if (problemsMap != null) problemsMap.remove(problem);
+				continue nextProblem;
+			}
+		}
+		if (removed > 0) {
+			for (int i = 0, index = 0; i < this.problemCount; i++) {
+				IProblem problem;
+				if ((problem = this.problems[i]) != null) {
+					if (i > index) {
+						this.problems[index++] = problem;
+					} else {
+						index++;
+					}
+				}
+			}
+			this.problemCount -= removed;
+		}
+	}
 	
 	public IProblem[] getAllProblems() {
 		IProblem[] onlyProblems = this.getProblems();
@@ -169,12 +218,8 @@
 	}
 	
 	public ClassFile[] getClassFiles() {
-		Enumeration files = compiledTypes.elements();
 		ClassFile[] classFiles = new ClassFile[compiledTypes.size()];
-		int index = 0;
-		while (files.hasMoreElements()){
-			classFiles[index++] = (ClassFile)files.nextElement();
-		}
+		compiledTypes.values().toArray(classFiles);
 		return classFiles;	
 	}
 
@@ -223,6 +268,7 @@
 		
 		// Re-adjust the size of the problems if necessary.
 		if (problems != null) {
+			discardSuppressedWarnings();
 	
 			if (this.problemCount != problems.length) {
 				System.arraycopy(problems, 0, (problems = new IProblem[problemCount]), 0, problemCount);
@@ -276,17 +322,6 @@
 		return problemCount != 0;
 	}
 
-	public boolean hasSyntaxError(){
-
-		if (problems != null)
-			for (int i = 0; i < problemCount; i++) {
-				IProblem problem = problems[i];
-				if ((problem.getID() & IProblem.Syntax) != 0 && problem.isError())
-					return true;
-			}
-		return false;
-	}
-
 	public boolean hasTasks() {
 		return this.taskCount != 0;
 	}
@@ -369,9 +404,10 @@
 
 	public void record(IProblem newProblem, ReferenceContext referenceContext) {
 
-		if (newProblem.getID() == IProblem.Task) {
-			recordTask(newProblem);
-			return;
+		//new Exception("VERBOSE PROBLEM REPORTING").printStackTrace();
+		if(newProblem.getID() == IProblem.Task) {
+				recordTask(newProblem);
+				return;
 		}
 		if (problemCount == 0) {
 			problems = new IProblem[5];
@@ -380,11 +416,25 @@
 		}
 		problems[problemCount++] = newProblem;
 		if (referenceContext != null){
-			if (problemsMap == null) problemsMap = new Hashtable(5);
-			if (firstErrorsMap == null) firstErrorsMap = new Hashtable(5);
-			if (newProblem.isError() && !referenceContext.hasErrors()) firstErrorsMap.put(newProblem, newProblem);
+			if (problemsMap == null) problemsMap = new HashMap(5);
+			if (firstErrors == null) firstErrors = new HashSet(5);
+			if (newProblem.isError() && !referenceContext.hasErrors()) firstErrors.add(newProblem);
 			problemsMap.put(newProblem, referenceContext);
 		}
+		if ((newProblem.getID() & IProblem.Syntax) != 0 && newProblem.isError())
+			this.hasSyntaxError = true;
+	}
+
+	public void recordSuppressWarnings(long irritant, int scopeStart, int scopeEnd) {
+		if (this.suppressWarningIrritants == null) {
+			this.suppressWarningIrritants = new long[3];
+			this.suppressWarningScopePositions = new long[3];
+		} else if (this.suppressWarningIrritants.length == this.suppressWarningsCount) {
+			System.arraycopy(this.suppressWarningIrritants, 0,this.suppressWarningIrritants = new long[2*this.suppressWarningsCount], 0, this.suppressWarningsCount);
+			System.arraycopy(this.suppressWarningScopePositions, 0,this.suppressWarningScopePositions = new long[2*this.suppressWarningsCount], 0, this.suppressWarningsCount);
+		}
+		this.suppressWarningIrritants[this.suppressWarningsCount] = irritant;
+		this.suppressWarningScopePositions[this.suppressWarningsCount++] = ((long)scopeStart<<32) + scopeEnd;
 	}
 
 	private void recordTask(IProblem newProblem) {
@@ -411,9 +461,9 @@
 		}
 		if (this.compiledTypes != null){
 			buffer.append("COMPILED type(s)	\n");  //$NON-NLS-1$
-			Enumeration typeNames = this.compiledTypes.keys();
-			while (typeNames.hasMoreElements()) {
-				char[] typeName = (char[]) typeNames.nextElement();
+			Iterator keys = this.compiledTypes.keySet().iterator();
+			while (keys.hasNext()) {
+				char[] typeName = (char[]) keys.next();
 				buffer.append("\t - ").append(typeName).append('\n');   //$NON-NLS-1$
 				
 			}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/Compiler.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/Compiler.java
index 6d9a508..c5f0d64 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/Compiler.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/Compiler.java
@@ -108,7 +108,7 @@
 		this.problemReporter =
 			new ProblemReporter(policy, this.options, problemFactory);
 		this.lookupEnvironment =
-			new LookupEnvironment(this, options, problemReporter, environment);
+			new LookupEnvironment(this, this.options, this.problemReporter, environment);
 		initializeParser();
 	}
 	
@@ -173,7 +173,7 @@
 			};
 		}
 		this.problemReporter = new ProblemReporter(policy, this.options, problemFactory);
-		this.lookupEnvironment = new LookupEnvironment(this, options, problemReporter, environment);
+		this.lookupEnvironment = new LookupEnvironment(this, this.options, problemReporter, environment);
 		initializeParser();
 	}
 	
@@ -181,7 +181,7 @@
 	 * Add an additional binary type
 	 */
 	public void accept(IBinaryType binaryType, PackageBinding packageBinding, AccessRestriction accessRestriction) {
-		if (options.verbose) {
+		if (this.options.verbose) {
 			System.out.println(
 				Messages.bind(Messages.compilation_loadBinary, new String(binaryType.getName())));
 //			new Exception("TRACE BINARY").printStackTrace(System.out);
@@ -315,7 +315,7 @@
 			beginToCompile(sourceUnits);
 
 			// process all units (some more could be injected in the loop by the lookup environment)
-			for (; i < totalUnits; i++) {
+			for (; i < this.totalUnits; i++) {
 				unit = unitsToProcess[i];
 				try {
 					if (options.verbose)
@@ -323,7 +323,7 @@
 							Messages.bind(Messages.compilation_process,
 							new String[] {
 								String.valueOf(i + 1),
-								String.valueOf(totalUnits),
+								String.valueOf(this.totalUnits),
 								new String(unitsToProcess[i].getFileName())
 							}));
 					process(unit, i);
@@ -338,7 +338,7 @@
 						Messages.bind(Messages.compilation_done,
 						new String[] {
 							String.valueOf(i + 1),
-							String.valueOf(totalUnits),
+							String.valueOf(this.totalUnits),
 							new String(unit.getFileName())
 						}));
 			}
@@ -354,12 +354,12 @@
 			this.reset();
 		}
 		if (options.verbose) {
-			if (totalUnits > 1) {
+			if (this.totalUnits > 1) {
 				System.out.println(
-					Messages.bind(Messages.compilation_units, String.valueOf(totalUnits))); 
+					Messages.bind(Messages.compilation_units, String.valueOf(this.totalUnits))); 
 			} else {
 				System.out.println(
-					Messages.bind(Messages.compilation_unit, String.valueOf(totalUnits))); 
+					Messages.bind(Messages.compilation_unit, String.valueOf(this.totalUnits))); 
 			}
 		}
 	}
@@ -372,9 +372,17 @@
 		CompilationUnitDeclaration unit,
 		CompilationResult result) {
 
-		/* find a compilation result */
-		if ((unit != null)) // basing result upon the current unit if available
+		if ((result == null) && (unit != null)) {
 			result = unit.compilationResult; // current unit being processed ?
+		}
+		// Lookup environment may be in middle of connecting types
+		if ((result == null) && lookupEnvironment.unitBeingCompleted != null) {
+		    result = lookupEnvironment.unitBeingCompleted.compilationResult;
+		}		
+		// Lookup environment may be in middle of connecting types
+		if ((result == null) && lookupEnvironment.unitBeingCompleted != null) {
+		    result = lookupEnvironment.unitBeingCompleted.compilationResult;
+		}		
 		if ((result == null) && (unitsToProcess != null) && (totalUnits > 0))
 			result = unitsToProcess[totalUnits - 1].compilationResult;
 		// last unit in beginToCompile ?
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java
index 1dcc37a..ade23b6 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java
@@ -40,7 +40,7 @@
 	public final static int Bit15 = 0x4000; 				// is unnecessary cast (expression)
 	public final static int Bit16 = 0x8000; 				// in javadoc comment (name ref, type ref, msg)
 	public final static int Bit17 = 0x10000; 				// compound assigned (reference lhs)
-	public final static int Bit18 = 0x20000; 
+	public final static int Bit18 = 0x20000; 				
 	public final static int Bit19 = 0x40000; 
 	public final static int Bit20 = 0x80000; 
 	public final static int Bit21 = 0x100000; 		
@@ -157,6 +157,9 @@
 	// for variable argument
 	public static final int IsVarArgs = Bit15;
 	
+	// for array initializer
+	public static final int IsAnnotationDefaultValue = Bit1;
+	
 	public ASTNode() {
 
 		super();
@@ -184,13 +187,13 @@
 		boolean isRawMemberInvocation = !method.isStatic() 
 				&& !receiverType.isUnboundWildcard() 
 				&& method.declaringClass.isRawType() 
-				&& (method.hasSubstitutedParameters() || method.hasSubstitutedReturnType());
+				&& method.hasSubstitutedParameters();
 		
 		MethodBinding rawOriginalGenericMethod = null;
 		if (!isRawMemberInvocation) {
 			if (method instanceof ParameterizedGenericMethodBinding) {
 				ParameterizedGenericMethodBinding paramMethod = (ParameterizedGenericMethodBinding) method;
-				if (paramMethod.isUnchecked || (paramMethod.isRaw && (method.hasSubstitutedParameters() || method.hasSubstitutedReturnType()))) {
+				if (paramMethod.isUnchecked || (paramMethod.isRaw && method.hasSubstitutedParameters())) {
 					rawOriginalGenericMethod = method.original();
 				}
 			}
@@ -250,7 +253,7 @@
 		}
 		if (unsafeWildcardInvocation) {
 		    scope.problemReporter().wildcardInvocation((ASTNode)invocationSite, receiverType, method, argumentTypes);
-		} else if (!method.isStatic() && !receiverType.isUnboundWildcard() && method.declaringClass.isRawType() && (method.hasSubstitutedParameters() || method.hasSubstitutedReturnType())) {
+		} else if (!method.isStatic() && !receiverType.isUnboundWildcard() && method.declaringClass.isRawType() && method.hasSubstitutedParameters()) {
 		    scope.problemReporter().unsafeRawInvocation((ASTNode)invocationSite, method);
 		} else if (rawOriginalGenericMethod != null) {
 		    scope.problemReporter().unsafeRawGenericMethodInvocation((ASTNode)invocationSite, method);
@@ -260,23 +263,20 @@
 		return this;
 	}
 	
-	/* Answer true if the field use is considered deprecated.
-	* An access in the same compilation unit is allowed.
-	*/
 	public final boolean isFieldUseDeprecated(FieldBinding field, Scope scope, boolean isStrictlyAssigned) {
-
-		if (!isStrictlyAssigned && field.isPrivate() && !scope.isDefinedInField(field)) {
+	
+		if (!isStrictlyAssigned && (field.isPrivate() || (field.declaringClass != null && field.declaringClass.isLocalType())) && !scope.isDefinedInField(field)) {
 			// ignore cases where field is used from within inside itself 
-			field.modifiers |= AccPrivateUsed;
+			field.original().modifiers |= AccLocallyUsed;
 		}
-
+	
 		if (!field.isViewedAsDeprecated()) return false;
-
+	
 		// inside same unit - no report
 		if (scope.isDefinedInSameUnit(field.declaringClass)) return false;
 		
 		// if context is deprecated, may avoid reporting
-		if (!scope.environment().options.reportDeprecationInsideDeprecatedCode && scope.isInsideDeprecatedCode()) return false;
+		if (!scope.compilerOptions().reportDeprecationInsideDeprecatedCode && scope.isInsideDeprecatedCode()) return false;
 		return true;
 	}
 
@@ -290,9 +290,9 @@
 	*/
 	public final boolean isMethodUseDeprecated(MethodBinding method, Scope scope) {
 
-		if (method.isPrivate() && !scope.isDefinedInMethod(method)) {
+		if ((method.isPrivate() || method.declaringClass.isLocalType()) && !scope.isDefinedInMethod(method)) {
 			// ignore cases where method is used from within inside itself (e.g. direct recursions)
-			method.original().modifiers |= AccPrivateUsed;
+			method.original().modifiers |= AccLocallyUsed;
 		}
 		
 		if (!method.isViewedAsDeprecated()) return false;
@@ -301,7 +301,7 @@
 		if (scope.isDefinedInSameUnit(method.declaringClass)) return false;
 		
 		// if context is deprecated, may avoid reporting
-		if (!scope.environment().options.reportDeprecationInsideDeprecatedCode && scope.isInsideDeprecatedCode()) return false;
+		if (!scope.compilerOptions().reportDeprecationInsideDeprecatedCode && scope.isInsideDeprecatedCode()) return false;
 		return true;
 	}
 
@@ -327,9 +327,9 @@
 
 		ReferenceBinding refType = (ReferenceBinding) type;
 
-		if (refType.isPrivate() && !scope.isDefinedInType(refType)) {
+		if ((refType.isPrivate() /*|| refType.isLocalType()*/) && !scope.isDefinedInType(refType)) {
 			// ignore cases where type is used from within inside itself 
-			((ReferenceBinding)refType.erasure()).modifiers |= AccPrivateUsed;
+			((ReferenceBinding)refType.erasure()).modifiers |= AccLocallyUsed;
 		}
 		
 		if (refType.hasRestrictedAccess()) {
@@ -344,7 +344,7 @@
 		if (scope.isDefinedInSameUnit(refType)) return false;
 		
 		// if context is deprecated, may avoid reporting
-		if (!scope.environment().options.reportDeprecationInsideDeprecatedCode && scope.isInsideDeprecatedCode()) return false;
+		if (!scope.compilerOptions().reportDeprecationInsideDeprecatedCode && scope.isInsideDeprecatedCode()) return false;
 		return true;
 	}
 
@@ -434,6 +434,7 @@
 			Annotation annotation = annotations[i];
 			annotation.recipient = recipient;
 			annotationTypes[i] = annotation.resolveType(scope);
+			
 		}
 		// check duplicate annotations
 		for (int i = 0; i < length; i++) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java
index ff98abc..836c3c8 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java
@@ -79,13 +79,16 @@
 
 		if (this.arguments != null) {
 			// by default arguments in abstract/native methods are considered to be used (no complaint is expected)
-			boolean used = this.binding == null || this.binding.isAbstract() || this.binding.isNative();
-
-			int length = this.arguments.length;
-			for (int i = 0; i < length; i++) {
-				TypeBinding argType = this.binding == null ? null : this.binding.parameters[i];
+			if (this.binding == null) {
+				for (int i = 0, length = this.arguments.length; i < length; i++) {
+					this.arguments[i].bind(this.scope, null, true);
+				}
+				return;
+			}
+			boolean used = this.binding.isAbstract() || this.binding.isNative();
+			for (int i = 0, length = this.arguments.length; i < length; i++) {
 				Argument argument = this.arguments[i];
-				argument.bind(this.scope, argType, used);
+				argument.bind(this.scope, this.binding.parameters[i], used);
 				if (argument.annotations != null) {
 					this.binding.tagBits |= TagBits.HasParameterAnnotations;
 				}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java
index a3e8027..8325d75 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java
@@ -190,7 +190,7 @@
 		if (this.codegenBinding.isPrivate()
 			&& (currentScope.enclosingSourceType() != this.codegenBinding.declaringClass)) {
 
-			if (currentScope.environment().options.isPrivateConstructorAccessChangingVisibility) {
+			if (currentScope.compilerOptions().isPrivateConstructorAccessChangingVisibility) {
 				this.codegenBinding.tagForClearingPrivateModifier();
 				// constructor will not be dumped as private, no emulation required thus
 			} else {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java
index 758660d..9efef0f 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java
@@ -12,6 +12,8 @@
 
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.ASTVisitor;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.jdt.internal.compiler.impl.Constant;
 import org.eclipse.jdt.internal.compiler.lookup.*;
 
 /**
@@ -161,6 +163,50 @@
 		return output;
 	}
 	
+	public void recordSuppressWarnings(Scope scope, int startSuppresss, int endSuppress, boolean isSuppressingWarnings) {
+		long suppressWarningIrritants = 0;
+		MemberValuePair[] pairs = this.memberValuePairs();
+		pairLoop: for (int i = 0, length = pairs.length; i < length; i++) {
+			MemberValuePair pair = pairs[i];
+			if (CharOperation.equals(pair.name, TypeConstants.VALUE)) {
+				Expression value = pair.value;
+				if (value instanceof ArrayInitializer) {
+					ArrayInitializer initializer = (ArrayInitializer) value;
+					Expression[] inits = initializer.expressions;
+					if (inits != null) {
+						for (int j = 0, initsLength = inits.length; j < initsLength; j++) {
+							Constant cst = inits[j].constant;
+							if (cst != Constant.NotAConstant && cst.typeID() == T_JavaLangString) {
+								long irritant = CompilerOptions.warningTokenToIrritant(cst.stringValue());
+								if (irritant != 0) {
+									suppressWarningIrritants |= irritant;
+									if (~suppressWarningIrritants == 0) break pairLoop;
+								} else {
+									scope.problemReporter().unhandledWarningToken(inits[j]);
+								}
+							}
+						}
+					}
+				} else {
+					Constant cst = value.constant;
+					if (cst != Constant.NotAConstant && cst.typeID() == T_JavaLangString) {
+						long irritant = CompilerOptions.warningTokenToIrritant(cst.stringValue());
+						if (irritant != 0) {
+							suppressWarningIrritants |= irritant;
+							if (~suppressWarningIrritants == 0) break pairLoop;
+						} else {
+							scope.problemReporter().unhandledWarningToken(value);
+						}
+					}	
+				}
+				break pairLoop;
+			}
+		}
+		if (isSuppressingWarnings && suppressWarningIrritants != 0) {
+			scope.referenceCompilationUnit().compilationResult.recordSuppressWarnings(suppressWarningIrritants, startSuppresss, endSuppress);
+		}
+	}
+	
 	public TypeBinding resolveType(BlockScope scope) {
 		
 		this.constant = NotAConstant;
@@ -232,6 +278,9 @@
 		}
 		// recognize standard annotations ?
 		long tagBits = detectStandardAnnotation(scope, annotationType, valueAttribute);
+
+		// record annotation positions in the compilation result
+		scope.referenceCompilationUnit().compilationResult.recordSuppressWarnings(CompilerOptions.NonExternalizedString, this.sourceStart, this.declarationSourceEnd);
 		if (this.recipient != null) {
 			if (tagBits != 0) {
 				// tag bits onto recipient
@@ -242,16 +291,38 @@
 					case Binding.TYPE :
 					case Binding.GENERIC_TYPE :
 					case Binding.TYPE_PARAMETER :
-						((ReferenceBinding)this.recipient).tagBits |= tagBits;
+						SourceTypeBinding sourceType = (SourceTypeBinding) this.recipient;
+						sourceType.tagBits |= tagBits;
+						if ((tagBits & TagBits.AnnotationSuppressWarnings) != 0) {
+							TypeDeclaration typeDeclaration =  sourceType.scope.referenceContext;
+							recordSuppressWarnings(scope, typeDeclaration.declarationSourceStart, typeDeclaration.declarationSourceEnd, scope.compilerOptions().suppressWarnings);
+						}
 						break;
 					case Binding.METHOD :
-						((MethodBinding)this.recipient).tagBits |= tagBits;
+						MethodBinding sourceMethod = (MethodBinding) this.recipient;
+						sourceMethod.tagBits |= tagBits;
+						if ((tagBits & TagBits.AnnotationSuppressWarnings) != 0) {
+							sourceType = (SourceTypeBinding) sourceMethod.declaringClass;
+							AbstractMethodDeclaration methodDeclaration = sourceType.scope.referenceContext.declarationOf(sourceMethod);
+							recordSuppressWarnings(scope, methodDeclaration.declarationSourceStart, methodDeclaration.declarationSourceEnd, scope.compilerOptions().suppressWarnings);
+						}
 						break;
 					case Binding.FIELD :
-						((FieldBinding)this.recipient).tagBits |= tagBits;
+						FieldBinding sourceField = (FieldBinding) this.recipient;
+						sourceField.tagBits |= tagBits;
+						if ((tagBits & TagBits.AnnotationSuppressWarnings) != 0) {
+							sourceType = (SourceTypeBinding) sourceField.declaringClass;
+							FieldDeclaration fieldDeclaration = sourceType.scope.referenceContext.declarationOf(sourceField);
+							recordSuppressWarnings(scope, fieldDeclaration.declarationSourceStart, fieldDeclaration.declarationSourceEnd, scope.compilerOptions().suppressWarnings);
+						}						
 						break;
 					case Binding.LOCAL :
-						((LocalVariableBinding)this.recipient).tagBits |= tagBits;
+						LocalVariableBinding variable = (LocalVariableBinding) this.recipient;
+						variable.tagBits |= tagBits;
+						if ((tagBits & TagBits.AnnotationSuppressWarnings) != 0) {
+							 LocalDeclaration localDeclaration = variable.declaration;
+							recordSuppressWarnings(scope, localDeclaration.declarationSourceStart, localDeclaration.declarationSourceEnd, scope.compilerOptions().suppressWarnings);
+						}									
 						break;
 				}			
 			}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Argument.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Argument.java
index 2f0e676..f9c6bcf 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Argument.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Argument.java
@@ -100,7 +100,7 @@
 
 		TypeBinding exceptionType = this.type.resolveType(scope, true /* check bounds*/);
 		if (exceptionType == null) return null;
-		if (exceptionType.isGenericType() || exceptionType.isParameterizedType()) {
+		if (exceptionType.isGenericType() || exceptionType.isBoundParameterizedType()) {
 			scope.problemReporter().invalidParameterizedExceptionType(exceptionType, this);
 			return null;
 		}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayInitializer.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayInitializer.java
index 9ac989a..0bfcf3f 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayInitializer.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayInitializer.java
@@ -128,7 +128,7 @@
 		return output.append('}');
 	}
 
-	public TypeBinding resolveTypeExpecting(BlockScope scope, TypeBinding expectedTb) {
+	public TypeBinding resolveTypeExpecting(BlockScope scope, TypeBinding expectedType) {
 		// Array initializers can only occur on the right hand side of an assignment
 		// expression, therefore the expected type contains the valid information
 		// concerning the type that must be enforced by the elements of the array initializer.
@@ -138,42 +138,44 @@
 		this.constant = NotAConstant;
 		
 		// allow new List<?>[5]
-		TypeBinding leafComponentType = expectedTb.leafComponentType();
-		if (leafComponentType.isBoundParameterizedType() || leafComponentType.isGenericType() || leafComponentType.isTypeVariable()) {
-		    scope.problemReporter().illegalGenericArray(leafComponentType, this);
+		if ((this.bits & IsAnnotationDefaultValue) == 0) { // annotation default value need only to be commensurate JLS9.7
+			TypeBinding leafComponentType = expectedType.leafComponentType();
+			if (leafComponentType.isBoundParameterizedType() || leafComponentType.isGenericType() || leafComponentType.isTypeVariable()) {
+			    scope.problemReporter().illegalGenericArray(leafComponentType, this);
+			}
 		}
 			
-		if (expectedTb.isArrayType()) {
-			this.resolvedType = this.binding = (ArrayBinding) expectedTb;
-			if (expressions == null)
-				return binding;
-			TypeBinding expectedElementsTb = binding.elementsType();
-			if (expectedElementsTb.isBaseType()) {
-				for (int i = 0, length = expressions.length; i < length; i++) {
-					Expression expression = expressions[i];
-					TypeBinding expressionTb =
-						(expression instanceof ArrayInitializer)
-							? expression.resolveTypeExpecting(scope, expectedElementsTb)
-							: expression.resolveType(scope);
-					if (expressionTb == null)
-						return null;
-	
-					// Compile-time conversion required?
-					if (expectedElementsTb != expressionTb) // must call before computeConversion() and typeMismatchError()
-						scope.compilationUnitScope().recordTypeConversion(expectedElementsTb, expressionTb);
-					if (expression.isConstantValueOfTypeAssignableToType(expressionTb, expectedElementsTb)
-						|| BaseTypeBinding.isWidening(expectedElementsTb.id, expressionTb.id)
-						|| scope.isBoxingCompatibleWith(expressionTb, expectedElementsTb)) {
-							expression.computeConversion(scope, expectedElementsTb, expressionTb);
-					} else {
-						scope.problemReporter().typeMismatchError(expressionTb, expectedElementsTb, expression);
-						return null;
-					}
-				}
-			} else {
-				for (int i = 0, length = expressions.length; i < length; i++)
-					if (expressions[i].resolveTypeExpecting(scope, expectedElementsTb) == null)
-						return null;
+		if (expectedType.isArrayType()) {
+			this.resolvedType = this.binding = (ArrayBinding) expectedType;
+			if (this.expressions == null)
+				return this.binding;
+			TypeBinding elementType = this.binding.elementsType();
+			for (int i = 0, length = expressions.length; i < length; i++) {
+				Expression expression = expressions[i];
+				TypeBinding exprType = expression instanceof ArrayInitializer
+						? expression.resolveTypeExpecting(scope, elementType)
+						: expression.resolveType(scope);
+				if (exprType == null)
+					return null;
+
+				// Compile-time conversion required?
+				if (elementType != exprType) // must call before computeConversion() and typeMismatchError()
+					scope.compilationUnitScope().recordTypeConversion(elementType, exprType);
+
+				if ((expression.isConstantValueOfTypeAssignableToType(exprType, elementType)
+						|| (elementType.isBaseType() && BaseTypeBinding.isWidening(elementType.id, exprType.id)))
+						|| exprType.isCompatibleWith(elementType)) {
+					expression.computeConversion(scope, elementType, exprType);
+				} else if (scope.isBoxingCompatibleWith(exprType, elementType) 
+									|| (exprType.isBaseType()  // narrowing then boxing ?
+											&& scope.compilerOptions().sourceLevel >= JDK1_5 // autoboxing
+											&& !elementType.isBaseType()
+											&& expression.isConstantValueOfTypeAssignableToType(exprType, scope.environment().computeBoxingType(elementType)))) {
+					expression.computeConversion(scope, elementType, exprType);
+				} else {
+					scope.problemReporter().typeMismatchError(exprType, elementType, expression);
+					return null;
+				} 				
 			}
 			return binding;
 		}
@@ -201,7 +203,7 @@
 		}
 		if (leafElementType != null) {
 			TypeBinding probableTb = scope.createArrayType(leafElementType, dim);
-			scope.problemReporter().typeMismatchError(probableTb, expectedTb, this);
+			scope.problemReporter().typeMismatchError(probableTb, expectedType, this);
 		}
 		return null;
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayReference.java
index 7307b3e..74b0f1a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayReference.java
@@ -175,7 +175,7 @@
 			implicitConversion);
 		codeStream.sendOperator(postIncrement.operator, this.implicitConversion & COMPILE_TYPE_MASK);
 		codeStream.generateImplicitConversion(
-			postIncrement.assignmentImplicitConversion);
+			postIncrement.preAssignImplicitConversion);
 		codeStream.arrayAtPut(this.resolvedType.id, false);
 	}
 
@@ -197,7 +197,7 @@
 			receiver.computeConversion(scope, arrayType, arrayType);
 			if (arrayType.isArrayType()) {
 				TypeBinding elementType = ((ArrayBinding) arrayType).elementsType();
-				this.resolvedType = ((this.bits & IsStrictlyAssignedMASK) == 0) ? elementType.capture() : elementType;
+				this.resolvedType = ((this.bits & IsStrictlyAssignedMASK) == 0) ? elementType.capture(scope, this.sourceEnd) : elementType;
 			} else {
 				scope.problemReporter().referenceMustBeArrayTypeAt(arrayType, this);
 			}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AssertStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AssertStatement.java
index f3dba55..2ef696d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AssertStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AssertStatement.java
@@ -177,7 +177,7 @@
 		for (int i = 0, max = methods.length; i < max; i++) {
 			AbstractMethodDeclaration method = methods[i];
 			if (method.isClinit()) {
-				((Clinit) method).setAssertionSupport(assertionSyntheticFieldBinding, currentScope.environment().options.sourceLevel < ClassFileConstants.JDK1_5);
+				((Clinit) method).setAssertionSupport(assertionSyntheticFieldBinding, currentScope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_5);
 				break;
 			}
 		}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java
index 75ea4b2..6ce6104 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java
@@ -169,16 +169,16 @@
 	public TypeBinding resolveType(BlockScope scope) {
 
 		// due to syntax lhs may be only a NameReference, a FieldReference or an ArrayReference
-		constant = NotAConstant;
+		this.constant = NotAConstant;
 		if (!(this.lhs instanceof Reference) || this.lhs.isThis()) {
 			scope.problemReporter().expressionShouldBeAVariable(this.lhs);
 			return null;
 		}
 		TypeBinding lhsType = lhs.resolveType(scope);
-		expression.setExpectedType(lhsType); // needed in case of generic method invocation
+		this.expression.setExpectedType(lhsType); // needed in case of generic method invocation
 		if (lhsType != null) 
-			this.resolvedType = lhsType.capture();
-		TypeBinding rhsType = expression.resolveType(scope);
+			this.resolvedType = lhsType.capture(scope, this.sourceEnd);
+		TypeBinding rhsType = this.expression.resolveType(scope);
 		if (lhsType == null || rhsType == null) {
 			return null;
 		}
@@ -188,17 +188,21 @@
 		// may require to widen the rhs expression at runtime
 		if (lhsType != rhsType) // must call before computeConversion() and typeMismatchError()
 			scope.compilationUnitScope().recordTypeConversion(lhsType, rhsType);
-		if ((expression.isConstantValueOfTypeAssignableToType(rhsType, lhsType)
+		if ((this.expression.isConstantValueOfTypeAssignableToType(rhsType, lhsType)
 				|| (lhsType.isBaseType() && BaseTypeBinding.isWidening(lhsType.id, rhsType.id)))
 				|| rhsType.isCompatibleWith(lhsType)) {
-			expression.computeConversion(scope, lhsType, rhsType);
+			this.expression.computeConversion(scope, lhsType, rhsType);
 			checkAssignment(scope, lhsType, rhsType);
 			return this.resolvedType;
-		} else if (scope.isBoxingCompatibleWith(rhsType, lhsType)) {
-			expression.computeConversion(scope, lhsType, rhsType);
+		} else if (scope.isBoxingCompatibleWith(rhsType, lhsType) 
+							|| (rhsType.isBaseType()  // narrowing then boxing ?
+									&& scope.compilerOptions().sourceLevel >= JDK1_5 // autoboxing
+									&& !lhsType.isBaseType()
+									&& this.expression.isConstantValueOfTypeAssignableToType(rhsType, scope.environment().computeBoxingType(lhsType)))) {
+			this.expression.computeConversion(scope, lhsType, rhsType);
 			return this.resolvedType;
 		} 
-		scope.problemReporter().typeMismatchError(rhsType, lhsType, expression);
+		scope.problemReporter().typeMismatchError(rhsType, lhsType, this.expression);
 		return lhsType;
 	}
 	/* (non-Javadoc)
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java
index cfb6a44..d200034 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java
@@ -1682,14 +1682,13 @@
 		int rightTypeID = rightType.id;
 
 		// autoboxing support
-		LookupEnvironment env = scope.environment();
-		boolean use15specifics = env.options.sourceLevel >= JDK1_5;
+		boolean use15specifics = scope.compilerOptions().sourceLevel >= JDK1_5;
 		if (use15specifics) {
 			if (!leftType.isBaseType() && rightTypeID != T_JavaLangString && rightTypeID != T_null) {
-				leftTypeID = env.computeBoxingType(leftType).id;
+				leftTypeID = scope.environment().computeBoxingType(leftType).id;
 			}
 			if (!rightType.isBaseType() && leftTypeID != T_JavaLangString && leftTypeID != T_null) {
-				rightTypeID = env.computeBoxingType(rightType).id;
+				rightTypeID = scope.environment().computeBoxingType(rightType).id;
 			}
 		}
 		if (leftTypeID > 15
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java
index 70c6a99..7fea712 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java
@@ -20,7 +20,7 @@
 	
 	public Expression constantExpression;
 	public CaseLabel targetLabel;
-	boolean isEnumConstant;
+	public boolean isEnumConstant;
 	
 	public CaseStatement(Expression constantExpression, int sourceEnd, int sourceStart) {
 		this.constantExpression = constantExpression;
@@ -121,7 +121,7 @@
 			} else {
 				return constantExpression.constant;
 			}
-		} else if (scope.isBoxingCompatibleWith(switchExpressionType, caseType)) {
+		} else if (scope.isBoxingCompatibleWith(caseType, switchExpressionType)) {
 			constantExpression.computeConversion(scope, caseType, switchExpressionType);
 			return constantExpression.constant;
 		}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java
index c179969..24de07e 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java
@@ -58,7 +58,7 @@
 	 */
 	public static void checkNeedForEnclosingInstanceCast(BlockScope scope, Expression enclosingInstance, TypeBinding enclosingInstanceType, TypeBinding memberType) {
 	
-		if (scope.environment().options.getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return;
+		if (scope.compilerOptions().getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return;
 		
 		TypeBinding castedExpressionType = ((CastExpression)enclosingInstance).expression.resolvedType;
 		if (castedExpressionType == null) return; // cannot do better
@@ -81,7 +81,7 @@
 	 */
 	public static void checkNeedForArgumentCast(BlockScope scope, int operator, int operatorSignature, Expression expression, int expressionTypeId) {
 	
-		if (scope.environment().options.getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return;
+		if (scope.compilerOptions().getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return;
 	
 		// check need for left operand cast
 		int alternateLeftTypeId = expressionTypeId;
@@ -117,7 +117,7 @@
 	 */
 	public static void checkNeedForArgumentCasts(BlockScope scope, Expression receiver, TypeBinding receiverType, MethodBinding binding, Expression[] arguments, TypeBinding[] argumentTypes, final InvocationSite invocationSite) {
 	
-		if (scope.environment().options.getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return;
+		if (scope.compilerOptions().getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return;
 		
 		int length = argumentTypes.length;
 
@@ -157,7 +157,7 @@
 	 */
 	public static void checkNeedForArgumentCasts(BlockScope scope, int operator, int operatorSignature, Expression left, int leftTypeId, boolean leftIsCast, Expression right, int rightTypeId, boolean rightIsCast) {
 
-		if (scope.environment().options.getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return;
+		if (scope.compilerOptions().getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return;
 
 		// check need for left operand cast
 		int alternateLeftTypeId = leftTypeId;
@@ -238,7 +238,18 @@
 					: scope.getMethod(receiverType, binding.selector, alternateArgumentTypes, fakeInvocationSite); 	
 			}
 			if (bindingIfNoCast == binding) {
-				for (int i = 0, length = originalArgumentTypes.length; i < length; i++) {
+				int argumentLength = originalArgumentTypes.length;
+				if (binding.isVarargs()) {
+					int paramLength = binding.parameters.length;
+				   if (paramLength == argumentLength) {
+						int varargIndex = paramLength - 1;
+						ArrayBinding varargType = (ArrayBinding) binding.parameters[varargIndex];
+						TypeBinding lastArgType = alternateArgumentTypes[varargIndex];
+						if (varargType.dimensions == lastArgType.dimensions() && varargType.leafComponentType != lastArgType.leafComponentType())
+								return;
+				   }
+				}
+				for (int i = 0; i < argumentLength; i++) {
 					if (originalArgumentTypes[i] != alternateArgumentTypes[i]) {
 						scope.problemReporter().unnecessaryCast((CastExpression)arguments[i]);
 					}
@@ -268,7 +279,7 @@
 					return true;
 				}
 			}
-		} else if (isNarrowing && castType.isTypeVariable()) {
+		} else if (isNarrowing && castType.leafComponentType().isTypeVariable()) {
 			this.bits |= UnsafeCastMask;
 			return true;
 		}
@@ -365,19 +376,19 @@
 				&& ((type.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT) == 0) { // no extra parenthesis around type: ((A))exp
 
 			this.resolvedType = type.resolveType(scope);
-			expression.setExpectedType(this.resolvedType); // needed in case of generic method invocation			
+			//expression.setExpectedType(this.resolvedType); // needed in case of generic method invocation			
 			TypeBinding expressionType = expression.resolveType(scope);
 			if (this.resolvedType != null && expressionType != null) {
 				boolean isLegal = checkCastTypesCompatibility(scope, this.resolvedType, expressionType, this.expression);
-				this.expression.computeConversion(scope, this.resolvedType, expressionType);
 				if (isLegal) {
+					this.expression.computeConversion(scope, this.resolvedType, expressionType);
 					if ((this.bits & UnsafeCastMask) != 0) { // unsafe cast
 						scope.problemReporter().unsafeCast(this, scope);
 					} else if ((this.bits & (UnnecessaryCastMASK|IgnoreNeedForCastCheckMASK)) == UnnecessaryCastMASK) { // unnecessary cast 
 						if (!isIndirectlyUsed()) // used for generic type inference or boxing ?
 							scope.problemReporter().unnecessaryCast(this);
 					}
-					this.resolvedType = this.resolvedType.capture();
+					this.resolvedType = this.resolvedType.capture(scope, this.sourceEnd);
 				} else { // illegal cast
 					scope.problemReporter().typeCastError(this,  this.resolvedType, expressionType);
 				}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ClassLiteralAccess.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ClassLiteralAccess.java
index c3af69f..6c706f7 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ClassLiteralAccess.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ClassLiteralAccess.java
@@ -39,7 +39,7 @@
 		if ((!(sourceType.isInterface()
 				// no field generated in interface case (would'nt verify) see 1FHHEZL
 				|| sourceType.isBaseType()))
-				&& currentScope.environment().options.sourceLevel <= ClassFileConstants.JDK1_5) {
+				&& currentScope.compilerOptions().sourceLevel <= ClassFileConstants.JDK1_5) {
 			syntheticField = sourceType.addSyntheticFieldForClassLiteral(targetType, currentScope);
 		}
 		return flowInfo;
@@ -91,12 +91,12 @@
 			if (targetType.id == T_void) {
 				boxedType = scope.environment().getType(JAVA_LANG_VOID);
 				if (boxedType == null) {
-					boxedType = new ProblemReferenceBinding(JAVA_LANG_VOID, ProblemReasons.NotFound);
+					boxedType = new ProblemReferenceBinding(JAVA_LANG_VOID, null, ProblemReasons.NotFound);
 				}
 			} else {
 				boxedType = scope.boxing(targetType);
 			}
-		    this.resolvedType = scope.createParameterizedType(classType, new TypeBinding[]{ boxedType }, null/*not a member*/);
+		    this.resolvedType = scope.environment().createParameterizedType(classType, new TypeBinding[]{ boxedType }, null/*not a member*/);
 		} else {
 		    this.resolvedType = classType;
 		}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompilationUnitDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompilationUnitDeclaration.java
index 363754d..4e4fde5 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompilationUnitDeclaration.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompilationUnitDeclaration.java
@@ -36,6 +36,8 @@
 	
 	public boolean isPropagatingInnerClassEmulation;
 
+	public Javadoc javadoc; // 1.5 addition for package-info.java
+	
 	public CompilationUnitDeclaration(
 		ProblemReporter problemReporter,
 		CompilationResult compilationResult,
@@ -138,9 +140,9 @@
 	}
 	
 	public CompilationResult compilationResult() {
-		return compilationResult;
+		return this.compilationResult;
 	}
-	
+
 	/*
 	 * Finds the matching type amoung this compilation unit types.
 	 * Returns null if no type with this name is found.
@@ -173,7 +175,7 @@
 			}
 			return;
 		}
-		if (this.isPackageInfo() && this.types != null) {
+		if (this.isPackageInfo() && this.types != null && this.currentPackage.annotations != null) {
 			types[0].annotations = this.currentPackage.annotations;
 		}
 		try {
@@ -218,7 +220,7 @@
 	public boolean isPackageInfo() {
 		return CharOperation.equals(this.getMainTypeName(), TypeConstants.PACKAGE_INFO_NAME)
 			&& this.currentPackage != null
-			&& this.currentPackage.annotations != null;
+			&& (this.currentPackage.annotations != null || this.javadoc != null);
 	}
 	
 	public boolean hasErrors() {
@@ -277,22 +279,25 @@
 
 	public void resolve() {
 		int startingTypeIndex = 0;
-		if (this.currentPackage != null) {
+		boolean isPackageInfo = isPackageInfo();
+		if (this.types != null && isPackageInfo) {
+            // resolve synthetic type declaration
+			final TypeDeclaration syntheticTypeDeclaration = types[0];
+			// set empty javadoc to avoid missing warning (see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=95286)
+			syntheticTypeDeclaration.javadoc = new Javadoc(syntheticTypeDeclaration.declarationSourceStart, syntheticTypeDeclaration.declarationSourceStart);
+			syntheticTypeDeclaration.resolve(this.scope);
+			// resolve annotations if any
 			if (this.currentPackage.annotations != null) {
-				if (CharOperation.equals(this.getMainTypeName(), TypeConstants.PACKAGE_INFO_NAME)) {
-                    if (this.types != null) {
-                        // resolve annotations
-    					final TypeDeclaration syntheticTypeDeclaration = types[0];
-    					syntheticTypeDeclaration.resolve(this.scope);
-    					resolveAnnotations(syntheticTypeDeclaration.staticInitializerScope, this.currentPackage.annotations, this.scope.fPackage);
-    					// set the synthetic bit
-    					syntheticTypeDeclaration.binding.modifiers |= AccSynthetic;
-    					startingTypeIndex = 1;
-                    }
-				} else {
-					scope.problemReporter().invalidFileNameForPackageAnnotations(this.currentPackage.annotations[0]);
-				}
+				resolveAnnotations(syntheticTypeDeclaration.staticInitializerScope, this.currentPackage.annotations, this.scope.fPackage);
 			}
+			// resolve javadoc package if any
+			if (this.javadoc != null) {
+				this.javadoc.resolve(syntheticTypeDeclaration.staticInitializerScope);
+    		}
+			startingTypeIndex = 1;
+		}
+		if (this.currentPackage != null && this.currentPackage.annotations != null && !isPackageInfo) {
+			scope.problemReporter().invalidFileNameForPackageAnnotations(this.currentPackage.annotations[0]);
 		}
 		try {
 			if (types != null) {
@@ -300,7 +305,7 @@
 					types[i].resolve(scope);
 				}
 			}
-			if (!this.compilationResult.hasSyntaxError()) checkUnusedImports();
+			if (!this.compilationResult.hasErrors()) checkUnusedImports();
 		} catch (AbortCompilationUnit e) {
 			this.ignoreFurtherInvestigation = true;
 			return;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompoundAssignment.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompoundAssignment.java
index 5135167..f4ed739 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompoundAssignment.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompoundAssignment.java
@@ -17,7 +17,7 @@
 
 public class CompoundAssignment extends Assignment implements OperatorIds {
 	public int operator;
-	public int assignmentImplicitConversion;
+	public int preAssignImplicitConversion;
 
 	//  var op exp is equivalent to var = (varType) var op exp
 	// assignmentImplicitConversion stores the cast needed for the assignment
@@ -47,9 +47,9 @@
 		// just a local variable.
 	
 		int pc = codeStream.position;
-		 ((Reference) lhs).generateCompoundAssignment(currentScope, codeStream, expression, operator, assignmentImplicitConversion, valueRequired);
+		 ((Reference) lhs).generateCompoundAssignment(currentScope, codeStream, this.expression, this.operator, this.preAssignImplicitConversion, valueRequired);
 		if (valueRequired) {
-			codeStream.generateImplicitConversion(implicitConversion);
+			codeStream.generateImplicitConversion(this.implicitConversion);
 		}
 		codeStream.recordPositionsFrom(pc, this.sourceStart);
 	}
@@ -106,7 +106,7 @@
 		// autoboxing support
 		LookupEnvironment env = scope.environment();
 		TypeBinding lhsType = originalLhsType, expressionType = originalExpressionType;
-		boolean use15specifics = scope.environment().options.sourceLevel >= JDK1_5;
+		boolean use15specifics = scope.compilerOptions().sourceLevel >= JDK1_5;
 		boolean unboxedLhs = false;
 		if (use15specifics) {
 			if (!lhsType.isBaseType() && expressionType.id != T_JavaLangString && expressionType.id != T_null) {
@@ -159,10 +159,9 @@
 				}
 			}
 		}
-		this.lhs.implicitConversion = (unboxedLhs ? UNBOXING : 0) | (result >>> 12);
-		if (unboxedLhs) scope.problemReporter().autoboxing(this.lhs, originalLhsType, lhsType);
+		this.lhs.computeConversion(scope, TypeBinding.wellKnownType(scope, (result >>> 16) & 0x0000F), originalLhsType);
 		this.expression.computeConversion(scope, TypeBinding.wellKnownType(scope, (result >>> 8) & 0x0000F), originalExpressionType);
-		this.assignmentImplicitConversion =  (unboxedLhs ? BOXING : 0) | (lhsID << 4) | (result & 0x0000F);
+		this.preAssignImplicitConversion =  (unboxedLhs ? BOXING : 0) | (lhsID << 4) | (result & 0x0000F);
 		if (unboxedLhs) scope.problemReporter().autoboxing(this, lhsType, originalLhsType);
 		return this.resolvedType = originalLhsType;
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java
index 8dddb92..4c96b09 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java
@@ -276,11 +276,12 @@
 	}
 
 	public TypeBinding resolveType(BlockScope scope) {
-		// specs p.368
+		// JLS3 15.25
 		constant = NotAConstant;
 		LookupEnvironment env = scope.environment();
-		boolean use15specifics = env.options.sourceLevel >= ClassFileConstants.JDK1_5;
+		boolean use15specifics = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5;
 		TypeBinding conditionType = condition.resolveTypeExpecting(scope, BooleanBinding);
+		condition.computeConversion(scope, BooleanBinding, conditionType);
 		
 		if (valueIfTrue instanceof CastExpression) valueIfTrue.bits |= IgnoreNeedForCastCheckMASK; // will check later on
 		TypeBinding originalValueIfTrueType = valueIfTrue.resolveType(scope);
@@ -293,23 +294,41 @@
 
 		TypeBinding valueIfTrueType = originalValueIfTrueType;
 		TypeBinding valueIfFalseType = originalValueIfFalseType;
-		if (use15specifics) {
-			if (valueIfTrueType != valueIfFalseType) {
-				TypeBinding unboxedIfTrueType = valueIfTrueType.isBaseType() ? valueIfTrueType : env.computeBoxingType(valueIfTrueType);
-				TypeBinding unboxedIfFalseType = valueIfFalseType.isBaseType() ? valueIfFalseType : env.computeBoxingType(valueIfFalseType);
-				if (unboxedIfTrueType.isNumericType() && unboxedIfFalseType.isNumericType()) {
-					valueIfTrueType = unboxedIfTrueType;
-					valueIfFalseType = unboxedIfFalseType;
-				} else if (valueIfTrueType.isBaseType()) {
-					if ((valueIfTrueType == NullBinding) == valueIfFalseType.isBaseType()) {  // bool ? null : 12 --> Integer
-						valueIfFalseType = env.computeBoxingType(valueIfFalseType);
+		if (use15specifics && valueIfTrueType != valueIfFalseType) {
+			if (valueIfTrueType.isBaseType()) {
+				if (valueIfFalseType.isBaseType()) {
+					// bool ? baseType : baseType
+					if (valueIfTrueType == NullBinding) {  // bool ? null : 12 --> Integer
+						valueIfFalseType = env.computeBoxingType(valueIfFalseType); // boxing
+					} else if (valueIfFalseType == NullBinding) {  // bool ? 12 : null --> Integer
+						valueIfTrueType = env.computeBoxingType(valueIfTrueType); // boxing
 					}
-				} else if (valueIfFalseType.isBaseType()) {
-					if ((valueIfFalseType == NullBinding) == valueIfTrueType.isBaseType()) {  // bool ? 12 : null --> Integer
-						valueIfTrueType = env.computeBoxingType(valueIfTrueType);
+				} else {
+					// bool ? baseType : nonBaseType
+					TypeBinding unboxedIfFalseType = valueIfFalseType.isBaseType() ? valueIfFalseType : env.computeBoxingType(valueIfFalseType);
+					if (valueIfTrueType.isNumericType() && unboxedIfFalseType.isNumericType()) {
+						valueIfFalseType = unboxedIfFalseType; // unboxing
+					} else if (valueIfTrueType != NullBinding) {  // bool ? 12 : new Integer(12) --> int
+						valueIfFalseType = env.computeBoxingType(valueIfFalseType); // unboxing
 					}
 				}
-			}
+			} else if (valueIfFalseType.isBaseType()) {
+					// bool ? nonBaseType : baseType
+					TypeBinding unboxedIfTrueType = valueIfTrueType.isBaseType() ? valueIfTrueType : env.computeBoxingType(valueIfTrueType);
+					if (unboxedIfTrueType.isNumericType() && valueIfFalseType.isNumericType()) {
+						valueIfTrueType = unboxedIfTrueType; // unboxing
+					} else if (valueIfFalseType != NullBinding) {  // bool ? new Integer(12) : 12 --> int
+						valueIfTrueType = env.computeBoxingType(valueIfTrueType); // unboxing
+					}					
+			} else {
+					// bool ? nonBaseType : nonBaseType
+					TypeBinding unboxedIfTrueType = env.computeBoxingType(valueIfTrueType);
+					TypeBinding unboxedIfFalseType = env.computeBoxingType(valueIfFalseType);
+					if (unboxedIfTrueType.isNumericType() && unboxedIfFalseType.isNumericType()) {
+						valueIfTrueType = unboxedIfTrueType;
+						valueIfFalseType = unboxedIfFalseType;
+					}
+			} 
 		}
 		// Propagate the constant value from the valueIfTrue and valueIFFalse expression if it is possible
 		Constant condConstant, trueConstant, falseConstant;
@@ -394,31 +413,46 @@
 			return this.resolvedType = DoubleBinding;
 		}
 		// Type references (null null is already tested)
-		if ((valueIfTrueType.isBaseType() && valueIfTrueType != NullBinding)
-				|| (valueIfFalseType.isBaseType() && valueIfFalseType != NullBinding)) {
-			scope.problemReporter().conditionalArgumentsIncompatibleTypes(
-				this,
-				valueIfTrueType,
-				valueIfFalseType);
-			return null;
+		if (valueIfTrueType.isBaseType() && valueIfTrueType != NullBinding) {
+			if (use15specifics) {
+				valueIfTrueType = env.computeBoxingType(valueIfTrueType);
+			} else {
+				scope.problemReporter().conditionalArgumentsIncompatibleTypes(this, valueIfTrueType, valueIfFalseType);
+				return null;
+			}
+		} else if (valueIfFalseType.isBaseType() && valueIfFalseType != NullBinding) {
+			if (use15specifics) {
+				valueIfFalseType = env.computeBoxingType(valueIfFalseType);
+			} else {
+				scope.problemReporter().conditionalArgumentsIncompatibleTypes(this, valueIfTrueType, valueIfFalseType);
+				return null;
+			}
 		}
-		if (valueIfFalseType.isCompatibleWith(valueIfTrueType)) {
-			valueIfTrue.computeConversion(scope, valueIfTrueType, originalValueIfTrueType);
-			valueIfFalse.computeConversion(scope, valueIfTrueType, originalValueIfFalseType);
-			return this.resolvedType = valueIfTrueType;
-		}
-		if (valueIfTrueType.isCompatibleWith(valueIfFalseType)) {
-			valueIfTrue.computeConversion(scope, valueIfFalseType, originalValueIfTrueType);
-			valueIfFalse.computeConversion(scope, valueIfFalseType, originalValueIfFalseType);
-			return this.resolvedType = valueIfFalseType;
-		}
-		// 1.5 addition: allow most common supertype 
 		if (use15specifics) {
-			TypeBinding commonType = scope.lowerUpperBound(new TypeBinding[] { valueIfTrueType, valueIfFalseType });
+			// >= 1.5 : LUB(operand types) must exist
+			TypeBinding commonType = null;
+			if (valueIfTrueType == NullBinding) {
+				commonType = valueIfFalseType;
+			} else if (valueIfFalseType == NullBinding) {
+				commonType = valueIfTrueType;
+			} else {
+				commonType = scope.lowerUpperBound(new TypeBinding[] { valueIfTrueType, valueIfFalseType });
+			}
 			if (commonType != null) {
-				valueIfTrue.computeConversion(scope, commonType, valueIfTrueType);
-				valueIfFalse.computeConversion(scope, commonType, valueIfFalseType);
-				return this.resolvedType = commonType.capture();
+				valueIfTrue.computeConversion(scope, commonType, originalValueIfTrueType);
+				valueIfFalse.computeConversion(scope, commonType, originalValueIfFalseType);
+				return this.resolvedType = commonType.capture(scope, this.sourceEnd);
+			}
+		} else {
+			// < 1.5 : one operand must be convertible to the other
+			if (valueIfFalseType.isCompatibleWith(valueIfTrueType)) {
+				valueIfTrue.computeConversion(scope, valueIfTrueType, originalValueIfTrueType);
+				valueIfFalse.computeConversion(scope, valueIfTrueType, originalValueIfFalseType);
+				return this.resolvedType = valueIfTrueType;
+			} else if (valueIfTrueType.isCompatibleWith(valueIfFalseType)) {
+				valueIfTrue.computeConversion(scope, valueIfFalseType, originalValueIfTrueType);
+				valueIfFalse.computeConversion(scope, valueIfFalseType, originalValueIfFalseType);
+				return this.resolvedType = valueIfFalseType;
 			}
 		}
 		scope.problemReporter().conditionalArgumentsIncompatibleTypes(
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java
index 7346dce..edbbb7d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java
@@ -40,8 +40,8 @@
 		if (ignoreFurtherInvestigation)
 			return;
 
-		if (this.binding != null && this.binding.isPrivate() && !this.binding.isPrivateUsed()) {
-			if (!classScope.referenceCompilationUnit().compilationResult.hasSyntaxError()) {
+		if (this.binding != null && !this.binding.isUsed() && (this.binding.isPrivate() || (this.binding.declaringClass.tagBits & (TagBits.IsAnonymousType|TagBits.IsLocalType)) == TagBits.IsLocalType)) {
+			if (!classScope.referenceCompilationUnit().compilationResult.hasSyntaxError) {
 				scope.problemReporter().unusedPrivateConstructor(this);
 			}
 		}
@@ -268,7 +268,7 @@
 			boolean needFieldInitializations = constructorCall == null || constructorCall.accessMode != ExplicitConstructorCall.This;
 
 			// post 1.4 source level, synthetic initializations occur prior to explicit constructor call
-			boolean preInitSyntheticFields = scope.environment().options.targetJDK >= ClassFileConstants.JDK1_4;
+			boolean preInitSyntheticFields = scope.compilerOptions().targetJDK >= ClassFileConstants.JDK1_4;
 
 			if (needFieldInitializations && preInitSyntheticFields){
 				generateSyntheticFieldInitializationsIfNecessary(scope, codeStream, declaringClass);
@@ -408,12 +408,18 @@
 	 */
 	public void resolveStatements() {
 
-		if (!CharOperation.equals(scope.enclosingSourceType().sourceName, selector)){
-			scope.problemReporter().missingReturnType(this);
+		if (!CharOperation.equals(this.scope.enclosingSourceType().sourceName, selector)){
+			this.scope.problemReporter().missingReturnType(this);
 		}
 
+		if (this.typeParameters != null) {
+			for (int i = 0, length = this.typeParameters.length; i < length; i++) {
+				this.typeParameters[i].resolve(this.scope);
+			}
+		}
+		
 		if (this.binding != null && this.binding.declaringClass.isAnnotationType()) {
-			scope.problemReporter().annotationTypeDeclarationCannotHaveConstructor(this);
+			this.scope.problemReporter().annotationTypeDeclarationCannotHaveConstructor(this);
 		}
 		// if null ==> an error has occurs at parsing time ....
 		if (this.constructorCall != null) {
@@ -422,7 +428,7 @@
 				&& this.binding.declaringClass.id == T_JavaLangObject
 				&& this.constructorCall.accessMode != ExplicitConstructorCall.This) {
 					if (this.constructorCall.accessMode == ExplicitConstructorCall.Super) {
-						scope.problemReporter().cannotUseSuperInJavaLangObject(this.constructorCall);
+						this.scope.problemReporter().cannotUseSuperInJavaLangObject(this.constructorCall);
 					}
 					this.constructorCall = null;
 			} else {
@@ -430,7 +436,7 @@
 			}
 		}
 		if ((modifiers & AccSemicolonBody) != 0) {
-			scope.problemReporter().methodNeedBody(this);		
+			this.scope.problemReporter().methodNeedBody(this);		
 		}
 		super.resolveStatements();
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EmptyStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EmptyStatement.java
index 9414844..ba03a7e 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EmptyStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EmptyStatement.java
@@ -32,7 +32,7 @@
 	public boolean complainIfUnreachable(FlowInfo flowInfo, BlockScope scope, boolean didAlreadyComplain) {
 		
 		// before 1.4, empty statements are tolerated anywhere
-		if (scope.environment().options.complianceLevel < ClassFileConstants.JDK1_4) {
+		if (scope.compilerOptions().complianceLevel < ClassFileConstants.JDK1_4) {
 			return false;
 		}
 		return super.complainIfUnreachable(flowInfo, scope, didAlreadyComplain);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java
index 4f1cea4..834d3c3 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java
@@ -420,17 +420,16 @@
 		}
 	
 		// autoboxing support
-		LookupEnvironment env = scope.environment();
-		boolean use15specifics = env.options.sourceLevel >= JDK1_5;
+		boolean use15specifics = scope.compilerOptions().sourceLevel >= JDK1_5;
 		TypeBinding leftType = originalLeftType, rightType = originalRightType;
 		if (use15specifics) {
 			if (leftType != NullBinding && leftType.isBaseType()) {
 				if (!rightType.isBaseType()) {
-					rightType = env.computeBoxingType(rightType);
+					rightType = scope.environment().computeBoxingType(rightType);
 				}
 			} else {
 				if (rightType != NullBinding && rightType.isBaseType()) {
-					leftType = env.computeBoxingType(leftType);
+					leftType = scope.environment().computeBoxingType(leftType);
 				}
 			}
 		}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java
index ac86e95..64e3789 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java
@@ -201,7 +201,7 @@
 		// perform some emulation work in case there is some and we are inside a local type only
 		if (binding.isPrivate() && accessMode != This) {
 
-			if (currentScope.environment().options.isPrivateConstructorAccessChangingVisibility) {
+			if (currentScope.compilerOptions().isPrivateConstructorAccessChangingVisibility) {
 				this.codegenBinding.tagForClearingPrivateModifier();
 				// constructor will not be dumped as private, no emulation required thus
 			} else {
@@ -328,8 +328,8 @@
 				if (isMethodUseDeprecated(binding, scope))
 					scope.problemReporter().deprecatedMethod(binding, this);
 				checkInvocationArguments(scope, null, receiverType, binding, this.arguments, argumentTypes, argsContainCast, this);
-				if (binding.isPrivate()) {
-					binding.original().modifiers |= AccPrivateUsed;
+				if (binding.isPrivate() || receiverType.isLocalType()) {
+					binding.original().modifiers |= AccLocallyUsed;
 				}				
 			} else {
 				if (binding.declaringClass == null)
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java
index 85fb5bc..b379b3f 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java
@@ -10,7 +10,7 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.ast;
 
-import java.util.ArrayList;
+import java.util.*;
 
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.ASTVisitor;
@@ -23,10 +23,7 @@
 
 public abstract class Expression extends Statement {
 	
-	public static final boolean isConstantValueRepresentable(
-		Constant constant,
-		int constantTypeID,
-		int targetTypeID) {
+	public static final boolean isConstantValueRepresentable(Constant constant, int constantTypeID, int targetTypeID) {
 
 		//true if there is no loss of precision while casting.
 		// constantTypeID == constant.typeID
@@ -222,8 +219,7 @@
 	
 		// identity conversion cannot be performed upfront, due to side-effects
 		// like constant propagation
-		LookupEnvironment env = scope.environment();
-		boolean use15specifics = env.options.sourceLevel >= JDK1_5;
+		boolean use15specifics = scope.compilerOptions().sourceLevel >= JDK1_5;
 		if (castType.isBaseType()) {
 			if (expressionType.isBaseType()) {
 				if (expressionType == castType) {
@@ -247,194 +243,239 @@
 					
 				}
 			} else if (use15specifics 
-								&& env.computeBoxingType(expressionType).isCompatibleWith(castType)) { // unboxing - only widening match is allowed
+								&& scope.environment().computeBoxingType(expressionType).isCompatibleWith(castType)) { // unboxing - only widening match is allowed
 				tagAsUnnecessaryCast(scope, castType);  
 				return true;
 			}
 			return false;
 		} else if (use15specifics 
 							&& expressionType.isBaseType() 
-							&& env.computeBoxingType(expressionType).isCompatibleWith(castType)) { // boxing - only widening match is allowed
+							&& scope.environment().computeBoxingType(expressionType).isCompatibleWith(castType)) { // boxing - only widening match is allowed
 			tagAsUnnecessaryCast(scope, castType);  
 			return true;
 		}
 	
-		//-----------cast to something which is NOT a base type--------------------------	
-		if (expressionType == NullBinding) {
-			tagAsUnnecessaryCast(scope, castType);
-			return true; //null is compatible with every thing
-		}
-		if (expressionType.isBaseType()) {
-			return false;
-		}
-	
-		if (expressionType.isArrayType()) {
-			if (castType == expressionType) {
-				tagAsUnnecessaryCast(scope, castType);
-				return true; // identity conversion
-			}
-	
-			if (castType.isArrayType()) {
-				//------- (castType.isArray) expressionType.isArray -----------
-				TypeBinding castElementType = ((ArrayBinding) castType).elementsType();
-				TypeBinding exprElementType = ((ArrayBinding) expressionType).elementsType();
-				if (exprElementType.isBaseType() || castElementType.isBaseType()) {
-					// <---stop the recursion------- 
-					if (castElementType == exprElementType) {
-						tagAsNeedCheckCast();
-						return true;
-					} else {
-						return false;
-					}
-				}
-				// recursively on the elements...
-				return checkCastTypesCompatibility(scope, ((ArrayBinding) castType).elementsType(), exprElementType, expression);
-			} else if (castType.isTypeVariable()) {
-				if (expressionType instanceof ReferenceBinding) {
-					ReferenceBinding match = ((ReferenceBinding)expressionType).findSuperTypeErasingTo((ReferenceBinding)castType);
-					if (match == null) {
-						checkUnsafeCast(scope, castType, expressionType, match, true);
-					}
-				} else {
-					checkUnsafeCast(scope, castType, expressionType, null, true);
-				}
-				// recursively on the type variable upper bound
-				return checkCastTypesCompatibility(scope, castType.erasure(), expressionType, expression);
-			} else if (castType.isClass() || castType.isEnum()) {
-				//------(castType.isClass) expressionType.isArray ---------------	
-				if (castType.id == T_JavaLangObject) {
+		switch(expressionType.kind()) {
+			case Binding.BASE_TYPE :
+				//-----------cast to something which is NOT a base type--------------------------	
+				if (expressionType == NullBinding) {
 					tagAsUnnecessaryCast(scope, castType);
-					return true;
+					return true; //null is compatible with every thing
 				}
-			} else { //------- (castType.isInterface) expressionType.isArray -----------
-				if (castType.id == T_JavaLangCloneable || castType.id == T_JavaIoSerializable) {
-					tagAsNeedCheckCast();
-					return true;
-				}
-			}
-			return false;
-		}
-		if (expressionType.isTypeVariable() || expressionType.isWildcard()) {
-			if (castType instanceof ReferenceBinding) {
-				TypeBinding match = ((ReferenceBinding)expressionType).findSuperTypeErasingTo((ReferenceBinding)castType);
-				if (match != null) {
-					tagAsUnnecessaryCast(scope, castType);
-					return true;
-				}
-			}
-			// recursively on the type variable upper bound
-			return checkCastTypesCompatibility(scope, castType, expressionType.erasure(), expression);
-		}
-		
-		if (expressionType.isClass() || expressionType.isEnum()) {
-			if (castType.isArrayType()) {
-				// ---- (castType.isArray) expressionType.isClass -------
-				if (expressionType.id == T_JavaLangObject) { // potential runtime error
-					tagAsNeedCheckCast();
-					return true;
-				}
-			} else if (castType.isTypeVariable()) {
-				TypeBinding match = ((ReferenceBinding)expressionType).findSuperTypeErasingTo((ReferenceBinding)castType);
-				if (match == null) {
-					checkUnsafeCast(scope, castType, expressionType, match, true);
-				}
-				// recursively on the type variable upper bound
-				return checkCastTypesCompatibility(scope, castType.erasure(), expressionType, expression);
-			} else if (castType.isClass() || castType.isEnum()) { // ----- (castType.isClass) expressionType.isClass ------
-				TypeBinding match = ((ReferenceBinding)expressionType).findSuperTypeErasingTo((ReferenceBinding)castType.erasure());
-				if (match != null) {
-					if (expression != null && castType.id == T_JavaLangString) this.constant = expression.constant; // (String) cst is still a constant
-					return checkUnsafeCast(scope, castType, expressionType, match, false);
-				}
-				match = ((ReferenceBinding)castType).findSuperTypeErasingTo((ReferenceBinding)expressionType.erasure());
-				if (match != null) {
-					tagAsNeedCheckCast();
-					return checkUnsafeCast(scope, castType, expressionType, match, true);
-				}
-			} else { // ----- (castType.isInterface) expressionType.isClass -------  
-
-				TypeBinding match = ((ReferenceBinding)expressionType).findSuperTypeErasingTo((ReferenceBinding)castType.erasure());
-				if (match != null) {
-					return checkUnsafeCast(scope, castType, expressionType, match, false);
-				}
-				// a subclass may implement the interface ==> no check at compile time
-				if (!((ReferenceBinding) expressionType).isFinal()) {
-					tagAsNeedCheckCast();
-					match = ((ReferenceBinding)castType).findSuperTypeErasingTo((ReferenceBinding)expressionType.erasure());
-					if (match != null) {
-						return checkUnsafeCast(scope, castType, expressionType, match, true);
-					}
-					return true;
-				}
-				// no subclass for expressionType, thus compile-time check is valid
-			}
-			return false;
-		}
-	
-		//	if (expressionType.isInterface()) { cannot be anything else
-		if (castType.isArrayType()) {
-			// ----- (castType.isArray) expressionType.isInterface ------
-			if (expressionType.id == T_JavaLangCloneable
-					|| expressionType.id == T_JavaIoSerializable) {// potential runtime error
-				tagAsNeedCheckCast();
-				return true;
-			} else {
 				return false;
-			}
-		} else if (castType.isTypeVariable()) {
-			TypeBinding match = ((ReferenceBinding)expressionType).findSuperTypeErasingTo((ReferenceBinding)castType);
-			if (match == null) {
-				checkUnsafeCast(scope, castType, expressionType, match, true);
-			}
-			// recursively on the type variable upper bound
-			return checkCastTypesCompatibility(scope, castType.erasure(), expressionType, expression);
-		} else if (castType.isClass() || castType.isEnum()) { // ----- (castType.isClass) expressionType.isInterface --------
-
-			if (castType.id == T_JavaLangObject) { // no runtime error
-				tagAsUnnecessaryCast(scope, castType);
-				return true;
-			}
-			if (((ReferenceBinding) castType).isFinal()) {
-				// no subclass for castType, thus compile-time check is valid
-				TypeBinding match = ((ReferenceBinding)castType).findSuperTypeErasingTo((ReferenceBinding)expressionType.erasure());
-				if (match == null) {
-					// potential runtime error
-					return false;
-				}				
-			}
-		} else { // ----- (castType.isInterface) expressionType.isInterface -------
-				ReferenceBinding interfaceType = (ReferenceBinding) expressionType;
-				TypeBinding match = interfaceType.findSuperTypeErasingTo((ReferenceBinding)castType.erasure());
-				if (match != null) {
-					return checkUnsafeCast(scope, castType, interfaceType, match, false);
-				}
 				
-				tagAsNeedCheckCast();
-				match = ((ReferenceBinding)castType).findSuperTypeErasingTo((ReferenceBinding)interfaceType.erasure());
-				if (match != null) {
-					return checkUnsafeCast(scope, castType, interfaceType, match, true);
+			case Binding.ARRAY_TYPE :
+				if (castType == expressionType) {
+					tagAsUnnecessaryCast(scope, castType);
+					return true; // identity conversion
 				}
-				if (use15specifics) {
-					// a subclass may implement the interface ==> no check at compile time
-					return true;
-				}
-				// pre1.5 semantics - no covariance allowed (even if 1.5 compliant, but 1.4 source)
-				MethodBinding[] castTypeMethods = getAllInheritedMethods((ReferenceBinding) castType);
-				MethodBinding[] expressionTypeMethods = getAllInheritedMethods((ReferenceBinding) expressionType);
-				int exprMethodsLength = expressionTypeMethods.length;
-				for (int i = 0, castMethodsLength = castTypeMethods.length; i < castMethodsLength; i++)
-					for (int j = 0; j < exprMethodsLength; j++) {
-						if ((castTypeMethods[i].returnType != expressionTypeMethods[j].returnType)
-								&& (CharOperation.equals(castTypeMethods[i].selector, expressionTypeMethods[j].selector))
-								&& castTypeMethods[i].areParametersEqual(expressionTypeMethods[j])) {
+				switch (castType.kind()) {
+					case Binding.ARRAY_TYPE : 
+						// ( ARRAY ) ARRAY
+						TypeBinding castElementType = ((ArrayBinding) castType).elementsType();
+						TypeBinding exprElementType = ((ArrayBinding) expressionType).elementsType();
+						if (exprElementType.isBaseType() || castElementType.isBaseType()) {
+							if (castElementType == exprElementType) {
+								tagAsNeedCheckCast();
+								return true;
+							} 
 							return false;
-
 						}
+						// recurse on array type elements
+						return checkCastTypesCompatibility(scope, castElementType, exprElementType, expression);
+						
+					case Binding.TYPE_PARAMETER : 
+						// ( TYPE_PARAMETER ) ARRAY
+						if (expressionType instanceof ReferenceBinding) {
+							ReferenceBinding match = ((ReferenceBinding)expressionType).findSuperTypeWithSameErasure(castType);
+							if (match == null) {
+								checkUnsafeCast(scope, castType, expressionType, match, true);
+							}
+						} else {
+							checkUnsafeCast(scope, castType, expressionType, null, true);
+						}
+						// recurse on the type variable upper bound
+						return checkCastTypesCompatibility(scope, ((TypeVariableBinding)castType).upperBound(), expressionType, expression);
+						
+					default:
+						// ( CLASS/INTERFACE ) ARRAY
+						switch (castType.id) {
+							case T_JavaLangCloneable :
+							case T_JavaIoSerializable :
+								tagAsNeedCheckCast();
+								return true;
+							case T_JavaLangObject :
+								tagAsUnnecessaryCast(scope, castType);
+								return true;
+							default :
+								return false;
+						}
+				}
+						
+			case Binding.TYPE_PARAMETER :
+				if (castType instanceof ReferenceBinding) {
+					TypeBinding match = ((ReferenceBinding)expressionType).findSuperTypeWithSameErasure(castType);
+					if (match != null) {
+						return checkUnsafeCast(scope, castType, expressionType, match, false);
+					}					
+				}
+				// recursively on the type variable upper bound
+				return checkCastTypesCompatibility(scope, castType, ((TypeVariableBinding)expressionType).upperBound(), expression);
+				
+			case Binding.WILDCARD_TYPE : // intersection type
+				if (castType instanceof ReferenceBinding) {
+					TypeBinding match = ((ReferenceBinding)expressionType).findSuperTypeWithSameErasure(castType);
+					if (match != null) {
+						return checkUnsafeCast(scope, castType, expressionType, match, false);
+					}						
+				}
+				// recursively on the type variable upper bound
+				return checkCastTypesCompatibility(scope, castType, ((WildcardBinding)expressionType).bound, expression);
+
+			default:
+				if (expressionType.isInterface()) {
+					switch (castType.kind()) {
+						case Binding.ARRAY_TYPE :
+							// ( ARRAY ) INTERFACE
+							switch (expressionType.id) {
+								case T_JavaLangCloneable :
+								case T_JavaIoSerializable :
+									tagAsNeedCheckCast();
+									return true;
+								default :									
+									return false;
+							}
+
+						case Binding.TYPE_PARAMETER :
+							// ( INTERFACE ) TYPE_PARAMETER
+							TypeBinding match = ((ReferenceBinding)expressionType).findSuperTypeWithSameErasure(castType);
+							if (match == null) {
+								checkUnsafeCast(scope, castType, expressionType, match, true);
+							}
+							// recurse on the type variable upper bound
+							return checkCastTypesCompatibility(scope, ((TypeVariableBinding)castType).upperBound(), expressionType, expression);
+
+						default :
+							if (castType.isInterface()) {
+								// ( INTERFACE ) INTERFACE
+								ReferenceBinding interfaceType = (ReferenceBinding) expressionType;
+								match = interfaceType.findSuperTypeWithSameErasure(castType);
+								if (match != null) {
+									return checkUnsafeCast(scope, castType, interfaceType, match, false);
+								}
+								tagAsNeedCheckCast();
+								match = ((ReferenceBinding)castType).findSuperTypeWithSameErasure(interfaceType);
+								if (match != null) {
+									return checkUnsafeCast(scope, castType, interfaceType, match, true);
+								}
+								if (use15specifics) {
+									// ensure there is no collision between both interfaces: i.e. I1 extends List<String>, I2 extends List<Object>
+									if (interfaceType.hasIncompatibleSuperType((ReferenceBinding)castType))
+										return false;
+								} else {
+									// pre1.5 semantics - no covariance allowed (even if 1.5 compliant, but 1.4 source)
+									MethodBinding[] castTypeMethods = getAllInheritedMethods((ReferenceBinding) castType);
+									MethodBinding[] expressionTypeMethods = getAllInheritedMethods((ReferenceBinding) expressionType);
+									int exprMethodsLength = expressionTypeMethods.length;
+									for (int i = 0, castMethodsLength = castTypeMethods.length; i < castMethodsLength; i++) {
+										for (int j = 0; j < exprMethodsLength; j++) {
+											if ((castTypeMethods[i].returnType != expressionTypeMethods[j].returnType)
+													&& (CharOperation.equals(castTypeMethods[i].selector, expressionTypeMethods[j].selector))
+													&& castTypeMethods[i].areParametersEqual(expressionTypeMethods[j])) {
+												return false;
+					
+											}
+										}
+									}
+								}
+								return true;		
+							} else {
+								// ( CLASS ) INTERFACE
+								if (castType.id == T_JavaLangObject) { // no runtime error
+									tagAsUnnecessaryCast(scope, castType);
+									return true;
+								}
+								if (((ReferenceBinding) castType).isFinal()) {
+									// no subclass for castType, thus compile-time check is valid
+									match = ((ReferenceBinding)castType).findSuperTypeWithSameErasure(expressionType);
+									if (match == null /*|| !match.isCompatibleWith(expressionType)*/) {
+										// potential runtime error
+										return false;
+									}
+								}
+								if (use15specifics) {
+									// ensure there is no collision between both interfaces: i.e. I1 extends List<String>, I2 extends List<Object>
+									if (((ReferenceBinding)castType).hasIncompatibleSuperType((ReferenceBinding) expressionType))
+										return false;
+								}
+							}
 					}
-				return true;
+					tagAsNeedCheckCast();
+					return true;
+				} else {
+					switch (castType.kind()) {
+						case Binding.ARRAY_TYPE :
+							// ( ARRAY ) CLASS
+							if (expressionType.id == T_JavaLangObject) { // potential runtime error
+								checkUnsafeCast(scope, castType, expressionType, expressionType, true);
+								tagAsNeedCheckCast();
+								return true;
+							}
+							return false;
+							
+						case Binding.TYPE_PARAMETER :
+							// ( TYPE_PARAMETER ) CLASS
+							TypeBinding match = ((ReferenceBinding)expressionType).findSuperTypeWithSameErasure(castType);
+							if (match == null) {
+								checkUnsafeCast(scope, castType, expressionType, match, true);
+							}
+							// recurse on the type variable upper bound
+							return checkCastTypesCompatibility(scope, ((TypeVariableBinding)castType).upperBound(), expressionType, expression);
+							
+						default :
+							if (castType.isInterface()) {
+								// ( INTERFACE ) CLASS
+								ReferenceBinding refExprType = (ReferenceBinding) expressionType;
+								match = refExprType.findSuperTypeWithSameErasure(castType);
+								if (refExprType.isFinal()) {
+									// unless final a subclass may implement the interface ==> no check at compile time
+									if (match == null || !match.isCompatibleWith(castType)) {
+										return false;
+									}
+									return checkUnsafeCast(scope, castType, expressionType, match, false);
+								} else {
+									if (match != null) {
+										return checkUnsafeCast(scope, castType, expressionType, match, false);
+									}
+								}
+								tagAsNeedCheckCast();
+								match = ((ReferenceBinding)castType).findSuperTypeWithSameErasure(expressionType);
+								if (match != null) {
+									return checkUnsafeCast(scope, castType, expressionType, match, true);
+								}
+								if (use15specifics) {
+									// ensure there is no collision between both interfaces: i.e. I1 extends List<String>, I2 extends List<Object>
+									if (refExprType.hasIncompatibleSuperType((ReferenceBinding) castType))
+										return false;
+								}								
+								return true;
+							} else {
+								// ( CLASS ) CLASS
+								match = ((ReferenceBinding)expressionType).findSuperTypeWithSameErasure(castType);
+								if (match != null) {
+									if (expression != null && castType.id == T_JavaLangString) this.constant = expression.constant; // (String) cst is still a constant
+									return checkUnsafeCast(scope, castType, expressionType, match, false);
+								}
+								match = ((ReferenceBinding)castType).findSuperTypeWithSameErasure(expressionType);
+								if (match != null) {
+									tagAsNeedCheckCast();
+									return checkUnsafeCast(scope, castType, expressionType, match, true);
+								}
+								return false;
+							}
+					}
+				}
 		}
-		tagAsNeedCheckCast();
-		return true;
 	}	
 	
 	public FlowInfo checkNullStatus(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, int nullStatus) {
@@ -483,7 +524,12 @@
 			if (!isNarrowing) tagAsUnnecessaryCast(scope, castType);
 			return true;
 		}
-		if (match != null && (castType.isBoundParameterizedType() || castType.isGenericType() || expressionType.isBoundParameterizedType() || expressionType.isGenericType())) {
+		if (match != null && (
+				castType.isBoundParameterizedType() 
+				|| castType.isGenericType() 
+				|| 	expressionType.isBoundParameterizedType() 
+				|| expressionType.isGenericType())) {
+			
 			if (match.isProvablyDistinctFrom(isNarrowing ? expressionType : castType, 0)) {
 				return false; 
 			}
@@ -496,38 +542,41 @@
 	 * Base types need that the widening is explicitly done by the compiler using some bytecode like i2f.
 	 * Also check unsafe type operations.
 	 */ 
-	public void computeConversion(Scope scope, TypeBinding runtimeTimeType, TypeBinding compileTimeType) {
+	public void computeConversion(Scope scope, TypeBinding runtimeType, TypeBinding compileTimeType) {
 
-		if (runtimeTimeType == null || compileTimeType == null)
+		if (runtimeType == null || compileTimeType == null)
 			return;
 		if (this.implicitConversion != 0) return; // already set independantly
-
+		
 		// it is possible for a Byte to be unboxed to a byte & then converted to an int
 		// but it is not possible for a byte to become Byte & then assigned to an Integer,
 		// or to become an int before boxed into an Integer
-		if (runtimeTimeType != NullBinding && runtimeTimeType.isBaseType()) {
+		if (runtimeType != NullBinding && runtimeType.isBaseType()) {
 			if (!compileTimeType.isBaseType()) {
 				TypeBinding unboxedType = scope.environment().computeBoxingType(compileTimeType);
 				this.implicitConversion = UNBOXING;
-				scope.problemReporter().autoboxing(this, compileTimeType, runtimeTimeType);
+				scope.problemReporter().autoboxing(this, compileTimeType, runtimeType);
 				compileTimeType = unboxedType;
 			}
 		} else {
 			if (compileTimeType != NullBinding && compileTimeType.isBaseType()) {
-				TypeBinding boxedType = scope.environment().computeBoxingType(runtimeTimeType);
-				if (boxedType == runtimeTimeType) // Object o = 12;
+				TypeBinding boxedType = scope.environment().computeBoxingType(runtimeType);
+				if (boxedType == runtimeType) // Object o = 12;
 					boxedType = compileTimeType; 
 				this.implicitConversion = BOXING | (boxedType.id << 4) + compileTimeType.id;
 				scope.problemReporter().autoboxing(this, compileTimeType, scope.environment().computeBoxingType(boxedType));
 				return;
 			}
 		}
-
-		switch (runtimeTimeType.id) {
+		int compileTimeTypeID, runtimeTypeID;
+		if ((compileTimeTypeID = compileTimeType.id) == NoId) { // e.g. ? extends String  ==> String (103227)
+			compileTimeTypeID = compileTimeType.erasure().id == T_JavaLangString ? T_JavaLangString : T_JavaLangObject;
+		}		
+		switch (runtimeTypeID = runtimeType.id) {
 			case T_byte :
 			case T_short :
 			case T_char :
-				this.implicitConversion |= (T_int << 4) + compileTimeType.id;
+				this.implicitConversion |= (T_int << 4) + compileTimeTypeID;
 				break;
 			case T_JavaLangString :
 			case T_float :
@@ -535,7 +584,7 @@
 			case T_double :
 			case T_int : //implicitConversion may result in i2i which will result in NO code gen
 			case T_long :
-				this.implicitConversion |= (runtimeTimeType.id << 4) + compileTimeType.id;
+				this.implicitConversion |= (runtimeTypeID << 4) + compileTimeTypeID;
 				break;
 			default : // regular object ref
 //				if (compileTimeType.isRawType() && runtimeTimeType.isBoundParameterizedType()) {
@@ -716,7 +765,7 @@
 	//(this request some work d be done by the VM on signed numbers)
 	public boolean isConstantValueOfTypeAssignableToType(TypeBinding constantType, TypeBinding targetType) {
 
-		if (constant == Constant.NotAConstant)
+		if (this.constant == Constant.NotAConstant)
 			return false;
 		if (constantType == targetType)
 			return true;
@@ -726,7 +775,7 @@
 				|| BaseTypeBinding.isWidening(T_int, constantType.id))
 				&& (BaseTypeBinding.isNarrowing(targetType.id, T_int))) {
 				//use current explicit conversion in order to get some new value to compare with current one
-				return isConstantValueRepresentable(constant, constantType.id, targetType.id);
+				return isConstantValueRepresentable(this.constant, constantType.id, targetType.id);
 			}
 		}
 		return false;
@@ -782,12 +831,11 @@
 	}
 
 	public TypeBinding resolveType(BlockScope scope) {
-		// by default... subclasses should implement a better TC if required.
-
+		// by default... subclasses should implement a better TB if required.
 		return null;
 	}
 
-	public TypeBinding resolveType(ClassScope classScope) {
+	public TypeBinding resolveType(ClassScope scope) {
 		// by default... subclasses should implement a better TB if required.
 		return null;
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java
index 552abcb..9a8b1bc 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java
@@ -56,9 +56,11 @@
 		FlowContext flowContext,
 		FlowInfo flowInfo) {
 
-		if (this.binding != null && this.binding.isPrivate() && !this.binding.isPrivateUsed()) {
-			if (!initializationScope.referenceCompilationUnit().compilationResult.hasSyntaxError()) {
-				initializationScope.problemReporter().unusedPrivateField(this);
+		if (this.binding != null && !this.binding.isUsed()) {
+			if (this.binding.isPrivate() || (this.binding.declaringClass != null && this.binding.declaringClass.isLocalType())) {
+				if (!initializationScope.referenceCompilationUnit().compilationResult.hasSyntaxError) {
+					initializationScope.problemReporter().unusedPrivateField(this);
+				}
 			}
 		}
 		// cannot define static non-constant field inside nested class
@@ -67,7 +69,6 @@
 				&& this.binding.isStatic()
 				&& !this.binding.isConstantValue()
 				&& this.binding.declaringClass.isNestedType()
-				&& this.binding.declaringClass.isClass() // no need to check for enum, since implicitly static
 				&& !this.binding.declaringClass.isStatic()) {
 			initializationScope.problemReporter().unexpectedStaticModifierForField(
 				(SourceTypeBinding) this.binding.declaringClass,
@@ -160,8 +161,6 @@
 
 			this.hasBeenResolved = true;
 
-			resolveAnnotations(initializationScope, this.annotations, this.binding);
-
 			// check if field is hiding some variable - issue is that field binding already got inserted in scope
 			// thus must lookup separately in super type and outer context
 			ClassScope classScope = initializationScope.enclosingClassScope();
@@ -202,6 +201,8 @@
 				initializationScope.initializedField = this.binding;
 				initializationScope.lastVisibleFieldID = this.binding.id;
 
+				resolveAnnotations(initializationScope, this.annotations, this.binding);
+				
 				// the resolution of the initialization hasn't been done
 				if (this.initialization == null) {
 					this.binding.setConstant(Constant.NotAConstant);
@@ -229,12 +230,11 @@
 							if (initializationType.needsUncheckedConversion(fieldType)) {
 								    initializationScope.problemReporter().unsafeTypeConversion(this.initialization, initializationType, fieldType);
 							}									
-						} else if (initializationScope.environment().options.sourceLevel >= JDK1_5 // autoboxing
-										&& (initializationScope.isBoxingCompatibleWith(initializationType, fieldType) 
-												|| (initializationType.isBaseType()  // narrowing then boxing ?
-														&& initializationType != null 
-														&& !fieldType.isBaseType()
-														&& initialization.isConstantValueOfTypeAssignableToType(initializationType, initializationScope.environment().computeBoxingType(fieldType))))) {
+						} else if (initializationScope.isBoxingCompatibleWith(initializationType, fieldType) 
+											|| (initializationType.isBaseType()  // narrowing then boxing ?
+													&& initializationScope.compilerOptions().sourceLevel >= JDK1_5 // autoboxing
+													&& !fieldType.isBaseType()
+													&& initialization.isConstantValueOfTypeAssignableToType(initializationType, initializationScope.environment().computeBoxingType(fieldType)))) {
 							this.initialization.computeConversion(initializationScope, fieldType, initializationType);
 						} else {
 							initializationScope.problemReporter().typeMismatchError(initializationType, fieldType, this);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java
index f1157b3..f25a065 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java
@@ -116,7 +116,7 @@
 		receiver.analyseCode(currentScope, flowContext, flowInfo, nonStatic);
 		if (nonStatic) receiver.checkNullStatus(currentScope, flowContext, flowInfo, FlowInfo.NON_NULL);
 		
-		if (valueRequired || currentScope.environment().options.complianceLevel >= ClassFileConstants.JDK1_4) {
+		if (valueRequired || currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4) {
 			manageSyntheticAccessIfNecessary(currentScope, flowInfo, true /*read-access*/);
 		}
 		return flowInfo;
@@ -203,7 +203,7 @@
 				}
 			} else {
 				receiver.generateCode(currentScope, codeStream, !isStatic);
-				if (valueRequired || currentScope.environment().options.complianceLevel >= ClassFileConstants.JDK1_4) {
+				if (valueRequired || currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4) {
 					if (this.codegenBinding.declaringClass == null) { // array length
 						codeStream.arraylength();
 						if (valueRequired) {
@@ -283,6 +283,8 @@
 				codeStream.generateStringConcatenationAppend(currentScope, null, expression);
 				break;
 			default :
+				if (this.genericCast != null)
+					codeStream.checkcast(this.genericCast);				
 				// promote the array reference to the suitable operation type
 				codeStream.generateImplicitConversion(implicitConversion);
 				// generate the increment value (will by itself  be promoted to the operation value)
@@ -346,13 +348,15 @@
 				}
 			}
 		}
-		codeStream.generateImplicitConversion(implicitConversion);		
+		if (this.genericCast != null)
+			codeStream.checkcast(this.genericCast);
+		codeStream.generateImplicitConversion(this.implicitConversion);		
 		codeStream.generateConstant(
 			postIncrement.expression.constant,
-			implicitConversion);
+			this.implicitConversion);
 		codeStream.sendOperator(postIncrement.operator, this.implicitConversion & COMPILE_TYPE_MASK);
 		codeStream.generateImplicitConversion(
-			postIncrement.assignmentImplicitConversion);
+			postIncrement.preAssignImplicitConversion);
 		fieldStore(codeStream, this.codegenBinding, syntheticAccessors == null ? null : syntheticAccessors[WRITE], false);
 	}
 	/**
@@ -483,7 +487,7 @@
 				&& !this.receiverType.isArrayType()
 				&& this.binding.declaringClass != null // array.length
 				&& !this.binding.isConstantValue()) {
-			CompilerOptions options = currentScope.environment().options;
+			CompilerOptions options = currentScope.compilerOptions();
 			if ((options.targetJDK >= ClassFileConstants.JDK1_2
 					&& (options.complianceLevel >= ClassFileConstants.JDK1_4 || !receiver.isImplicitThis() || !this.codegenBinding.isStatic())
 					&& this.binding.declaringClass.id != T_JavaLangObject) // no change for Object fields
@@ -535,7 +539,7 @@
 		}
 		TypeBinding receiverErasure = this.receiverType.erasure();
 		if (receiverErasure instanceof ReferenceBinding) {
-			ReferenceBinding match = ((ReferenceBinding)receiverErasure).findSuperTypeErasingTo((ReferenceBinding)fieldBinding.declaringClass.erasure());
+			ReferenceBinding match = ((ReferenceBinding)receiverErasure).findSuperTypeWithSameErasure(fieldBinding.declaringClass);
 			if (match == null) {
 				this.receiverType = fieldBinding.declaringClass; // handle indirect inheritance thru variable secondary bound
 			}
@@ -563,7 +567,7 @@
 		// perform capture conversion if read access
 		return this.resolvedType = 
 			(((this.bits & IsStrictlyAssignedMASK) == 0) 
-				? fieldBinding.type.capture()
+				? fieldBinding.type.capture(scope, this.sourceEnd)
 				: fieldBinding.type);
 	}
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java
index 5ca6e7d..c9a4364 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java
@@ -99,7 +99,7 @@
 		LoopingFlowContext loopingContext;
 		FlowInfo actionInfo;
 		if (action == null 
-			|| (action.isEmptyBlock() && currentScope.environment().options.complianceLevel <= ClassFileConstants.JDK1_3)) {
+			|| (action.isEmptyBlock() && currentScope.compilerOptions().complianceLevel <= ClassFileConstants.JDK1_3)) {
 			if (condLoopContext != null)
 				condLoopContext.complainOnDeferredChecks(scope, condInfo);
 			if (isConditionTrue) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java
index 0594781..e140c0f 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java
@@ -94,7 +94,7 @@
 		FlowInfo actionInfo = condInfo.initsWhenTrue().copy();
 		FlowInfo exitBranch;
 		if (!(action == null || (action.isEmptyBlock() 
-		        	&& currentScope.environment().options.complianceLevel <= ClassFileConstants.JDK1_3))) {
+		        	&& currentScope.compilerOptions().complianceLevel <= ClassFileConstants.JDK1_3))) {
 
 			if (!this.action.complainIfUnreachable(actionInfo, scope, false)) {
 				actionInfo = action.analyseCode(scope, loopingContext, actionInfo);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java
index 8f4c949..c9dea82 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java
@@ -95,7 +95,9 @@
 	 * @see org.eclipse.jdt.internal.compiler.ast.Expression#tagAsUnnecessaryCast(Scope,TypeBinding)
 	 */
 	public void tagAsUnnecessaryCast(Scope scope, TypeBinding castType) {
-		scope.problemReporter().unnecessaryInstanceof(this, castType);
+		// null is not instanceof Type, recognize direct scenario
+		if (expression.resolvedType != NullBinding)
+			scope.problemReporter().unnecessaryInstanceof(this, castType);
 	}
 	public void traverse(ASTVisitor visitor, BlockScope scope) {
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Javadoc.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Javadoc.java
index 407c27f..f56df89 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Javadoc.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Javadoc.java
@@ -75,19 +75,19 @@
 	/*
 	 * Resolve type javadoc while a class scope
 	 */
-	public void resolve(ClassScope classScope) {
+	public void resolve(ClassScope scope) {
 
 		// @param tags
 		int paramTagsSize = this.paramReferences == null ? 0 : this.paramReferences.length;
 		for (int i = 0; i < paramTagsSize; i++) {
 			JavadocSingleNameReference param = this.paramReferences[i];
-			classScope.problemReporter().javadocUnexpectedTag(param.tagSourceStart, param.tagSourceEnd);
+			scope.problemReporter().javadocUnexpectedTag(param.tagSourceStart, param.tagSourceEnd);
 		}
-		resolveTypeParameterTags(classScope, true);
+		resolveTypeParameterTags(scope, true);
 
 		// @return tags
 		if (this.returnStatement != null) {
-			classScope.problemReporter().javadocUnexpectedTag(this.returnStatement.sourceStart, this.returnStatement.sourceEnd);
+			scope.problemReporter().javadocUnexpectedTag(this.returnStatement.sourceStart, this.returnStatement.sourceEnd);
 		}
 
 		// @throws/@exception tags
@@ -107,13 +107,13 @@
 				start = typeRef.sourceStart;
 				end = typeRef.sourceEnd;
 			}
-			classScope.problemReporter().javadocUnexpectedTag(start, end);
+			scope.problemReporter().javadocUnexpectedTag(start, end);
 		}
 
 		// @see tags
 		int seeTagsLength = this.seeReferences == null ? 0 : this.seeReferences.length;
 		for (int i = 0; i < seeTagsLength; i++) {
-			resolveReference(this.seeReferences[i], classScope);
+			resolveReference(this.seeReferences[i], scope);
 		}
 	}
 	
@@ -143,12 +143,12 @@
 						if (messageSend.binding != null && messageSend.binding.isValidBinding()) {
 							if (methDecl.binding.declaringClass.isCompatibleWith(messageSend.actualReceiverType) &&
 								CharOperation.equals(messageSend.selector, methDecl.selector) &&
-								(messageSend.binding.returnType == methDecl.binding.returnType)) {
+								(methDecl.binding.returnType.isCompatibleWith(messageSend.binding.returnType))) {
 								if (messageSend.arguments == null && methDecl.arguments == null) {
 									superRef = true;
 								}
 								else if (messageSend.arguments != null && methDecl.arguments != null) {
-									superRef = methDecl.binding.areParametersEqual(messageSend.binding);
+									superRef = methDecl.binding.areParametersCompatibleWith(messageSend.binding.parameters);
 								}
 							}
 						}
@@ -162,7 +162,7 @@
 									superRef = true;
 								}
 								else if (allocationExpr.arguments != null && methDecl.arguments != null) {
-									superRef = methDecl.binding.areParametersEqual(allocationExpr.binding);
+									superRef = methDecl.binding.areParametersCompatibleWith(allocationExpr.binding.parameters);
 								}
 							}
 						}
@@ -217,14 +217,14 @@
 		switch (scope.kind) {
 			case Scope.METHOD_SCOPE:
 				reference.resolveType((MethodScope)scope);
-			break;
+				break;
 			case Scope.CLASS_SCOPE:
 				reference.resolveType((ClassScope)scope);
-			break;
+				break;
 		}
 
 		// Verify field references
-		boolean verifyValues = scope.environment().options.sourceLevel >= ClassFileConstants.JDK1_5;
+		boolean verifyValues = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5;
 		if (reference instanceof JavadocFieldReference) {
 			JavadocFieldReference fieldRef = (JavadocFieldReference) reference;
 			int modifiers = fieldRef.binding==null ? -1 : fieldRef.binding.modifiers;
@@ -270,6 +270,12 @@
 				scope.problemReporter().javadocInvalidValueReference(alloc.sourceStart, alloc.sourceEnd, modifiers);
 			}
 		}
+		
+		// Verify that there's no type variable reference
+		// (javadoc does not accept them and this is not a referenced bug or requested enhancement)
+		if (reference.resolvedType != null && reference.resolvedType.isTypeVariable()) {
+			scope.problemReporter().javadocInvalidReference(reference.sourceStart, reference.sourceEnd);
+		}
 	}
 
 	/*
@@ -392,7 +398,6 @@
 		// Otherwise verify that all param tags match type parameters
 		} else if (typeVariables.length == typeParametersLength) {
 			TypeVariableBinding[] bindings = new TypeVariableBinding[paramTypeParamLength];
-			int maxBindings = 0;
 
 			// Scan all @param tags
 			for (int i = 0; i < paramTypeParamLength; i++) {
@@ -402,14 +407,14 @@
 					if (paramBindind.isTypeVariable()) {
 						// Verify duplicated tags
 						boolean duplicate = false;
-						for (int j = 0; j < maxBindings && !duplicate; j++) {
+						for (int j = 0; j < i && !duplicate; j++) {
 							if (bindings[j] == param.resolvedType) {
 								scope.problemReporter().javadocDuplicatedParamTag(param.token, param.sourceStart, param.sourceEnd, modifiers);
 								duplicate = true;
 							}
 						}
 						if (!duplicate) {
-							bindings[maxBindings++] = (TypeVariableBinding) param.resolvedType;
+							bindings[i] = (TypeVariableBinding) param.resolvedType;
 						}
 					} else {
 						scope.problemReporter().javadocUndeclaredParamTagName(param.token, param.sourceStart, param.sourceEnd, modifiers);
@@ -418,18 +423,25 @@
 			}
 
 			// Look for undocumented type parameters
-			if (reportMissing) {
-				for (int i = 0; i < typeParametersLength; i++) {
-					TypeParameter parameter = parameters[i];
-					boolean found = false;
-					for (int j = 0; j < maxBindings && !found; j++) {
-						if (parameter.binding == bindings[j]) {
-							found = true;
-						}
+			for (int i = 0; i < typeParametersLength; i++) {
+				TypeParameter parameter = parameters[i];
+				boolean found = false;
+				for (int j = 0; j < paramTypeParamLength && !found; j++) {
+					if (parameter.binding == bindings[j]) {
+						found = true;
+						bindings[j] = null;
 					}
-					if (!found) {
-						scope.problemReporter().javadocMissingParamTag(parameter.name, parameter.sourceStart, parameter.sourceEnd, modifiers);
-					}
+				}
+				if (!found && reportMissing) {
+					scope.problemReporter().javadocMissingParamTag(parameter.name, parameter.sourceStart, parameter.sourceEnd, modifiers);
+				}
+			}
+			
+			// Report invalid param
+			for (int i=0; i<paramTypeParamLength; i++) {
+				if (bindings[i] != null) {
+					JavadocSingleTypeReference param = this.paramTypeParameters[i];
+					scope.problemReporter().javadocUndeclaredParamTagName(param.token, param.sourceStart, param.sourceEnd, modifiers);
 				}
 			}
 		}
@@ -530,9 +542,7 @@
 					}
 			
 					//  If not compatible only complain on unchecked exception
-					if (!compatible &&
-						 !typeRef.resolvedType.isCompatibleWith(methScope.getJavaLangRuntimeException()) &&
-						 !typeRef.resolvedType.isCompatibleWith(methScope.getJavaLangError())) {
+					if (!compatible && !typeRef.resolvedType.isUncheckedException(false)) {
 						methScope.problemReporter().javadocInvalidThrowsClassName(typeRef, md.binding.modifiers);
 					}
 				}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocAllocationExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocAllocationExpression.java
index a662865..245b2e5 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocAllocationExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocAllocationExpression.java
@@ -11,8 +11,6 @@
 package org.eclipse.jdt.internal.compiler.ast;
 
 import org.eclipse.jdt.internal.compiler.lookup.*;
-import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
-import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
 
 public class JavadocAllocationExpression extends AllocationExpression {
 
@@ -70,8 +68,9 @@
 		if (this.resolvedType == null) {
 			return null;
 		}
-		this.resolvedType = scope.convertToRawType(this.type.resolvedType);
-		this.superAccess = scope.enclosingSourceType().isCompatibleWith(this.resolvedType);
+		this.resolvedType = scope.environment().convertToRawType(this.type.resolvedType);
+		SourceTypeBinding enclosingType = scope.enclosingSourceType();
+		this.superAccess = enclosingType==null ? false : enclosingType.isCompatibleWith(this.resolvedType);
 	
 		ReferenceBinding allocationType = (ReferenceBinding) this.resolvedType;
 		this.binding = scope.getConstructor(allocationType, argumentTypes, this);
@@ -124,27 +123,17 @@
 		if (isMethodUseDeprecated(this.binding, scope)) {
 			scope.problemReporter().javadocDeprecatedMethod(this.binding, this, scope.getDeclarationModifiers());
 		}
-		// TODO (frederic) add support for unsafe type operation warning
 		return allocationType;
 	}
-	
-	/* (non-Javadoc)
-	 * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#isSuperAccess()
-	 */
+
 	public boolean isSuperAccess() {
 		return this.superAccess;
 	}
 
-	/* (non-Javadoc)
-	 * @see org.eclipse.jdt.internal.compiler.ast.Expression#resolveType(org.eclipse.jdt.internal.compiler.lookup.BlockScope)
-	 */
 	public TypeBinding resolveType(BlockScope scope) {
 		return internalResolveType(scope);
 	}
 
-	/* (non-Javadoc)
-	 * @see org.eclipse.jdt.internal.compiler.ast.Expression#resolveType(org.eclipse.jdt.internal.compiler.lookup.BlockScope)
-	 */
 	public TypeBinding resolveType(ClassScope scope) {
 		return internalResolveType(scope);
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocArgumentExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocArgumentExpression.java
index 0ba6dae..ea24ba9 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocArgumentExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocArgumentExpression.java
@@ -13,9 +13,6 @@
 import org.eclipse.jdt.internal.compiler.ASTVisitor;
 import org.eclipse.jdt.internal.compiler.env.IConstants;
 import org.eclipse.jdt.internal.compiler.lookup.*;
-import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
-import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
-
 
 public class JavadocArgumentExpression extends Expression {
 	public char[] token;
@@ -51,7 +48,7 @@
 					scope.problemReporter().javadocDeprecatedType(this.resolvedType, typeRef, scope.getDeclarationModifiers());
 					return null;
 				}
-				return this.resolvedType = scope.convertToRawType(this.resolvedType);
+				return this.resolvedType = scope.environment().convertToRawType(this.resolvedType);
 			}
 		}
 		return null;
@@ -82,7 +79,7 @@
 	public TypeBinding resolveType(ClassScope scope) {
 		return internalResolveType(scope);
 	}
-	
+
 	/* (non-Javadoc)
 	 * Redefine to capture javadoc specific signatures
 	 * @see org.eclipse.jdt.internal.compiler.ast.ASTNode#traverse(org.eclipse.jdt.internal.compiler.ASTVisitor, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocFieldReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocFieldReference.java
index d776a53..43f8e0a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocFieldReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocFieldReference.java
@@ -65,7 +65,8 @@
 						fieldBinding = closestMatch; // ignore problem if can reach target field through it
 					}
 			}
-		}			
+		}
+		// When there's no valid field binding, try to resolve possible method reference without parenthesis
 		if (!fieldBinding.isValidBinding() || !(fieldBinding instanceof FieldBinding)) {
 			if (this.receiverType instanceof ReferenceBinding) {
 				ReferenceBinding refBinding = (ReferenceBinding) this.receiverType;
@@ -75,12 +76,15 @@
 				} else {
 					switch (methodBindings.length) {
 						case 0:
+							// no method was found: report problem
 							scope.problemReporter().javadocInvalidField(this.sourceStart, this.sourceEnd, fieldBinding, this.receiverType, scope.getDeclarationModifiers());
 							break;
 						case 1:
+							// one method binding was found: store binding in specific field
 							this.methodBinding = methodBindings[0];
 							break;
 						default:
+							// several method binding were found: store first binding in specific field and report ambiguous error
 							this.methodBinding = methodBindings[0];
 							scope.problemReporter().javadocAmbiguousMethodReference(this.sourceStart, this.sourceEnd, fieldBinding, scope.getDeclarationModifiers());
 							break;
@@ -97,9 +101,6 @@
 		return this.resolvedType = this.binding.type;
 	}
 	
-	/* (non-Javadoc)
-	 * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#isSuperAccess()
-	 */
 	public boolean isSuperAccess() {
 		return this.superAccess;
 	}
@@ -113,16 +114,10 @@
 		return output;
 	}
 
-	/* (non-Javadoc)
-	 * @see org.eclipse.jdt.internal.compiler.ast.Expression#resolveType(org.eclipse.jdt.internal.compiler.lookup.BlockScope)
-	 */
 	public TypeBinding resolveType(BlockScope scope) {
 		return internalResolveType(scope);
 	}
 
-	/* (non-Javadoc)
-	 * @see org.eclipse.jdt.internal.compiler.ast.Expression#resolveType(org.eclipse.jdt.internal.compiler.lookup.BlockScope)
-	 */
 	public TypeBinding resolveType(ClassScope scope) {
 		return internalResolveType(scope);
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocImplicitTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocImplicitTypeReference.java
index 606e479..b173c98 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocImplicitTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocImplicitTypeReference.java
@@ -11,10 +11,7 @@
 package org.eclipse.jdt.internal.compiler.ast;
 
 import org.eclipse.jdt.internal.compiler.ASTVisitor;
-import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
-import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
-import org.eclipse.jdt.internal.compiler.lookup.Scope;
-import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.*;
 
 public class JavadocImplicitTypeReference extends TypeReference {
 	
@@ -56,7 +53,8 @@
 	}
 
 	/*
-	 * Resolves type on a Block or Class scope.
+	 * Resolves type on a Block, Class or CompilationUnit scope.
+	 * We need to modify resoling behavior to avoid raw type creation.
 	 */
 	private TypeBinding internalResolveType(Scope scope) {
 		// handle the error here
@@ -76,39 +74,22 @@
 		return this.resolvedType;
 	}
 
-	/* (non-Javadoc)
-	 * Override super implementation to avoid raw type creation.
-	 * @see org.eclipse.jdt.internal.compiler.ast.TypeReference#resolveType(org.eclipse.jdt.internal.compiler.lookup.BlockScope, boolean)
-	 */
 	public TypeBinding resolveType(BlockScope blockScope, boolean checkBounds) {
 		return internalResolveType(blockScope);
 	}
 
-	/* (non-Javadoc)
-	 * Override super implementation to avoid raw type creation.
-	 * @see org.eclipse.jdt.internal.compiler.ast.Expression#resolveType(org.eclipse.jdt.internal.compiler.lookup.ClassScope)
-	 */
 	public TypeBinding resolveType(ClassScope classScope) {
 		return internalResolveType(classScope);
 	}
 
-	/* (non-Javadoc)
-	 * @see org.eclipse.jdt.internal.compiler.ast.TypeReference#traverse(org.eclipse.jdt.internal.compiler.ASTVisitor, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
-	 */
 	public void traverse(ASTVisitor visitor, BlockScope classScope) {
 		// Do nothing
 	}
 
-	/* (non-Javadoc)
-	 * @see org.eclipse.jdt.internal.compiler.ast.TypeReference#traverse(org.eclipse.jdt.internal.compiler.ASTVisitor, org.eclipse.jdt.internal.compiler.lookup.ClassScope)
-	 */
 	public void traverse(ASTVisitor visitor, ClassScope classScope) {
 		// Do nothing
 	}
 
-	/* (non-Javadoc)
-	 * @see org.eclipse.jdt.internal.compiler.ast.Expression#printExpression(int, java.lang.StringBuffer)
-	 */
 	public StringBuffer printExpression(int indent, StringBuffer output) {
 		return new StringBuffer();
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocMessageSend.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocMessageSend.java
index 278a6fa..ecf97d4 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocMessageSend.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocMessageSend.java
@@ -78,8 +78,9 @@
 		if (this.actualReceiverType == null) {
 			return null;
 		}
-		this.actualReceiverType = scope.convertToRawType(this.receiver.resolvedType);
-		this.superAccess = scope.enclosingSourceType().isCompatibleWith(this.actualReceiverType);
+		this.actualReceiverType = scope.environment().convertToRawType(this.receiver.resolvedType);
+		SourceTypeBinding enclosingType = scope.enclosingSourceType();
+		this.superAccess = enclosingType==null ? false : enclosingType.isCompatibleWith(this.actualReceiverType);
 
 		// base type cannot receive any message
 		if (this.actualReceiverType.isBaseType()) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocQualifiedTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocQualifiedTypeReference.java
index 0122c16..0f4d84c 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocQualifiedTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocQualifiedTypeReference.java
@@ -47,7 +47,7 @@
 	}
 
 	/*
-	 *
+	 * We need to modify resolving behavior to handle package references
 	 */
 	private TypeBinding internalResolveType(Scope scope, boolean checkBounds) {
 		// handle the error here
@@ -73,18 +73,10 @@
 		return resolvedType;
 	}
 
-	/* (non-Javadoc)
-	 * @see org.eclipse.jdt.internal.compiler.ast.Expression#resolveType(org.eclipse.jdt.internal.compiler.lookup.BlockScope)
-	 * We need to override to handle package references
-	 */
 	public TypeBinding resolveType(BlockScope blockScope, boolean checkBounds) {
 		return internalResolveType(blockScope, checkBounds);
 	}
 
-	/* (non-Javadoc)
-	 * @see org.eclipse.jdt.internal.compiler.ast.Expression#resolveType(org.eclipse.jdt.internal.compiler.lookup.ClassScope)
-	 * We need to override to handle package references
-	 */
 	public TypeBinding resolveType(ClassScope classScope) {
 		return internalResolveType(classScope, false);
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocSingleTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocSingleTypeReference.java
index 8e9a9b0..48d5262 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocSingleTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocSingleTypeReference.java
@@ -47,6 +47,9 @@
 		visitor.endVisit(this, scope);
 	}
 
+	/*
+	 * We need to modify resolving behavior to handle package references
+	 */
 	TypeBinding internalResolveType(Scope scope) {
 		// handle the error here
 		this.constant = NotAConstant;
@@ -60,6 +63,13 @@
 			if (binding instanceof PackageBinding) {
 				this.packageBinding = (PackageBinding) binding;
 			} else {
+				if (this.resolvedType.problemId() == ProblemReasons.NonStaticReferenceInStaticContext) {
+					ReferenceBinding closestMatch = ((ProblemReferenceBinding)this.resolvedType).closestMatch;
+					if (closestMatch != null && closestMatch.isTypeVariable()) {
+						this.resolvedType = closestMatch; // ignore problem as we want report specific javadoc one instead
+						return resolvedType;
+					}
+				}
 				reportInvalidType(scope);
 			}
 			return null;
@@ -80,10 +90,6 @@
 		return internalResolveType(blockScope);
 	}
 
-	/* (non-Javadoc)
-	 * @see org.eclipse.jdt.internal.compiler.ast.Expression#resolveType(org.eclipse.jdt.internal.compiler.lookup.ClassScope)
-	 * We need to override to handle package references
-	 */
 	public TypeBinding resolveType(ClassScope classScope) {
 		return internalResolveType(classScope);
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LabeledStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LabeledStatement.java
index fd2032d..b97b9c2 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LabeledStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LabeledStatement.java
@@ -83,6 +83,9 @@
 	 */
 	public void generateCode(BlockScope currentScope, CodeStream codeStream) {
 		
+		if ((bits & IsReachableMASK) == 0) {
+			return;
+		}		
 		int pc = codeStream.position;
 		if (targetLabel != null) {
 			targetLabel.initialize(codeStream);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java
index 210e765..dc7d371 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java
@@ -178,8 +178,6 @@
 			this.binding.setConstant(NotAConstant);
 			// allow to recursivelly target the binding....
 			// the correct constant is harmed if correctly computed at the end of this method
-			
-			resolveAnnotations(scope, this.annotations, this.binding);
 		}
 
 		if (variableType == null) {
@@ -209,12 +207,11 @@
 						if (initializationType.needsUncheckedConversion(variableType)) {
 						    scope.problemReporter().unsafeTypeConversion(this.initialization, initializationType, variableType);
 						}						
-					} else if (scope.environment().options.sourceLevel >= JDK1_5 // autoboxing
-									&& (scope.isBoxingCompatibleWith(initializationType, variableType) 
-											|| (initializationType.isBaseType()  // narrowing then boxing ?
-													&& initializationType != null 
-													&& !variableType.isBaseType()
-													&& initialization.isConstantValueOfTypeAssignableToType(initializationType, scope.environment().computeBoxingType(variableType))))) {
+					} else if (scope.isBoxingCompatibleWith(initializationType, variableType) 
+										|| (initializationType.isBaseType()  // narrowing then boxing ?
+												&& scope.compilerOptions().sourceLevel >= JDK1_5 // autoboxing
+												&& !variableType.isBaseType()
+												&& initialization.isConstantValueOfTypeAssignableToType(initializationType, scope.environment().computeBoxingType(variableType)))) {
 						this.initialization.computeConversion(scope, variableType, initializationType);
 					} else {
 						scope.problemReporter().typeMismatchError(initializationType, variableType, this);
@@ -232,6 +229,9 @@
 						: NotAConstant);
 			}
 		}
+		// only resolve annotation at the end, for constant to be positionned before (96991)
+		if (this.binding != null)
+			resolveAnnotations(scope, this.annotations, this.binding);
 	}
 
 	public void traverse(ASTVisitor visitor, BlockScope scope) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LongLiteral.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LongLiteral.java
index 63288c0..300b141 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LongLiteral.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LongLiteral.java
@@ -30,50 +30,71 @@
 public void computeConstant() {
 	//the overflow (when radix=10) is tested using the fact that
 	//the value should always grow during its computation
-
 	int length = source.length - 1; //minus one because the last char is 'l' or 'L'
 	
 	long computedValue ;
-	if (source[0] == '0')
-	{	if (length == 1) { 	constant = Constant.fromValue(0L);	return;	}
+	if (source[0] == '0') {
+		if (length == 1) {
+			constant = Constant.fromValue(0L);
+			return;
+		}
 		final int shift,radix;
 		int j ;
-		if ( (source[1] == 'x') || (source[1] == 'X') )
-		{	shift = 4 ; j = 2; radix = 16;}
-		else
-		{	shift = 3 ; j = 1; radix = 8;}
+		if ( (source[1] == 'x') || (source[1] == 'X') ) {
+			shift = 4 ; j = 2; radix = 16;
+		} else {
+			shift = 3 ; j = 1; radix = 8;
+		}
 		int nbDigit = 0;
-		while (source[j]=='0') 
-		{	j++; //jump over redondant zero
-			if ( j == length)
-			{	//watch for 0000000000000L
+		while (source[j]=='0') {
+			j++; //jump over redondant zero
+			if ( j == length) {
+				//watch for 0000000000000L
 				constant = Constant.fromValue(value = 0L);
-				return ;}}
+				return ;
+			}
+		}
 				
 		int digitValue ;
-		if ((digitValue = Character.digit(source[j++],radix))	< 0 ) 	
-		{	constant = FORMAT_ERROR; return ;}
-		if (digitValue >= 8) nbDigit = 4;
-		else 	if (digitValue >= 4) nbDigit = 3;
-				else 	if (digitValue >= 2) nbDigit = 2;
-						else nbDigit = 1; //digitValue is not 0
+		if ((digitValue = Character.digit(source[j++],radix)) < 0 ) {
+			constant = FORMAT_ERROR; return ;
+		}
+		if (digitValue >= 8)
+			nbDigit = 4;
+		else if (digitValue >= 4)
+			nbDigit = 3;
+		else if (digitValue >= 2)
+			nbDigit = 2;
+		else
+			nbDigit = 1; //digitValue is not 0
 		computedValue = digitValue ;
-		while (j<length)
-		{	if ((digitValue = Character.digit(source[j++],radix))	< 0 ) 	
-			{	constant = FORMAT_ERROR; return ;}
-			if ((nbDigit += shift) > 64) return /*constant stays null*/ ;
-			computedValue = (computedValue<<shift) | digitValue ;}}
-
-	else
-	{	//-----------case radix=10-----------------
-		long previous = computedValue = 0;
-		for (int i = 0 ; i < length; i++) 
-		{	int digitValue ;	
-			if ((digitValue = Character.digit(source[i], 10)) < 0 ) return /*constant stays null*/ ;
+		while (j<length) {
+			if ((digitValue = Character.digit(source[j++],radix)) < 0) {
+				constant = FORMAT_ERROR; return ;
+			}
+			if ((nbDigit += shift) > 64)
+				return /*constant stays null*/ ;
+			computedValue = (computedValue<<shift) | digitValue ;
+		}
+	} else {
+		//-----------case radix=10-----------------
+		long previous = 0;
+		computedValue = 0;
+		final long limit = Long.MAX_VALUE / 10; // needed to check prior to the multiplication
+		for (int i = 0 ; i < length; i++) {
+			int digitValue ;	
+			if ((digitValue = Character.digit(source[i], 10)) < 0 ) return /*constant stays null*/;
 			previous = computedValue;
-			computedValue = 10 * computedValue + digitValue ;
-			if (previous > computedValue) return /*constant stays null*/;}}
-	
+			if (computedValue > limit)
+				return /*constant stays null*/;
+			computedValue *= 10;
+			if ((computedValue + digitValue) > Long.MAX_VALUE)
+				return /*constant stays null*/;
+			computedValue += digitValue;
+			if (previous > computedValue)
+				return /*constant stays null*/;
+		}
+	}
 	constant = Constant.fromValue(value = computedValue);
 }
 /**
@@ -118,7 +139,8 @@
 			(source[15] == '5') &&
 			(source[16] == '8') &&			
 			(source[17] == '0') &&
-			(source[18] == '8'));}
+			(source[18] == '8'));
+}
 public TypeBinding resolveType(BlockScope scope) {
 	// the format may be incorrect while the scanner could detect
 	// such error only on painfull tests...easier and faster here
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MemberValuePair.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MemberValuePair.java
index 4c943da..0106577 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MemberValuePair.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MemberValuePair.java
@@ -32,6 +32,9 @@
 		this.sourceStart = sourceStart;
 		this.sourceEnd = sourceEnd;
 		this.value = value;
+		if (value instanceof ArrayInitializer) {
+			value.bits |= IsAnnotationDefaultValue;
+		}
 	}
 	
 	/* (non-Javadoc)
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java
index 624b6a6..0ac05f2 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java
@@ -76,7 +76,7 @@
 		} 	else if (this.actualReceiverType.isArrayType() 
 						&& runtimeTimeType.id != T_JavaLangObject
 						&& this.binding.parameters == NoParameters 
-						&& scope.environment().options.complianceLevel >= JDK1_5 
+						&& scope.compilerOptions().complianceLevel >= JDK1_5 
 						&& CharOperation.equals(this.binding.selector, CLONE)) {
 					// from 1.5 compliant mode on, array#clone() resolves to array type, but codegen to #clone()Object - thus require extra inserted cast
 			this.valueCast = runtimeTimeType;			
@@ -204,7 +204,7 @@
 	// and not from Object or implicit static method call.	
 	if (this.binding.declaringClass != this.actualReceiverType
 			&& !this.actualReceiverType.isArrayType()) {
-		CompilerOptions options = currentScope.environment().options;
+		CompilerOptions options = currentScope.compilerOptions();
 		if ((options.targetJDK >= ClassFileConstants.JDK1_2
 				&& (options.complianceLevel >= ClassFileConstants.JDK1_4 || !receiver.isImplicitThis() || !this.codegenBinding.isStatic())
 				&& this.binding.declaringClass.id != T_JavaLangObject) // no change for Object methods
@@ -337,9 +337,9 @@
 		// record the closest match, for clients who may still need hint about possible method match
 		if (closestMatch != null) {
 			this.binding = closestMatch;
-			if (closestMatch.isPrivate() && !scope.isDefinedInMethod(closestMatch)) {
+			if ((closestMatch.isPrivate() || closestMatch.declaringClass.isLocalType()) && !scope.isDefinedInMethod(closestMatch)) {
 				// ignore cases where method is used from within inside itself (e.g. direct recursions)
-				closestMatch.original().modifiers |= AccPrivateUsed;
+				closestMatch.original().modifiers |= AccLocallyUsed;
 			}
 		}
 		return this.resolvedType;
@@ -353,7 +353,7 @@
 			// compute generic cast if necessary
 			TypeBinding receiverErasure = this.actualReceiverType.erasure();
 			if (receiverErasure instanceof ReferenceBinding) {
-				ReferenceBinding match = ((ReferenceBinding)receiverErasure).findSuperTypeErasingTo((ReferenceBinding)this.binding.declaringClass.erasure());
+				ReferenceBinding match = ((ReferenceBinding)receiverErasure).findSuperTypeWithSameErasure(this.binding.declaringClass);
 				if (match == null) {
 					this.actualReceiverType = this.binding.declaringClass; // handle indirect inheritance thru variable secondary bound
 				}
@@ -387,18 +387,19 @@
 	// from 1.5 compliance on, array#clone() returns the array type (but binding still shows Object)
 	if (actualReceiverType.isArrayType() 
 			&& this.binding.parameters == NoParameters 
-			&& scope.environment().options.complianceLevel >= JDK1_5 
+			&& scope.compilerOptions().complianceLevel >= JDK1_5 
 			&& CharOperation.equals(this.binding.selector, CLONE)) {
 		this.resolvedType = actualReceiverType;
 	} else {
 		TypeBinding returnType = this.binding.returnType;
-		if (returnType != null) returnType = returnType.capture();
+		if (returnType != null) returnType = returnType.capture(scope, this.sourceEnd);
 		this.resolvedType = returnType;
 	}
 	return this.resolvedType;
 }
 
 public void setActualReceiverType(ReferenceBinding receiverType) {
+	if (receiverType == null) return; // error scenario only
 	this.actualReceiverType = receiverType;
 }
 /**
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java
index 6fd8b8d..e27fa76 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java
@@ -45,8 +45,10 @@
 			if (binding == null)
 				return;
 				
-			if (this.binding.isPrivate() && !this.binding.isPrivateUsed()) {
-				if (!classScope.referenceCompilationUnit().compilationResult.hasSyntaxError()) {
+			if (!this.binding.isUsed() && 
+					(this.binding.isPrivate() 
+						|| (((this.binding.modifiers & (AccOverriding|AccImplementing)) == 0) && this.binding.declaringClass.isLocalType()))) {
+				if (!classScope.referenceCompilationUnit().compilationResult.hasSyntaxError) {
 					scope.problemReporter().unusedPrivateMethod(this);
 				}
 			}
@@ -128,28 +130,35 @@
 			// record the return type binding
 		}
 		// check if method with constructor name
-		if (CharOperation.equals(scope.enclosingSourceType().sourceName, selector)) {
-			scope.problemReporter().methodWithConstructorName(this);
+		if (CharOperation.equals(this.scope.enclosingSourceType().sourceName, selector)) {
+			this.scope.problemReporter().methodWithConstructorName(this);
+		}
+		
+		if (this.typeParameters != null) {
+			for (int i = 0, length = this.typeParameters.length; i < length; i++) {
+				this.typeParameters[i].resolve(this.scope);
+			}
 		}
 		
 		// check @Override annotation
-		if (this.binding != null) {
+		checkOverride: {
+			if (this.binding == null) break checkOverride;
+			if (this.scope.compilerOptions().sourceLevel < JDK1_5) break checkOverride;
 			int bindingModifiers = this.binding.modifiers;
-			if ((this.binding.tagBits & TagBits.AnnotationOverride) != 0 
-					&& (bindingModifiers & AccOverriding) == 0) {
-				// claims to override, and doesn't actually do so
-				scope.problemReporter().methodMustOverride(this);
-			} else	if ((this.binding.tagBits & TagBits.AnnotationOverride) == 0 
-						&& (this.binding.declaringClass.modifiers & AccInterface) == 0
-						&& (bindingModifiers & (AccStatic|AccOverriding)) == AccOverriding
-						&& scope.environment().options.sourceLevel >= JDK1_5) {
+			boolean hasOverrideAnnotation = (this.binding.tagBits & TagBits.AnnotationOverride) != 0;
+			boolean isInterfaceMethod = this.binding.declaringClass.isInterface();
+			if (hasOverrideAnnotation) {
+				if ((bindingModifiers & AccOverriding) == 0 || isInterfaceMethod)
+					// claims to override, and doesn't actually do so
+					this.scope.problemReporter().methodMustOverride(this);					
+			} else if (!isInterfaceMethod 	&& (bindingModifiers & (AccStatic|AccOverriding)) == AccOverriding) {
 				// actually overrides, but did not claim to do so
-				scope.problemReporter().missingOverrideAnnotation(this);
+				this.scope.problemReporter().missingOverrideAnnotation(this);
 			}
 		}
 				
 		// by grammatical construction, interface methods are always abstract
-		switch (scope.referenceType().kind()) {
+		switch (this.scope.referenceType().kind()) {
 			case IGenericType.ENUM_DECL :
 				if (this.selector == TypeConstants.VALUES) break;
 				if (this.selector == TypeConstants.VALUEOF) break;
@@ -159,11 +168,11 @@
 				if ((this.modifiers & AccSemicolonBody) != 0) {
 					if ((this.modifiers & AccNative) == 0)
 						if ((this.modifiers & AccAbstract) == 0)
-							scope.problemReporter().methodNeedBody(this);
+							this.scope.problemReporter().methodNeedBody(this);
 				} else {
 					// the method HAS a body --> abstract native modifiers are forbiden
 					if (((this.modifiers & AccNative) != 0) || ((this.modifiers & AccAbstract) != 0))
-						scope.problemReporter().methodNeedingNoBody(this);
+						this.scope.problemReporter().methodNeedingNoBody(this);
 				}
 		}
 		super.resolveStatements(); 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NameReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NameReference.java
index eb40f09..b3c4ea6 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NameReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NameReference.java
@@ -47,6 +47,7 @@
 	return binding instanceof ReferenceBinding;
 }
 public void setActualReceiverType(ReferenceBinding receiverType) {
+	if (receiverType == null) return; // error scenario only
 	this.actualReceiverType = receiverType;
 }
 public void setDepth(int depth) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java
index a2b82dc..940846c 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java
@@ -51,17 +51,12 @@
 			TypeVariableBinding[] typeVariables = currentType.typeVariables();
 			TypeBinding[] argTypes = parameterizedType.arguments;
 			if (argTypes != null && typeVariables != null) { // argTypes may be null in error cases
-				for (int i = 0, argLength = typeVariables.length; i < argLength; i++)
-				    if (typeVariables[i].boundCheck(parameterizedType, argTypes[i])  != TypeConstants.OK)
-						scope.problemReporter().typeMismatchError(argTypes[i], typeVariables[i], currentType, this.typeArguments[index][i]);
+				parameterizedType.boundCheck(scope, this.typeArguments[index]);
 			}
 		}
 	}
 	public TypeReference copyDims(int dim){
-		//return a type reference copy of me with some dimensions
-		//warning : the new type ref has a null binding
-		this.dimensions = dim;
-		return this;
+		return new ParameterizedQualifiedTypeReference(this.tokens, this.typeArguments, dim, this.sourcePositions);
 	}	
 	
 	/**
@@ -146,12 +141,17 @@
 				}
 			}				
 			if (typeIsConsistent && currentType.isStatic() && qualifiedType != null && (qualifiedType.isParameterizedType() || qualifiedType.isGenericType())) {
-				scope.problemReporter().staticMemberOfParameterizedType(this, scope.createParameterizedType((ReferenceBinding)currentType.erasure(), null, qualifiedType));
+				scope.problemReporter().staticMemberOfParameterizedType(this, scope.environment().createParameterizedType((ReferenceBinding)currentType.erasure(), null, qualifiedType));
 				typeIsConsistent = false;
 			}			
 			// check generic and arity
 		    TypeReference[] args = this.typeArguments[i];
 		    if (args != null) {
+			    TypeReference keep = null;
+			    if (isClassScope) {
+			    	keep = ((ClassScope) scope).superTypeReference;
+			    	((ClassScope) scope).superTypeReference = null;
+			    }
 				int argLength = args.length;
 				TypeBinding[] argTypes = new TypeBinding[argLength];
 				boolean argHasError = false;
@@ -165,14 +165,15 @@
 					} else {
 						argTypes[j] = argType;
 					}			    
-				}
+				}				
 				if (argHasError) {
 					return null;
 				}
-// TODO (philippe)	if ((this.bits & ASTNode.IsSuperType) != 0)
-				if (isClassScope)
+				if (isClassScope) {
+					((ClassScope) scope).superTypeReference = keep;
 					if (((ClassScope) scope).detectHierarchyCycle(currentType, this, argTypes))
 						return null;
+				}
 
 			    TypeVariableBinding[] typeVariables = currentType.typeVariables();
 				if (typeVariables == NoTypeVariables) { // check generic
@@ -201,28 +202,25 @@
 			    if (isIdentical) {
 			    	qualifiedType = (ReferenceBinding) currentType.erasure();
 			    } else {
-					ParameterizedTypeBinding parameterizedType = scope.createParameterizedType((ReferenceBinding)currentType.erasure(), argTypes, qualifiedType);
+					ParameterizedTypeBinding parameterizedType = scope.environment().createParameterizedType((ReferenceBinding)currentType.erasure(), argTypes, qualifiedType);
 					// check argument type compatibility
 					if (checkBounds) // otherwise will do it in Scope.connectTypeVariables() or generic method resolution
-						for (int j = 0; j < argLength; j++)
-						    if (typeVariables[j].boundCheck(parameterizedType, argTypes[j]) != TypeConstants.OK)
-								scope.problemReporter().typeMismatchError(argTypes[j], typeVariables[j], currentType, args[j]);
+						parameterizedType.boundCheck(scope, args);
 					qualifiedType = parameterizedType;
 			    }
 		    } else {
-// TODO (philippe)	if ((this.bits & ASTNode.IsSuperType) != 0)
 				if (isClassScope)
 					if (((ClassScope) scope).detectHierarchyCycle(currentType, this, null))
 						return null;
 				if (currentType.isGenericType()) {
 	   			    if (typeIsConsistent && qualifiedType != null && qualifiedType.isParameterizedType()) {
-						scope.problemReporter().parameterizedMemberTypeMissingArguments(this, scope.createParameterizedType((ReferenceBinding)currentType.erasure(), null, qualifiedType));
+						scope.problemReporter().parameterizedMemberTypeMissingArguments(this, scope.environment().createParameterizedType((ReferenceBinding)currentType.erasure(), null, qualifiedType));
 						typeIsConsistent = false;
 					}
 	   			    qualifiedType = scope.environment().createRawType(currentType, qualifiedType); // raw type
 				} else {
 					qualifiedType = (qualifiedType != null && qualifiedType.isParameterizedType())
-													? scope.createParameterizedType((ReferenceBinding)currentType.erasure(), null, qualifiedType)
+													? scope.environment().createParameterizedType((ReferenceBinding)currentType.erasure(), null, qualifiedType)
 													: currentType;
 				}
 			}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java
index 587c70a..e06dc97 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java
@@ -37,9 +37,7 @@
 			TypeVariableBinding[] typeVariables = currentType.typeVariables();
 			TypeBinding[] argTypes = parameterizedType.arguments;
 			if (argTypes != null && typeVariables != null) { // may be null in error cases
-				for (int i = 0, argLength = typeVariables.length; i < argLength; i++)
-					if (typeVariables[i].boundCheck(parameterizedType, argTypes[i]) != TypeConstants.OK)
-						scope.problemReporter().typeMismatchError(argTypes[i], typeVariables[i], currentType, this.typeArguments[i]);
+				parameterizedType.boundCheck(scope, this.typeArguments);
 			}
 		}
 	}
@@ -47,8 +45,7 @@
 	 * @see org.eclipse.jdt.internal.compiler.ast.TypeReference#copyDims(int)
 	 */
 	public TypeReference copyDims(int dim) {
-		this.dimensions = dim;
-		return this;
+		return new ParameterizedSingleTypeReference(this.token, this.typeArguments, dim, (((long)this.sourceStart)<<32) + this.sourceEnd);
 	}
 
 	/**
@@ -109,7 +106,7 @@
 				if (currentType.isStatic() 
 						|| (enclosingType.isGenericType() 
 								&& enclosingType.outermostEnclosingType() != scope.outerMostClassScope().referenceContext.binding)) {
-					enclosingType = (ReferenceBinding) scope.convertToRawType(enclosingType);
+					enclosingType = (ReferenceBinding) scope.environment().convertToRawType(enclosingType);
 				}
 			}
 		} else { // resolving member type (relatively to enclosingType)
@@ -124,6 +121,11 @@
 
 		// check generic and arity
 	    boolean isClassScope = scope.kind == Scope.CLASS_SCOPE;
+	    TypeReference keep = null;
+	    if (isClassScope) {
+	    	keep = ((ClassScope) scope).superTypeReference;
+	    	((ClassScope) scope).superTypeReference = null;
+	    }
 		ReferenceBinding currentType = (ReferenceBinding) this.resolvedType;
 		int argLength = this.typeArguments.length;
 		TypeBinding[] argTypes = new TypeBinding[argLength];
@@ -140,10 +142,11 @@
 		     }
 		}
 		if (argHasError) return null;
-// TODO (philippe)	if ((this.bits & ASTNode.IsSuperType) != 0)
-		if (isClassScope)
+		if (isClassScope) {
+	    	((ClassScope) scope).superTypeReference = keep;
 			if (((ClassScope) scope).detectHierarchyCycle(currentType, this, argTypes))
 				return null;
+		}
 
 		TypeVariableBinding[] typeVariables = currentType.typeVariables();
 		if (typeVariables == NoTypeVariables) { // check generic
@@ -159,20 +162,26 @@
 		}
 
 		// if generic type X<T> is referred to as parameterized X<T>, then answer itself
-		boolean allEqual = true;
-	    for (int i = 0; allEqual && i < argLength; i++)
-			allEqual = typeVariables[i] == argTypes[i];
-	    if (!allEqual) {
-	    	ParameterizedTypeBinding parameterizedType = scope.createParameterizedType((ReferenceBinding)currentType.erasure(), argTypes, enclosingType);
+		boolean isIdentical = true; //this.resolvedType instanceof SourceTypeBinding;
+		if (isIdentical) {
+		    for (int i = 0; i < argLength; i++) {
+				if (typeVariables[i] != argTypes[i]) {
+					isIdentical = false;
+				    break;
+				}
+			}
+		}		
+	    if (!isIdentical) {
+	    	ParameterizedTypeBinding parameterizedType = scope.environment().createParameterizedType((ReferenceBinding)currentType.erasure(), argTypes, enclosingType);
 			// check argument type compatibility
 			if (checkBounds) // otherwise will do it in Scope.connectTypeVariables() or generic method resolution
-				for (int i = 0; i < argLength; i++)
-				    if (typeVariables[i].boundCheck(parameterizedType, argTypes[i]) != TypeConstants.OK)
-						scope.problemReporter().typeMismatchError(argTypes[i], typeVariables[i], currentType, this.typeArguments[i]);
+				parameterizedType.boundCheck(scope, this.typeArguments);
 	
 			this.resolvedType = parameterizedType;
 			if (isTypeUseDeprecated(this.resolvedType, scope))
 				reportDeprecatedType(scope);
+		} else {
+			this.resolvedType = this.resolvedType.erasure();
 		}
 		// array type ?
 		if (this.dimensions > 0) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java
index 9e66270..fa53857 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java
@@ -253,11 +253,16 @@
 		}
 		if (receiverType == null) {
 			hasError = true;
-		} else if (((ReferenceBinding) receiverType).isFinal() && this.anonymousType != null) {
-			if (!receiverType.isEnum()) {
-				scope.problemReporter().anonymousClassCannotExtendFinalClass(type, receiverType);
+		} else if (((ReferenceBinding) receiverType).isFinal()) {
+			if (this.anonymousType != null) {
+				if (!receiverType.isEnum()) {
+					scope.problemReporter().anonymousClassCannotExtendFinalClass(type, receiverType);
+					hasError = true;
+				}
+			} else if (!receiverType.canBeInstantiated()) {
+				scope.problemReporter().cannotInstantiate(type, receiverType);
+				return this.resolvedType = receiverType;
 			}
-			hasError = true;
 		}
 		// resolve type arguments (for generic constructor call)
 		if (this.typeArguments != null) {
@@ -290,11 +295,11 @@
 		if (hasError) return this.resolvedType = receiverType;
 		if (this.anonymousType == null) {
 			// qualified allocation with no anonymous type
-			ReferenceBinding allocationType = (ReferenceBinding) receiverType;
 			if (!receiverType.canBeInstantiated()) {
 				scope.problemReporter().cannotInstantiate(type, receiverType);
 				return this.resolvedType = receiverType;
 			}
+			ReferenceBinding allocationType = (ReferenceBinding) receiverType;
 			if ((this.binding = scope.getConstructor(allocationType, argumentTypes, this)).isValidBinding()) {
 				if (isMethodUseDeprecated(binding, scope)) {
 					scope.problemReporter().deprecatedMethod(this.binding, this);
@@ -314,7 +319,7 @@
 				scope.compilationUnitScope().recordTypeConversion(expectedType, enclosingInstanceType);
 			if (enclosingInstanceType.isCompatibleWith(expectedType) || scope.isBoxingCompatibleWith(enclosingInstanceType, expectedType)) {
 				enclosingInstance.computeConversion(scope, expectedType, enclosingInstanceType);
-				return receiverType;
+				return this.resolvedType = receiverType;
 			}
 			scope.problemReporter().typeMismatchError(enclosingInstanceType, expectedType, this.enclosingInstance);
 			return this.resolvedType = receiverType;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java
index 2a2905a..dbfa039 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java
@@ -58,7 +58,23 @@
 				lastFieldBinding = (FieldBinding) binding;
 				if (needValue) {
 					manageSyntheticAccessIfNecessary(currentScope, lastFieldBinding, this.actualReceiverType, 0, flowInfo);
-				}				// check if final blank field
+				}
+				if (this.indexOfFirstFieldBinding == 1) { // was an implicit reference to the first field binding
+					ReferenceBinding declaringClass = lastFieldBinding.declaringClass;
+					// check if accessing enum static field in initializer					
+					if (declaringClass.isEnum()) {
+						MethodScope methodScope = currentScope.methodScope();
+						SourceTypeBinding sourceType = methodScope.enclosingSourceType();
+						if (lastFieldBinding.isStatic()
+								&& (sourceType == declaringClass || sourceType.superclass == declaringClass) // enum constant body
+								&& lastFieldBinding.constant() == NotAConstant
+								&& !methodScope.isStatic
+								&& methodScope.isInsideInitializerOrConstructor()) {
+							currentScope.problemReporter().enumStaticFieldUsedDuringInitialization(lastFieldBinding, this);
+						}
+					}				
+				}				
+				// check if final blank field
 				if (lastFieldBinding.isBlankFinal()
 				    && this.otherBindings != null // the last field binding is only assigned
 	 				&& currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)) {
@@ -90,7 +106,7 @@
 		}
 		// all intermediate field accesses are read accesses
 		if (otherBindings != null) {
-			boolean complyTo14 = currentScope.environment().options.complianceLevel >= ClassFileConstants.JDK1_4;
+			boolean complyTo14 = currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4;
 			for (int i = 0; i < otherBindingsCount-1; i++) {
 				lastFieldBinding = otherBindings[i];
 				needValue = !otherBindings[i+1].isStatic();
@@ -200,14 +216,27 @@
 				if (needValue) {
 					manageSyntheticAccessIfNecessary(currentScope, (FieldBinding) binding, this.actualReceiverType, 0, flowInfo);
 				}
-				// check if reading a final blank field
-				FieldBinding fieldBinding;
-					if ((fieldBinding = (FieldBinding) binding).isBlankFinal()
-						&& (indexOfFirstFieldBinding == 1)
-					// was an implicit reference to the first field binding
-						&& currentScope.allowBlankFinalFieldAssignment(fieldBinding)
-						&& (!flowInfo.isDefinitelyAssigned(fieldBinding))) {
-					currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this);
+				if (this.indexOfFirstFieldBinding == 1) { // was an implicit reference to the first field binding
+					FieldBinding fieldBinding = (FieldBinding) binding;
+					ReferenceBinding declaringClass = fieldBinding.declaringClass;
+					// check if accessing enum static field in initializer					
+					if (declaringClass.isEnum()) {
+						MethodScope methodScope = currentScope.methodScope();
+						SourceTypeBinding sourceType = methodScope.enclosingSourceType();
+						if (fieldBinding.isStatic()
+								&& (sourceType == declaringClass || sourceType.superclass == declaringClass) // enum constant body
+								&& fieldBinding.constant() == NotAConstant
+								&& !methodScope.isStatic
+								&& methodScope.isInsideInitializerOrConstructor()) {
+							currentScope.problemReporter().enumStaticFieldUsedDuringInitialization(fieldBinding, this);
+						}
+					}				
+					// check if reading a final blank field
+					if (fieldBinding.isBlankFinal()
+							&& currentScope.allowBlankFinalFieldAssignment(fieldBinding)
+							&& !flowInfo.isDefinitelyAssigned(fieldBinding)) {
+						currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this);
+					}
 				}
 				break;
 			case Binding.LOCAL : // reading a local variable
@@ -228,7 +257,7 @@
 			// only for first binding
 		}
 		if (otherBindings != null) {
-			boolean complyTo14 = currentScope.environment().options.complianceLevel >= ClassFileConstants.JDK1_4;
+			boolean complyTo14 = currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4;
 			for (int i = 0; i < otherBindingsCount; i++) {
 				needValue = i < otherBindingsCount-1 ? !otherBindings[i+1].isStatic() : valueRequired;
 				if (needValue || complyTo14) {
@@ -255,15 +284,15 @@
 	 * Check and/or redirect the field access to the delegate receiver if any
 	 */
 	public TypeBinding checkFieldAccess(BlockScope scope) {
-		// check for forward references
 		FieldBinding fieldBinding = (FieldBinding) binding;
 		MethodScope methodScope = scope.methodScope();
-		if (methodScope.enclosingSourceType() == fieldBinding.declaringClass
-			&& methodScope.lastVisibleFieldID >= 0
-			&& fieldBinding.id >= methodScope.lastVisibleFieldID) {
-			if ((!fieldBinding.isStatic() || methodScope.isStatic)
-				&& this.indexOfFirstFieldBinding == 1)
-				scope.problemReporter().forwardReference(this, 0, scope.enclosingSourceType());
+		// check for forward references
+		if (this.indexOfFirstFieldBinding == 1
+				&& methodScope.enclosingSourceType() == fieldBinding.declaringClass
+				&& methodScope.lastVisibleFieldID >= 0
+				&& fieldBinding.id >= methodScope.lastVisibleFieldID
+				&& (!fieldBinding.isStatic() || methodScope.isStatic)) {
+			scope.problemReporter().forwardReference(this, 0, methodScope.enclosingSourceType());
 		}
 		bits &= ~RestrictiveFlagMASK; // clear bits
 		bits |= Binding.FIELD;
@@ -340,7 +369,7 @@
 						codeStream.generateConstant(lastFieldBinding.constant(), implicitConversion);
 					}
 				} else {
-					if (valueRequired  || currentScope.environment().options.complianceLevel >= ClassFileConstants.JDK1_4) {
+					if (valueRequired  || currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4) {
 						if (lastFieldBinding.declaringClass == null) { // array length
 							codeStream.arraylength();
 							if (valueRequired) {
@@ -427,6 +456,8 @@
 				codeStream.generateStringConcatenationAppend(currentScope, null, expression);
 				break;
 			default :
+				TypeBinding requiredGenericCast = getGenericCast(this.otherCodegenBindings == null ? 0 : this.otherCodegenBindings.length);
+				if (requiredGenericCast != null) codeStream.checkcast(requiredGenericCast);				
 				// promote the array reference to the suitable operation type
 				codeStream.generateImplicitConversion(implicitConversion);
 				// generate the increment value (will by itself  be promoted to the operation value)
@@ -487,13 +518,16 @@
 				}
 			}
 		}
+		TypeBinding requiredGenericCast = getGenericCast(this.otherCodegenBindings == null ? 0 : this.otherCodegenBindings.length);
+		if (requiredGenericCast != null) codeStream.checkcast(requiredGenericCast);
+		
 		codeStream.generateImplicitConversion(implicitConversion);		
 		codeStream.generateConstant(
 			postIncrement.expression.constant,
 			implicitConversion);
 		codeStream.sendOperator(postIncrement.operator, this.implicitConversion & COMPILE_TYPE_MASK);
 		codeStream.generateImplicitConversion(
-			postIncrement.assignmentImplicitConversion);
+			postIncrement.preAssignImplicitConversion);
 		fieldStore(codeStream, lastFieldBinding, syntheticWriteAccessor, false);
 	}
 	/*
@@ -507,7 +541,7 @@
 		boolean needValue = otherBindingsCount == 0 || !this.otherBindings[0].isStatic();
 		FieldBinding lastFieldBinding = null;
 		TypeBinding lastGenericCast = null;
-		boolean complyTo14 = currentScope.environment().options.complianceLevel >= ClassFileConstants.JDK1_4;
+		boolean complyTo14 = currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4;
 
 		switch (bits & RestrictiveFlagMASK) {
 			case Binding.FIELD :
@@ -657,7 +691,7 @@
 			this.constant = FieldReference.getConstantFor((FieldBinding) binding, this, false, scope);
 			// perform capture conversion if read access
 			return (type != null && (this.bits & IsStrictlyAssignedMASK) == 0)
-					? type.capture()
+					? type.capture(scope, this.sourceEnd)
 					: type;
 		}
 		// allocation of the fieldBindings array	and its respective constants
@@ -679,7 +713,7 @@
 
 			bits &= ~DepthMASK; // flush previous depth if any		
 			FieldBinding previousField = field;
-			field = scope.getField(type.capture(), token, this);
+			field = scope.getField(type.capture(scope, (int)this.sourcePositions[index]), token, this);
 			int place = index - indexOfFirstFieldBinding;
 			otherBindings[place] = field;
 			otherDepths[place] = (bits & DepthMASK) >> DepthSHIFT;
@@ -689,7 +723,7 @@
 					TypeBinding fieldReceiverType = type;
 					TypeBinding receiverErasure = type.erasure();
 					if (receiverErasure instanceof ReferenceBinding) {
-						ReferenceBinding match = ((ReferenceBinding)receiverErasure).findSuperTypeErasingTo((ReferenceBinding)field.declaringClass.erasure());
+						ReferenceBinding match = ((ReferenceBinding)receiverErasure).findSuperTypeWithSameErasure(field.declaringClass);
 						if (match == null) {
 							fieldReceiverType = field.declaringClass; // handle indirect inheritance thru variable secondary bound
 						}
@@ -730,7 +764,7 @@
 		type = (otherBindings[otherBindingsLength - 1]).type;
 		// perform capture conversion if read access
 		return (type != null && (this.bits & IsStrictlyAssignedMASK) == 0)
-				? type.capture()
+				? type.capture(scope, this.sourceEnd)
 				: type;		
 	}
 	public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
@@ -794,7 +828,7 @@
 				&& !lastReceiverType.isArrayType()
 				&& fieldBinding.declaringClass != null // array.length
 				&& !fieldBinding.isConstantValue()) {
-			CompilerOptions options = currentScope.environment().options;
+			CompilerOptions options = currentScope.compilerOptions();
 			if ((options.targetJDK >= ClassFileConstants.JDK1_2
 					&& (options.complianceLevel >= ClassFileConstants.JDK1_4 || fieldBinding != binding || indexOfFirstFieldBinding > 1 || !fieldBinding.isStatic())
 					&& fieldBinding.declaringClass.id != T_JavaLangObject) // no change for Object fields
@@ -851,20 +885,20 @@
 						return this.resolvedType = getOtherFieldBindings(scope);
 					}
 					if (binding instanceof FieldBinding) {
-						// check for forward references
 						FieldBinding fieldBinding = (FieldBinding) binding;
 						MethodScope methodScope = scope.methodScope();
-						if (methodScope.enclosingSourceType() == fieldBinding.declaringClass
+						ReferenceBinding declaringClass = fieldBinding.declaringClass;
+						// check for forward references
+						if (this.indexOfFirstFieldBinding == 1
+								&& methodScope.enclosingSourceType() == declaringClass
 								&& methodScope.lastVisibleFieldID >= 0
-								&& fieldBinding.id >= methodScope.lastVisibleFieldID) {
-							if ((!fieldBinding.isStatic() || methodScope.isStatic)
-								&& this.indexOfFirstFieldBinding == 1) {
-								scope.problemReporter().forwardReference(this, 0, scope.enclosingSourceType());
-							}
+								&& fieldBinding.id >= methodScope.lastVisibleFieldID
+								&& (!fieldBinding.isStatic() || methodScope.isStatic)) {
+							scope.problemReporter().forwardReference(this, 0, methodScope.enclosingSourceType());
 						}
 						if (!fieldBinding.isStatic() 
 								&& this.indexOfFirstFieldBinding == 1
-								&& scope.environment().options.getSeverity(CompilerOptions.UnqualifiedFieldAccess) != ProblemSeverities.Ignore) {
+								&& scope.compilerOptions().getSeverity(CompilerOptions.UnqualifiedFieldAccess) != ProblemSeverities.Ignore) {
 							scope.problemReporter().unqualifiedFieldAccess(this, fieldBinding);
 						}
 						bits &= ~RestrictiveFlagMASK; // clear bits
@@ -886,7 +920,7 @@
 				    TypeBinding type = (TypeBinding) binding;
 					if (isTypeUseDeprecated(type, scope))
 						scope.problemReporter().deprecatedType(type, this);
-					return this.resolvedType = scope.convertToRawType(type);
+					return this.resolvedType = scope.environment().convertToRawType(type);
 			}
 		}
 		//========error cases===============
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedThisReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedThisReference.java
index 58c59a7..1c647f1 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedThisReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedThisReference.java
@@ -72,15 +72,13 @@
 	public TypeBinding resolveType(BlockScope scope) {
 
 		constant = NotAConstant;
-		TypeBinding type = this.resolvedType = this.qualification.resolveType(scope, true /* check bounds*/);
+		TypeBinding type = this.qualification.resolveType(scope, true /* check bounds*/);
 		if (type == null) return null;
-		// X.this is not a raw type as denoting enclosing instance
-		if (type.isRawType()) {
-		    RawTypeBinding rawType = (RawTypeBinding) type;
-		    type = this.resolvedType = rawType.type; // unwrap
-		}
+		// X.this is not a param/raw type as denoting enclosing instance
+		this.resolvedType = type = type.erasure();
+
 		// the qualification MUST exactly match some enclosing type name
-		// Its possible to qualify 'this' by the name of the current class
+		// It is possible to qualify 'this' by the name of the current class
 		int depth = 0;
 		this.currentCompatibleType = scope.referenceType().binding;
 		while (this.currentCompatibleType != null
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java
index 004b9af..acffa43 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java
@@ -43,7 +43,7 @@
 					ProblemReferenceBinding problemBinding = (ProblemReferenceBinding) this.resolvedType;
 					this.resolvedType = new ProblemReferenceBinding(
 						org.eclipse.jdt.core.compiler.CharOperation.subarray(this.tokens, 0, tokenIndex + 1),
-						problemBinding.original,
+						problemBinding.closestMatch,
 						this.resolvedType.problemId());
 				}
 			}
@@ -75,13 +75,20 @@
 				if (((ClassScope) scope).detectHierarchyCycle(this.resolvedType, this, null)) // must connect hierarchy to find inherited member types
 					return null;
 			ReferenceBinding currentType = (ReferenceBinding) this.resolvedType;
-			if (currentType.isGenericType()) {
-				qualifiedType = scope.environment().createRawType(currentType, qualifiedType);
+			if (qualifiedType != null) {
+				boolean rawQualified;
+				if (currentType.isGenericType()) {
+					qualifiedType = scope.environment().createRawType(currentType, qualifiedType);
+				} else if ((rawQualified = qualifiedType.isRawType()) && !currentType.isStatic()) {
+					qualifiedType = scope.environment().createRawType((ReferenceBinding)currentType.erasure(), qualifiedType);
+				} else if (rawQualified || qualifiedType.isParameterizedType()) {
+					qualifiedType = scope.environment().createParameterizedType((ReferenceBinding)currentType.erasure(), null, qualifiedType);
+				} else {
+					qualifiedType = currentType;
+				}
 			} else {
-				qualifiedType = (qualifiedType != null && (qualifiedType.isRawType() || qualifiedType.isParameterizedType()))
-										? scope.createParameterizedType((ReferenceBinding)currentType.erasure(), null, qualifiedType)
-										: currentType;
-			}
+				qualifiedType = currentType.isGenericType() ? (ReferenceBinding)scope.environment().convertToRawType(currentType) : currentType;
+			}			
 		}
 		this.resolvedType = qualifiedType;
 		return this.resolvedType;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleMemberAnnotation.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleMemberAnnotation.java
index 40e5780..e3273fa 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleMemberAnnotation.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleMemberAnnotation.java
@@ -20,7 +20,7 @@
 public class SingleMemberAnnotation extends Annotation {
 	
 	public Expression memberValue;
-	public MemberValuePair singlePair; // fake pair, only value has accurate positions
+	private MemberValuePair[] singlePairs; // fake pair set, only value has accurate positions
 
 	public SingleMemberAnnotation(TypeReference type, int sourceStart) {
 		this.type = type;
@@ -32,8 +32,13 @@
 	 * @see org.eclipse.jdt.internal.compiler.ast.Annotation#memberValuePairs()
 	 */
 	public MemberValuePair[] memberValuePairs() {
-		this.singlePair =  new MemberValuePair(VALUE, this.memberValue.sourceStart, this.memberValue.sourceEnd, this.memberValue);
-		return new MemberValuePair[] { singlePair };
+		if (this.singlePairs == null) {
+			this.singlePairs =  
+				new MemberValuePair[]{ 
+					new MemberValuePair(VALUE, this.memberValue.sourceStart, this.memberValue.sourceEnd, this.memberValue)
+				};
+		}
+		return this.singlePairs;
 	}
 	
 	public StringBuffer printExpression(int indent, StringBuffer output) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java
index 4bbe1a8..e79b6cc 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java
@@ -69,9 +69,22 @@
 			case Binding.FIELD : // assigning to a field
 				manageSyntheticAccessIfNecessary(currentScope, flowInfo, false /*write-access*/);
 	
+				FieldBinding fieldBinding = (FieldBinding) binding;
+				ReferenceBinding declaringClass = fieldBinding.declaringClass;
+				// check if accessing enum static field in initializer
+				if (declaringClass.isEnum()) {
+					MethodScope methodScope = currentScope.methodScope();
+					SourceTypeBinding sourceType = currentScope.enclosingSourceType();
+					if (fieldBinding.isStatic()
+							&& this.constant == NotAConstant
+							&& !methodScope.isStatic
+							&& (sourceType == declaringClass || sourceType.superclass == declaringClass) // enum constant body
+							&& methodScope.isInsideInitializerOrConstructor()) {
+						currentScope.problemReporter().enumStaticFieldUsedDuringInitialization(fieldBinding, this);
+					}
+				}					
 				// check if assigning a final field
-				FieldBinding fieldBinding;
-				if ((fieldBinding = (FieldBinding) binding).isFinal()) {
+				if (fieldBinding.isFinal()) {
 					// inside a context where allowed
 					if (!isCompound && fieldBinding.isBlankFinal() && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) {
 						if (flowInfo.isPotentiallyAssigned(fieldBinding)) {
@@ -121,10 +134,22 @@
 				if (valueRequired) {
 					manageSyntheticAccessIfNecessary(currentScope, flowInfo, true /*read-access*/);
 				}
+				FieldBinding fieldBinding = (FieldBinding) binding;
+				ReferenceBinding declaringClass = fieldBinding.declaringClass;
+				// check if accessing enum static field in initializer
+				if (declaringClass.isEnum()) {
+					MethodScope methodScope = currentScope.methodScope();
+					SourceTypeBinding sourceType = currentScope.enclosingSourceType();
+					if (fieldBinding.isStatic()
+							&& this.constant == NotAConstant
+							&& !methodScope.isStatic
+							&& (sourceType == declaringClass || sourceType.superclass == declaringClass) // enum constant body
+							&& methodScope.isInsideInitializerOrConstructor()) {
+						currentScope.problemReporter().enumStaticFieldUsedDuringInitialization(fieldBinding, this);
+					}
+				}				
 				// check if reading a final blank field
-				FieldBinding fieldBinding;
-				if ((fieldBinding = (FieldBinding) binding).isBlankFinal() 
-						&& currentScope.allowBlankFinalFieldAssignment(fieldBinding)) {
+				if (fieldBinding.isBlankFinal() && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) {
 					if (!flowInfo.isDefinitelyAssigned(fieldBinding)) {
 						currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this);
 					}
@@ -153,27 +178,28 @@
 		
 		bits &= ~RestrictiveFlagMASK; // clear bits
 		bits |= Binding.FIELD;
-		if (!((FieldBinding) binding).isStatic()) {
+		MethodScope methodScope = scope.methodScope();
+		boolean isStatic = fieldBinding.isStatic();
+		if (!isStatic) {
 			// must check for the static status....
-			if (scope.methodScope().isStatic) {
+			if (methodScope.isStatic) {
 				scope.problemReporter().staticFieldAccessToNonStaticVariable(this, fieldBinding);
-				constant = NotAConstant;
+				this.constant = NotAConstant;
 				return fieldBinding.type;
 			}
 		}
-		constant = FieldReference.getConstantFor(fieldBinding, this, true, scope);
+		this.constant = FieldReference.getConstantFor(fieldBinding, this, true, scope);
 	
 		if (isFieldUseDeprecated(fieldBinding, scope, (this.bits & IsStrictlyAssignedMASK) !=0))
 			scope.problemReporter().deprecatedField(fieldBinding, this);
 	
-		MethodScope ms = scope.methodScope();
 		if ((this.bits & IsStrictlyAssignedMASK) == 0
-			&& ms.enclosingSourceType() == fieldBinding.declaringClass
-			&& ms.lastVisibleFieldID >= 0
-			&& fieldBinding.id >= ms.lastVisibleFieldID) {
+			&& methodScope.enclosingSourceType() == fieldBinding.declaringClass
+			&& methodScope.lastVisibleFieldID >= 0
+			&& fieldBinding.id >= methodScope.lastVisibleFieldID) {
 			//if the field is static and ms is not .... then it is valid
-			if (!fieldBinding.isStatic() || ms.isStatic)
-				scope.problemReporter().forwardReference(this, 0, scope.enclosingSourceType());
+			if (!fieldBinding.isStatic() || methodScope.isStatic)
+				scope.problemReporter().forwardReference(this, 0, methodScope.enclosingSourceType());
 		}
 		//====================================================
 	
@@ -208,21 +234,27 @@
 		// optimizing assignment like: i = i + 1 or i = 1 + i
 		if (assignment.expression.isCompactableOperation()) {
 			BinaryExpression operation = (BinaryExpression) assignment.expression;
+			int operator = (operation.bits & OperatorMASK) >> OperatorSHIFT;
 			SingleNameReference variableReference;
 			if ((operation.left instanceof SingleNameReference) && ((variableReference = (SingleNameReference) operation.left).binding == binding)) {
 				// i = i + value, then use the variable on the right hand side, since it has the correct implicit conversion
-				variableReference.generateCompoundAssignment(currentScope, codeStream, syntheticAccessors == null ? null : syntheticAccessors[WRITE], operation.right, (operation.bits & OperatorMASK) >> OperatorSHIFT, operation.implicitConversion, valueRequired);
+				variableReference.generateCompoundAssignment(currentScope, codeStream, syntheticAccessors == null ? null : syntheticAccessors[WRITE], operation.right, operator, operation.implicitConversion, valueRequired);
+				if (valueRequired) {
+					codeStream.generateImplicitConversion(assignment.implicitConversion);
+				}				
 				return;
-			}
-			int operator = (operation.bits & OperatorMASK) >> OperatorSHIFT;
+			} 
 			if ((operation.right instanceof SingleNameReference)
-				&& ((operator == PLUS) || (operator == MULTIPLY)) // only commutative operations
-				&& ((variableReference = (SingleNameReference) operation.right).binding == binding)
-				&& (operation.left.constant != NotAConstant) // exclude non constant expressions, since could have side-effect
-				&& (((operation.left.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) != T_JavaLangString) // exclude string concatenation which would occur backwards
-				&& (((operation.right.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) != T_JavaLangString)) { // exclude string concatenation which would occur backwards
+					&& ((operator == PLUS) || (operator == MULTIPLY)) // only commutative operations
+					&& ((variableReference = (SingleNameReference) operation.right).binding == binding)
+					&& (operation.left.constant != NotAConstant) // exclude non constant expressions, since could have side-effect
+					&& (((operation.left.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) != T_JavaLangString) // exclude string concatenation which would occur backwards
+					&& (((operation.right.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) != T_JavaLangString)) { // exclude string concatenation which would occur backwards
 				// i = value + i, then use the variable on the right hand side, since it has the correct implicit conversion
 				variableReference.generateCompoundAssignment(currentScope, codeStream, syntheticAccessors == null ? null : syntheticAccessors[WRITE], operation.left, operator, operation.implicitConversion, valueRequired);
+				if (valueRequired) {
+					codeStream.generateImplicitConversion(assignment.implicitConversion);
+				}				
 				return;
 			}
 		}
@@ -308,7 +340,7 @@
 							codeStream.generateConstant(fieldBinding.constant(), implicitConversion);
 						}
 					} else {
-						if (valueRequired || currentScope.environment().options.complianceLevel >= ClassFileConstants.JDK1_4) {
+						if (valueRequired || currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4) {
 							boolean isStatic = fieldBinding.isStatic();
 							if (!isStatic) {
 								if ((bits & DepthMASK) != 0) {
@@ -462,10 +494,12 @@
 				break;
 			default :
 				// promote the array reference to the suitable operation type
-				codeStream.generateImplicitConversion(implicitConversion);
+				if (this.genericCast != null)
+					codeStream.checkcast(this.genericCast);
+				codeStream.generateImplicitConversion(this.implicitConversion);
 				// generate the increment value (will by itself  be promoted to the operation value)
 				if (expression == IntLiteral.One){ // prefix operation
-					codeStream.generateConstant(expression.constant, implicitConversion);			
+					codeStream.generateConstant(expression.constant, this.implicitConversion);			
 				} else {
 					expression.generateCode(currentScope, codeStream, true);
 				}		
@@ -533,11 +567,13 @@
 						}
 					}
 				}
-				codeStream.generateImplicitConversion(implicitConversion);		
-				codeStream.generateConstant(postIncrement.expression.constant, implicitConversion);
+				if (this.genericCast != null) 
+					codeStream.checkcast(this.genericCast);
+				codeStream.generateImplicitConversion(this.implicitConversion);		
+				codeStream.generateConstant(postIncrement.expression.constant, this.implicitConversion);
 				codeStream.sendOperator(postIncrement.operator, this.implicitConversion & COMPILE_TYPE_MASK);
-				codeStream.generateImplicitConversion(postIncrement.assignmentImplicitConversion);
-				fieldStore(codeStream, fieldBinding, syntheticAccessors == null ? null : syntheticAccessors[WRITE], false);
+				codeStream.generateImplicitConversion(postIncrement.preAssignImplicitConversion);
+				fieldStore(codeStream, fieldBinding, this.syntheticAccessors == null ? null : this.syntheticAccessors[WRITE], false);
 				// no need for generic cast 
 				return;
 			case Binding.LOCAL : // assigning to a local variable
@@ -564,7 +600,7 @@
 					codeStream.generateImplicitConversion(implicitConversion);
 					codeStream.generateConstant(postIncrement.expression.constant, implicitConversion);
 					codeStream.sendOperator(postIncrement.operator, this.implicitConversion & COMPILE_TYPE_MASK);
-					codeStream.generateImplicitConversion(postIncrement.assignmentImplicitConversion);
+					codeStream.generateImplicitConversion(postIncrement.preAssignImplicitConversion);
 	
 					codeStream.store(localBinding, false);
 				}
@@ -624,7 +660,7 @@
 					&& !this.actualReceiverType.isArrayType()
 					&& fieldBinding.declaringClass != null // array.length
 					&& !fieldBinding.isConstantValue()) {
-				CompilerOptions options = currentScope.environment().options;
+				CompilerOptions options = currentScope.compilerOptions();
 				if ((options.targetJDK >= ClassFileConstants.JDK1_2
 						&& (options.complianceLevel >= ClassFileConstants.JDK1_4 || !fieldBinding.isStatic())
 						&& fieldBinding.declaringClass.id != T_JavaLangObject) // no change for Object fields
@@ -682,7 +718,7 @@
 							if ((this.bits & IsStrictlyAssignedMASK) == 0) {
 								constant = variable.constant();
 								if (fieldType != null) 
-									fieldType = fieldType.capture(); // perform capture conversion if read access
+									fieldType = fieldType.capture(scope, this.sourceEnd); // perform capture conversion if read access
 							} else {
 								constant = NotAConstant;
 							}
@@ -690,14 +726,14 @@
 						}
 						// a field
 						FieldBinding field = (FieldBinding) this.binding;
-						if (!field.isStatic() && scope.environment().options.getSeverity(CompilerOptions.UnqualifiedFieldAccess) != ProblemSeverities.Ignore) {
+						if (!field.isStatic() && scope.compilerOptions().getSeverity(CompilerOptions.UnqualifiedFieldAccess) != ProblemSeverities.Ignore) {
 							scope.problemReporter().unqualifiedFieldAccess(this, field);
 						}
 						// perform capture conversion if read access
 						TypeBinding fieldType = checkFieldAccess(scope);
 						return this.resolvedType = 
 							(((this.bits & IsStrictlyAssignedMASK) == 0) 
-								? fieldType.capture()
+								? fieldType.capture(scope, this.sourceEnd)
 								: fieldType);
 					}
 	
@@ -710,7 +746,7 @@
 					TypeBinding type = (TypeBinding)binding;
 					if (isTypeUseDeprecated(type, scope))
 						scope.problemReporter().deprecatedType(type, this);
-					return this.resolvedType = scope.convertToRawType(type);
+					return this.resolvedType = scope.environment().convertToRawType(type);
 			}
 		}
 	
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java
index a560b5e..9002931 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java
@@ -63,7 +63,7 @@
 		}
 		if (isTypeUseDeprecated(memberType, scope))
 			scope.problemReporter().deprecatedType(memberType, this);
-		return this.resolvedType = scope.convertToRawType(memberType);
+		return this.resolvedType = scope.environment().convertToRawType(memberType);
 	}
 
 	public void traverse(ASTVisitor visitor, BlockScope scope) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java
index fe0e0fb..ccaa21c 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java
@@ -57,6 +57,7 @@
 			}
 
 			ArrayBinding varArgsType = (ArrayBinding) params[varArgIndex]; // parameterType has to be an array type
+			ArrayBinding codeGenVarArgsType = (ArrayBinding) binding.parameters[varArgIndex].erasure();
 			int elementsTypeID = varArgsType.elementsType().id;
 			int argLength = arguments == null ? 0 : arguments.length;
 
@@ -65,7 +66,7 @@
 				// called with (argLength - lastIndex) elements : foo(1, 2) or foo(1, 2, 3, 4)
 				// need to gen elements into an array, then gen each remaining element into created array
 				codeStream.generateInlinedValue(argLength - varArgIndex);
-				codeStream.newArray(varArgsType); // create a mono-dimensional array
+				codeStream.newArray(codeGenVarArgsType); // create a mono-dimensional array
 				for (int i = varArgIndex; i < argLength; i++) {
 					codeStream.dup();
 					codeStream.generateInlinedValue(i - varArgIndex);
@@ -84,7 +85,7 @@
 					// right number but not directly compatible or too many arguments - wrap extra into array
 					// need to gen elements into an array, then gen each remaining element into created array
 					codeStream.generateInlinedValue(1);
-					codeStream.newArray(varArgsType); // create a mono-dimensional array
+					codeStream.newArray(codeGenVarArgsType); // create a mono-dimensional array
 					codeStream.dup();
 					codeStream.generateInlinedValue(0);
 					arguments[varArgIndex].generateCode(currentScope, codeStream, true);
@@ -94,7 +95,7 @@
 				// scenario: foo(1) --> foo(1, new int[0])
 				// generate code for an empty array of parameterType
 				codeStream.generateInlinedValue(0);
-				codeStream.newArray(varArgsType); // create a mono-dimensional array
+				codeStream.newArray(codeGenVarArgsType); // create a mono-dimensional array
 			}
 		} else if (arguments != null) { // standard generation for method arguments
 			for (int i = 0, max = arguments.length; i < max; i++)
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java
index 26e4cf1..5df3b6a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java
@@ -32,6 +32,8 @@
 	public int caseCount;
 	int[] constants;
 	
+	public SyntheticMethodBinding synthetic; // use for switch on enums types
+	
 	// for local variables table attributes
 	int preSwitchInitStateIndex = -1;
 	int mergedInitStateIndex = -1;
@@ -75,6 +77,11 @@
 				}
 			}
 	
+			final TypeBinding resolvedTypeBinding = this.expression.resolvedType;
+			if (caseCount > 0 && resolvedTypeBinding.isEnum()) {
+				final SourceTypeBinding sourceTypeBinding = this.scope.classScope().referenceContext.binding;
+				this.synthetic = sourceTypeBinding.addSyntheticMethodForSwitchEnum(resolvedTypeBinding);
+			}
 			// if no default case, then record it may jump over the block directly to the end
 			if (defaultCase == null) {
 				// only retain the potential initializations
@@ -120,8 +127,24 @@
 			if (defaultCase != null) {
 				defaultCase.targetLabel = defaultLabel;
 			}
-			// generate expression testes
-			expression.generateCode(currentScope, codeStream, needSwitch);
+
+			final TypeBinding resolvedType = this.expression.resolvedType;
+			if (resolvedType.isEnum()) {
+				if (needSwitch) {
+					// go through the translation table
+					codeStream.invokestatic(this.synthetic);
+					expression.generateCode(currentScope, codeStream, true);
+					// get enum constant ordinal()
+					codeStream.invokeEnumOrdinal(resolvedType.constantPoolName());
+					codeStream.iaload();
+				} else {
+					// no need to go through the translation table
+					expression.generateCode(currentScope, codeStream, false);
+				}
+			} else {
+				// generate expression
+				expression.generateCode(currentScope, codeStream, needSwitch); // value required (switch without cases)
+			}
 			// generate the appropriate switch table/lookup bytecode
 			if (needSwitch) {
 				int[] sortedIndexes = new int[this.caseCount];
@@ -133,17 +156,13 @@
 				System.arraycopy(this.constants, 0, (localKeysCopy = new int[this.caseCount]), 0, this.caseCount);
 				CodeStream.sort(localKeysCopy, 0, this.caseCount - 1, sortedIndexes);
 
-				// for enum constants, actually switch on constant ordinal()
-				if (this.expression.resolvedType.isEnum()) {
-					codeStream.invokeEnumOrdinal(this.expression.resolvedType.constantPoolName());
-				}
 				int max = localKeysCopy[this.caseCount - 1];
 				int min = localKeysCopy[0];
 				if ((long) (caseCount * 2.5) > ((long) max - (long) min)) {
 					
 					// work-around 1.3 VM bug, if max>0x7FFF0000, must use lookup bytecode
 					// see http://dev.eclipse.org/bugs/show_bug.cgi?id=21557
-					if (max > 0x7FFF0000 && currentScope.environment().options.complianceLevel < ClassFileConstants.JDK1_4) {
+					if (max > 0x7FFF0000 && currentScope.compilerOptions().complianceLevel < ClassFileConstants.JDK1_4) {
 						codeStream.lookupswitch(defaultLabel, this.constants, sortedIndexes, caseLabels);
 	
 					} else {
@@ -297,7 +316,7 @@
 			}
 			// for enum switch, check if all constants are accounted for (if no default) 
 			if (isEnumSwitch && defaultCase == null 
-					&& upperScope.environment().options.getSeverity(CompilerOptions.IncompleteEnumSwitch) != ProblemSeverities.Ignore) {
+					&& upperScope.compilerOptions().getSeverity(CompilerOptions.IncompleteEnumSwitch) != ProblemSeverities.Ignore) {
 				int constantCount = this.constants == null ? 0 : this.constants.length; // could be null if no case statement
 				if (constantCount == caseCount // ignore diagnosis if unresolved constants
 						&& caseCount != ((ReferenceBinding)expressionType).enumConstantCount()) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java
index c5820ab..cbcb0ef 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java
@@ -64,7 +64,7 @@
 		exceptionType = exception.resolveTypeExpecting(scope, scope.getJavaLangThrowable());
 		
 		if (exceptionType == NullBinding
-				&& scope.environment().options.complianceLevel <= ClassFileConstants.JDK1_3){
+				&& scope.compilerOptions().complianceLevel <= ClassFileConstants.JDK1_3){
 			// if compliant with 1.4, this problem will not be reported
 			scope.problemReporter().cannotThrowNull(this);
 	 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java
index 9431f4a..2518cf8 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java
@@ -208,7 +208,7 @@
 		} else {
 			if (this.isSubRoutineEscaping) {
 				finallyMode = FINALLY_DOES_NOT_COMPLETE;
-			} else if (scope.environment().options.inlineJsrBytecode) {
+			} else if (scope.compilerOptions().inlineJsrBytecode) {
 				finallyMode = FINALLY_MUST_BE_INLINED;
 			} else {
 				finallyMode = FINALLY_SUBROUTINE;
@@ -411,9 +411,11 @@
 		if (this.isSubRoutineEscaping) {
 				codeStream.goto_(this.subRoutineStartLabel);
 		} else {
-			if (currentScope.environment().options.inlineJsrBytecode) { 
+			if (currentScope.compilerOptions().inlineJsrBytecode) {
 				// cannot use jsr bytecode, then simply inline the subroutine
+				this.exitAnyExceptionHandler();				
 				this.finallyBlock.generateCode(currentScope, codeStream);
+				this.enterAnyExceptionHandler(codeStream);
 			} else {
 				// classic subroutine invocation, distinguish case of non-returning subroutine
 				codeStream.jsr(this.subRoutineStartLabel);
@@ -463,7 +465,7 @@
 				MethodScope methodScope = scope.methodScope();
 	
 				// the type does not matter as long as it is not a base type
-				if (!upperScope.environment().options.inlineJsrBytecode) {
+				if (!upperScope.compilerOptions().inlineJsrBytecode) {
 					this.returnAddressVariable =
 						new LocalVariableBinding(SecretReturnName, upperScope.getJavaLangObject(), AccDefault, false);
 					finallyScope.addLocalVariable(returnAddressVariable);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java
index 9722d1d..177ba8b 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java
@@ -11,7 +11,6 @@
 package org.eclipse.jdt.internal.compiler.ast;
 
 import org.eclipse.jdt.core.compiler.*;
-import org.eclipse.jdt.internal.compiler.ASTVisitor;
 import org.eclipse.jdt.internal.compiler.*;
 import org.eclipse.jdt.internal.compiler.impl.*;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
@@ -51,7 +50,7 @@
 	public CompilationResult compilationResult;
 	public MethodDeclaration[] missingAbstractMethods;
 	public Javadoc javadoc;	
-
+	
 	public QualifiedAllocationExpression allocation; // for anonymous only
 	public TypeDeclaration enclosingType; // for member types only
 	
@@ -307,7 +306,7 @@
 
 		return this.compilationResult;
 	}
-
+	
 	public ConstructorDeclaration createDefaultConstructor(
 		boolean needExplicitConstructorCall,
 		boolean needToInsert) {
@@ -626,8 +625,8 @@
 	 */
 	public void internalAnalyseCode(FlowContext flowContext, FlowInfo flowInfo) {
 
-		if (this.binding.isPrivate() && !this.binding.isPrivateUsed()) {
-			if (!scope.referenceCompilationUnit().compilationResult.hasSyntaxError()) {
+		if ((this.binding.isPrivate()/* || (this.binding.tagBits & (TagBits.IsAnonymousType|TagBits.IsLocalType)) == TagBits.IsLocalType*/) && !this.binding.isUsed()) {
+			if (!scope.referenceCompilationUnit().compilationResult.hasSyntaxError) {
 				scope.problemReporter().unusedPrivateType(this);
 			}
 		}
@@ -764,7 +763,7 @@
 			//		M() { this(new Object() { void baz() { foo(); }}); } // access to #foo() indirects through constructor synthetic arg: val$this$0
 			//	}
 			//}
-			if (!methodScope.isStatic && methodScope.isConstructorCall && currentScope.environment().options.complianceLevel >= ClassFileConstants.JDK1_5) {
+			if (!methodScope.isStatic && methodScope.isConstructorCall && currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_5) {
 				ReferenceBinding enclosing = nestedType.enclosingType();
 				if (enclosing.isNestedType()) {
 					NestedTypeBinding nestedEnclosing = (NestedTypeBinding)enclosing;
@@ -974,7 +973,7 @@
 				this.scope.problemReporter().undocumentedEmptyBlock(this.bodyStart-1, this.bodyEnd);
 			}
 			boolean needSerialVersion = 
-							this.scope.environment().options.getSeverity(CompilerOptions.MissingSerialVersion) != ProblemSeverities.Ignore
+							this.scope.compilerOptions().getSeverity(CompilerOptions.MissingSerialVersion) != ProblemSeverities.Ignore
 							&& sourceType.isClass() 
 							&& !sourceType.isAbstract() 
 							&& sourceType.findSuperTypeErasingTo(T_JavaIoSerializable, false /*Serializable is not a class*/) != null;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeParameter.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeParameter.java
index 4b5511f..bec3a42 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeParameter.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeParameter.java
@@ -42,16 +42,26 @@
 		}
 	}
 	
-	public void resolve(ClassScope scope) {
+	private void internalResolve(Scope scope, boolean staticContext) {
 	    // detect variable/type name collisions
 		if (this.binding != null) {
-			Scope outerScope = scope.parent;
-			Binding existingType = outerScope.getBinding(this.name, Binding.TYPE, this, false);
-			if (existingType != null && this.binding != existingType && existingType.isValidBinding()) {
+			Binding existingType = scope.parent.getBinding(this.name, Binding.TYPE, this, false);
+			if (existingType != null 
+					&& this.binding != existingType 
+					&& existingType.isValidBinding()
+					&& (existingType.kind() != Binding.TYPE_PARAMETER || !staticContext)) {
 				scope.problemReporter().typeHiding(this, existingType);
 			}
 		}
 	}
+	
+	public void resolve(BlockScope scope) {
+		internalResolve(scope, scope.methodScope().isStatic);
+	}
+	
+	public void resolve(ClassScope scope) {
+		internalResolve(scope, scope.enclosingSourceType().isStatic());
+	}
 
 	/* (non-Javadoc)
 	 * @see org.eclipse.jdt.internal.compiler.ast.AstNode#print(int, java.lang.StringBuffer)
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java
index 2f9f08e..8eff119 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java
@@ -130,7 +130,7 @@
 	}
 	if (isTypeUseDeprecated(this.resolvedType, blockScope))
 		reportDeprecatedType(blockScope);
-	return this.resolvedType = blockScope.convertToRawType(this.resolvedType);
+	return this.resolvedType = blockScope.environment().convertToRawType(this.resolvedType);
 }
 public TypeBinding resolveType(ClassScope classScope) {
 	// handle the error here
@@ -147,7 +147,7 @@
 	}
 	if (isTypeUseDeprecated(this.resolvedType, classScope))
 		reportDeprecatedType(classScope);
-	return this.resolvedType = classScope.convertToRawType(this.resolvedType);
+	return this.resolvedType = classScope.environment().convertToRawType(this.resolvedType);
 }
 
 public TypeBinding resolveTypeArgument(BlockScope blockScope, ReferenceBinding genericType, int rank) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/UnaryExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/UnaryExpression.java
index dc81aa9..76a9062 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/UnaryExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/UnaryExpression.java
@@ -214,11 +214,10 @@
 		}
 		int expressionTypeID = expressionType.id;
 		// autoboxing support
-		LookupEnvironment env = scope.environment();
-		boolean use15specifics = env.options.sourceLevel >= JDK1_5;
+		boolean use15specifics = scope.compilerOptions().sourceLevel >= JDK1_5;
 		if (use15specifics) {
 			if (!expressionType.isBaseType()) {
-				expressionTypeID = env.computeBoxingType(expressionType).id;
+				expressionTypeID = scope.environment().computeBoxingType(expressionType).id;
 			}
 		}		
 		if (expressionTypeID > 15) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java
index 4bc538e..99321ef 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java
@@ -66,7 +66,7 @@
 		FlowInfo actionInfo;
 		FlowInfo exitBranch;
 		if (action == null 
-			|| (action.isEmptyBlock() && currentScope.environment().options.complianceLevel <= ClassFileConstants.JDK1_3)) {
+			|| (action.isEmptyBlock() && currentScope.compilerOptions().complianceLevel <= ClassFileConstants.JDK1_3)) {
 			condLoopContext.complainOnDeferredChecks(currentScope, condInfo);
 			if (isConditionTrue) {
 				return FlowInfo.DEAD_END;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java
index 3d13e57..643e073 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java
@@ -801,6 +801,9 @@
 		if ((this.getTagBits() & TagBits.AnnotationTargetMASK|TagBits.AnnotationDeprecated|TagBits.AnnotationRetentionMASK) != (newClassFile.getTagBits() & TagBits.AnnotationTargetMASK|TagBits.AnnotationDeprecated|TagBits.AnnotationRetentionMASK))
 			return true;
 		
+		// generic signature
+		if (!CharOperation.equals(this.getGenericSignature(), newClassFile.getGenericSignature()))
+			return true;
 		// superclass
 		if (!CharOperation.equals(this.getSuperclassName(), newClassFile.getSuperclassName()))
 			return true;
@@ -895,6 +898,9 @@
 	}
 }
 private boolean hasStructuralFieldChanges(FieldInfo currentFieldInfo, FieldInfo otherFieldInfo) {
+	// generic signature
+	if (!CharOperation.equals(currentFieldInfo.getGenericSignature(), otherFieldInfo.getGenericSignature()))
+		return true;
 	if (currentFieldInfo.getModifiers() != otherFieldInfo.getModifiers())
 		return true;
 	if ((currentFieldInfo.getTagBits() & TagBits.AnnotationDeprecated) != (otherFieldInfo.getTagBits() & TagBits.AnnotationDeprecated))
@@ -936,6 +942,9 @@
 	return false;
 }
 private boolean hasStructuralMethodChanges(MethodInfo currentMethodInfo, MethodInfo otherMethodInfo) {
+	// generic signature
+	if (!CharOperation.equals(currentMethodInfo.getGenericSignature(), otherMethodInfo.getGenericSignature()))
+		return true;
 	if (currentMethodInfo.getModifiers() != otherMethodInfo.getModifiers())
 		return true;
 	if ((currentMethodInfo.getTagBits() & TagBits.AnnotationDeprecated) != (otherMethodInfo.getTagBits() & TagBits.AnnotationDeprecated))
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/FieldInfo.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/FieldInfo.java
index 23c238f..86def37 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/FieldInfo.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/FieldInfo.java
@@ -118,7 +118,7 @@
 			readOffset += 2;
 			break;
 		case '@' :
-			readOffset += decodeAnnotation(readOffset);
+			readOffset = decodeAnnotation(readOffset);
 			break;
 		case '[' :
 			int numberOfValues = u2At(readOffset);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/MethodInfo.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/MethodInfo.java
index 54c4829..2e485ad 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/MethodInfo.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/MethodInfo.java
@@ -110,7 +110,7 @@
 			readOffset += 2;
 			break;
 		case '@' :
-			readOffset += decodeAnnotation(readOffset);
+			readOffset = decodeAnnotation(readOffset);
 			break;
 		case '[' :
 			int numberOfValues = u2At(readOffset);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java
index ca2388c..334bc9a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java
@@ -10,11 +10,13 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.codegen;
 
+import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.*;
 
 import org.eclipse.jdt.internal.compiler.impl.*;
 import org.eclipse.jdt.internal.compiler.ast.*;
 import org.eclipse.jdt.internal.compiler.classfmt.*;
+import org.eclipse.jdt.internal.compiler.env.IConstants;
 import org.eclipse.jdt.internal.compiler.flow.*;
 import org.eclipse.jdt.internal.compiler.lookup.*;
 
@@ -32,7 +34,7 @@
 	public byte[] bCodeStream;
 	public int pcToSourceMapSize;
 	public int[] pcToSourceMap = new int[24];
-	public int lastEntryPC; // last entry recorded
+	public int lastEntryPC; // last entry recorded 
 	public int[] lineSeparatorPositions;
 	public int position; // So when first set can be incremented
 	public int classFileOffset;
@@ -1796,7 +1798,7 @@
 		ASTNode invocationSite) {
 
 	// supplying enclosing instance for the anonymous type's superclass
-	ReferenceBinding checkedTargetType = targetType.isAnonymousType() ? targetType.superclass() : targetType;
+	ReferenceBinding checkedTargetType = targetType.isAnonymousType() ? (ReferenceBinding)targetType.superclass().erasure() : targetType;
 	boolean hasExtraEnclosingInstance = enclosingInstance != null;
 	if (hasExtraEnclosingInstance 
 			&& (!checkedTargetType.isNestedType() || checkedTargetType.isStatic())) {
@@ -1809,7 +1811,7 @@
 	if ((syntheticArgumentTypes = targetType.syntheticEnclosingInstanceTypes()) != null) {
 
 		ReferenceBinding targetEnclosingType = checkedTargetType.enclosingType();
-		long compliance = currentScope.environment().options.complianceLevel;
+		long compliance = currentScope.compilerOptions().complianceLevel;
 
 		// deny access to enclosing instance argument for allocation and super constructor call (if 1.4)
 		// always consider it if complying to 1.5
@@ -1998,32 +2000,89 @@
 	this.invokeJavaLangIllegalArgumentExceptionStringConstructor();
 	this.athrow();
 }
+public void generateSyntheticBodyForSwitchTable(SyntheticMethodBinding methodBinding) {
+	ClassScope scope = ((SourceTypeBinding)methodBinding.declaringClass).scope;
+	initializeMaxLocals(methodBinding);
+	final Label nullLabel = new Label(this);
+	FieldBinding syntheticFieldBinding = methodBinding.targetReadField;
+
+	this.getstatic(syntheticFieldBinding);
+	this.dup();
+	this.ifnull(nullLabel);
+	final int stackSizeForIf = this.stackDepth;
+	this.areturn();
+	nullLabel.place();
+	this.stackDepth = stackSizeForIf;
+	this.pop();
+	ReferenceBinding enumBinding = (ReferenceBinding) methodBinding.targetEnumType;
+	char[] signature = "()".toCharArray(); //$NON-NLS-1$
+	ArrayBinding arrayBinding = scope.createArrayType(enumBinding, 1);
+	signature = CharOperation.concat(signature, arrayBinding.constantPoolName());
+	this.invoke(OPC_invokestatic, 0, 1, enumBinding.constantPoolName(), TypeConstants.VALUES, signature);
+	this.arraylength();
+	this.newarray(INT_ARRAY);
+	this.astore_0();
+	final FieldBinding[] fields = enumBinding.fields();
+	if (fields != null) {
+		for (int i = 0, max = fields.length; i < max; i++) {
+			FieldBinding fieldBinding = fields[i];
+			if ((fieldBinding.getAccessFlags() & IConstants.AccEnum) != 0) {
+				final Label endLabel = new Label(this);
+				final ExceptionLabel anyExceptionHandler = new ExceptionLabel(this, BaseTypes.LongBinding /* represents NoSuchFieldError*/);
+				this.aload_0();
+				this.getstatic(fieldBinding);
+				this.invokeEnumOrdinal(enumBinding.constantPoolName());
+				this.generateInlinedValue(fieldBinding.id);
+				this.iastore();
+				anyExceptionHandler.placeEnd();
+				this.goto_(endLabel);
+				// Generate the body of the exception handler
+				final int saveStackSize = stackDepth;
+				stackDepth = 1;
+				anyExceptionHandler.place();
+				this.pop(); // we don't use it so we can pop it
+				stackDepth = saveStackSize;
+				endLabel.place();				
+			}
+		}
+	}
+	this.aload_0();
+	this.dup();
+	this.putstatic(syntheticFieldBinding);
+	areturn();
+}
 public void generateSyntheticBodyForFieldReadAccess(SyntheticMethodBinding accessBinding) {
 	initializeMaxLocals(accessBinding);
 	FieldBinding fieldBinding = accessBinding.targetReadField;
-	TypeBinding type;
 	if (fieldBinding.isStatic())
 		this.getstatic(fieldBinding);
 	else {
 		this.aload_0();
 		this.getfield(fieldBinding);
 	}
-	if ((type = fieldBinding.type).isBaseType()) {
-		if (type == IntBinding)
+	switch (fieldBinding.type.id) {
+//		case T_void :
+//			this.return_();
+//			break;
+		case T_boolean :
+		case T_byte :
+		case T_char :
+		case T_short :
+		case T_int :
 			this.ireturn();
-		else
-			if (type == FloatBinding)
-				this.freturn();
-			else
-				if (type == LongBinding)
-					this.lreturn();
-				else
-					if (type == DoubleBinding)
-						this.dreturn();
-					else
-						this.ireturn();
-	} else
-		this.areturn();
+			break;
+		case T_long :
+			this.lreturn();
+			break;
+		case T_float :
+			this.freturn();
+			break;
+		case T_double :
+			this.dreturn();
+			break;
+		default :
+			this.areturn();
+	}	
 }
 public void generateSyntheticBodyForFieldWriteAccess(SyntheticMethodBinding accessBinding) {
 	initializeMaxLocals(accessBinding);
@@ -2038,17 +2097,17 @@
 	}
 	this.return_();
 }
-public void generateSyntheticBodyForMethodAccess(SyntheticMethodBinding accessBinding) {
+public void generateSyntheticBodyForMethodAccess(SyntheticMethodBinding accessMethod) {
 
-	initializeMaxLocals(accessBinding);
-	MethodBinding methodBinding = accessBinding.targetMethod;
-	TypeBinding[] parameters = methodBinding.parameters;
+	initializeMaxLocals(accessMethod);
+	MethodBinding targetMethod = accessMethod.targetMethod;
+	TypeBinding[] parameters = targetMethod.parameters;
 	int length = parameters.length;
-	TypeBinding[] arguments = accessBinding.kind == SyntheticMethodBinding.BridgeMethod 
-													? accessBinding.parameters
+	TypeBinding[] arguments = accessMethod.kind == SyntheticMethodBinding.BridgeMethod 
+													? accessMethod.parameters
 													: null;
 	int resolvedPosition;
-	if (methodBinding.isStatic())
+	if (targetMethod.isStatic())
 		resolvedPosition = 0;
 	else {
 		this.aload_0();
@@ -2069,42 +2128,48 @@
 		else
 			resolvedPosition++;
 	}
-	TypeBinding type;
-	if (methodBinding.isStatic())
-		this.invokestatic(methodBinding);
+	if (targetMethod.isStatic())
+		this.invokestatic(targetMethod);
 	else {
-		if (methodBinding.isConstructor()
-			|| methodBinding.isPrivate()
+		if (targetMethod.isConstructor()
+			|| targetMethod.isPrivate()
 			// qualified super "X.super.foo()" targets methods from superclass
-			|| accessBinding.kind == SyntheticMethodBinding.SuperMethodAccess){
-			this.invokespecial(methodBinding);
+			|| accessMethod.kind == SyntheticMethodBinding.SuperMethodAccess){
+			this.invokespecial(targetMethod);
 		} else {
-			if (methodBinding.declaringClass.isInterface()) { // interface or annotation type
-				this.invokeinterface(methodBinding);
+			if (targetMethod.declaringClass.isInterface()) { // interface or annotation type
+				this.invokeinterface(targetMethod);
 			} else {
-				this.invokevirtual(methodBinding);
+				this.invokevirtual(targetMethod);
 			}
 		}
 	}
-	if ((type = methodBinding.returnType).isBaseType())
-		if (type == VoidBinding)
+	switch (targetMethod.returnType.id) {
+		case T_void :
 			this.return_();
-		else
-			if (type == IntBinding)
-				this.ireturn();
-			else
-				if (type == FloatBinding)
-					this.freturn();
-				else
-					if (type == LongBinding)
-						this.lreturn();
-					else
-						if (type == DoubleBinding)
-							this.dreturn();
-						else
-							this.ireturn();
-	else
-		this.areturn();
+			break;
+		case T_boolean :
+		case T_byte :
+		case T_char :
+		case T_short :
+		case T_int :
+			this.ireturn();
+			break;
+		case T_long :
+			this.lreturn();
+			break;
+		case T_float :
+			this.freturn();
+			break;
+		case T_double :
+			this.dreturn();
+			break;
+		default :
+			TypeBinding accessErasure = accessMethod.returnType.erasure();
+			if (!targetMethod.returnType.isCompatibleWith(accessErasure))
+				this.checkcast(accessErasure); // for bridge methods
+			this.areturn();
+	}
 }
 public void generateBoxingConversion(int unboxedTypeID) {
 	switch (unboxedTypeID) {
@@ -5421,7 +5486,7 @@
 public void reset(AbstractMethodDeclaration referenceMethod, ClassFile targetClassFile) {
 	init(targetClassFile);
 	this.methodDeclaration = referenceMethod;
-	preserveUnusedLocals = referenceMethod.scope.problemReporter().options.preserveAllLocalVariables;
+	this.preserveUnusedLocals = referenceMethod.scope.compilerOptions().preserveAllLocalVariables;
 	initializeMaxLocals(referenceMethod.binding);
 }
 /**
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/ConstantPool.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/ConstantPool.java
index 15fd1bc..745edf0 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/ConstantPool.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/ConstantPool.java
@@ -150,6 +150,7 @@
 	public static final char[] JavaLangIntegerConstantPoolName = "java/lang/Integer".toCharArray(); //$NON-NLS-1$
 	public static final char[] JavaLangLongConstantPoolName = "java/lang/Long".toCharArray(); //$NON-NLS-1$
 	public static final char[] JavaLangNoClassDefFoundErrorConstantPoolName = "java/lang/NoClassDefFoundError".toCharArray(); //$NON-NLS-1$
+	public static final char[] JavaLangNoSuchFieldErrorConstantPoolName = "java/lang/NoSuchFieldError".toCharArray(); //$NON-NLS-1$
 	public static final char[] JavaLangObjectConstantPoolName = "java/lang/Object".toCharArray(); //$NON-NLS-1$
 	public static final char[] JAVALANGREFLECTACCESSIBLEOBJECT_CONSTANTPOOLNAME = "java/lang/reflect/AccessibleObject".toCharArray(); //$NON-NLS-1$
 	public static final char[] JAVALANGREFLECTARRAY_CONSTANTPOOLNAME = "java/lang/reflect/Array".toCharArray(); //$NON-NLS-1$
@@ -177,6 +178,7 @@
 	public static final char[] Next = "next".toCharArray();//$NON-NLS-1$
 	public static final char[] NextSignature = "()Ljava/lang/Object;".toCharArray();//$NON-NLS-1$
 	public static final char[] ObjectConstrSignature = "(Ljava/lang/Object;)V".toCharArray(); //$NON-NLS-1$
+	public static final char[] ObjectSignature = "Ljava/lang/Object;".toCharArray(); //$NON-NLS-1$
 	public static final char[] Ordinal = "ordinal".toCharArray(); //$NON-NLS-1$
 	public static final char[] OrdinalSignature = "()I".toCharArray(); //$NON-NLS-1$
 	public static final char[] Out = "out".toCharArray(); //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/AccessRuleSet.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/AccessRuleSet.java
index 4a51ece..408acf0 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/AccessRuleSet.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/AccessRuleSet.java
@@ -25,6 +25,10 @@
 	public AccessRuleSet(AccessRule[] accessRules) {
 		this.accessRules = accessRules;
 	}
+	public AccessRuleSet(AccessRule[] accessRules, String messageTemplate) {
+		this.accessRules = accessRules;
+		this.messageTemplate = messageTemplate;
+	}
 	/**
 	 * @see java.lang.Object#equals(java.lang.Object)
 	 */
@@ -50,7 +54,7 @@
 	
 	/**
 	 * Select the first access rule which is violated when accessing a given type, or null if no 'non accessible' access rule applies.
-	 * Target type file path is formed as: "org/eclipse/jdt/core/JavaCore.java".
+	 * Target type file path is formed as: "org/eclipse/jdt/core/JavaCore".
 	 */
 	public AccessRestriction getViolatedRestriction(char[] targetTypeFilePath) {
 		
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java
index ae7ba28..629e08d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java
@@ -59,10 +59,8 @@
 		this.initsOnExceptions = new UnconditionalFlowInfo[count];
 		for (int i = 0; i < count; i++) {
 			this.indexes.put(handledExceptions[i], i); // key type  -> value index
-			boolean isUnchecked =
-				(scope.compareUncheckedException(handledExceptions[i]) != NotRelated);
 			int cacheIndex = i / BitCacheSize, bitMask = 1 << (i % BitCacheSize);
-			if (isUnchecked) {
+			if (handledExceptions[i].isUncheckedException(true)) {
 				isReached[cacheIndex] |= bitMask;
 				this.initsOnExceptions[i] = flowInfo.copy().unconditionalInits();
 			} else {
@@ -77,7 +75,7 @@
 		MethodScope scope = method.scope;
 		// can optionally skip overriding methods
 		if ((method.binding.modifiers & (CompilerModifiers.AccOverriding | CompilerModifiers.AccImplementing)) != 0
-		        && !scope.environment().options.reportUnusedDeclaredThrownExceptionWhenOverriding) {
+		        && !scope.compilerOptions().reportUnusedDeclaredThrownExceptionWhenOverriding) {
 		    return;
 		}
 		    
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java
index ce08eae..8964f18 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java
@@ -139,8 +139,7 @@
 					for (int i = 0; i < raisedCount; i++) {
 						TypeBinding raisedException;
 						if ((raisedException = raisedExceptions[i]) != null) {
-							if (raisedException.isCompatibleWith(scope.getJavaLangRuntimeException())
-								|| raisedException.isCompatibleWith(scope.getJavaLangError())) {
+							if (raisedException.isUncheckedException(false)) {
 								remainingCount--;
 								raisedExceptions[i] = null;
 							}
@@ -248,8 +247,7 @@
 				}
 				// method treatment for unchecked exceptions
 				if (exceptionContext.isMethodContext) {
-					if (raisedException.isCompatibleWith(scope.getJavaLangRuntimeException())
-						|| raisedException.isCompatibleWith(scope.getJavaLangError()))
+					if (raisedException.isUncheckedException(false))
 						return;
 						
 					// anonymous constructors are allowed to throw any exceptions (their thrown exceptions
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java
index 703c0f0..3c5c088 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java
@@ -99,6 +99,8 @@
 	public static final String OPTION_ReportIncompleteEnumSwitch = "org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch"; //$NON-NLS-1$
 	public static final String OPTION_ReportForbiddenReference =  "org.eclipse.jdt.core.compiler.problem.forbiddenReference"; //$NON-NLS-1$
 	public static final String OPTION_ReportDiscouragedReference =  "org.eclipse.jdt.core.compiler.problem.discouragedReference"; //$NON-NLS-1$
+	public static final String OPTION_SuppressWarnings =  "org.eclipse.jdt.core.compiler.problem.suppressWarnings"; //$NON-NLS-1$
+	public static final String OPTION_ReportUnhandledWarningToken =  "org.eclipse.jdt.core.compiler.problem.unhandledWarningToken"; //$NON-NLS-1$
 	
 	// Backward compatibility
 	public static final String OPTION_ReportInvalidAnnotation = "org.eclipse.jdt.core.compiler.problem.invalidAnnotation"; //$NON-NLS-1$
@@ -177,6 +179,14 @@
 	public static final long IncompleteEnumSwitch = ASTNode.Bit42L;
 	public static final long MissingDeprecatedAnnotation = ASTNode.Bit43L;
 	public static final long DiscouragedReference = ASTNode.Bit44L;
+	public static final long UnhandledWarningToken = ASTNode.Bit45L;
+	
+	// TODO (olivier) remove once http://gcc.gnu.org/bugzilla/show_bug.cgi?id=21540 is fixed
+	private static final int IntMissingSerialVersion = (int) (MissingSerialVersion >>> 32);
+	private static final int IntAutoBoxing = (int) (Autoboxing >>> 32);
+	private static final int IntTypeParameterHiding = (int) (TypeParameterHiding >>> 32);
+	private static final int IntIncompleteEnumSwitch = (int) (IncompleteEnumSwitch >>> 32);
+	private static final int IntMissingDeprecatedAnnotation = (int) (MissingDeprecatedAnnotation >>> 32);
 	
 	// Default severity level for handlers
 	public long errorThreshold = 0;
@@ -202,6 +212,9 @@
 		| AnnotationSuperInterface
 		| TypeParameterHiding
 		| FinalParameterBound
+		| UnhandledWarningToken
+		| UnusedLocalVariable
+		| UnusedPrivateMember
 		/*| NullReference*/;
 
 	// Debug attributes
@@ -264,18 +277,20 @@
 
 	// check missing javadoc tags
 	public int reportMissingJavadocTagsVisibility = AccPrivate; 
-	public boolean reportMissingJavadocTagsOverriding = true;
+	public boolean reportMissingJavadocTagsOverriding = false;
 
 	// check missing javadoc comments
 	public int reportMissingJavadocCommentsVisibility = AccPublic; 
-	public boolean reportMissingJavadocCommentsOverriding = true; 
-	
+	public boolean reportMissingJavadocCommentsOverriding = false; 
+
 	// JSR bytecode inlining
 	public boolean inlineJsrBytecode = false;
 	
 	// javadoc comment support
 	public boolean docCommentSupport = false;
 	
+	// suppress warning annotation
+	public boolean suppressWarnings = true;
 	
 	/** 
 	 * Initializing the compiler options with defaults
@@ -369,15 +384,17 @@
 		optionsMap.put(OPTION_ReportSpecialParameterHidingField, this.reportSpecialParameterHidingField ? ENABLED : DISABLED); 
 		optionsMap.put(OPTION_MaxProblemPerUnit, String.valueOf(this.maxProblemsPerUnit));
 		optionsMap.put(OPTION_InlineJsr, this.inlineJsrBytecode ? ENABLED : DISABLED); 
-		optionsMap.put(OPTION_ReportNullReference, getSeverityString(NullReference)); 
+		optionsMap.put(OPTION_ReportNullReference, getSeverityString(NullReference));
+		optionsMap.put(OPTION_SuppressWarnings, this.suppressWarnings ? ENABLED : DISABLED); 
+		optionsMap.put(OPTION_ReportUnhandledWarningToken, getSeverityString(UnhandledWarningToken));
 		return optionsMap;		
 	}
 	
 	public int getSeverity(long irritant) {
-		if((this.warningThreshold & irritant) != 0)
-			return Warning;
 		if((this.errorThreshold & irritant) != 0)
 			return Error;
+		if((this.warningThreshold & irritant) != 0)
+			return Warning;
 		return Ignore;
 	}
 
@@ -553,6 +570,13 @@
 				}
 			}
 		}
+		if ((optionValue = optionsMap.get(OPTION_SuppressWarnings)) != null) {
+			if (ENABLED.equals(optionValue)) {
+				this.suppressWarnings = true;
+			} else if (DISABLED.equals(optionValue)) {
+				this.suppressWarnings = false;
+			}
+		}		
 		if ((optionValue = optionsMap.get(OPTION_ReportMethodWithConstructorName)) != null) updateSeverity(MethodWithConstructorName, optionValue);
 		if ((optionValue = optionsMap.get(OPTION_ReportOverridingPackageDefaultMethod)) != null) updateSeverity(OverriddenPackageDefaultMethod, optionValue);
 		if ((optionValue = optionsMap.get(OPTION_ReportDeprecation)) != null) updateSeverity(UsingDeprecatedAPI, optionValue);
@@ -593,6 +617,7 @@
 		if ((optionValue = optionsMap.get(OPTION_ReportMissingOverrideAnnotation)) != null) updateSeverity(MissingOverrideAnnotation, optionValue);
 		if ((optionValue = optionsMap.get(OPTION_ReportMissingDeprecatedAnnotation)) != null) updateSeverity(MissingDeprecatedAnnotation, optionValue);
 		if ((optionValue = optionsMap.get(OPTION_ReportIncompleteEnumSwitch)) != null) updateSeverity(IncompleteEnumSwitch, optionValue);
+		if ((optionValue = optionsMap.get(OPTION_ReportUnhandledWarningToken)) != null) updateSeverity(UnhandledWarningToken, optionValue);
 		
 		// Javadoc options
 		if ((optionValue = optionsMap.get(OPTION_DocCommentSupport)) != null) {
@@ -605,7 +630,7 @@
 		if ((optionValue = optionsMap.get(OPTION_ReportInvalidJavadoc)) != null) {
 			updateSeverity(InvalidJavadoc, optionValue);
 		}
-		if ((optionValue = optionsMap.get(OPTION_ReportInvalidJavadocTagsVisibility)) != null) {
+		if ( (optionValue = optionsMap.get(OPTION_ReportInvalidJavadocTagsVisibility)) != null) {
 			if (PUBLIC.equals(optionValue)) {
 				this.reportInvalidJavadocTagsVisibility = AccPublic;
 			} else if (PROTECTED.equals(optionValue)) {
@@ -752,7 +777,9 @@
 		buf.append("\n\t- annotation super interface: ").append(getSeverityString(AnnotationSuperInterface)); //$NON-NLS-1$
 		buf.append("\n\t- missing @Override annotation: ").append(getSeverityString(MissingOverrideAnnotation)); //$NON-NLS-1$		
 		buf.append("\n\t- missing @Deprecated annotation: ").append(getSeverityString(MissingDeprecatedAnnotation)); //$NON-NLS-1$		
-		buf.append("\n\t- incomplete enum switch: ").append(getSeverityString(IncompleteEnumSwitch)); //$NON-NLS-1$		
+		buf.append("\n\t- incomplete enum switch: ").append(getSeverityString(IncompleteEnumSwitch)); //$NON-NLS-1$
+		buf.append("\n\t- suppress warnings: ").append(this.suppressWarnings ? ENABLED : DISABLED); //$NON-NLS-1$
+		buf.append("\n\t- unhandled warning token: ").append(getSeverityString(UnhandledWarningToken)); //$NON-NLS-1$
 		return buf.toString();
 	}
 
@@ -797,4 +824,158 @@
 		}
 		return ""; // unknown version //$NON-NLS-1$
 	}
+	
+	/**
+	 * Return all warning option names for use as keys in compiler options maps.
+	 * @return all warning option names
+	 */
+	public static String[] warningOptionNames() {
+		String[] result = {
+			OPTION_ReportAnnotationSuperInterface,
+			OPTION_ReportAssertIdentifier,
+			OPTION_ReportAutoboxing,
+			OPTION_ReportDeprecation,
+			OPTION_ReportDiscouragedReference,
+			OPTION_ReportEmptyStatement,
+			OPTION_ReportEnumIdentifier,
+			OPTION_ReportFieldHiding,
+			OPTION_ReportFinalParameterBound,
+			OPTION_ReportFinallyBlockNotCompletingNormally,
+			OPTION_ReportForbiddenReference,
+			OPTION_ReportHiddenCatchBlock,
+			OPTION_ReportIncompatibleNonInheritedInterfaceMethod,
+			OPTION_ReportIncompleteEnumSwitch,
+			OPTION_ReportIndirectStaticAccess,
+			OPTION_ReportInvalidJavadoc,
+			OPTION_ReportLocalVariableHiding,
+			OPTION_ReportMethodWithConstructorName,
+			OPTION_ReportMissingDeprecatedAnnotation,
+			OPTION_ReportMissingJavadocComments,
+			OPTION_ReportMissingJavadocTags,
+			OPTION_ReportMissingOverrideAnnotation,
+			OPTION_ReportMissingSerialVersion,
+			OPTION_ReportNoEffectAssignment,
+			OPTION_ReportNoImplicitStringConversion,
+			OPTION_ReportNonExternalizedStringLiteral,
+			OPTION_ReportNonStaticAccessToStatic,
+			OPTION_ReportNullReference,
+			OPTION_ReportOverridingPackageDefaultMethod,
+			OPTION_ReportPossibleAccidentalBooleanAssignment,
+			OPTION_ReportSyntheticAccessEmulation,
+			OPTION_ReportTypeParameterHiding,
+			OPTION_ReportUncheckedTypeOperation,
+			OPTION_ReportUndocumentedEmptyBlock,
+			OPTION_ReportUnnecessaryElse,
+			OPTION_ReportUnnecessaryTypeCheck,
+			OPTION_ReportUnqualifiedFieldAccess,
+			OPTION_ReportUnusedDeclaredThrownException,
+			OPTION_ReportUnusedImport,
+			OPTION_ReportUnusedLocal,
+			OPTION_ReportUnusedParameter,
+			OPTION_ReportUnusedPrivateMember,
+			OPTION_ReportVarargsArgumentNeedCast,
+			OPTION_ReportUnhandledWarningToken,
+		};
+		return result;
+	}
+	
+	public static String warningTokenFromIrritant(long irritant) {
+		int irritantInt = (int) irritant;
+		if (irritantInt == irritant) {
+			switch (irritantInt) {
+				case (int) (InvalidJavadoc | UsingDeprecatedAPI) :
+				case (int) UsingDeprecatedAPI :
+					return "deprecation"; //$NON-NLS-1$
+				case (int) FinallyBlockNotCompleting :
+					return "finally"; //$NON-NLS-1$
+				case (int) FieldHiding :
+				case (int) LocalVariableHiding :
+				case (int) MaskedCatchBlock :
+					return "hiding"; //$NON-NLS-1$
+				case (int) NonExternalizedString :
+					return "nls"; //$NON-NLS-1$
+				case (int) UnusedLocalVariable :
+				case (int) UnusedArgument :
+				case (int) UnusedPrivateMember:
+				case (int) UnusedDeclaredThrownException:
+					return "unused"; //$NON-NLS-1$
+				case (int) IndirectStaticAccess :
+				case (int) NonStaticAccessToStatic :
+					return "static-access"; //$NON-NLS-1$
+				case (int) AccessEmulation :
+					return "synthetic-access"; //$NON-NLS-1$
+				case (int) UnqualifiedFieldAccess :
+					return "unqualified-field-access"; //$NON-NLS-1$
+				case (int) UncheckedTypeOperation :
+					return "unchecked"; //$NON-NLS-1$
+			}
+		} else {
+			irritantInt = (int)(irritant >>> 32);
+			// TODO (olivier) remove contants once http://gcc.gnu.org/bugzilla/show_bug.cgi?id=21540 is fixed
+			switch (irritantInt) {
+				case IntMissingSerialVersion :
+					return "serial"; //$NON-NLS-1$
+				case IntAutoBoxing :
+					return "boxing"; //$NON-NLS-1$
+				case IntTypeParameterHiding :
+					return "hiding"; //$NON-NLS-1$
+				case IntIncompleteEnumSwitch :
+					return "incomplete-switch"; //$NON-NLS-1$
+				case IntMissingDeprecatedAnnotation :
+					return "dep-ann"; //$NON-NLS-1$
+			}
+		}
+		return null;
+	}
+	public static long warningTokenToIrritant(String warningToken) {
+		if (warningToken == null || warningToken.length() == 0) return 0;
+		switch (warningToken.charAt(0)) {
+			case 'a' :
+				if ("all".equals(warningToken)) //$NON-NLS-1$
+					return 0xFFFFFFFFFFFFFFFFl; // suppress all warnings
+				break;
+			case 'b' :
+				if ("boxing".equals(warningToken)) //$NON-NLS-1$
+					return Autoboxing;
+				break;
+			case 'd' :
+				if ("deprecation".equals(warningToken)) //$NON-NLS-1$
+					return UsingDeprecatedAPI;
+				if ("dep-ann".equals(warningToken)) //$NON-NLS-1$
+					return MissingDeprecatedAnnotation;
+				break;
+			case 'f' :
+				if ("finally".equals(warningToken)) //$NON-NLS-1$
+					return FinallyBlockNotCompleting;
+				break;
+			case 'h' :
+				if ("hiding".equals(warningToken)) //$NON-NLS-1$
+					return FieldHiding | LocalVariableHiding | MaskedCatchBlock | TypeParameterHiding;
+			case 'i' :
+				if ("incomplete-switch".equals(warningToken)) //$NON-NLS-1$
+					return IncompleteEnumSwitch;
+				break;
+			case 'n' :
+				if ("nls".equals(warningToken)) //$NON-NLS-1$
+					return NonExternalizedString;
+				break;
+			case 's' :
+				if ("serial".equals(warningToken)) //$NON-NLS-1$
+					return MissingSerialVersion;
+				if ("static-access".equals(warningToken)) //$NON-NLS-1$
+					return IndirectStaticAccess | NonStaticAccessToStatic;
+				if ("synthetic-access".equals(warningToken)) //$NON-NLS-1$
+					return AccessEmulation;
+				break;
+			case 'u' :
+				if ("unused".equals(warningToken)) //$NON-NLS-1$
+					return UnusedLocalVariable | UnusedArgument | UnusedPrivateMember | UnusedDeclaredThrownException;
+				if ("unchecked".equals(warningToken)) //$NON-NLS-1$
+					return UncheckedTypeOperation;
+				if ("unqualified-field-access".equals(warningToken)) //$NON-NLS-1$
+					return UnqualifiedFieldAccess;
+				break;
+		}
+		return 0;
+	}
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ReferenceContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ReferenceContext.java
index 43baa94..53374fe 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ReferenceContext.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ReferenceContext.java
@@ -21,6 +21,6 @@
 public interface ReferenceContext {
 	void abort(int abortLevel, IProblem problem);
 	CompilationResult compilationResult();
-	void tagAsHavingErrors();
 	boolean hasErrors();
+	void tagAsHavingErrors();
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ArrayBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ArrayBinding.java
index faccf47..6e0e788 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ArrayBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ArrayBinding.java
@@ -36,10 +36,6 @@
     	this.tagBits |= type.tagBits & (HasTypeVariable | HasDirectWildcard);
 }
 
-public int kind() {
-	return ARRAY_TYPE;
-}
-
 /**
  * Collect the substitutes into a map for certain type variables inside the receiver type
  * e.g.   Collection<T>.collectSubstitutes(Collection<List<X>>, Map), will populate Map with: T --> List<X>
@@ -70,10 +66,10 @@
  * brakets leafUniqueKey
  * p.X[][] --> [[Lp/X;
  */
-public char[] computeUniqueKey(boolean withAccessFlags) {
+public char[] computeUniqueKey(boolean isLeaf) {
 	char[] brackets = new char[dimensions];
 	for (int i = dimensions - 1; i >= 0; i--) brackets[i] = '[';
-	return CharOperation.concat(brackets, this.leafComponentType.computeUniqueKey(false/*without access flags*/));
+	return CharOperation.concat(brackets, this.leafComponentType.computeUniqueKey(isLeaf));
  }
 	
 /**
@@ -121,6 +117,31 @@
     return this.environment;
 }
 
+/**
+ * Find supertype which erases to a given type, or null if not found
+ */
+public TypeBinding findSuperTypeWithSameErasure(TypeBinding otherType) {
+
+	if (this == otherType) return this;
+	int otherDim = otherType.dimensions();
+	if (this.dimensions != otherDim) {
+		switch(otherType.id) {
+			case T_JavaLangObject :
+			case T_JavaIoSerializable :
+			case T_JavaLangCloneable :
+				return otherType;
+		}
+		if (otherDim < this.dimensions & otherType.leafComponentType().id == T_JavaLangObject) {
+			return otherType; // X[][] has Object[] as an implicit supertype
+		}
+		return null;
+	}
+	if (!(this.leafComponentType instanceof ReferenceBinding)) return null;
+	TypeBinding leafSuperType = ((ReferenceBinding)this.leafComponentType).findSuperTypeWithSameErasure(otherType.leafComponentType());
+	if (leafSuperType == null) return null;
+	return environment().createArrayType(leafSuperType, this.dimensions);	
+}
+
 public char[] genericTypeSignature() {
 	
     if (this.genericTypeSignature == null) {
@@ -134,33 +155,48 @@
 public PackageBinding getPackage() {
 	return leafComponentType.getPackage();
 }
+
 public int hashCode() {
 	return this.leafComponentType == null ? super.hashCode() : this.leafComponentType.hashCode();
 }
+
 /* Answer true if the receiver type can be assigned to the argument type (right)
 */
-public boolean isCompatibleWith(TypeBinding right) {
-	if (this == right)
+public boolean isCompatibleWith(TypeBinding otherType) {
+	if (this == otherType)
 		return true;
 
-	switch (right.kind()) {
+	switch (otherType.kind()) {
 		case Binding.ARRAY_TYPE :
-			ArrayBinding rightArray = (ArrayBinding) right;
-			if (rightArray.leafComponentType.isBaseType())
+			ArrayBinding otherArray = (ArrayBinding) otherType;
+			if (otherArray.leafComponentType.isBaseType())
 				return false; // relying on the fact that all equal arrays are identical
-			if (dimensions == rightArray.dimensions)
-				return leafComponentType.isCompatibleWith(rightArray.leafComponentType);
-			if (dimensions < rightArray.dimensions)
+			if (dimensions == otherArray.dimensions)
+				return leafComponentType.isCompatibleWith(otherArray.leafComponentType);
+			if (dimensions < otherArray.dimensions)
 				return false; // cannot assign 'String[]' into 'Object[][]' but can assign 'byte[][]' into 'Object[]'
 			break;
 		case Binding.BASE_TYPE :
 			return false;
 		case Binding.WILDCARD_TYPE :
-		    return ((WildcardBinding) right).boundCheck(this);
+		    return ((WildcardBinding) otherType).boundCheck(this);
+		    
+		case Binding.TYPE_PARAMETER :
+			// check compatibility with capture of ? super X
+			if (otherType.isCapture()) {
+				CaptureBinding otherCapture = (CaptureBinding) otherType;
+				TypeBinding otherLowerBound;
+				if ((otherLowerBound = otherCapture.lowerBound) != null) {
+					if (!otherLowerBound.isArrayType()) return false;					
+					return this.isCompatibleWith(otherLowerBound);
+				}
+			}
+			return false;
+
 	}
 	//Check dimensions - Java does not support explicitly sized dimensions for types.
 	//However, if it did, the type checking support would go here.
-	switch (right.leafComponentType().id) {
+	switch (otherType.leafComponentType().id) {
 	    case T_JavaLangObject :
 	    case T_JavaLangCloneable :
 	    case T_JavaIoSerializable :
@@ -169,6 +205,10 @@
 	return false;
 }
 
+public int kind() {
+	return ARRAY_TYPE;
+}
+
 public TypeBinding leafComponentType(){
 	return leafComponentType;
 }
@@ -177,7 +217,6 @@
 * Answer the problem id associated with the receiver.
 * NoError if the receiver is a valid binding.
 */
-
 public int problemId() {
 	return leafComponentType.problemId();
 }
@@ -221,7 +260,7 @@
 }
 public void swapUnresolved(UnresolvedReferenceBinding unresolvedType, ReferenceBinding resolvedType, LookupEnvironment env) {
 	if (this.leafComponentType == unresolvedType) {
-		this.leafComponentType = resolvedType.isGenericType() ? env.createRawType(resolvedType, resolvedType.enclosingType()) : resolvedType;
+		this.leafComponentType = env.convertToRawType(resolvedType);
 		this.tagBits |= this.leafComponentType.tagBits & (HasTypeVariable | HasDirectWildcard);
 	}
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BaseTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BaseTypeBinding.java
index 96f3d51..d4d76f6 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BaseTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BaseTypeBinding.java
@@ -26,7 +26,7 @@
 	/**
 	 * int -> I
 	 */
-	public char[] computeUniqueKey(boolean withAccessFlags) {
+	public char[] computeUniqueKey(boolean isLeaf) {
 		return constantPoolName();
 	}
 	
@@ -136,7 +136,13 @@
 				return false;
 		}
 	}
-
+	/**
+	 * T_null is acting as an unchecked exception
+	 * @see org.eclipse.jdt.internal.compiler.lookup.TypeBinding#isUncheckedException(boolean)
+	 */
+	public boolean isUncheckedException(boolean includeSupertype) {
+		return this == NullBinding;
+	}
 	public static final boolean isWidening(int left, int right) {
 
 		//can "left" store a "right" using some widening conversion
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java
index 9cbcb0d..9f8ff61 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java
@@ -54,8 +54,8 @@
 	if (type.isWildcard())
 		return ((WildcardBinding) type).resolve();
 
-	if (convertGenericToRawType && type.isGenericType()) // raw reference to generic ?
-	    return environment.createRawType(type, type.enclosingType());
+	if (convertGenericToRawType) // raw reference to generic ?
+		return (ReferenceBinding) environment.convertToRawType(type);
 	return type;
 }
 public static TypeBinding resolveType(TypeBinding type, LookupEnvironment environment, ParameterizedTypeBinding parameterizedType, int rank) {
@@ -77,7 +77,7 @@
 						
 		case Binding.GENERIC_TYPE :
 			if (parameterizedType == null) // raw reference to generic ?
-			    return environment.createRawType((ReferenceBinding) type, type.enclosingType());
+				return environment.convertToRawType(type);
 			break;
 			
 		default:			
@@ -108,7 +108,7 @@
 	this.fPackage = packageBinding;
 	this.fileName = binaryType.getFileName();
 
-	char[] typeSignature = environment.options.sourceLevel >= ClassFileConstants.JDK1_5 ? binaryType.getGenericSignature() : null;
+	char[] typeSignature = environment.globalOptions.sourceLevel >= ClassFileConstants.JDK1_5 ? binaryType.getGenericSignature() : null;
 	this.typeVariables = typeSignature != null && typeSignature.length > 0 && typeSignature[0] == '<'
 		? null // is initialized in cachePartsFrom (called from LookupEnvironment.createBinaryTypeFrom())... must set to null so isGenericType() answers true
 		: NoTypeVariables;
@@ -134,6 +134,18 @@
 	} else if (binaryType.isMember()) {
 		this.tagBits |= MemberTypeMask;
 	}
+	// need enclosing type to access type variables
+	char[] enclosingTypeName = binaryType.getEnclosingTypeName();
+	if (enclosingTypeName != null) {
+		// attempt to find the enclosing type if it exists in the cache (otherwise - resolve it when requested)
+		this.enclosingType = environment.getTypeFromConstantPoolName(enclosingTypeName, 0, -1, true); // pretend parameterized to avoid raw
+		this.tagBits |= MemberTypeMask;   // must be a member type not a top-level or local type
+		this.tagBits |= 	HasUnresolvedEnclosingType;
+		if (this.enclosingType().isStrictfp())
+			this.modifiers |= AccStrictfp;
+		if (this.enclosingType().isDeprecated())
+			this.modifiers |= AccDeprecatedImplicitly;
+	}	
 }
 
 public FieldBinding[] availableFields() {
@@ -178,20 +190,7 @@
 	this.typeVariables = NoTypeVariables;
 	this.superInterfaces = NoSuperInterfaces;
 
-	// need enclosing type to access type variables
-	char[] enclosingTypeName = binaryType.getEnclosingTypeName();
-	if (enclosingTypeName != null) {
-		// attempt to find the enclosing type if it exists in the cache (otherwise - resolve it when requested)
-		this.enclosingType = environment.getTypeFromConstantPoolName(enclosingTypeName, 0, -1, true); // pretend parameterized to avoid raw
-		this.tagBits |= MemberTypeMask;   // must be a member type not a top-level or local type
-		this.tagBits |= 	HasUnresolvedEnclosingType;
-		if (this.enclosingType().isStrictfp())
-			this.modifiers |= AccStrictfp;
-		if (this.enclosingType().isDeprecated())
-			this.modifiers |= AccDeprecatedImplicitly;
-	}
-
-	long sourceLevel = environment.options.sourceLevel;
+	long sourceLevel = environment.globalOptions.sourceLevel;
 	char[] typeSignature = null;
 	if (sourceLevel >= ClassFileConstants.JDK1_5) {
 		typeSignature = binaryType.getGenericSignature();
@@ -293,6 +292,8 @@
 					field.tagBits |= binaryField.getTagBits();
 				if (isViewedAsDeprecated && !field.isDeprecated())
 					field.modifiers |= AccDeprecatedImplicitly;
+				if (fieldSignature != null)
+					field.modifiers |= AccGenericSignature;
 				this.fields[i] = field;
 			}
 		}
@@ -353,6 +354,7 @@
 		if (!method.isConstructor())
 			returnType = environment.getTypeFromSignature(methodDescriptor, index + 1, -1, false, this);   // index is currently pointing at the ')'
 	} else {
+		methodModifiers |= AccGenericSignature;
 		// MethodTypeSignature = ParameterPart(optional) '(' TypeSignatures ')' return_typeSignature ['^' TypeSignature (optional)]
 		SignatureWrapper wrapper = new SignatureWrapper(methodSignature);
 		if (wrapper.signature[wrapper.start] == '<') {
@@ -794,72 +796,75 @@
 	return this.typeVariables;
 }
 public String toString() {
-	String s = ""; //$NON-NLS-1$
+	StringBuffer buffer = new StringBuffer();
 
-	if (isDeprecated()) s += "deprecated "; //$NON-NLS-1$
-	if (isPublic()) s += "public "; //$NON-NLS-1$
-	if (isProtected()) s += "protected "; //$NON-NLS-1$
-	if (isPrivate()) s += "private "; //$NON-NLS-1$
-	if (isAbstract() && isClass()) s += "abstract "; //$NON-NLS-1$
-	if (isStatic() && isNestedType()) s += "static "; //$NON-NLS-1$
-	if (isFinal()) s += "final "; //$NON-NLS-1$
+	if (isDeprecated()) buffer.append("deprecated "); //$NON-NLS-1$
+	if (isPublic()) buffer.append("public "); //$NON-NLS-1$
+	if (isProtected()) buffer.append("protected "); //$NON-NLS-1$
+	if (isPrivate()) buffer.append("private "); //$NON-NLS-1$
+	if (isAbstract() && isClass()) buffer.append("abstract "); //$NON-NLS-1$
+	if (isStatic() && isNestedType()) buffer.append("static "); //$NON-NLS-1$
+	if (isFinal()) buffer.append("final "); //$NON-NLS-1$
 
-	s += isInterface() ? "interface " : "class "; //$NON-NLS-1$ //$NON-NLS-2$
-	s += (compoundName != null) ? CharOperation.toString(compoundName) : "UNNAMED TYPE"; //$NON-NLS-1$
+	if (isEnum()) buffer.append("enum "); //$NON-NLS-1$
+	else if (isAnnotationType()) buffer.append("@interface "); //$NON-NLS-1$
+	else if (isClass()) buffer.append("class "); //$NON-NLS-1$
+	else buffer.append("interface "); //$NON-NLS-1$	
+	buffer.append((compoundName != null) ? CharOperation.toString(compoundName) : "UNNAMED TYPE"); //$NON-NLS-1$
 
-	s += "\n\textends "; //$NON-NLS-1$
-	s += (superclass != null) ? superclass.debugName() : "NULL TYPE"; //$NON-NLS-1$
+	buffer.append("\n\textends "); //$NON-NLS-1$
+	buffer.append((superclass != null) ? superclass.debugName() : "NULL TYPE"); //$NON-NLS-1$
 
 	if (superInterfaces != null) {
 		if (superInterfaces != NoSuperInterfaces) {
-			s += "\n\timplements : "; //$NON-NLS-1$
+			buffer.append("\n\timplements : "); //$NON-NLS-1$
 			for (int i = 0, length = superInterfaces.length; i < length; i++) {
 				if (i  > 0)
-					s += ", "; //$NON-NLS-1$
-				s += (superInterfaces[i] != null) ? superInterfaces[i].debugName() : "NULL TYPE"; //$NON-NLS-1$
+					buffer.append(", "); //$NON-NLS-1$
+				buffer.append((superInterfaces[i] != null) ? superInterfaces[i].debugName() : "NULL TYPE"); //$NON-NLS-1$
 			}
 		}
 	} else {
-		s += "NULL SUPERINTERFACES"; //$NON-NLS-1$
+		buffer.append("NULL SUPERINTERFACES"); //$NON-NLS-1$
 	}
 
 	if (enclosingType != null) {
-		s += "\n\tenclosing type : "; //$NON-NLS-1$
-		s += enclosingType.debugName();
+		buffer.append("\n\tenclosing type : "); //$NON-NLS-1$
+		buffer.append(enclosingType.debugName());
 	}
 
 	if (fields != null) {
 		if (fields != NoFields) {
-			s += "\n/*   fields   */"; //$NON-NLS-1$
+			buffer.append("\n/*   fields   */"); //$NON-NLS-1$
 			for (int i = 0, length = fields.length; i < length; i++)
-				s += (fields[i] != null) ? "\n" + fields[i].toString() : "\nNULL FIELD"; //$NON-NLS-1$ //$NON-NLS-2$
+				buffer.append((fields[i] != null) ? "\n" + fields[i].toString() : "\nNULL FIELD"); //$NON-NLS-1$ //$NON-NLS-2$
 		}
 	} else {
-		s += "NULL FIELDS"; //$NON-NLS-1$
+		buffer.append("NULL FIELDS"); //$NON-NLS-1$
 	}
 
 	if (methods != null) {
 		if (methods != NoMethods) {
-			s += "\n/*   methods   */"; //$NON-NLS-1$
+			buffer.append("\n/*   methods   */"); //$NON-NLS-1$
 			for (int i = 0, length = methods.length; i < length; i++)
-				s += (methods[i] != null) ? "\n" + methods[i].toString() : "\nNULL METHOD"; //$NON-NLS-1$ //$NON-NLS-2$
+				buffer.append((methods[i] != null) ? "\n" + methods[i].toString() : "\nNULL METHOD"); //$NON-NLS-1$ //$NON-NLS-2$
 		}
 	} else {
-		s += "NULL METHODS"; //$NON-NLS-1$
+		buffer.append("NULL METHODS"); //$NON-NLS-1$
 	}
 
 	if (memberTypes != null) {
 		if (memberTypes != NoMemberTypes) {
-			s += "\n/*   members   */"; //$NON-NLS-1$
+			buffer.append("\n/*   members   */"); //$NON-NLS-1$
 			for (int i = 0, length = memberTypes.length; i < length; i++)
-				s += (memberTypes[i] != null) ? "\n" + memberTypes[i].toString() : "\nNULL TYPE"; //$NON-NLS-1$ //$NON-NLS-2$
+				buffer.append((memberTypes[i] != null) ? "\n" + memberTypes[i].toString() : "\nNULL TYPE"); //$NON-NLS-1$ //$NON-NLS-2$
 		}
 	} else {
-		s += "NULL MEMBER TYPES"; //$NON-NLS-1$
+		buffer.append("NULL MEMBER TYPES"); //$NON-NLS-1$
 	}
 
-	s += "\n\n\n"; //$NON-NLS-1$
-	return s;
+	buffer.append("\n\n\n"); //$NON-NLS-1$
+	return buffer.toString();
 }
 MethodBinding[] unResolvedMethods() { // for the MethodVerifier so it doesn't resolve types
 	return methods;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java
index 389003f..e7bc26b 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java
@@ -30,9 +30,6 @@
 	public static final int GENERIC_TYPE = TYPE | ASTNode.Bit12;
 	public static final int TYPE_PARAMETER = TYPE | ASTNode.Bit13;
 	
-	// TODO (jerome) change to true to fix https://bugs.eclipse.org/bugs/show_bug.cgi?id=90392
-	public static boolean USE_ACCESS_FLAGS_IN_BINDING_KEY = false;
-	
 	/* API
 	* Answer the receiver's binding type from Binding.BindingID.
 	*
@@ -45,13 +42,13 @@
 	 * Returns null if binding is not a TypeBinding, a MethodBinding, a FieldBinding or a PackageBinding.
 	 */
 	public char[] computeUniqueKey() {
-		return computeUniqueKey(USE_ACCESS_FLAGS_IN_BINDING_KEY/*without access flags*/);
+		return computeUniqueKey(true/*leaf*/);
 	}
 	/*
 	 * Computes a key that uniquely identifies this binding. Optinaly include access flags.
 	 * Returns null if binding is not a TypeBinding, a MethodBinding, a FieldBinding or a PackageBinding.
 	 */
-	public char[] computeUniqueKey(boolean withAccessFlags) {
+	public char[] computeUniqueKey(boolean isLeaf) {
 		return null;
 	}
 	
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java
index 4562dac..bd18bac 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java
@@ -152,8 +152,7 @@
 		if (methodScope.isStatic != binding.isStatic())
 			return false;
 		return methodScope.isInsideInitializer() // inside initializer
-				|| ((AbstractMethodDeclaration) methodScope.referenceContext)
-					.isInitializationMethod(); // inside constructor or clinit
+				|| ((AbstractMethodDeclaration) methodScope.referenceContext).isInitializationMethod(); // inside constructor or clinit
 	}
 	String basicToString(int tab) {
 		String newLine = "\n"; //$NON-NLS-1$
@@ -235,7 +234,7 @@
 				
 				// could be optimized out, but does need to preserve unread variables ?
 				if (!generateCurrentLocalVar) {
-					if (local.declaration != null && environment().options.preserveAllLocalVariables) {
+					if (local.declaration != null && compilerOptions().preserveAllLocalVariables) {
 						generateCurrentLocalVar = true; // force it to be preserved in the generated code
 						local.useFlag = LocalVariableBinding.USED;
 					}
@@ -320,7 +319,7 @@
 	 */
 	public final ReferenceBinding findLocalType(char[] name) {
 
-		long compliance = environment().options.complianceLevel;
+		long compliance = compilerOptions().complianceLevel;
 		for (int i = 0, length = subscopeCount; i < length; i++) {
 			if (subscopes[i] instanceof ClassScope) {
 				LocalTypeBinding sourceType = (LocalTypeBinding)((ClassScope) subscopes[i]).referenceContext.binding;
@@ -402,6 +401,7 @@
 						// must be a type if its the last name, otherwise we have no idea if its a package or type
 						return new ProblemReferenceBinding(
 							CharOperation.subarray(compoundName, 0, currentIndex),
+							null,
 							NotFound);
 					}
 					return new ProblemBinding(
@@ -412,6 +412,7 @@
 					if (!binding.isValidBinding())
 						return new ProblemReferenceBinding(
 							CharOperation.subarray(compoundName, 0, currentIndex),
+							null, // TODO should improve
 							binding.problemId());
 					if (!((ReferenceBinding) binding).canBeSeenBy(this))
 						return new ProblemReferenceBinding(
@@ -426,10 +427,12 @@
 			// It is illegal to request a PACKAGE from this method.
 			return new ProblemReferenceBinding(
 				CharOperation.subarray(compoundName, 0, currentIndex),
+				null,
 				NotFound);
 		}
 
 		// know binding is now a ReferenceBinding
+		binding = environment().convertToRawType((ReferenceBinding) binding);
 		while (currentIndex < length) {
 			ReferenceBinding typeBinding = (ReferenceBinding) binding;
 			char[] nextName = compoundName[currentIndex++];
@@ -438,7 +441,7 @@
 			if ((mask & Binding.FIELD) != 0 && (binding = findField(typeBinding, nextName, invocationSite, true /*resolve*/)) != null) {
 				if (!binding.isValidBinding())
 					return new ProblemFieldBinding(
-						((FieldBinding) binding).declaringClass,
+						(FieldBinding)binding,
 						CharOperation.subarray(compoundName, 0, currentIndex),
 						binding.problemId());
 				break; // binding is now a field
@@ -458,6 +461,7 @@
 			if (!binding.isValidBinding())
 				return new ProblemReferenceBinding(
 					CharOperation.subarray(compoundName, 0, currentIndex),
+					null, // TODO should improve
 					binding.problemId());
 		}
 		if ((mask & Binding.FIELD) != 0 && (binding instanceof FieldBinding)) {
@@ -465,7 +469,7 @@
 			FieldBinding field = (FieldBinding) binding;
 			if (!field.isStatic())
 				return new ProblemFieldBinding(
-					field.declaringClass,
+					field,
 					CharOperation.subarray(compoundName, 0, currentIndex),
 					NonStaticReferenceInStaticContext);
 			return binding;
@@ -505,6 +509,7 @@
 						// must be a type if its the last name, otherwise we have no idea if its a package or type
 						return new ProblemReferenceBinding(
 							CharOperation.subarray(compoundName, 0, currentIndex),
+							null,
 							NotFound);
 					}
 					return new ProblemBinding(
@@ -515,6 +520,7 @@
 					if (!binding.isValidBinding())
 						return new ProblemReferenceBinding(
 							CharOperation.subarray(compoundName, 0, currentIndex),
+							null, // TODO should improve
 							binding.problemId());
 					if (!((ReferenceBinding) binding).canBeSeenBy(this))
 						return new ProblemReferenceBinding(
@@ -534,12 +540,12 @@
 				if ((binding = findField(typeBinding, nextName, invocationSite, true /*resolve*/)) != null) {
 					if (!binding.isValidBinding())
 						return new ProblemFieldBinding(
-							((FieldBinding) binding).declaringClass,
+							(FieldBinding) binding,
 							CharOperation.subarray(compoundName, 0, currentIndex),
 							binding.problemId());
 					if (!((FieldBinding) binding).isStatic())
 						return new ProblemFieldBinding(
-							((FieldBinding) binding).declaringClass,
+							(FieldBinding) binding,
 							CharOperation.subarray(compoundName, 0, currentIndex),
 							NonStaticReferenceInStaticContext);
 					break foundField; // binding is now a field
@@ -552,6 +558,7 @@
 				if (!binding.isValidBinding())
 					return new ProblemReferenceBinding(
 						CharOperation.subarray(compoundName, 0, currentIndex),
+						null, // TODO should improve
 						binding.problemId());
 			}
 			return binding;
@@ -645,7 +652,7 @@
 
 		// use 'this' if possible
 		if (!currentMethodScope.isStatic && !currentMethodScope.isConstructorCall) {
-			if (sourceType == targetEnclosingType || (!onlyExactMatch && sourceType.findSuperTypeErasingTo(targetEnclosingType) != null)) {
+			if (sourceType == targetEnclosingType || (!onlyExactMatch && sourceType.findSuperTypeWithSameErasure(targetEnclosingType) != null)) {
 				return EmulationPathToImplicitThis; // implicit this is good enough
 			}
 		}
@@ -665,7 +672,7 @@
 				// reject allocation and super constructor call
 				if (denyEnclosingArgInConstructorCall
 						&& currentMethodScope.isConstructorCall 
-						&& (sourceType == targetEnclosingType || (!onlyExactMatch && sourceType.findSuperTypeErasingTo(targetEnclosingType) != null))) {
+						&& (sourceType == targetEnclosingType || (!onlyExactMatch && sourceType.findSuperTypeWithSameErasure(targetEnclosingType) != null))) {
 					return NoEnclosingInstanceInConstructorCall;
 				}
 				return new Object[] { syntheticArg };
@@ -684,7 +691,7 @@
 				if (enclosingArgument != null) {
 					FieldBinding syntheticField = sourceType.getSyntheticField(enclosingArgument);
 					if (syntheticField != null) {
-						if (syntheticField.type == targetEnclosingType || (!onlyExactMatch && ((ReferenceBinding)syntheticField.type).findSuperTypeErasingTo(targetEnclosingType) != null))
+						if (syntheticField.type == targetEnclosingType || (!onlyExactMatch && ((ReferenceBinding)syntheticField.type).findSuperTypeWithSameErasure(targetEnclosingType) != null))
 							return new Object[] { syntheticField };
 					}
 				}
@@ -717,7 +724,7 @@
 
 				//done?
 				if (currentType == targetEnclosingType
-					|| (!onlyExactMatch && currentType.findSuperTypeErasingTo(targetEnclosingType) != null))	break;
+					|| (!onlyExactMatch && currentType.findSuperTypeWithSameErasure(targetEnclosingType) != null))	break;
 
 				if (currentMethodScope != null) {
 					currentMethodScope = currentMethodScope.enclosingMethodScope();
@@ -741,7 +748,7 @@
 				currentType = currentEnclosingType;
 			}
 			if (currentType == targetEnclosingType
-				|| (!onlyExactMatch && currentType.findSuperTypeErasingTo(targetEnclosingType) != null)) {
+				|| (!onlyExactMatch && currentType.findSuperTypeWithSameErasure(targetEnclosingType) != null)) {
 				return path;
 			}
 		}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java
index 49db10a..226704d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java
@@ -18,46 +18,38 @@
 	public TypeBinding lowerBound;
 	public WildcardBinding wildcard;
 	
-	public CaptureBinding(WildcardBinding wildcard) {
+	/* information to compute unique binding key */
+	public ReferenceBinding sourceType;
+	public int position;
+	
+	public CaptureBinding(WildcardBinding wildcard, ReferenceBinding sourceType, int position) {
 		super(WILDCARD_CAPTURE_NAME, null, 0);
 		this.wildcard = wildcard;
 		this.modifiers = AccPublic | AccGenericSignature; // treat capture as public
 		this.fPackage = wildcard.fPackage;
-		
-		TypeVariableBinding wildcardVariable = wildcard.typeVariable();
-		switch (wildcard.boundKind) {
-			case Wildcard.EXTENDS :
-				this.superclass = wildcard.superclass();
-				this.firstBound = wildcard.bound;
-				ReferenceBinding[] wildcardInterfaces = wildcard.superInterfaces();
-				if (wildcardInterfaces == NoSuperInterfaces) {
-					this.superInterfaces = NoSuperInterfaces;
-				} else {
-					this.superInterfaces = Scope.greaterLowerBound(wildcardInterfaces);
-				}
-				if ((wildcard.bound.tagBits & HasTypeVariable) == 0)
-					this.tagBits &= ~HasTypeVariable;
-				break;
-			case Wildcard.UNBOUND :
-				this.superclass = wildcardVariable.superclass();
-				this.superInterfaces = wildcardVariable.superInterfaces();
-				this.tagBits &= ~HasTypeVariable;
-				break;
-			case Wildcard.SUPER :
-				this.superclass = wildcardVariable.superclass();
-				if (wildcardVariable.firstBound == this.superclass || wildcard.bound == this.superclass) {
-					this.firstBound = this.superclass;
-				}
-				this.superInterfaces = wildcardVariable.superInterfaces();
-				this.lowerBound = wildcard.bound;
-				if ((wildcard.bound.tagBits & HasTypeVariable) == 0)
-					this.tagBits &= ~HasTypeVariable;
-				break;
-		}
+		this.sourceType = sourceType;
+		this.position = position;
 	}
 
-	public char[] computeUniqueKey(boolean withAccessFlags) {
-		return CharOperation.concat(WILDCARD_CAPTURE, this.wildcard.computeUniqueKey(withAccessFlags));
+	/*
+	 * sourceTypeKey ! wildcardKey position semi-colon
+	 * p.X { capture of ? } --> !*123; (Lp/X; in declaring type except if leaf)
+	 * p.X { capture of ? extends p.Y } --> !+Lp/Y;123; (Lp/X; in declaring type except if leaf)
+	 */
+	public char[] computeUniqueKey(boolean isLeaf) {
+		StringBuffer buffer = new StringBuffer();
+		if (isLeaf) {
+			buffer.append(this.sourceType.computeUniqueKey(false/*not a leaf*/));
+			buffer.append('&');
+		}
+		buffer.append(WILDCARD_CAPTURE);
+		buffer.append(this.wildcard.computeUniqueKey(false/*not a leaf*/));
+		buffer.append(this.position);
+		buffer.append(';');
+		int length = buffer.length();
+		char[] uniqueKey = new char[length];
+		buffer.getChars(0, length, uniqueKey, 0);
+		return uniqueKey;
 	}	
 
 	public String debugName() {
@@ -73,6 +65,71 @@
 		}
 		return this.genericTypeSignature;
 	}
+
+	/**
+	 * Initialize capture bounds using substituted supertypes
+	 * e.g. given X<U, V extends X<U, V>>,     capture(X<E,?>) = X<E,capture>, where capture extends X<E,capture>
+	 */
+	public void initializeBounds(ParameterizedTypeBinding capturedParameterizedType) {
+		TypeVariableBinding wildcardVariable = wildcard.typeVariable();
+		ReferenceBinding originalVariableSuperclass = wildcardVariable.superclass;
+		ReferenceBinding substitutedVariableSuperclass = (ReferenceBinding) Scope.substitute(capturedParameterizedType, originalVariableSuperclass);
+		// prevent cyclic capture: given X<T>, capture(X<? extends T> could yield a circular type
+		if (substitutedVariableSuperclass == this) substitutedVariableSuperclass = originalVariableSuperclass;
+		
+		ReferenceBinding[] originalVariableInterfaces = wildcardVariable.superInterfaces();		
+		ReferenceBinding[] substitutedVariableInterfaces = Scope.substitute(capturedParameterizedType, originalVariableInterfaces);
+		if (substitutedVariableInterfaces != originalVariableInterfaces) {
+			// prevent cyclic capture: given X<T>, capture(X<? extends T> could yield a circular type
+			for (int i = 0, length = substitutedVariableInterfaces.length; i < length; i++) {
+				if (substitutedVariableInterfaces[i] == this) substitutedVariableInterfaces[i] = originalVariableInterfaces[i];
+			}
+		}
+		// no substitution for wildcard bound (only formal bounds from type variables are to be substituted: 104082)
+		TypeBinding originalWildcardBound = wildcard.bound;
+		// prevent cyclic capture: given X<T>, capture(X<? extends T> could yield a circular type
+//		TypeBinding substitutedWildcardBound = originalWildcardBound == null ? null : Scope.substitute(capturedParameterizedType, originalWildcardBound);
+//		if (substitutedWildcardBound == this) substitutedWildcardBound = originalWildcardBound;
+		
+		switch (wildcard.boundKind) {
+			case Wildcard.EXTENDS :
+				if (wildcard.bound.isInterface()) {
+					this.superclass = substitutedVariableSuperclass;
+					// merge wildcard bound into variable superinterfaces using glb
+					if (substitutedVariableInterfaces == NoSuperInterfaces) {
+						this.superInterfaces = new ReferenceBinding[] { (ReferenceBinding) originalWildcardBound };
+					} else {
+						int length = substitutedVariableInterfaces.length;
+						System.arraycopy(substitutedVariableInterfaces, 0, substitutedVariableInterfaces = new ReferenceBinding[length+1], 1, length);
+						substitutedVariableInterfaces[0] =  (ReferenceBinding) originalWildcardBound;
+						this.superInterfaces = Scope.greaterLowerBound(substitutedVariableInterfaces);
+					}
+				} else {
+					// per construction the wildcard bound is a subtype of variable superclass
+					this.superclass = wildcard.bound.isArrayType() ? substitutedVariableSuperclass : (ReferenceBinding)originalWildcardBound;
+					this.superInterfaces = substitutedVariableInterfaces;
+				}
+				this.firstBound =  originalWildcardBound;
+				if ((originalWildcardBound.tagBits & HasTypeVariable) == 0)
+					this.tagBits &= ~HasTypeVariable;
+				break;
+			case Wildcard.UNBOUND :
+				this.superclass = substitutedVariableSuperclass;
+				this.superInterfaces = substitutedVariableInterfaces;
+				this.tagBits &= ~HasTypeVariable;
+				break;
+			case Wildcard.SUPER :
+				this.superclass = substitutedVariableSuperclass;
+				if (wildcardVariable.firstBound == substitutedVariableSuperclass || originalWildcardBound == substitutedVariableSuperclass) {
+					this.firstBound = substitutedVariableSuperclass;
+				}
+				this.superInterfaces = substitutedVariableInterfaces;
+				this.lowerBound = originalWildcardBound;
+				if ((originalWildcardBound.tagBits & HasTypeVariable) == 0)
+					this.tagBits &= ~HasTypeVariable;
+				break;
+		}		
+	}
 	
 	/**
 	 * @see org.eclipse.jdt.internal.compiler.lookup.TypeBinding#isCapture()
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java
index b24595d..c58b20b 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java
@@ -10,11 +10,14 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.lookup;
 
+import java.util.*;
+
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.ast.ASTNode;
 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression;
 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.TypeParameter;
 import org.eclipse.jdt.internal.compiler.ast.TypeReference;
@@ -26,8 +29,9 @@
 import org.eclipse.jdt.internal.compiler.util.HashtableOfObject;
 
 public class ClassScope extends Scope {
+	
 	public TypeDeclaration referenceContext;
-	private TypeReference superTypeReference;
+	public TypeReference superTypeReference;
 
 	private final static char[] IncompleteHierarchy = new char[] {'h', 'a', 's', ' ', 'i', 'n', 'c', 'o', 'n', 's', 'i', 's', 't', 'e', 'n', 't', ' ', 'h', 'i', 'e', 'r', 'a', 'r', 'c', 'h', 'y'};
 
@@ -334,7 +338,7 @@
 		TypeParameter[] typeParameters = referenceContext.typeParameters;
 		
 	    // do not construct type variables if source < 1.5
-		if (typeParameters == null || environment().options.sourceLevel < ClassFileConstants.JDK1_5) {
+		if (typeParameters == null || compilerOptions().sourceLevel < ClassFileConstants.JDK1_5) {
 		    sourceType.typeVariables = NoTypeVariables;
 		    return;
 		}
@@ -356,9 +360,8 @@
 		ReferenceBinding enclosingType = sourceType.enclosingType();
 		boolean isMemberType = sourceType.isMemberType();
 		if (isMemberType) {
+			modifiers |= (enclosingType.modifiers & (AccGenericSignature|AccStrictfp));
 			// checks for member types before local types to catch local members
-			if (enclosingType.isStrictfp())
-				modifiers |= AccStrictfp;
 			if (enclosingType.isInterface())
 				modifiers |= AccPublic;
 			if (sourceType.isEnum()) {
@@ -466,9 +469,36 @@
 					problemReporter().illegalModifierForEnum(sourceType);
 			}
 
-// what about inherited interface methods?
-			if ((referenceContext.bits & ASTNode.HasAbstractMethods) != 0)
+			// what about inherited interface methods?
+			if ((referenceContext.bits & ASTNode.HasAbstractMethods) != 0) {
 				modifiers |= AccAbstract;
+			} else if (!sourceType.isAnonymousType()) {
+				// body of enum constant must implement any inherited abstract methods
+				// enum type needs to implement abstract methods if one of its constants does not supply a body
+				checkAbstractEnum: {
+					TypeDeclaration typeDeclaration = this.referenceContext;
+					FieldDeclaration[] fields = typeDeclaration.fields;
+					int fieldsLength = fields == null ? 0 : fields.length;
+					if (fieldsLength == 0) break checkAbstractEnum; // has no constants so must implement the method itself
+					AbstractMethodDeclaration[] methods = typeDeclaration.methods;
+					int methodsLength = methods == null ? 0 : methods.length;
+					// TODO (kent) cannot tell that the superinterfaces are empty or that their methods are implemented
+					boolean definesAbstractMethod = typeDeclaration.superInterfaces != null;
+					for (int i = 0; i < methodsLength && !definesAbstractMethod; i++)
+						definesAbstractMethod = methods[i].isAbstract();
+					if (!definesAbstractMethod) break checkAbstractEnum; // all methods have bodies
+					for (int i = 0; i < fieldsLength; i++) {
+						FieldDeclaration fieldDecl = fields[i];
+						if (fieldDecl.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT)
+							if (!(fieldDecl.initialization instanceof QualifiedAllocationExpression))
+								break checkAbstractEnum;
+					}
+					// tag this enum as abstract since an abstract method must be implemented AND all enum constants define an anonymous body
+					// as a result, each of its anonymous constants will see it as abstract and must implement each inherited abstract method					
+					modifiers |= AccAbstract;
+				}
+			}
+			modifiers |= AccFinal;
 		} else {
 			// detect abnormal cases for classes
 			if (isMemberType) { // includes member types defined inside local types
@@ -566,6 +596,8 @@
 		
 			// set the modifiers
 			int implicitValue = AccPublic | AccStatic | AccFinal | AccEnum;
+			if (fieldDecl.initialization instanceof QualifiedAllocationExpression)
+				declaringClass.modifiers &= ~AccFinal;
 			fieldBinding.modifiers|= implicitValue;
 			return;
 		}
@@ -660,7 +692,7 @@
 		} while ((currentType = currentType.superclass()) != null && (currentType.tagBits & HasNoMemberTypes) == 0);
 	}
 	// Perform deferred bound checks for parameterized type references (only done after hierarchy is connected)
-	private void  checkParameterizedTypeBounds() {
+	public void  checkParameterizedTypeBounds() {
 		TypeReference superclass = referenceContext.superclass;
 		if (superclass != null) {
 			superclass.checkBounds(this);
@@ -677,6 +709,12 @@
 				typeParameters[i].checkBounds(this);
 			}
 		}
+		// propagate to member types
+		ReferenceBinding[] memberTypes = referenceContext.binding.memberTypes;
+		if (memberTypes != null && memberTypes != NoMemberTypes) {
+			for (int i = 0, size = memberTypes.length; i < size; i++)
+				 ((SourceTypeBinding) memberTypes[i]).scope.checkParameterizedTypeBounds();
+		}		
 	}
 
 	private void connectMemberTypes() {
@@ -710,7 +748,7 @@
 			return true; // do not propagate Object's hierarchy problems down to every subtype
 		}
 		if (referenceContext.superclass == null) {
-			if (sourceType.isEnum() && environment().options.sourceLevel >= JDK1_5) // do not connect if source < 1.5 as enum already got flagged as syntax error
+			if (sourceType.isEnum() && compilerOptions().sourceLevel >= JDK1_5) // do not connect if source < 1.5 as enum already got flagged as syntax error
 				return connectEnumSuperclass();
 			sourceType.superclass = getJavaLangObject();
 			return !detectHierarchyCycle(sourceType, sourceType.superclass, null);
@@ -756,12 +794,12 @@
 			return false; // cannot reach here as AbortCompilation is thrown
 		}			
 		// check argument type compatibility
-		ParameterizedTypeBinding  superType = createParameterizedType(rootEnumType, new TypeBinding[]{ sourceType } , null);
+		ParameterizedTypeBinding  superType = environment().createParameterizedType(rootEnumType, new TypeBinding[]{ environment().convertToRawType(sourceType) } , null);
 		sourceType.superclass = superType;
-		// bound check
+		// bound check (in case of bogus definition of Enum type)
 		if (refTypeVariables[0].boundCheck(superType, sourceType) != TypeConstants.OK) {
 			problemReporter().typeMismatchError(rootEnumType, refTypeVariables[0], sourceType, null);
-		}
+		}		
 		return !foundCycle;
 	}
 
@@ -779,7 +817,7 @@
 		SourceTypeBinding sourceType = referenceContext.binding;
 		sourceType.superInterfaces = NoSuperInterfaces;
 		if (referenceContext.superInterfaces == null) {
-			if (sourceType.isAnnotationType() && environment().options.sourceLevel >= JDK1_5) { // do not connect if source < 1.5 as annotation already got flagged as syntax error) {
+			if (sourceType.isAnnotationType() && compilerOptions().sourceLevel >= JDK1_5) { // do not connect if source < 1.5 as annotation already got flagged as syntax error) {
 				ReferenceBinding annotationType = getJavaLangAnnotationAnnotation();
 				boolean foundCycle = detectHierarchyCycle(sourceType, annotationType, null);
 				sourceType.superInterfaces = new ReferenceBinding[] { annotationType };
@@ -803,10 +841,11 @@
 				continue nextInterface;
 			}
 			superInterfaceRef.resolvedType = superInterface; // hold onto the problem type
+			// check for simple interface collisions 
 			// Check for a duplicate interface once the name is resolved, otherwise we may be confused (ie : a.b.I and c.d.I)
-			for (int k = 0; k < count; k++) {
-				if (interfaceBindings[k].erasure() == superInterface.erasure()) {
-					problemReporter().duplicateSuperinterface(sourceType, referenceContext, (ReferenceBinding) superInterface.erasure());
+			for (int j = 0; j < i; j++) {
+				if (interfaceBindings[j] == superInterface) {
+					problemReporter().duplicateSuperinterface(sourceType, superInterfaceRef, superInterface);
 					continue nextInterface;
 				}
 			}
@@ -824,22 +863,64 @@
 				noProblems = false;
 				continue nextInterface;
 			}
-			ReferenceBinding invalid = findAmbiguousInterface(superInterface, sourceType);
-			if (invalid != null) {
-				ReferenceBinding generic = null;
-				if (superInterface.isParameterizedType())
-					generic = ((ParameterizedTypeBinding) superInterface).type;
-				else if (invalid.isParameterizedType())
-					generic = ((ParameterizedTypeBinding) invalid).type;
-				problemReporter().superinterfacesCollide(generic, referenceContext, superInterface, invalid);
-				sourceType.tagBits |= HierarchyHasProblems;
-				noProblems = false;
-				continue nextInterface;
-			}
-
 			// only want to reach here when no errors are reported
 			interfaceBindings[count++] = superInterface;
 		}
+		// check for parameterized interface collisions (when different parameterizations occur)
+		if (compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) {
+			TypeBinding[] types = new TypeBinding[2];
+			Map invocations = new HashMap(2);
+			nextInterface: for (int i = 0; i < count; i++) {
+				ReferenceBinding superInterface =  interfaceBindings[i];
+				// check against superclass
+				if (!sourceType.isInterface()) {
+					types[0] = sourceType.superclass;
+					types[1] = superInterface;
+					TypeBinding[] mecs = minimalErasedCandidates(types, invocations);
+					if (mecs != null) {
+						nextCandidate: for (int k = 0, max = mecs.length; k < max; k++) {
+							TypeBinding mec = mecs[k];
+							if (mec == null) continue nextCandidate;
+							Set invalidInvocations = (Set)invocations.get(mec);
+							int invalidSize = invalidInvocations.size();
+							if (invalidSize > 1) {
+								TypeBinding[] collisions;
+								invalidInvocations.toArray(collisions = new TypeBinding[invalidSize]);
+								problemReporter().superinterfacesCollide(collisions[0].erasure(), referenceContext, collisions[0], collisions[1]);
+								sourceType.tagBits |= HierarchyHasProblems;
+								noProblems = false;
+								continue nextInterface;
+							}
+						}					
+					}					
+				}
+				// check against other super-interfaces
+				types[0] = superInterface;
+				nextOtherInterface: for (int j = 0; j < i; j++) {
+					ReferenceBinding otherInterface = interfaceBindings[j];
+					if (otherInterface == null) continue nextOtherInterface;
+					types[1] = otherInterface;
+					invocations.clear();
+					TypeBinding[] mecs = minimalErasedCandidates(types, invocations);
+					if (mecs != null) {
+						nextCandidate: for (int k = 0, max = mecs.length; k < max; k++) {
+							TypeBinding mec = mecs[k];
+							if (mec == null) continue nextCandidate;
+							Set invalidInvocations = (Set)invocations.get(mec);
+							int invalidSize = invalidInvocations.size();
+							if (invalidSize > 1) {
+								TypeBinding[] collisions;
+								invalidInvocations.toArray(collisions = new TypeBinding[invalidSize]);
+								problemReporter().superinterfacesCollide(collisions[0].erasure(), referenceContext, collisions[0], collisions[1]);
+								sourceType.tagBits |= HierarchyHasProblems;
+								noProblems = false;
+								continue nextInterface;
+							}
+						}					
+					}
+				}
+			}
+		}
 		// hold onto all correctly resolved superinterfaces
 		if (count > 0) {
 			if (count != length)
@@ -860,8 +941,6 @@
 			if (noProblems && sourceType.isHierarchyInconsistent())
 				problemReporter().hierarchyHasProblems(sourceType);
 		}
-		// Perform deferred bound checks for parameterized type references (only done after hierarchy is connected)
-		checkParameterizedTypeBounds();
 		connectMemberTypes();
 		try {
 			checkForInheritedMemberTypes(sourceType);
@@ -936,17 +1015,18 @@
 			return true;
 		}
 
-		if (superType.isMemberType()) {
-			ReferenceBinding current = superType.enclosingType();
-			do {
-				if (current.isHierarchyBeingConnected()) {
-					problemReporter().hierarchyCircularity(sourceType, current, reference);
-					sourceType.tagBits |= HierarchyHasProblems;
-					current.tagBits |= HierarchyHasProblems;
-					return true;
-				}
-			} while ((current = current.enclosingType()) != null);
-		}
+// No longer believe this code is necessary, since we changed supertype lookup to use TypeReference resolution
+//		if (superType.isMemberType()) {
+//			ReferenceBinding current = superType.enclosingType();
+//			do {
+//				if (current.isHierarchyBeingConnected()) {
+//					problemReporter().hierarchyCircularity(sourceType, current, reference);
+//					sourceType.tagBits |= HierarchyHasProblems;
+//					current.tagBits |= HierarchyHasProblems;
+//					return true;
+//				}
+//			} while ((current = current.enclosingType()) != null);
+//		}
 
 		if (superType.isBinaryBinding()) {
 			// force its superclass & superinterfaces to be found... 2 possibilities exist - the source type is included in the hierarchy of:
@@ -993,7 +1073,8 @@
 		}
 
 		if (superType.isHierarchyBeingConnected()) {
-			if (((SourceTypeBinding) superType).scope.superTypeReference != null) { // if null then its connecting its type variables
+			org.eclipse.jdt.internal.compiler.ast.TypeReference ref = ((SourceTypeBinding) superType).scope.superTypeReference;
+			if (ref != null && ref.resolvedType != null && ((ReferenceBinding) ref.resolvedType).isHierarchyBeingConnected()) { // if null then its connecting its type variables
 				problemReporter().hierarchyCircularity(sourceType, superType, reference);
 				sourceType.tagBits |= HierarchyHasProblems;
 				superType.tagBits |= HierarchyHasProblems;
@@ -1008,40 +1089,6 @@
 		return false;
 	}
 
-	private ReferenceBinding findAmbiguousInterface(ReferenceBinding newInterface, ReferenceBinding currentType) {
-		TypeBinding newErasure = newInterface.erasure();
-		if (newInterface == newErasure) return null;
-
-		ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[5][];
-		int lastPosition = -1;
-		do {
-			ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
-			if (itsInterfaces != NoSuperInterfaces) {
-				if (++lastPosition == interfacesToVisit.length)
-					System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition);
-				interfacesToVisit[lastPosition] = itsInterfaces;
-			}
-		} while ((currentType = currentType.superclass()) != null);
-
-		for (int i = 0; i <= lastPosition; i++) {
-			ReferenceBinding[] interfaces = interfacesToVisit[i];
-			for (int j = 0, length = interfaces.length; j < length; j++) {
-				currentType = interfaces[j];
-				if (currentType.erasure() == newErasure)
-					if (currentType != newInterface)
-						return currentType;
-
-				ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
-				if (itsInterfaces != NoSuperInterfaces) {
-					if (++lastPosition == interfacesToVisit.length)
-						System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition);
-					interfacesToVisit[lastPosition] = itsInterfaces;
-				}
-			}
-		}
-		return null;
-	}
-
 	private ReferenceBinding findSupertype(TypeReference typeReference) {
 		try {
 			typeReference.aboutToResolve(this); // allows us to trap completion & selection nodes
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java
index 56b966b..9ef88fc 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java
@@ -19,21 +19,21 @@
 
 public class CompilationUnitScope extends Scope {
 	
-	public LookupEnvironment environment;
-	public CompilationUnitDeclaration referenceContext;
-	public char[][] currentPackageName;
-	public PackageBinding fPackage;
-	public ImportBinding[] imports;
-	public HashtableOfObject resolvedSingeTypeImports;
-	
-	public SourceTypeBinding[] topLevelTypes;
+public LookupEnvironment environment;
+public CompilationUnitDeclaration referenceContext;
+public char[][] currentPackageName;
+public PackageBinding fPackage;
+public ImportBinding[] imports;
+public HashtableOfObject typeOrPackageCache; // used in Scope.getTypeOrPackage()
 
-	private CompoundNameVector qualifiedReferences;
-	private SimpleNameVector simpleNameReferences;
-	private ObjectVector referencedTypes;
-	private ObjectVector referencedSuperTypes;
-	
-	HashtableOfType constantPoolNameUsage;
+public SourceTypeBinding[] topLevelTypes;
+
+private CompoundNameVector qualifiedReferences;
+private SimpleNameVector simpleNameReferences;
+private ObjectVector referencedTypes;
+private ObjectVector referencedSuperTypes;
+
+HashtableOfType constantPoolNameUsage;
 
 public CompilationUnitScope(CompilationUnitDeclaration unit, LookupEnvironment environment) {
 	super(COMPILATION_UNIT_SCOPE, null);
@@ -42,7 +42,7 @@
 	unit.scope = this;
 	this.currentPackageName = unit.currentPackage == null ? CharOperation.NO_CHAR_CHAR : unit.currentPackage.tokens;
 
-	if (environment.options.produceReferenceInfo) {
+	if (compilerOptions().produceReferenceInfo) {
 		this.qualifiedReferences = new CompoundNameVector();
 		this.simpleNameReferences = new SimpleNameVector();
 		this.referencedTypes = new ObjectVector();
@@ -179,6 +179,10 @@
 		System.arraycopy(resolvedImports, 0, resolvedImports = new ImportBinding[index], 0, index);
 	imports = resolvedImports;
 }
+void checkParameterizedTypeBounds() {
+	for (int i = 0, length = topLevelTypes.length; i < length; i++)
+		topLevelTypes[i].scope.checkParameterizedTypeBounds();
+}
 /*
  * INTERNAL USE-ONLY
  * Innerclasses get their name computed as they are generated, since some may not
@@ -198,6 +202,7 @@
 	// ensure there is not already such a local type name defined by the user
 	int index = 0;
 	char[] candidateName;
+	boolean isCompliant15 = compilerOptions().complianceLevel >= ClassFileConstants.JDK1_5;
 	while(true) {
 		if (localType.isMemberType()){
 			if (index == 0){
@@ -221,12 +226,22 @@
 					String.valueOf(index+1).toCharArray(),
 					'$');
 		} else {
+			// local type
+			if (isCompliant15) {
+				candidateName = CharOperation.concat(
+					CharOperation.concat(
+						outerMostEnclosingType.constantPoolName(),
+						String.valueOf(index+1).toCharArray(),
+						'$'),
+					localType.sourceName);
+			} else {
 				candidateName = CharOperation.concat(
 					outerMostEnclosingType.constantPoolName(),
 					'$',
 					String.valueOf(index+1).toCharArray(),
 					'$',
 					localType.sourceName);
+			}				
 		}						
 		if (constantPoolNameUsage.get(candidateName) != null) {
 			index ++;
@@ -243,8 +258,10 @@
 		topLevelTypes[i].scope.connectTypeHierarchy();
 }
 void faultInImports() {
-	if (referenceContext.imports == null)
+	if (referenceContext.imports == null) {
+		this.typeOrPackageCache = new HashtableOfObject(1);
 		return;
+	}
 
 	// collect the top level type names if a single type import exists
 	int numberOfStatements = referenceContext.imports.length;
@@ -314,9 +331,15 @@
 				problemReporter().cannotImportPackage(importReference);
 				continue nextImport;
 			}
+			ReferenceBinding conflictingType = null;
+			if (importBinding instanceof MethodBinding) {
+				conflictingType = (ReferenceBinding) getType(compoundName, compoundName.length);
+				if (!conflictingType.isValidBinding())
+					conflictingType = null;
+			}
 			// collisions between an imported static field & a type should be checked according to spec... but currently not by javac
-			if (importBinding instanceof ReferenceBinding) {
-				ReferenceBinding referenceBinding = (ReferenceBinding) importBinding;
+			if (importBinding instanceof ReferenceBinding || conflictingType != null) {
+				ReferenceBinding referenceBinding = conflictingType == null ? (ReferenceBinding) importBinding : conflictingType;
 				if (importReference.isTypeUseDeprecated(referenceBinding, this))
 					problemReporter().deprecatedType(referenceBinding, importReference);
 
@@ -348,7 +371,9 @@
 					}
 				}
 			}
-			resolvedImports[index++] = new ImportBinding(compoundName, false, importBinding, importReference);
+			resolvedImports[index++] = conflictingType == null
+				? new ImportBinding(compoundName, false, importBinding, importReference)
+				: new ImportConflictBinding(compoundName, importBinding, conflictingType, importReference);
 		}
 	}
 
@@ -358,11 +383,11 @@
 	imports = resolvedImports;
 
 	int length = imports.length;
-	resolvedSingeTypeImports = new HashtableOfObject(length);
+	this.typeOrPackageCache = new HashtableOfObject(length);
 	for (int i = 0; i < length; i++) {
 		ImportBinding binding = imports[i];
-		if (!binding.onDemand && binding.resolvedImport instanceof ReferenceBinding)
-			resolvedSingeTypeImports.put(binding.compoundName[binding.compoundName.length - 1], binding);
+		if (!binding.onDemand && binding.resolvedImport instanceof ReferenceBinding || binding instanceof ImportConflictBinding)
+			this.typeOrPackageCache.put(binding.compoundName[binding.compoundName.length - 1], binding);
 	}
 }
 public void faultInTypes() {
@@ -394,11 +419,11 @@
 
 	ReferenceBinding type;
 	if (binding == null) {
-		if (environment.defaultPackage == null || environment.options.complianceLevel >= ClassFileConstants.JDK1_4)
-			return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, i), NotFound);
+		if (environment.defaultPackage == null || compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4)
+			return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, i), null, NotFound);
 		type = findType(compoundName[0], environment.defaultPackage, environment.defaultPackage);
 		if (type == null || !type.isValidBinding())
-			return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, i), NotFound);
+			return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, i), null, NotFound);
 		i = 1; // reset to look for member types inside the default package type
 	} else {
 		type = (ReferenceBinding) binding;
@@ -412,7 +437,7 @@
 		// does not look for inherited member types on purpose, only immediate members
 		type = type.getMemberType(name);
 		if (type == null)
-			return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, i), NotFound);
+			return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, i), null, NotFound);
 	}
 	if (!type.canBeSeenBy(fPackage))
 		return new ProblemReferenceBinding(compoundName, type, NotVisible);
@@ -422,11 +447,11 @@
 	if (compoundName.length == 1) {
 		// findType records the reference
 		// the name cannot be a package
-		if (environment.defaultPackage == null || environment.options.complianceLevel >= ClassFileConstants.JDK1_4)
-			return new ProblemReferenceBinding(compoundName, NotFound);
+		if (environment.defaultPackage == null || compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4)
+			return new ProblemReferenceBinding(compoundName, null, NotFound);
 		ReferenceBinding typeBinding = findType(compoundName[0], environment.defaultPackage, fPackage);
 		if (typeBinding == null)
-			return new ProblemReferenceBinding(compoundName, NotFound);
+			return new ProblemReferenceBinding(compoundName, null, NotFound);
 		return typeBinding;
 	}
 
@@ -442,7 +467,7 @@
 	if (binding instanceof PackageBinding) {
 		Binding temp = ((PackageBinding) binding).getTypeOrPackage(name);
 		if (temp != null && temp instanceof ReferenceBinding) // must resolve to a member type or field, not a top level type
-			return new ProblemReferenceBinding(compoundName, InvalidTypeForStaticImport);
+			return new ProblemReferenceBinding(compoundName, (ReferenceBinding) temp, InvalidTypeForStaticImport);
 		return binding; // cannot be a package, error is caught in sender
 	}
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilerModifiers.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilerModifiers.java
index 395a1a5..6badbc2 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilerModifiers.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilerModifiers.java
@@ -32,7 +32,7 @@
 	final int AccClearPrivateModifier = ASTNode.Bit27; // might be requested during private access emulation
 	final int AccBlankFinal = ASTNode.Bit27; // for blank final variables
 	final int AccIsDefaultConstructor = ASTNode.Bit27; // for default constructor
-	final int AccPrivateUsed = ASTNode.Bit28; // used to diagnose unused private members
+	final int AccLocallyUsed = ASTNode.Bit28; // used to diagnose unused private/local members
 	final int AccVisibilityMASK = AccPublic | AccProtected | AccPrivate;
 	
 	final int AccOverriding = ASTNode.Bit29; // record fact a method overrides another one
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java
index 2dcd27a..d4d570a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java
@@ -80,7 +80,7 @@
 		ReferenceBinding receiverErasure = (ReferenceBinding)receiverType.erasure();
 		ReferenceBinding declaringErasure = (ReferenceBinding) declaringClass.erasure();
 		do {
-			if (currentType.findSuperTypeErasingTo(declaringErasure) != null) {
+			if (currentType.findSuperTypeWithSameErasure(declaringErasure) != null) {
 				if (invocationSite.isSuperAccess()){
 					return true;
 				}
@@ -92,7 +92,7 @@
 					if (depth > 0) invocationSite.setDepth(depth);
 					return true; // see 1FMEPDL - return invocationSite.isTypeAccess();
 				}
-				if (currentType == receiverErasure || receiverErasure.findSuperTypeErasingTo(currentType) != null){
+				if (currentType == receiverErasure || receiverErasure.findSuperTypeWithSameErasure(currentType) != null){
 					if (depth > 0) invocationSite.setDepth(depth);
 					return true;
 				}
@@ -151,43 +151,33 @@
 }
 /*
  * declaringUniqueKey dot fieldName
- * p.X { X<T> x} --> Lp/X;.x^123
+ * p.X { X<T> x} --> Lp/X;.x)p/X<TT;>;
  */
-public char[] computeUniqueKey(boolean withAccessFlags) {
+public char[] computeUniqueKey(boolean isLeaf) {
 	// declaring key
 	char[] declaringKey = 
 		this.declaringClass == null /*case of length field for an array*/ 
 			? CharOperation.NO_CHAR 
-			: this.declaringClass.computeUniqueKey(false/*without access flags*/);
+			: this.declaringClass.computeUniqueKey(false/*not a leaf*/);
 	int declaringLength = declaringKey.length;
 	
 	// name
 	int nameLength = this.name.length;
 	
-	if (withAccessFlags) {
-		// flags
-		String flags = Integer.toString(getAccessFlags());
-		int flagsLength = flags.length();
+	// return type
+	char[] returnTypeKey = this.type == null ? new char[] {'V'} : this.type.computeUniqueKey(false/*not a leaf*/);
+	int returnTypeLength = returnTypeKey.length;
 	
-		char[] uniqueKey = new char[declaringLength + 1 + nameLength + 1 + flagsLength];
-		int index = 0;
-		System.arraycopy(declaringKey, 0, uniqueKey, index, declaringLength);
-		index += declaringLength;
-		uniqueKey[index++] = '.';
-		System.arraycopy(this.name, 0, uniqueKey, index, nameLength);
-		index += nameLength;
-		uniqueKey[index++] = '^';
-		flags.getChars(0, flagsLength, uniqueKey, index);
-		return uniqueKey;
-	} else {
-		char[] uniqueKey = new char[declaringLength + 1 + nameLength];
-		int index = 0;
-		System.arraycopy(declaringKey, 0, uniqueKey, index, declaringLength);
-		index += declaringLength;
-		uniqueKey[index++] = '.';
-		System.arraycopy(this.name, 0, uniqueKey, index, nameLength);
-		return uniqueKey;
-	}
+	char[] uniqueKey = new char[declaringLength + 1 + nameLength + 1 + returnTypeLength];
+	int index = 0;
+	System.arraycopy(declaringKey, 0, uniqueKey, index, declaringLength);
+	index += declaringLength;
+	uniqueKey[index++] = '.';
+	System.arraycopy(this.name, 0, uniqueKey, index, nameLength);
+	index += nameLength;
+	uniqueKey[index++] = ')';
+	System.arraycopy(returnTypeKey, 0, uniqueKey, index, returnTypeLength);
+	return uniqueKey;
 }
 /**
  * X<T> t   -->  LX<TT;>;
@@ -211,8 +201,19 @@
 	if ((originalField.tagBits & TagBits.AnnotationResolved) == 0 && originalField.declaringClass instanceof SourceTypeBinding) {
 		TypeDeclaration typeDecl = ((SourceTypeBinding)originalField.declaringClass).scope.referenceContext;
 		FieldDeclaration fieldDecl = typeDecl.declarationOf(originalField);
-		if (fieldDecl != null)
-			ASTNode.resolveAnnotations(isStatic() ? typeDecl.staticInitializerScope : typeDecl.initializerScope, fieldDecl.annotations, originalField);
+		if (fieldDecl != null) {
+			MethodScope initializationScope = isStatic() ? typeDecl.staticInitializerScope : typeDecl.initializerScope;
+			FieldBinding previousField = initializationScope.initializedField;
+			int previousFieldID = initializationScope.lastVisibleFieldID;			
+			try {
+				initializationScope.initializedField = originalField;
+				initializationScope.lastVisibleFieldID = originalField.id;
+				ASTNode.resolveAnnotations(initializationScope, fieldDecl.annotations, originalField);
+			} finally {
+				initializationScope.initializedField = previousField;
+				initializationScope.lastVisibleFieldID = previousFieldID;
+			}
+		}
 	}
 	return originalField.tagBits;
 }
@@ -238,8 +239,8 @@
 /* Answer true if the receiver has private visibility and is used locally
 */
 
-public final boolean isPrivateUsed() {
-	return (modifiers & AccPrivateUsed) != 0;
+public final boolean isUsed() {
+	return (modifiers & AccLocallyUsed) != 0;
 }
 /* Answer true if the receiver has protected visibility
 */
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImportConflictBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImportConflictBinding.java
new file mode 100644
index 0000000..5409b41
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImportConflictBinding.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * 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.compiler.lookup;
+
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.ast.ImportReference;
+
+public class ImportConflictBinding extends ImportBinding {
+public ReferenceBinding conflictingTypeBinding; // must ensure the import is resolved
+	
+public ImportConflictBinding(char[][] compoundName, Binding methodBinding, ReferenceBinding conflictingTypeBinding, ImportReference reference) {
+	super(compoundName, false, methodBinding, reference);
+	this.conflictingTypeBinding = conflictingTypeBinding;
+}
+public char[] readableName() {
+	return CharOperation.concatWith(compoundName, '.');
+}
+public String toString() {
+	return "method import : " + new String(readableName()); //$NON-NLS-1$
+}
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LocalTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LocalTypeBinding.java
index c96f153..9bc1b82 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LocalTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LocalTypeBinding.java
@@ -62,21 +62,17 @@
 	dependents[index] = new InnerEmulationDependency(dependentScope, wasEnclosingInstanceSupplied);
 	//  System.out.println("Adding dependency: "+ new String(scope.enclosingType().readableName()) + " --> " + new String(this.readableName()));
 }
-public char[] computeUniqueKey(boolean withAccessFlags) {
-	ReferenceBinding enclosing = enclosingType();
-	ReferenceBinding temp;
-	while ((temp = enclosing.enclosingType()) != null)
-		enclosing = temp;
-	StringBuffer buffer = new StringBuffer();
-	buffer.append(enclosing.computeUniqueKey(withAccessFlags));
-	int semicolon = buffer.lastIndexOf(";"); //$NON-NLS-1$
-	buffer.insert(semicolon, '$');
-	semicolon = buffer.lastIndexOf(";"); //$NON-NLS-1$
-	buffer.insert(semicolon, this.sourceStart);
-	int length = buffer.length();
-	char[] uniqueKey = new char[length];
-	buffer.getChars(0, length, uniqueKey, 0);
-	return uniqueKey;
+public char[] computeUniqueKey(boolean isLeaf) {
+	char[] outerKey = outermostEnclosingType().computeUniqueKey(isLeaf);
+	int semicolon = CharOperation.lastIndexOf(';', outerKey);
+	
+	// insert $sourceStart
+	return CharOperation.concat(
+			CharOperation.concat(
+					CharOperation.subarray(outerKey, 0, semicolon),
+					String.valueOf(this.sourceStart).toCharArray(),
+					'$'),
+			CharOperation.subarray(outerKey, semicolon, outerKey.length));
 }
 
 public char[] constantPoolName() /* java/lang/Object */ {
@@ -100,6 +96,21 @@
 	return localArrayBindings[length] = new ArrayBinding(this, dimensionCount, scope.environment());
 }
 
+/*
+ * Overriden for code assist. In this case, the constantPoolName() has not been computed yet.
+ * Slam the source name so that the signature is syntactically correct.
+ * (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=99686)
+ */
+public char[] genericTypeSignature() {
+	if (this.genericReferenceTypeSignature == null && constantPoolName() == null) {
+		if (isAnonymousType())
+			setConstantPoolName(superclass().sourceName());
+		else
+			setConstantPoolName(sourceName());
+	}
+	return super.genericTypeSignature();
+}
+
 public char[] readableName() /*java.lang.Object,  p.X<T> */ {
     char[] readableName;
 	if (isAnonymousType()) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LocalVariableBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LocalVariableBinding.java
index 80173f6..3757fdc 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LocalVariableBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LocalVariableBinding.java
@@ -57,9 +57,9 @@
 	
 	/*
 	 * declaringUniqueKey # scopeIndex / varName
-	 * p.X { void foo() { int local; } } --> Lp/X;.foo()V#1/local^123
+	 * p.X { void foo() { int local; } } --> Lp/X;.foo()V#1/local
 	 */
-	public char[] computeUniqueKey(boolean withAccessFlags) {
+	public char[] computeUniqueKey(boolean isLeaf) {
 		StringBuffer buffer = new StringBuffer();
 		
 		// declaring method or type
@@ -69,12 +69,12 @@
 		if (referenceContext instanceof AbstractMethodDeclaration) {
 			MethodBinding methodBinding = ((AbstractMethodDeclaration) referenceContext).binding;
 			if (methodBinding != null) {
-				buffer.append(methodBinding.computeUniqueKey(false/*without access flags*/));
+				buffer.append(methodBinding.computeUniqueKey(false/*not a leaf*/));
 			}
 		} else if (referenceContext instanceof TypeDeclaration) {
 			TypeBinding typeBinding = ((TypeDeclaration) referenceContext).binding;
 			if (typeBinding != null) {
-				buffer.append(typeBinding.computeUniqueKey(false/*without access flags*/));
+				buffer.append(typeBinding.computeUniqueKey(false/*not a leaf*/));
 			}
 		}
 
@@ -85,12 +85,6 @@
 		buffer.append('#');
 		buffer.append(this.name);
 		
-		// flags
-		if (withAccessFlags) {
-			buffer.append('^');
-			buffer.append(this.modifiers & AccJustFlag);
-		}
-		
 		int length = buffer.length();
 		char[] uniqueKey = new char[length];
 		buffer.getChars(0, length, uniqueKey, 0);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java
index 31bf1c8..ff4fbef 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java
@@ -30,7 +30,7 @@
 	final static int CHECK_AND_SET_IMPORTS = 2;
 	final static int CONNECT_TYPE_HIERARCHY = 3;
 	static final ProblemPackageBinding TheNotFoundPackage = new ProblemPackageBinding(CharOperation.NO_CHAR, NotFound);
-	static final ProblemReferenceBinding TheNotFoundType = new ProblemReferenceBinding(CharOperation.NO_CHAR, NotFound);
+	static final ProblemReferenceBinding TheNotFoundType = new ProblemReferenceBinding(CharOperation.NO_CHAR, null, NotFound);
 	
 	/**
 	 * Map from typeBinding -> accessRestriction rule
@@ -44,7 +44,7 @@
 	private int lastUnitIndex = -1;
 
 	public INameEnvironment nameEnvironment;
-	public CompilerOptions options;
+	public CompilerOptions globalOptions;
 	public ProblemReporter problemReporter;
 
 	// shared byte[]'s used by ClassFile to avoid allocating MBs during a build
@@ -68,9 +68,9 @@
 	private CompilationUnitDeclaration[] units = new CompilationUnitDeclaration[4];
 	private MethodVerifier verifier;
 
-public LookupEnvironment(ITypeRequestor typeRequestor, CompilerOptions options, ProblemReporter problemReporter, INameEnvironment nameEnvironment) {
+public LookupEnvironment(ITypeRequestor typeRequestor, CompilerOptions globalOptions, ProblemReporter problemReporter, INameEnvironment nameEnvironment) {
 	this.typeRequestor = typeRequestor;
-	this.options = options;
+	this.globalOptions = globalOptions;
 	this.problemReporter = problemReporter;
 	this.defaultPackage = new PackageBinding(this); // assume the default package always exists
 	this.defaultImports = null;
@@ -197,7 +197,9 @@
 	stepCompleted = CONNECT_TYPE_HIERARCHY;
 
 	for (int i = this.lastCompletedUnitIndex + 1; i <= this.lastUnitIndex; i++) {
-		(this.unitBeingCompleted = this.units[i]).scope.buildFieldsAndMethods();
+		CompilationUnitScope unitScope = (this.unitBeingCompleted = this.units[i]).scope;
+		unitScope.checkParameterizedTypeBounds();
+		unitScope.buildFieldsAndMethods();
 		this.units[i] = null; // release unnecessary reference to the parsed unit
 	}
 	stepCompleted = BUILD_FIELDS_AND_METHODS;
@@ -247,6 +249,7 @@
 
 	(this.unitBeingCompleted = parsedUnit).scope.checkAndSetImports();
 	parsedUnit.scope.connectTypeHierarchy();
+	parsedUnit.scope.checkParameterizedTypeBounds();	
 	if (buildFieldsAndMethods)
 		parsedUnit.scope.buildFieldsAndMethods();
 	this.unitBeingCompleted = null;
@@ -274,35 +277,35 @@
 		case TypeIds.T_int :
 			boxedType = getType(JAVA_LANG_INTEGER);
 			if (boxedType != null) return boxedType;
-			return new ProblemReferenceBinding(	JAVA_LANG_INTEGER, NotFound);				
+			return new ProblemReferenceBinding(	JAVA_LANG_INTEGER, null, NotFound);				
 		case TypeIds.T_byte :
 			boxedType = getType(JAVA_LANG_BYTE);
 			if (boxedType != null) return boxedType;
-			return new ProblemReferenceBinding(	JAVA_LANG_BYTE, NotFound);				
+			return new ProblemReferenceBinding(	JAVA_LANG_BYTE, null, NotFound);				
 		case TypeIds.T_short :
 			boxedType = getType(JAVA_LANG_SHORT);
 			if (boxedType != null) return boxedType;
-			return new ProblemReferenceBinding(	JAVA_LANG_SHORT, NotFound);				
+			return new ProblemReferenceBinding(	JAVA_LANG_SHORT, null, NotFound);				
 		case TypeIds.T_char :
 			boxedType = getType(JAVA_LANG_CHARACTER);
 			if (boxedType != null) return boxedType;
-			return new ProblemReferenceBinding(	JAVA_LANG_CHARACTER, NotFound);				
+			return new ProblemReferenceBinding(	JAVA_LANG_CHARACTER, null, NotFound);				
 		case TypeIds.T_long :
 			boxedType = getType(JAVA_LANG_LONG);
 			if (boxedType != null) return boxedType;
-			return new ProblemReferenceBinding(	JAVA_LANG_LONG, NotFound);				
+			return new ProblemReferenceBinding(	JAVA_LANG_LONG, null, NotFound);				
 		case TypeIds.T_float :
 			boxedType = getType(JAVA_LANG_FLOAT);
 			if (boxedType != null) return boxedType;
-			return new ProblemReferenceBinding(	JAVA_LANG_FLOAT, NotFound);				
+			return new ProblemReferenceBinding(	JAVA_LANG_FLOAT, null, NotFound);				
 		case TypeIds.T_double :
 			boxedType = getType(JAVA_LANG_DOUBLE);
 			if (boxedType != null) return boxedType;
-			return new ProblemReferenceBinding(	JAVA_LANG_DOUBLE, NotFound);				
+			return new ProblemReferenceBinding(	JAVA_LANG_DOUBLE, null, NotFound);				
 		case TypeIds.T_boolean :
 			boxedType = getType(JAVA_LANG_BOOLEAN);
 			if (boxedType != null) return boxedType;
-			return new ProblemReferenceBinding(	JAVA_LANG_BOOLEAN, NotFound);				
+			return new ProblemReferenceBinding(	JAVA_LANG_BOOLEAN, null, NotFound);				
 	}
 	// allow indirect unboxing conversion for wildcards and type parameters
 	switch (type.kind()) {
@@ -349,11 +352,83 @@
 	return packageBinding;
 }
 
+public TypeBinding convertToRawType(TypeBinding type) {
+
+	int dimension;
+	TypeBinding originalType;
+	switch(type.kind()) {
+		case Binding.BASE_TYPE :
+		case Binding.TYPE_PARAMETER:
+		case Binding.WILDCARD_TYPE:
+		case Binding.RAW_TYPE:
+			return type;
+		case Binding.ARRAY_TYPE:
+			dimension = type.dimensions();
+			originalType = type.leafComponentType();
+			break;
+		default:
+			dimension = 0;
+			originalType = type;
+	}
+	boolean needToConvert;
+	switch (originalType.kind()) {
+		case Binding.BASE_TYPE :
+			return type;
+		case Binding.GENERIC_TYPE :
+			needToConvert = true;
+			break;
+		case Binding.PARAMETERIZED_TYPE :
+			ParameterizedTypeBinding paramType = (ParameterizedTypeBinding) originalType;
+			needToConvert = paramType.type.isGenericType(); // only recursive call to enclosing type can find parameterizedType with arguments
+			break;
+		default :
+			needToConvert = false;
+			break;
+	}
+	ReferenceBinding originalEnclosing = originalType.enclosingType();
+	TypeBinding convertedType;
+	if (originalEnclosing == null) {
+		convertedType = needToConvert ? createRawType((ReferenceBinding)originalType.erasure(), null) : originalType;
+	} else {
+		ReferenceBinding convertedEnclosing;
+		switch (originalEnclosing.kind()) {
+			case Binding.GENERIC_TYPE :
+			case Binding.PARAMETERIZED_TYPE :
+				if (needToConvert || ((ReferenceBinding)originalType).isStatic()) {
+					convertedEnclosing = (ReferenceBinding) convertToRawType(originalEnclosing);
+				} else {
+					convertedEnclosing = originalEnclosing;
+				}
+				break;
+			case Binding.RAW_TYPE :
+				needToConvert |= !((ReferenceBinding)originalType).isStatic();
+			default :
+				convertedEnclosing = originalEnclosing;
+				break;
+		}
+		ReferenceBinding originalGeneric = (ReferenceBinding) originalType.erasure();
+		if (needToConvert) {
+			convertedType = createRawType(originalGeneric, convertedEnclosing);
+		} else if (originalEnclosing != convertedEnclosing) {
+			if (originalGeneric.isStatic())
+				convertedType = createParameterizedType(originalGeneric, null, convertedEnclosing);
+			else 
+				convertedType = createRawType(originalGeneric, convertedEnclosing);
+		} else {
+			convertedType = originalType;
+		}
+	}
+	if (originalType != convertedType) {
+		return dimension > 0 ? (TypeBinding)createArrayType(convertedType, dimension) : convertedType;
+	}
+	return type;
+}
+
 /* Used to guarantee array type identity.
 */
-public ArrayBinding createArrayType(TypeBinding type, int dimensionCount) {
-	if (type instanceof LocalTypeBinding) // cache local type arrays with the local type itself
-		return ((LocalTypeBinding) type).createArrayType(dimensionCount);
+public ArrayBinding createArrayType(TypeBinding leafComponentType, int dimensionCount) {
+	if (leafComponentType instanceof LocalTypeBinding) // cache local type arrays with the local type itself
+		return ((LocalTypeBinding) leafComponentType).createArrayType(dimensionCount);
 
 	// find the array binding cache for this dimension
 	int dimIndex = dimensionCount - 1;
@@ -376,8 +451,8 @@
 	while (++index < length) {
 		ArrayBinding currentBinding = arrayBindings[index];
 		if (currentBinding == null) // no matching array, but space left
-			return arrayBindings[index] = new ArrayBinding(type, dimensionCount, this);
-		if (currentBinding.leafComponentType == type)
+			return arrayBindings[index] = new ArrayBinding(leafComponentType, dimensionCount, this);
+		if (currentBinding.leafComponentType == leafComponentType)
 			return currentBinding;
 	}
 
@@ -387,7 +462,7 @@
 		(arrayBindings = new ArrayBinding[length * 2]), 0,
 		length); 
 	uniqueArrayBindings[dimIndex] = arrayBindings;
-	return arrayBindings[length] = new ArrayBinding(type, dimensionCount, this);
+	return arrayBindings[length] = new ArrayBinding(leafComponentType, dimensionCount, this);
 }
 public BinaryTypeBinding createBinaryTypeFrom(IBinaryType binaryType, PackageBinding packageBinding, AccessRestriction accessRestriction) {
 	return createBinaryTypeFrom(binaryType, packageBinding, true, accessRestriction);
@@ -398,11 +473,15 @@
 	// resolve any array bindings which reference the unresolvedType
 	ReferenceBinding cachedType = packageBinding.getType0(binaryBinding.compoundName[binaryBinding.compoundName.length - 1]);
 	if (cachedType != null) { // update reference to unresolved binding after having read classfile (knows whether generic for raw conversion)
-		// TODO (kent) suspect the check below is no longer required, since we should not be requesting a binary which is already in the cache
-		if (cachedType.isBinaryBinding()) // sanity check before the cast... at this point the cache should ONLY contain unresolved types
-			return (BinaryTypeBinding) cachedType;
-
-		((UnresolvedReferenceBinding) cachedType).setResolvedType(binaryBinding, this);
+		if (cachedType instanceof UnresolvedReferenceBinding) {
+			((UnresolvedReferenceBinding) cachedType).setResolvedType(binaryBinding, this);
+		} else {
+			if (cachedType.isBinaryBinding()) // sanity check... at this point the cache should ONLY contain unresolved types
+				return (BinaryTypeBinding) cachedType;
+			// it is possible with a large number of source files (exceeding AbstractImageBuilder.MAX_AT_ONCE) that a member type can be in the cache as an UnresolvedType,
+			// but because its enclosingType is resolved while its created (call to BinaryTypeBinding constructor), its replaced with a source type
+			return null;
+		}
 	}
 
 	packageBinding.addType(binaryBinding);
@@ -668,7 +747,7 @@
 
 	// compoundName refers to a nested type incorrectly (for example, package1.A$B)
 	if (referenceBinding.isNestedType())
-		return new ProblemReferenceBinding(compoundName, InternalNameProvided);
+		return new ProblemReferenceBinding(compoundName, referenceBinding, InternalNameProvided);
 	return referenceBinding;
 }
 private TypeBinding[] getTypeArgumentsFromSignature(SignatureWrapper wrapper, TypeVariableBinding[] staticVariables, ReferenceBinding enclosingType, ReferenceBinding genericType) {
@@ -704,9 +783,9 @@
 	} else if (binding == TheNotFoundType) {
 		problemReporter.isClassPathCorrect(compoundName, null);
 		return null; // will not get here since the above error aborts the compilation
-	} else if (!isParameterized && binding.isGenericType()) {
+	} else if (!isParameterized) {
 	    // check raw type, only for resolved types
-        binding = createRawType(binding, binding.enclosingType());
+        binding = (ReferenceBinding)convertToRawType(binding);
 	}
 	return binding;
 }
@@ -809,7 +888,11 @@
 	// type must be a ReferenceBinding at this point, cannot be a BaseTypeBinding or ArrayTypeBinding
 	ReferenceBinding actualType = (ReferenceBinding) type;
 	TypeBinding[] typeArguments = getTypeArgumentsFromSignature(wrapper, staticVariables, enclosingType, actualType);
-	ParameterizedTypeBinding parameterizedType = createParameterizedType(actualType, typeArguments, null);
+	ReferenceBinding actualEnclosing = actualType.enclosingType();
+	if (actualEnclosing != null) { // convert needed if read some static member type
+		actualEnclosing = (ReferenceBinding) convertToRawType(actualEnclosing);
+	}
+	ParameterizedTypeBinding parameterizedType = createParameterizedType(actualType, typeArguments, actualEnclosing);
 
 	while (wrapper.signature[wrapper.start] == '.') {
 		wrapper.start++; // skip '.'
@@ -856,13 +939,7 @@
 			return getTypeFromTypeSignature(wrapper, staticVariables, enclosingType);
 	}
 }
-public boolean isBoxingCompatibleWith(TypeBinding left, TypeBinding right) {
-	if (options.sourceLevel < ClassFileConstants.JDK1_5 || left.isBaseType() == right.isBaseType())
-		return false;
 
-	TypeBinding convertedType = computeBoxingType(left);
-	return convertedType == right || convertedType.isCompatibleWith(right);
-}
 /* Ask the oracle if a package exists named name in the package named compoundName.
 */
 boolean isPackage(char[][] compoundName, char[] name) {
@@ -874,7 +951,7 @@
 
 public MethodVerifier methodVerifier() {
 	if (verifier == null)
-		verifier = this.options.complianceLevel < ClassFileConstants.JDK1_5
+		verifier = this.globalOptions.complianceLevel < ClassFileConstants.JDK1_5
 			? new MethodVerifier(this)
 			: new MethodVerifier15(this); // check for covariance even if sourceLevel is < 1.5
 	return verifier;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java
index 766a764..728f220 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java
@@ -219,7 +219,7 @@
 		ReferenceBinding declaringErasure = (ReferenceBinding) declaringClass.erasure();
 		int depth = 0;
 		do {
-			if (currentType.findSuperTypeErasingTo(declaringErasure) != null) {
+			if (currentType.findSuperTypeWithSameErasure(declaringErasure) != null) {
 				if (invocationSite.isSuperAccess()){
 					return true;
 				}
@@ -231,7 +231,7 @@
 					if (depth > 0) invocationSite.setDepth(depth);
 					return true; // see 1FMEPDL - return invocationSite.isTypeAccess();
 				}
-				if (currentType == receiverErasure || ((ReferenceBinding)receiverErasure).findSuperTypeErasingTo(currentType) != null){
+				if (currentType == receiverErasure || ((ReferenceBinding)receiverErasure).findSuperTypeWithSameErasure(currentType) != null){
 					if (depth > 0) invocationSite.setDepth(depth);
 					return true;
 				}
@@ -288,16 +288,30 @@
 	} while ((type = type.superclass()) != null);
 	return false;
 }
+MethodBinding computeSubstitutedMethod(MethodBinding method, LookupEnvironment env) {
+	TypeVariableBinding[] vars = this.typeVariables;
+	TypeVariableBinding[] vars2 = method.typeVariables;
+	if (vars.length != vars2.length)
+		return null;
+	for (int v = vars.length; --v >= 0;)
+		if (!vars[v].isInterchangeableWith(env, vars2[v]))
+			return null;
+
+	// must substitute to detect cases like:
+	//   <T1 extends X<T1>> void dup() {}
+	//   <T2 extends X<T2>> Object dup() {return null;}
+	return new ParameterizedGenericMethodBinding(method, vars, env);
+}
 /*
  * declaringUniqueKey dot selector genericSignature
- * p.X { <T> void bar(X<T> t) } --> Lp/X;.bar<T:Ljava/lang/Object;>(LX<TT;>;)V^123
+ * p.X { <T> void bar(X<T> t) } --> Lp/X;.bar<T:Ljava/lang/Object;>(LX<TT;>;)V
  */
-public char[] computeUniqueKey(boolean withAccessFlags) {
-	return computeUniqueKey(this, withAccessFlags);
+public char[] computeUniqueKey(boolean isLeaf) {
+	return computeUniqueKey(this, isLeaf);
 }
-protected char[] computeUniqueKey(MethodBinding methodBinding, boolean withAccessFlags) {
+protected char[] computeUniqueKey(MethodBinding methodBinding, boolean isLeaf) {
 	// declaring class 
-	char[] declaringKey = this.declaringClass.computeUniqueKey(false/*without access flags*/);
+	char[] declaringKey = this.declaringClass.computeUniqueKey(false/*not a leaf*/);
 	int declaringLength = declaringKey.length;
 	
 	// selector
@@ -308,36 +322,16 @@
 	if (sig == null) sig = methodBinding.signature();
 	int signatureLength = sig.length;
 	
-	if (withAccessFlags) {
-		// flags
-		String flags = Integer.toString(methodBinding.getAccessFlags());
-		int flagsLength = flags.length();
-		
-		char[] uniqueKey = new char[declaringLength + 1 + selectorLength + signatureLength + 1 + flagsLength];
-		int index = 0;
-		System.arraycopy(declaringKey, 0, uniqueKey, index, declaringLength);
-		index = declaringLength;
-		uniqueKey[index++] = '.';
-		System.arraycopy(this.selector, 0, uniqueKey, index, selectorLength);
-		index += selectorLength;
-		System.arraycopy(sig, 0, uniqueKey, index, signatureLength);
-		index += signatureLength;
-		uniqueKey[index++] = '^';
-		flags.getChars(0, flagsLength, uniqueKey, index);
-		// index += modifiersLength
-		return uniqueKey;
-	} else {
-		char[] uniqueKey = new char[declaringLength + 1 + selectorLength + signatureLength];
-		int index = 0;
-		System.arraycopy(declaringKey, 0, uniqueKey, index, declaringLength);
-		index = declaringLength;
-		uniqueKey[index++] = '.';
-		System.arraycopy(this.selector, 0, uniqueKey, index, selectorLength);
-		index += selectorLength;
-		System.arraycopy(sig, 0, uniqueKey, index, signatureLength);
-		//index += signatureLength;
-		return uniqueKey;
-	}
+	char[] uniqueKey = new char[declaringLength + 1 + selectorLength + signatureLength];
+	int index = 0;
+	System.arraycopy(declaringKey, 0, uniqueKey, index, declaringLength);
+	index = declaringLength;
+	uniqueKey[index++] = '.';
+	System.arraycopy(this.selector, 0, uniqueKey, index, selectorLength);
+	index += selectorLength;
+	System.arraycopy(sig, 0, uniqueKey, index, signatureLength);
+	//index += signatureLength;
+	return uniqueKey;
 }
 /* 
  * Answer the declaring class to use in the constant pool
@@ -524,8 +518,8 @@
 
 /* Answer true if the receiver has private visibility and is used locally
 */
-public final boolean isPrivateUsed() {
-	return (modifiers & AccPrivateUsed) != 0;
+public final boolean isUsed() {
+	return (modifiers & AccLocallyUsed) != 0;
 }
 
 /* Answer true if the receiver has protected visibility
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java
index 39d9264..4a97210 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java
@@ -20,7 +20,6 @@
 import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
 import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
 import org.eclipse.jdt.internal.compiler.flow.UnconditionalFlowInfo;
-import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
 import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
 
@@ -212,10 +211,9 @@
 		if (referenceContext instanceof AbstractMethodDeclaration) {
 			AbstractMethodDeclaration methodDecl = (AbstractMethodDeclaration)referenceContext;
 			MethodBinding method = methodDecl.binding;
-			CompilerOptions options = compilationUnitScope().environment.options;
 			if (!(method.isAbstract()
-					|| (method.isImplementing() && !options.reportUnusedParameterWhenImplementingAbstract) 
-					|| (method.isOverriding() && !method.isImplementing() && !options.reportUnusedParameterWhenOverridingConcrete)
+					|| (method.isImplementing() && !compilerOptions().reportUnusedParameterWhenImplementingAbstract) 
+					|| (method.isOverriding() && !method.isImplementing() && !compilerOptions().reportUnusedParameterWhenOverridingConcrete)
 					|| method.isMain())) {
 				isReportingUnusedArgument = true;
 			}
@@ -300,7 +298,7 @@
 
 		Argument[] argTypes = method.arguments;
 		int argLength = argTypes == null ? 0 : argTypes.length;
-		if (argLength > 0 && environment().options.sourceLevel >= ClassFileConstants.JDK1_5) {
+		if (argLength > 0 && compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) {
 			if (argTypes[--argLength].isVarArgs())
 				method.binding.modifiers |= AccVarargs;
 			while (--argLength >= 0) {
@@ -311,7 +309,7 @@
 		
 		TypeParameter[] typeParameters = method.typeParameters();
 	    // do not construct type variables if source < 1.5
-		if (typeParameters == null || environment().options.sourceLevel < ClassFileConstants.JDK1_5) {
+		if (typeParameters == null || compilerOptions().sourceLevel < ClassFileConstants.JDK1_5) {
 		    method.binding.typeVariables = NoTypeVariables;
 		} else {
 			method.binding.typeVariables = createTypeVariables(typeParameters, method.binding);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier.java
index a51f5bc..0046db1 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier.java
@@ -12,6 +12,7 @@
 
 import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
 import org.eclipse.jdt.internal.compiler.util.HashtableOfObject;
 
@@ -100,6 +101,7 @@
 }
 void checkAgainstInheritedMethods(MethodBinding currentMethod, MethodBinding[] methods, int length, MethodBinding[] otherInheritedMethods) {
 	boolean isAnnotationMember = this.type.isAnnotationType();
+	CompilerOptions options = type.scope.compilerOptions();
 	nextMethod : for (int i = length; --i >= 0;) {
 		MethodBinding inheritedMethod = methods[i];
 		if (isAnnotationMember) { // annotation cannot override any method
@@ -135,8 +137,8 @@
 			problemReporter(currentMethod).finalMethodCannotBeOverridden(currentMethod, inheritedMethod);
 		if (!isAsVisible(currentMethod, inheritedMethod))
 			problemReporter(currentMethod).visibilityConflict(currentMethod, inheritedMethod);
-		if (environment.options.reportDeprecationWhenOverridingDeprecatedMethod && inheritedMethod.isViewedAsDeprecated()) {
-			if (!currentMethod.isViewedAsDeprecated() || environment.options.reportDeprecationInsideDeprecatedCode) {
+		if (options.reportDeprecationWhenOverridingDeprecatedMethod && inheritedMethod.isViewedAsDeprecated()) {
+			if (!currentMethod.isViewedAsDeprecated() || options.reportDeprecationInsideDeprecatedCode) {
 				// check against the other inherited methods to see if they hide this inheritedMethod
 				ReferenceBinding declaringClass = inheritedMethod.declaringClass;
 				if (declaringClass.isInterface())
@@ -176,7 +178,7 @@
 		int j = inheritedExceptions.length;
 		while (--j > -1 && !isSameClassOrSubclassOf(newException, inheritedExceptions[j])){/*empty*/}
 		if (j == -1)
-			if (!(newException.isCompatibleWith(runtimeException()) || newException.isCompatibleWith(errorException())))
+			if (!newException.isUncheckedException(false))
 				problemReporter(newMethod).incompatibleExceptionInThrowsClause(this.type, newMethod, inheritedMethod, newException);
 	}
 }
@@ -275,9 +277,8 @@
 				while (index >= 0) matchingInherited[index--] = null; // clear the previous contents of the matching methods
 				MethodBinding currentMethod = current[i];
 				for (int j = 0, length2 = inherited.length; j < length2; j++) {
-					MethodBinding inheritedMethod = inherited[j];
+					MethodBinding inheritedMethod = computeSubstituteMethod(inherited[j], currentMethod);
 					if (inheritedMethod != null) {
-						inheritedMethod = computeSubstituteMethod(inheritedMethod, currentMethod);
 						if (areMethodsEqual(currentMethod, inheritedMethod)) {
 							matchingInherited[++index] = inheritedMethod;
 							inherited[j] = null; // do not want to find it again
@@ -301,11 +302,13 @@
 					if (canSkipInheritedMethods(inheritedMethod, otherInheritedMethod))
 						continue;
 					otherInheritedMethod = computeSubstituteMethod(otherInheritedMethod, inheritedMethod);
-					if (areMethodsEqual(inheritedMethod, otherInheritedMethod)) {
-						matchingInherited[++index] = otherInheritedMethod;
-						inherited[j] = null; // do not want to find it again
-					} else {
-						checkForInheritedNameClash(inheritedMethod, otherInheritedMethod);
+					if (otherInheritedMethod != null) {
+						if (areMethodsEqual(inheritedMethod, otherInheritedMethod)) {
+							matchingInherited[++index] = otherInheritedMethod;
+							inherited[j] = null; // do not want to find it again
+						} else {
+							checkForInheritedNameClash(inheritedMethod, otherInheritedMethod);
+						}
 					}
 				}
 			}
@@ -507,20 +510,12 @@
 	}
 }
 MethodBinding computeSubstituteMethod(MethodBinding inheritedMethod, MethodBinding currentMethod) {
+	if (inheritedMethod == null) return null;
+	if (currentMethod.parameters.length != inheritedMethod.parameters.length) return null; // no match
 	return inheritedMethod;
 }
 public boolean doesMethodOverride(MethodBinding method, MethodBinding inheritedMethod) {
-	return areReturnTypesEqual(method, inheritedMethod) && areMethodsEqual(method, inheritedMethod);
-}
-public boolean doReturnTypesCollide(MethodBinding method, MethodBinding inheritedMethod) {
-	return method.returnType != inheritedMethod.returnType
-		&& org.eclipse.jdt.core.compiler.CharOperation.equals(method.selector, inheritedMethod.selector)
-		&& method.areParametersEqual(inheritedMethod);
-}
-ReferenceBinding errorException() {
-	if (errorException == null)
-		this.errorException = this.type.scope.getJavaLangError();
-	return errorException;
+	return areMethodsEqual(method, inheritedMethod) && areReturnTypesEqual(method, inheritedMethod);
 }
 boolean isAsVisible(MethodBinding newMethod, MethodBinding inheritedMethod) {
 	if (inheritedMethod.modifiers == newMethod.modifiers) return true;
@@ -585,11 +580,6 @@
 		exceptions[i] = BinaryTypeBinding.resolveType(exceptions[i], this.environment, true);
 	return exceptions;
 }
-ReferenceBinding runtimeException() {
-	if (runtimeException == null)
-		this.runtimeException = this.type.scope.getJavaLangRuntimeException();
-	return runtimeException;
-}
 void verify(SourceTypeBinding someType) {
 	this.type = someType;
 	computeMethods();
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java
index bab6c81..b4ab0e6 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java
@@ -10,11 +10,6 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.lookup;
 
-import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
-import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
-import org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression;
-import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
-import org.eclipse.jdt.internal.compiler.env.IConstants;
 import org.eclipse.jdt.internal.compiler.util.HashtableOfObject;
 
 class MethodVerifier15 extends MethodVerifier {
@@ -36,8 +31,9 @@
 	for (int i = 0; i < length; i++) {
 		if (!areTypesEqual(oneArgs[i], twoArgs[i])) {
 			// methods with raw parameters are considered equal to inherited methods with parameterized parameters for backwards compatibility
-			if (oneArgs[i].isRawType() && !one.declaringClass.isInterface() && oneArgs[i].isEquivalentTo(twoArgs[i]))
-				continue;
+			if (!one.declaringClass.isInterface() && oneArgs[i].leafComponentType().isRawType())
+				if (oneArgs[i].dimensions() == twoArgs[i].dimensions() && oneArgs[i].leafComponentType().isEquivalentTo(twoArgs[i].leafComponentType()))
+					continue;
 			return false;
 		}
 	}
@@ -298,7 +294,7 @@
 					if (canSkipInheritedMethods(inheritedMethod, otherInheritedMethod))
 						continue;
 					otherInheritedMethod = computeSubstituteMethod(otherInheritedMethod, inheritedMethod);
-					if (areMethodsEqual(inheritedMethod, otherInheritedMethod)) {
+					if (otherInheritedMethod != null && areMethodsEqual(inheritedMethod, otherInheritedMethod)) {
 						matchingInherited[++index] = otherInheritedMethod;
 						inherited[j] = null; // do not want to find it again
 					}
@@ -311,6 +307,7 @@
 }
 MethodBinding computeSubstituteMethod(MethodBinding inheritedMethod, MethodBinding currentMethod) {
 	if (inheritedMethod == null) return null;
+	if (currentMethod.parameters.length != inheritedMethod.parameters.length) return null; // no match
 
 	// due to hierarchy & compatibility checks, we need to ensure these 2 methods are resolved
 	if (currentMethod.declaringClass instanceof BinaryTypeBinding)
@@ -318,11 +315,10 @@
 	if (inheritedMethod.declaringClass instanceof BinaryTypeBinding)
 		((BinaryTypeBinding) inheritedMethod.declaringClass).resolveTypesFor(inheritedMethod);
 
-	TypeVariableBinding[] inheritedTypeVariables = inheritedMethod.typeVariables();
+	TypeVariableBinding[] inheritedTypeVariables = inheritedMethod.typeVariables;
 	if (inheritedTypeVariables == NoTypeVariables) return inheritedMethod;
-	TypeVariableBinding[] typeVariables = currentMethod == null ? NoTypeVariables : currentMethod.typeVariables;
-
 	int inheritedLength = inheritedTypeVariables.length;
+	TypeVariableBinding[] typeVariables = currentMethod.typeVariables;
 	int length = typeVariables.length;
 	TypeBinding[] arguments = new TypeBinding[inheritedLength];
 	if (inheritedLength <= length) {
@@ -330,7 +326,7 @@
 	} else {
 		System.arraycopy(typeVariables, 0, arguments, 0, length);
 		for (int i = length; i < inheritedLength; i++)
-			arguments[i] = inheritedTypeVariables[i].erasure();
+			arguments[i] = inheritedTypeVariables[i].upperBound();
 	}
 	ParameterizedGenericMethodBinding substitute =
 		new ParameterizedGenericMethodBinding(inheritedMethod, arguments, this.environment);
@@ -357,7 +353,8 @@
 	return false;
 }
 public boolean doesMethodOverride(MethodBinding one, MethodBinding two) {
-	return super.doesMethodOverride(one, computeSubstituteMethod(two, one));
+	MethodBinding sub = computeSubstituteMethod(two, one);
+	return sub != null && super.doesMethodOverride(one, sub);
 }
 boolean doParametersClash(MethodBinding one, MethodBinding substituteTwo) {
 	// must check each parameter pair to see if parameterized types are compatible
@@ -381,45 +378,18 @@
 	}
 	return false;
 }
-public boolean doReturnTypesCollide(MethodBinding method, MethodBinding inheritedMethod) {
-	MethodBinding sub = computeSubstituteMethod(inheritedMethod, method);
-	return org.eclipse.jdt.core.compiler.CharOperation.equals(method.selector, sub.selector)
-		&& method.areParameterErasuresEqual(sub)
-		&& !areReturnTypesEqual(method, sub);
-}
 boolean doTypeVariablesClash(MethodBinding one, MethodBinding substituteTwo) {
 	return one.typeVariables != NoTypeVariables && !one.areTypeVariableErasuresEqual(substituteTwo.original());
 }
 boolean isInterfaceMethodImplemented(MethodBinding inheritedMethod, MethodBinding existingMethod, ReferenceBinding superType) {
+	if (inheritedMethod.original() != inheritedMethod && existingMethod.declaringClass.isInterface())
+		return false; // must hold onto ParameterizedMethod to see if a bridge method is necessary
+
 	inheritedMethod = computeSubstituteMethod(inheritedMethod, existingMethod);
-	return inheritedMethod.returnType == existingMethod.returnType
+	return inheritedMethod != null
+		&& inheritedMethod.returnType == existingMethod.returnType
 		&& super.isInterfaceMethodImplemented(inheritedMethod, existingMethod, superType);
 }
-boolean mustImplementAbstractMethod(ReferenceBinding declaringClass) {
-	if (!this.type.isEnum())
-		return super.mustImplementAbstractMethod(declaringClass);
-	if (this.type.isAnonymousType())
-		return true; // body of enum constant must implement any inherited abstract methods
-	if (this.type.isAbstract())
-		return false; // is an enum that has since been tagged as abstract by the code below
-
-	// enum type needs to implement abstract methods if one of its constants does not supply a body
-	TypeDeclaration typeDeclaration = this.type.scope.referenceContext;
-	FieldDeclaration[] fields = typeDeclaration.fields;
-	int length = typeDeclaration.fields == null ? 0 : typeDeclaration.fields.length;
-	if (length == 0) return true; // has no constants so must implement the method itself
-	for (int i = 0; i < length; i++) {
-		FieldDeclaration fieldDecl = fields[i];
-		if (fieldDecl.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT)
-			if (!(fieldDecl.initialization instanceof QualifiedAllocationExpression))
-				return true;
-	}
-
-	// tag this enum as abstract since an abstract method must be implemented AND all enum constants define an anonymous body
-	// as a result, each of its anonymous constants will see it as abstract and must implement each inherited abstract method
-	this.type.modifiers |= IConstants.AccAbstract;
-	return false;
-}
 void verify(SourceTypeBinding someType) {
 	if (someType.isAnnotationType())
 		someType.detectAnnotationCycle();
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/NestedTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/NestedTypeBinding.java
index 1e220cd..a6cb34c 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/NestedTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/NestedTypeBinding.java
@@ -209,7 +209,7 @@
 		if (!onlyExactMatch){
 			for (int i = enclosingInstances.length; --i >= 0;)
 				if (enclosingInstances[i].actualOuterLocalVariable == null)
-					if (((ReferenceBinding)enclosingInstances[i].type).findSuperTypeErasingTo(targetEnclosingType) != null)
+					if (((ReferenceBinding)enclosingInstances[i].type).findSuperTypeWithSameErasure(targetEnclosingType) != null)
 						return enclosingInstances[i];
 		}
 		return null;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java
index d62d0cc..f4bf02e 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java
@@ -68,7 +68,7 @@
  * slash separated name
  * org.eclipse.jdt.core --> org/eclipse/jdt/core
  */
-public char[] computeUniqueKey(boolean withAccessFlags) {
+public char[] computeUniqueKey(boolean isLeaf) {
 	return CharOperation.concatWith(compoundName, '/');
 }
 private PackageBinding findPackage(char[] name) {
@@ -135,7 +135,7 @@
 
 	typeBinding = BinaryTypeBinding.resolveType(typeBinding, environment, false); // no raw conversion for now
 	if (typeBinding.isNestedType())
-		return new ProblemReferenceBinding(name, InternalNameProvided);
+		return new ProblemReferenceBinding(name, typeBinding, InternalNameProvided);
 	return typeBinding;
 }
 /* Answer the type named name if it exists in the cache.
@@ -166,7 +166,7 @@
 	if (typeBinding != null && typeBinding != LookupEnvironment.TheNotFoundType) {
 		typeBinding = BinaryTypeBinding.resolveType(typeBinding, environment, false); // no raw conversion for now
 		if (typeBinding.isNestedType())
-			return new ProblemReferenceBinding(name, InternalNameProvided);
+			return new ProblemReferenceBinding(name, typeBinding, InternalNameProvided);
 		return typeBinding;
 	}
 
@@ -177,7 +177,7 @@
 	if (typeBinding == null) { // have not looked for it before
 		if ((typeBinding = environment.askForType(this, name)) != null) {
 			if (typeBinding.isNestedType())
-				return new ProblemReferenceBinding(name, InternalNameProvided);
+				return new ProblemReferenceBinding(name, typeBinding, InternalNameProvided);
 			return typeBinding;
 		}
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedFieldBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedFieldBinding.java
index ab78214..7f8ef3d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedFieldBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedFieldBinding.java
@@ -25,7 +25,11 @@
 	public ParameterizedFieldBinding(ParameterizedTypeBinding parameterizedDeclaringClass, FieldBinding originalField) {
 	    super (
 	            originalField.name, 
-	            originalField.isStatic() ? originalField.type : Scope.substitute(parameterizedDeclaringClass, originalField.type), 
+	            (originalField.modifiers & AccEnum) != 0
+	            	? parameterizedDeclaringClass // enum constant get paramType as its type
+           			: (originalField.modifiers & AccStatic) != 0 
+           					? originalField.type // no subst for static field
+           					: Scope.substitute(parameterizedDeclaringClass, originalField.type), 
 	            originalField.modifiers, 
 	            parameterizedDeclaringClass, 
 	            null);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java
index 659cde6..2b04872 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java
@@ -68,23 +68,13 @@
 			// 15.12.2.8 - inferring unresolved type arguments
 			if (hasUnresolvedTypeArgument(substitutes)) {
 				TypeBinding expectedType = null;
-				// if message invocation has expected type
-				if (invocationSite instanceof MessageSend) {
-					MessageSend message = (MessageSend) invocationSite;
-					expectedType = message.expectedType;
-				}
-				TypeBinding upperBound = null;
-				if (methodSubstitute.returnType.isTypeVariable()) {
-					// should be: if no expected type, then assume Object
-					// actually it rather seems to handle the returned variable case by expecting its erasure instead
-					upperBound = methodSubstitute.returnType.erasure();
-				} else {
-					if (methodSubstitute.returnType.id != TypeIds.T_void)
-						upperBound = scope.getJavaLangObject(); 
-				}
-				// Object o = foo(); // where <T extends Serializable> T foo();
-				if (expectedType == null || upperBound.isCompatibleWith(expectedType)) {
-					expectedType = upperBound;
+				if (methodSubstitute.returnType != VoidBinding) {
+					// if message invocation has expected type
+					if (invocationSite instanceof MessageSend) {
+						MessageSend message = (MessageSend) invocationSite;
+						expectedType = message.expectedType;
+					}
+					if (expectedType == null) expectedType = scope.getJavaLangObject(); // assume Object by default
 				}
 				methodSubstitute = methodSubstitute.inferFromExpectedType(scope, expectedType, collectedSubstitutes, substitutes);
 				if (methodSubstitute == null) 
@@ -100,7 +90,12 @@
 				switch (typeVariable.boundCheck(methodSubstitute, substitute)) {
 					case TypeConstants.MISMATCH :
 				        // incompatible due to bound check
-				        return new ProblemMethodBinding(methodSubstitute, originalMethod.selector, new TypeBinding[]{substitute, typeVariables[i] }, ParameterBoundMismatch);
+						int argLength = arguments.length;
+						TypeBinding[] augmentedArguments = new TypeBinding[argLength + 2]; // append offending substitute and typeVariable 
+						System.arraycopy(arguments, 0, augmentedArguments, 0, argLength);
+						augmentedArguments[argLength] = substitute;
+						augmentedArguments[argLength+1] = typeVariable;
+				        return new ProblemMethodBinding(methodSubstitute, originalMethod.selector, augmentedArguments, ParameterBoundMismatch);
 					case TypeConstants.UNCHECKED :
 						// tolerate unchecked bounds
 						methodSubstitute.isUnchecked = true;
@@ -141,10 +136,21 @@
 			if (minArgLength < argLength) {
 				TypeBinding varargType = parameters[minArgLength]; // last arg type - as is ?
 				TypeBinding lastArgument = arguments[minArgLength];
-				if (paramLength != argLength // argument is passed as is ?
-						||  (lastArgument != NullBinding
-								&& (lastArgument.dimensions() == 0 || lastArgument.leafComponentType().isBaseType() != varargType.leafComponentType().isBaseType()))) { 
-					varargType = ((ArrayBinding)varargType).elementsType(); // eliminate one array dimension
+				checkVarargDimension: {
+					if (paramLength == argLength) {
+						if (lastArgument == NullBinding) break checkVarargDimension;
+						switch (lastArgument.dimensions()) {
+							case 0 :
+								break; // will remove one dim
+							case 1 :
+								if (!lastArgument.leafComponentType().isBaseType()) break checkVarargDimension;
+								break; // will remove one dim
+							default :
+								break checkVarargDimension;
+						}
+					}
+					// eliminate one array dimension
+					varargType = ((ArrayBinding)varargType).elementsType(); 
 				}
 				for (int i = minArgLength; i < argLength; i++) {
 					varargType.collectSubstitutes(scope, arguments[i], collectedSubstitutes, CONSTRAINT_EXTENDS);
@@ -201,6 +207,18 @@
 							TypeBinding equalSubstitute = equalSubstitutes[j];
 							if (equalSubstitute == null) continue nextConstraint;
 //							if (equalSubstitute == current) continue nextConstraint;
+							if (equalSubstitute == current) {
+								// try to find a better different match if any in subsequent equal candidates
+								for (int k = j+1; k < equalLength; k++) {
+									equalSubstitute = equalSubstitutes[k];
+									if (equalSubstitute != current && equalSubstitute != null) {
+										substitutes[i] = equalSubstitute;
+										continue nextTypeParameter;
+									}
+								}
+								substitutes[i] = current;
+								continue nextTypeParameter;
+							}
 //							if (equalSubstitute.isTypeVariable()) {
 //								TypeVariableBinding variable = (TypeVariableBinding) equalSubstitute;
 //								// substituted by a variable of the same method, ignore
@@ -264,7 +282,7 @@
 		int length = originalVariables.length;
 		TypeBinding[] rawArguments = new TypeBinding[length];
 		for (int i = 0; i < length; i++) {
-			rawArguments[i] = originalVariables[i].erasure();
+			rawArguments[i] = originalVariables[i].upperBound();
 		}		
 	    this.isRaw = true;
 		this.isUnchecked = false;
@@ -310,19 +328,19 @@
 
 	/*
 	 * parameterizedDeclaringUniqueKey dot selector originalMethodGenericSignature percent typeArguments
-	 * p.X<U> { <T> void bar(T t, U u) { new X<String>().bar(this, "") } } --> Lp/X<Ljava/lang/String;>;.bar<T:Ljava/lang/Object;>(TT;TU;)V^123%<Lp/X;>
+	 * p.X<U> { <T> void bar(T t, U u) { new X<String>().bar(this, "") } } --> Lp/X<Ljava/lang/String;>;.bar<T:Ljava/lang/Object;>(TT;Ljava/lang/String;)V%<Lp/X;>
 	 */
-	public char[] computeUniqueKey(boolean withAccessFlags) {
-		if (this.isRaw)
-			return super.computeUniqueKey(withAccessFlags);
+	public char[] computeUniqueKey(boolean isLeaf) {
 		StringBuffer buffer = new StringBuffer();
-		buffer.append(super.computeUniqueKey(withAccessFlags));
+		buffer.append(this.originalMethod.computeUniqueKey(false/*not a leaf*/));
 		buffer.append('%');
 		buffer.append('<');
-		int length = this.typeArguments.length;
-		for (int i = 0; i < length; i++) {
-			TypeBinding typeArgument = this.typeArguments[i];
-			buffer.append(typeArgument.computeUniqueKey(false/*without access flags*/));
+		if (!this.isRaw) {
+			int length = this.typeArguments.length;
+			for (int i = 0; i < length; i++) {
+				TypeBinding typeArgument = this.typeArguments[i];
+				buffer.append(typeArgument.computeUniqueKey(false/*not a leaf*/));
+			}
 		}
 		buffer.append('>');
 		int resultLength = buffer.length();
@@ -368,19 +386,28 @@
 		computeSubstitutes: {
 		    // infer from expected return type
 			if (expectedType != null) {
-			    returnType.collectSubstitutes(scope, expectedType, collectedSubstitutes, CONSTRAINT_SUPER);
+			    this.returnType.collectSubstitutes(scope, expectedType, collectedSubstitutes, CONSTRAINT_SUPER);
 			}
 		    // infer from bounds of type parameters
 			for (int i = 0; i < varLength; i++) {
 				TypeVariableBinding originalVariable = originalVariables[i];
 				TypeBinding argument = this.typeArguments[i];
+				boolean argAlreadyInferred = argument != originalVariable;
 				if (originalVariable.firstBound == originalVariable.superclass) {
-					Scope.substitute(this, originalVariable.firstBound) // substitue original bound with resolved variables
-						.collectSubstitutes(scope, argument, collectedSubstitutes, CONSTRAINT_EXTENDS);
+					TypeBinding substitutedBound = Scope.substitute(this, originalVariable.superclass);
+					argument.collectSubstitutes(scope, substitutedBound, collectedSubstitutes, CONSTRAINT_SUPER);
+					// JLS 15.12.2.8 claims reverse inference shouldn't occur, however it improves inference
+					// e.g. given: <E extends Object, S extends Collection<E>> S test1(S param)
+					//                   invocation: test1(new Vector<String>())    will infer: S=Vector<String>  and with code below: E=String
+					if (argAlreadyInferred)
+						substitutedBound.collectSubstitutes(scope, argument, collectedSubstitutes, CONSTRAINT_EXTENDS);
 				}
 				for (int j = 0, max = originalVariable.superInterfaces.length; j < max; j++) {
-					Scope.substitute(this, originalVariable.superInterfaces[j]) // substitue original bound with resolved variables
-						.collectSubstitutes(scope, argument, collectedSubstitutes, CONSTRAINT_EXTENDS);
+					TypeBinding substitutedBound = Scope.substitute(this, originalVariable.superInterfaces[j]);
+					argument.collectSubstitutes(scope, substitutedBound, collectedSubstitutes, CONSTRAINT_SUPER);
+					// JLS 15.12.2.8 claims reverse inference shouldn't occur, however it improves inference
+					if (argAlreadyInferred)
+						substitutedBound.collectSubstitutes(scope, argument, collectedSubstitutes, CONSTRAINT_EXTENDS);
 				}
 			}
 			substitutes = resolveSubstituteConstraints(scope, originalVariables, substitutes, true/*consider Ti<:Uk*/, collectedSubstitutes);
@@ -391,7 +418,7 @@
 		    	this.isRaw = true;
 				this.isUnchecked = false;
 		    	for (int i = 0; i < varLength; i++) {
-		    		this.typeArguments[i] = originalVariables[i].erasure();
+		    		this.typeArguments[i] = originalVariables[i].upperBound();
 		    	}
 		    	break computeSubstitutes;
 			}
@@ -402,7 +429,7 @@
 	    			this.typeArguments[i] = substitutes[i];
 	    		} else {
 	    			// remaining unresolved variable are considered to be Object (or their bound actually)
-		    		this.typeArguments[i] = originalVariables[i].erasure();
+		    		this.typeArguments[i] = originalVariables[i].upperBound();
 		    	}
 	    	}
 		}		
@@ -443,7 +470,7 @@
 	 */
 	public MethodBinding tiebreakMethod() {
 		if (this.tiebreakMethod == null) {
-			this.tiebreakMethod = new ParameterizedGenericMethodBinding(this.originalMethod, (RawTypeBinding)null, this.environment);
+			this.tiebreakMethod = this.isRaw ? this : new ParameterizedGenericMethodBinding(this.originalMethod, (RawTypeBinding)null, this.environment);
 		} 
 		return this.tiebreakMethod;
 	}	
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedMethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedMethodBinding.java
index d3e82eb..0bdbc4c 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedMethodBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedMethodBinding.java
@@ -75,11 +75,14 @@
 			for (int i = 0; i < length; i++) {
 				TypeVariableBinding originalVariable = originalVariables[i];
 				TypeVariableBinding substitutedVariable = substitutedVariables[i];
-				substitutedVariable.superclass = (ReferenceBinding) Scope.substitute(substitution, originalVariable.superclass);
+				TypeBinding substitutedSuperclass = Scope.substitute(substitution, originalVariable.superclass);
+				substitutedVariable.superclass = (ReferenceBinding) (substitutedSuperclass.isArrayType() 
+							? parameterizedDeclaringClass.environment.getType(JAVA_LANG_OBJECT)
+							: substitutedSuperclass);
 				substitutedVariable.superInterfaces = Scope.substitute(substitution, originalVariable.superInterfaces);
 				if (originalVariable.firstBound != null) {
 					substitutedVariable.firstBound = originalVariable.firstBound == originalVariable.superclass
-						? substitutedVariable.superclass
+						? substitutedSuperclass // could be array type
 						: substitutedVariable.superInterfaces[0];
 				}
 			}
@@ -95,14 +98,6 @@
 		// no init
 	}
 
-	/*
-	 * parameterizedDeclaringUniqueKey dot selector originalMethodGenericSignature
-	 * p.X<U> { void bar(U u) { new X<String>().bar("") } } --> Lp/X<Ljava/lang/String;>;.bar(TU;)V^123
-	 */
-	public char[] computeUniqueKey(boolean withAccessFlags) {
-		return computeUniqueKey(original(), withAccessFlags);
-	}
-
 	/**
 	 * The type of x.getClass() is substituted from 'Class<? extends Object>' into: 'Class<? extends |X|> where |X| is X's erasure.
 	 */
@@ -116,7 +111,7 @@
 		method.parameters = originalMethod.parameters;
 		method.thrownExceptions = originalMethod.thrownExceptions;
 		ReferenceBinding genericClassType = scope.getJavaLangClass();
-		method.returnType = scope.createParameterizedType(
+		method.returnType = scope.environment().createParameterizedType(
 			genericClassType,
 			new TypeBinding[] {  scope.environment().createWildcard(genericClassType, 0, receiverType.erasure(), null /*no extra bound*/, Wildcard.EXTENDS) },
 			null);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java
index 1217d4c..3dcf439 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java
@@ -12,6 +12,7 @@
 
 import java.util.Map;
 import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.ast.TypeReference;
 import org.eclipse.jdt.internal.compiler.ast.Wildcard;
 
 /**
@@ -33,9 +34,8 @@
 	public ParameterizedTypeBinding(ReferenceBinding type, TypeBinding[] arguments,  ReferenceBinding enclosingType, LookupEnvironment environment){
 
 		this.environment = environment;
-		initialize(type, arguments);
 		this.enclosingType = enclosingType; // never unresolved, never lazy per construction
-
+		initialize(type, arguments);
 		if (type instanceof UnresolvedReferenceBinding)
 			((UnresolvedReferenceBinding) type).addWrapper(this);
 		if (arguments != null) {
@@ -47,6 +47,25 @@
 	}
 
 	/**
+	 * Iterate type arguments, and validate them according to corresponding variable bounds.
+	 */
+	public void boundCheck(Scope scope, TypeReference[] argumentReferences) {
+		if ((this.tagBits & PassedBoundCheck) == 0) {
+			boolean hasErrors = false;
+			TypeVariableBinding[] typeVariables = this.type.typeVariables();
+			if (this.arguments != null && typeVariables != null) { // arguments may be null in error cases
+				for (int i = 0, length = typeVariables.length; i < length; i++) {
+				    if (typeVariables[i].boundCheck(this, this.arguments[i])  != TypeConstants.OK) {
+				    	hasErrors = true;
+						scope.problemReporter().typeMismatchError(this.arguments[i], typeVariables[i], this.type, argumentReferences[i]);
+				    }
+				}
+			}	
+			if (!hasErrors) this.tagBits |= PassedBoundCheck; // no need to recheck it in the future
+		}
+	}
+	
+	/**
 	 * @see org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding#canBeInstantiated()
 	 */
 	public boolean canBeInstantiated() {
@@ -57,26 +76,36 @@
 	}	
 	/**
 	 * Perform capture conversion for a parameterized type with wildcard arguments
-	 * @see org.eclipse.jdt.internal.compiler.lookup.TypeBinding#capture()
+	 * @see org.eclipse.jdt.internal.compiler.lookup.TypeBinding#capture(Scope,int)
 	 */
-	public TypeBinding capture() {
-		TypeBinding[] originalArguments = arguments, capturedArguments = originalArguments;
-		if ((this.tagBits & TagBits.HasDirectWildcard) != 0) {
-			int length = originalArguments.length;
-			capturedArguments = new TypeBinding[length];
-			for (int i = 0; i < length; i++) {
-				TypeBinding argument = originalArguments[i];
-				if (argument.kind() == Binding.WILDCARD_TYPE) {
-					capturedArguments[i] = new CaptureBinding((WildcardBinding) argument);
-				} else {
-					capturedArguments[i] = argument;
-				}
+	public TypeBinding capture(Scope scope, int position) {
+		if ((this.tagBits & TagBits.HasDirectWildcard) == 0) 
+			return this;
+		
+		TypeBinding[] originalArguments = arguments;
+		int length = originalArguments.length;
+		TypeBinding[] capturedArguments = new TypeBinding[length];
+		
+		// Retrieve the type context for capture bindingKey
+		ReferenceBinding contextType = scope.enclosingSourceType();
+		if (contextType != null) contextType = contextType.outermostEnclosingType(); // maybe null when used programmatically by DOM
+		
+		for (int i = 0; i < length; i++) {
+			TypeBinding argument = originalArguments[i];
+			if (argument.kind() == Binding.WILDCARD_TYPE && ((WildcardBinding)argument).otherBounds == null) { // no capture for intersection types
+				capturedArguments[i] = new CaptureBinding((WildcardBinding) argument, contextType, position);
+			} else {
+				capturedArguments[i] = argument;
 			}
 		}
-		if (capturedArguments != originalArguments) {
-			return this.environment.createParameterizedType(this.type, capturedArguments, enclosingType());
+		ParameterizedTypeBinding capturedParameterizedType = this.environment.createParameterizedType(this.type, capturedArguments, enclosingType());
+		for (int i = 0; i < length; i++) {
+			TypeBinding argument = capturedArguments[i];
+			if (argument.isCapture()) {
+				((CaptureBinding)argument).initializeBounds(capturedParameterizedType);
+			}
 		}
-		return this;
+		return capturedParameterizedType;
 	}
 	/**
 	 * Collect the substitutes into a map for certain type variables inside the receiver type
@@ -94,12 +123,12 @@
 			case CONSTRAINT_EQUAL :
 			case CONSTRAINT_EXTENDS :
 				equivalent = this;
-		        otherEquivalent = ((ReferenceBinding)otherType).findSuperTypeErasingTo((ReferenceBinding)this.type.erasure());
+		        otherEquivalent = ((ReferenceBinding)otherType).findSuperTypeWithSameErasure(this.type);
 		        if (otherEquivalent == null) return;
 		        break;
 			case CONSTRAINT_SUPER :
 	        default:
-		        equivalent = this.findSuperTypeErasingTo((ReferenceBinding)(otherType.erasure()));
+		        equivalent = this.findSuperTypeWithSameErasure(otherType);
 		        if (equivalent == null) return;
 		        otherEquivalent = (ReferenceBinding) otherType;
 		        break;
@@ -145,10 +174,10 @@
 		this.id = NoId;		
 	}
 	
-	public char[] computeUniqueKey(boolean withAccessFlags) {
+	public char[] computeUniqueKey(boolean isLeaf) {
 	    StringBuffer sig = new StringBuffer(10);
 		if (this.isMemberType() && enclosingType().isParameterizedType()) {
-		    char[] typeSig = enclosingType().computeUniqueKey(false/*without access flags*/);
+		    char[] typeSig = enclosingType().computeUniqueKey(false/*not a leaf*/);
 		    for (int i = 0; i < typeSig.length-1; i++) sig.append(typeSig[i]); // copy all but trailing semicolon
 		    sig.append('.').append(sourceName());
 		} else if(this.type.isLocalType()){
@@ -157,26 +186,32 @@
 			ReferenceBinding temp;
 			while ((temp = enclosing.enclosingType()) != null)
 				enclosing = temp;
-			char[] typeSig = enclosing.signature();
+			char[] typeSig = enclosing.computeUniqueKey(false/*not a leaf*/);
 		    for (int i = 0; i < typeSig.length-1; i++) sig.append(typeSig[i]); // copy all but trailing semicolon
 			sig.append('$');
 			sig.append(localTypeBinding.sourceStart);
 		} else {
-		    char[] typeSig = this.type.signature();
+		    char[] typeSig = this.type.computeUniqueKey(false/*not a leaf*/);
 		    for (int i = 0; i < typeSig.length-1; i++) sig.append(typeSig[i]); // copy all but trailing semicolon
-		}	   	    
+		}
+		ReferenceBinding captureSourceType = null;
 		if (this.arguments != null) {
 		    sig.append('<');
 		    for (int i = 0, length = this.arguments.length; i < length; i++) {
-		        sig.append(this.arguments[i].computeUniqueKey(false/*without access flags*/));
+		    	TypeBinding typeBinding = this.arguments[i];
+		        sig.append(typeBinding.computeUniqueKey(false/*not a leaf*/));
+		        if (typeBinding instanceof CaptureBinding)
+		        	captureSourceType = ((CaptureBinding) typeBinding).sourceType;
 		    }
 		    sig.append('>'); //$NON-NLS-1$
 		}
 		sig.append(';');
-		if (withAccessFlags) {
-			sig.append('^');
-			sig.append(getAccessFlags());
+		if (captureSourceType != null && captureSourceType != this.type) {
+			// contains a capture binding
+			sig.insert(0, "&"); //$NON-NLS-1$
+			sig.insert(0, captureSourceType.computeUniqueKey(false/*not a leaf*/));
 		}
+
 		int sigLength = sig.length();
 		char[] uniqueKey = new char[sigLength];
 		sig.getChars(0, sigLength, uniqueKey, 0);			
@@ -215,12 +250,6 @@
 	 * @see org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding#enclosingType()
 	 */
 	public ReferenceBinding enclosingType() {
-		if (this.isMemberType() && this.enclosingType == null) {
-			ReferenceBinding originalEnclosing = this.type.enclosingType();
-			this.enclosingType = originalEnclosing.isGenericType()
-				? this.environment.createRawType(originalEnclosing, originalEnclosing.enclosingType()) // TODO (need to propagate in depth on enclosing type)
-				: originalEnclosing;
-		}
 	    return this.enclosingType;
 	}
 
@@ -502,7 +531,12 @@
 		// this.superInterfaces = null;
 		// this.fields = null;
 		// this.methods = null;		
-		this.modifiers = someType.modifiers | AccGenericSignature;
+		this.modifiers = someType.modifiers;
+		// only set AccGenericSignature if parameterized or have enclosing type required signature
+		if (someArguments != null)
+			this.modifiers |= AccGenericSignature;
+		else if (this.enclosingType != null) 
+			this.modifiers |= (this.enclosingType.modifiers & AccGenericSignature);
 		if (someArguments != null) {
 			this.arguments = someArguments;
 			for (int i = 0, length = someArguments.length; i < length; i++) {
@@ -536,15 +570,20 @@
 	        	return ((WildcardBinding) otherType).boundCheck(this);
 	    		
 	    	case Binding.PARAMETERIZED_TYPE :
-	            if ((otherType.tagBits & HasDirectWildcard) == 0 && (!this.isMemberType() || !otherType.isMemberType())) 
-	            	return false; // should have been identical
 	            ParameterizedTypeBinding otherParamType = (ParameterizedTypeBinding) otherType;
 	            if (this.type != otherParamType.type) 
 	                return false;
 	            if (!isStatic()) { // static member types do not compare their enclosing
-		            ReferenceBinding enclosing = enclosingType();
-		            if (enclosing != null && !enclosing.isEquivalentTo(otherParamType.enclosingType()))
-		                return false;
+	            	ReferenceBinding enclosing = enclosingType();
+	            	if (enclosing != null) {
+	            		ReferenceBinding otherEnclosing = otherParamType.enclosingType();
+	            		if (otherEnclosing == null) return false;
+	            		if ((otherEnclosing.tagBits & HasDirectWildcard) == 0) {
+							if (enclosing != otherEnclosing) return false;
+	            		} else {
+	            			if (!enclosing.isEquivalentTo(otherParamType.enclosingType())) return false;
+	            		}
+	            	}
 	            }
 	            int length = this.arguments == null ? 0 : this.arguments.length;
 	            TypeBinding[] otherArguments = otherParamType.arguments;
@@ -563,6 +602,73 @@
         return false;
 	}
 
+	public boolean isIntersectingWith(TypeBinding otherType) {
+		if (this == otherType) 
+		    return true;
+	    if (otherType == null) 
+	        return false;
+	    switch(otherType.kind()) {
+	
+	    	case Binding.PARAMETERIZED_TYPE :
+	            ParameterizedTypeBinding otherParamType = (ParameterizedTypeBinding) otherType;
+	            if (this.type != otherParamType.type) 
+	                return false;
+	            if (!isStatic()) { // static member types do not compare their enclosing
+	            	ReferenceBinding enclosing = enclosingType();
+	            	if (enclosing != null) {
+	            		ReferenceBinding otherEnclosing = otherParamType.enclosingType();
+	            		if (otherEnclosing == null) return false;
+	            		if ((otherEnclosing.tagBits & HasDirectWildcard) == 0) {
+							if (enclosing != otherEnclosing) return false;
+	            		} else {
+	            			if (!enclosing.isEquivalentTo(otherParamType.enclosingType())) return false;
+	            		}
+	            	}
+	            }
+	            int length = this.arguments == null ? 0 : this.arguments.length;
+	            TypeBinding[] otherArguments = otherParamType.arguments;
+	            int otherLength = otherArguments == null ? 0 : otherArguments.length;
+	            if (otherLength != length) 
+	                return false;
+	            for (int i = 0; i < length; i++) {
+	            	if (!this.arguments[i].isTypeArgumentIntersecting(otherArguments[i]))
+	            		return false;
+	            }
+	            return true;
+
+	    	case Binding.GENERIC_TYPE :
+	            SourceTypeBinding otherGenericType = (SourceTypeBinding) otherType;
+	            if (this.type != otherGenericType) 
+	                return false;
+	            if (!isStatic()) { // static member types do not compare their enclosing
+	            	ReferenceBinding enclosing = enclosingType();
+	            	if (enclosing != null) {
+	            		ReferenceBinding otherEnclosing = otherGenericType.enclosingType();
+	            		if (otherEnclosing == null) return false;
+	            		if ((otherEnclosing.tagBits & HasDirectWildcard) == 0) {
+							if (enclosing != otherEnclosing) return false;
+	            		} else {
+	            			if (!enclosing.isEquivalentTo(otherGenericType.enclosingType())) return false;
+	            		}
+	            	}
+	            }
+	            length = this.arguments == null ? 0 : this.arguments.length;
+	            otherArguments = otherGenericType.typeVariables();
+	            otherLength = otherArguments == null ? 0 : otherArguments.length;
+	            if (otherLength != length) 
+	                return false;
+	            for (int i = 0; i < length; i++) {
+	            	if (!this.arguments[i].isTypeArgumentIntersecting(otherArguments[i]))
+	            		return false;
+	            }
+	            return true;
+	            
+	    	case Binding.RAW_TYPE :
+	            return erasure() == otherType.erasure();
+	    }
+        return false;
+	}
+	
 	/**
 	 * @see org.eclipse.jdt.internal.compiler.lookup.TypeBinding#isParameterizedType()
 	 */
@@ -586,9 +692,12 @@
 				ReferenceBinding[] originalMemberTypes = this.type.memberTypes();
 				int length = originalMemberTypes.length;
 				ReferenceBinding[] parameterizedMemberTypes = new ReferenceBinding[length];
+				// boolean isRaw = this.isRawType();
 				for (int i = 0; i < length; i++)
 					// substitute all member types, so as to get updated enclosing types
-					parameterizedMemberTypes[i] = this.environment.createParameterizedType(originalMemberTypes[i], null, this);
+					parameterizedMemberTypes[i] = /*isRaw && originalMemberTypes[i].isGenericType()
+						? this.environment.createRawType(originalMemberTypes[i], this)
+						: */ this.environment.createParameterizedType(originalMemberTypes[i], null, this);
 				this.memberTypes = parameterizedMemberTypes;	    
 			} finally {
 				// if the original fields cannot be retrieved (ex. AbortCompilation), then assume we do not have any fields
@@ -673,14 +782,14 @@
 			} else if (argLength != refTypeVariables.length) { // check arity
 				this.environment.problemReporter.incorrectArityForParameterizedType(null, resolvedType, this.arguments);
 				return this; // cannot reach here as AbortCompilation is thrown
-			}			
-			// check argument type compatibility
-			for (int i = 0; i < argLength; i++) {
-			    TypeBinding resolvedArgument = this.arguments[i];
-				if (refTypeVariables[i].boundCheck(this, resolvedArgument) != TypeConstants.OK) {
-					this.environment.problemReporter.typeMismatchError(resolvedArgument, refTypeVariables[i], resolvedType, null);
-			    }
 			}
+			// check argument type compatibility... REMOVED for now since incremental build will propagate change & detect in source
+//			for (int i = 0; i < argLength; i++) {
+//			    TypeBinding resolvedArgument = this.arguments[i];
+//				if (refTypeVariables[i].boundCheck(this, resolvedArgument) != TypeConstants.OK) {
+//					this.environment.problemReporter.typeMismatchError(resolvedArgument, refTypeVariables[i], resolvedType, null);
+//			    }
+//			}
 		}
 		return this;
 	}
@@ -781,11 +890,15 @@
 		if (this.type == unresolvedType) {
 			this.type = resolvedType; // cannot be raw since being parameterized below
 			update = true;
+			ReferenceBinding enclosing = resolvedType.enclosingType();
+			if (enclosing != null) {
+				this.enclosingType = (ReferenceBinding) env.convertToRawType(enclosing); // needed when binding unresolved member type
+			}
 		}
 		if (this.arguments != null) {
 			for (int i = 0, l = this.arguments.length; i < l; i++) {
 				if (this.arguments[i] == unresolvedType) {
-					this.arguments[i] = resolvedType.isGenericType() ? env.createRawType(resolvedType, resolvedType.enclosingType()) : resolvedType;
+					this.arguments[i] = env.convertToRawType(resolvedType);
 					update = true;
 				}
 			}
@@ -828,7 +941,10 @@
 		if (isStatic() && isNestedType()) buffer.append("static "); //$NON-NLS-1$
 		if (isFinal()) buffer.append("final "); //$NON-NLS-1$
 	
-		buffer.append(isInterface() ? "interface " : "class "); //$NON-NLS-1$ //$NON-NLS-2$
+		if (isEnum()) buffer.append("enum "); //$NON-NLS-1$
+		else if (isAnnotationType()) buffer.append("@interface "); //$NON-NLS-1$
+		else if (isClass()) buffer.append("class "); //$NON-NLS-1$
+		else buffer.append("interface "); //$NON-NLS-1$
 		buffer.append(this.debugName());
 	
 		buffer.append("\n\textends "); //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemFieldBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemFieldBinding.java
index 0410c5c..f0cf4a1 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemFieldBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemFieldBinding.java
@@ -18,8 +18,8 @@
 		
 // NOTE: must only answer the subset of the name related to the problem
 
-public ProblemFieldBinding(ReferenceBinding declaringClass, char[][] compoundName, int problemId) {
-	this(null, declaringClass, CharOperation.concatWith(compoundName, '.'), problemId);
+public ProblemFieldBinding(FieldBinding closestMatch, char[][] compoundName, int problemId) {
+	this(closestMatch, closestMatch == null ? null : closestMatch.declaringClass, CharOperation.concatWith(compoundName, '.'), problemId);
 }
 public ProblemFieldBinding(ReferenceBinding declaringClass, char[] name, int problemId) {
 	this(null, declaringClass, name, problemId);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemReferenceBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemReferenceBinding.java
index a4a3985..8da32b1 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemReferenceBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemReferenceBinding.java
@@ -11,26 +11,18 @@
 package org.eclipse.jdt.internal.compiler.lookup;
 
 public class ProblemReferenceBinding extends ReferenceBinding {
-	public ReferenceBinding original;
+	public ReferenceBinding closestMatch;
 	private int problemReason;
-	public ReferenceBinding alternateMatch;
 	
 // NOTE: must only answer the subset of the name related to the problem
 
-public ProblemReferenceBinding(char[][] compoundName, int problemReason) {
-	this(compoundName, null, problemReason);
-}
-public ProblemReferenceBinding(char[] name, int problemReason) {
-	this(new char[][] {name}, null, problemReason);
-}
-
-public ProblemReferenceBinding(char[][] compoundName, ReferenceBinding original, int problemReason) {
+public ProblemReferenceBinding(char[][] compoundName, ReferenceBinding closestMatch, int problemReason) {
 	this.compoundName = compoundName;
-	this.original = original;
+	this.closestMatch = closestMatch;
 	this.problemReason = problemReason;
 }
-public ProblemReferenceBinding(char[] name, ReferenceBinding original, int problemReason) {
-	this(new char[][] {name}, original, problemReason);
+public ProblemReferenceBinding(char[] name, ReferenceBinding closestMatch, int problemReason) {
+	this(new char[][] {name}, closestMatch, problemReason);
 }
 /* API
 * Answer the problem id associated with the receiver.
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/RawTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/RawTypeBinding.java
index 352de0d..06f5a68 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/RawTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/RawTypeBinding.java
@@ -30,20 +30,17 @@
 			this.modifiers &= ~AccGenericSignature; // only need signature if enclosing needs one
 	}    
 	
-	public char[] computeUniqueKey(boolean withAccessFlags) {
+	public char[] computeUniqueKey(boolean isLeaf) {
 	    StringBuffer sig = new StringBuffer(10);
 		if (isMemberType() && enclosingType().isParameterizedType()) {
-		    char[] typeSig = enclosingType().computeUniqueKey(false/*without access flags*/);
+		    char[] typeSig = enclosingType().computeUniqueKey(false/*not a leaf*/);
 		    for (int i = 0; i < typeSig.length-1; i++) sig.append(typeSig[i]); // copy all but trailing semicolon
 		    sig.append('.').append(sourceName()).append('<').append('>').append(';');
 		} else {
-		     sig.append(this.type.signature()); // erasure
+		     sig.append(this.type.computeUniqueKey(false/*not a leaf*/));
 		     sig.insert(sig.length()-1, "<>"); //$NON-NLS-1$
 		}
-		if (withAccessFlags) {
-			sig.append('^');
-			sig.append(getAccessFlags());
-		}
+
 		int sigLength = sig.length();
 		char[] uniqueKey = new char[sigLength];
 		sig.getChars(0, sigLength, uniqueKey, 0);						    
@@ -112,6 +109,22 @@
 	    }
         return false;
 	}
+    
+    public boolean isIntersectingWith(TypeBinding otherType) {
+		if (this == otherType) 
+		    return true;
+	    if (otherType == null) 
+	        return false;
+	    switch(otherType.kind()) {
+	
+	    	case Binding.GENERIC_TYPE :
+	    	case Binding.PARAMETERIZED_TYPE :
+	    	case Binding.RAW_TYPE :
+	            return erasure() == otherType.erasure();
+	    }
+        return false;
+	}
+    
 	/**
 	 * Raw type is not treated as a standard parameterized type
 	 * @see org.eclipse.jdt.internal.compiler.lookup.TypeBinding#isParameterizedType()
@@ -128,7 +141,8 @@
 		int length = typeVariables.length;
 		TypeBinding[] typeArguments = new TypeBinding[length];
 		for (int i = 0; i < length; i++) {
-		    typeArguments[i] = typeVariables[i].erasure();
+			// perform raw conversion on variable upper bound - could cause infinite regression if arguments were initialized lazily
+		    typeArguments[i] = this.environment.convertToRawType(typeVariables[i].erasure());
 		}
 		this.arguments = typeArguments;
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
index 2b3456f..1d67eea 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
@@ -87,7 +87,7 @@
 		if (declaringClass == null) return false; // could be null if incorrect top-level protected type
 		//int depth = 0;
 		do {
-			if (currentType.findSuperTypeErasingTo(declaringErasure) != null) return true;
+			if (currentType.findSuperTypeWithSameErasure(declaringErasure) != null) return true;
 			//depth++;
 			currentType = currentType.enclosingType();
 		} while (currentType != null);
@@ -199,24 +199,38 @@
 	return invocationType.fPackage == fPackage;
 }
 public char[] computeGenericTypeSignature(TypeVariableBinding[] typeVariables) {
-    if (typeVariables == NoTypeVariables) {
-        return signature();
-    } else {
-	    char[] typeSig = signature();
-	    StringBuffer sig = new StringBuffer(10);
+
+	boolean isMemberOfGeneric = isMemberType() && (enclosingType().modifiers & AccGenericSignature) != 0;
+	if (typeVariables == NoTypeVariables && !isMemberOfGeneric) {
+		return signature();
+	}
+	StringBuffer sig = new StringBuffer(10);
+	if (isMemberOfGeneric) {
+	    char[] typeSig = enclosingType().genericTypeSignature();
 	    for (int i = 0; i < typeSig.length-1; i++) { // copy all but trailing semicolon
 	    	sig.append(typeSig[i]);
 	    }
+	    sig.append('.'); // NOTE: cannot override trailing ';' with '.' in enclosing signature, since shared char[]
+	    sig.append(this.sourceName);
+	}	else {
+	    char[] typeSig = signature();
+	    for (int i = 0; i < typeSig.length-1; i++) { // copy all but trailing semicolon
+	    	sig.append(typeSig[i]);
+	    }
+	}
+	if (typeVariables == NoTypeVariables) {
+	    sig.append(';');
+	} else {
 	    sig.append('<');
 	    for (int i = 0, length = typeVariables.length; i < length; i++) {
 	        sig.append(typeVariables[i].genericTypeSignature());
 	    }
 	    sig.append(">;"); //$NON-NLS-1$
-		int sigLength = sig.length();
-		char[] result = new char[sigLength];
-		sig.getChars(0, sigLength, result, 0);
-		return result;
-    }
+	}
+	int sigLength = sig.length();
+	char[] result = new char[sigLength];
+	sig.getChars(0, sigLength, result, 0);
+	return result;
 }
 public void computeId() {
 	
@@ -301,6 +315,10 @@
 					else if (CharOperation.equals(typeName, JAVA_LANG_OVERRIDE[2]))
 						id = T_JavaLangOverride;
 					return;
+				case 'R' :
+					if (CharOperation.equals(typeName, JAVA_LANG_RUNTIMEEXCEPTION[2]))
+						id = 	T_JavaLangRuntimeException;
+					break;
 				case 'S' :
 					if (CharOperation.equals(typeName, JAVA_LANG_STRING[2]))
 						id = T_JavaLangString;
@@ -373,28 +391,11 @@
 	}
 }
 /*
- * p.X<T extends Y & I, U extends Y> {} -> Lp/X<TT;TU;>;^123
+ * p.X<T extends Y & I, U extends Y> {} -> Lp/X<TT;TU;>;
  */
-public char[] computeUniqueKey(boolean withAccessFlags) {
-	// generic type signature
-	char[] genericSignature = genericTypeSignature();
-	int sigLength = genericSignature.length;
-	
-	if (!withAccessFlags) return genericSignature;
-	
-	// flags
-	String flags = Integer.toString(getAccessFlags());
-	int flagsLength = flags.length();
-	
-	// unique key
-	char[] uniqueKey = new char[sigLength + 1 + flagsLength];
-	int index = 0;
-	System.arraycopy(genericSignature, 0, uniqueKey, index, sigLength);
-	index += sigLength;
-	uniqueKey[index++] = '^';
-	flags.getChars(0, flagsLength, uniqueKey, index);
-	
-	return uniqueKey;
+public char[] computeUniqueKey(boolean isLeaf) {
+	if (!isLeaf) return signature();
+	return genericTypeSignature();
 }
 /* Answer the receiver's constant pool name.
 *
@@ -461,14 +462,16 @@
  * same id though being distincts.
  *
  */
-public ReferenceBinding findSuperTypeErasingTo(int erasureId, boolean erasureIsClass) {
+public ReferenceBinding findSuperTypeErasingTo(int wellKnownErasureID, boolean erasureIsClass) {
 
-    if (this.id == erasureId || erasure().id == erasureId) return this;
+    // do not allow type variables to match with erasures for free
+    if (this.id == wellKnownErasureID || (!isTypeVariable() && erasure().id == wellKnownErasureID)) return this;
+
     ReferenceBinding currentType = this;
     // iterate superclass to avoid recording interfaces if searched supertype is class
     if (erasureIsClass) {
 		while ((currentType = currentType.superclass()) != null) { 
-			if (currentType.id == erasureId || currentType.erasure().id == erasureId) return currentType;
+			if (currentType.id == wellKnownErasureID || (!currentType.isTypeVariable() && currentType.erasure().id == wellKnownErasureID)) return currentType;
 		}    
 		return null;
     }
@@ -486,7 +489,7 @@
 	for (int i = 0; i <= lastPosition; i++) {
 		ReferenceBinding[] interfaces = interfacesToVisit[i];
 		for (int j = 0, length = interfaces.length; j < length; j++) {
-			if ((currentType = interfaces[j]).id == erasureId || currentType.erasure().id == erasureId)
+			if ((currentType = interfaces[j]).id == wellKnownErasureID || (!currentType.isTypeVariable() && currentType.erasure().id == wellKnownErasureID))
 				return currentType;
 
 			ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
@@ -499,16 +502,20 @@
 	}
 	return null;
 }
+
 /**
  * Find supertype which erases to a given type, or null if not found
  */
-public ReferenceBinding findSuperTypeErasingTo(ReferenceBinding erasure) {
+public ReferenceBinding findSuperTypeWithSameErasure(TypeBinding otherType) {
 
-    if (this == erasure || erasure() == erasure) return this;
+    // do not allow type variables to match with erasures for free
+    if (!otherType.isTypeVariable()) otherType = otherType.erasure();
+    if (this == otherType || (!isTypeVariable() && erasure() == otherType)) return this;
+    
     ReferenceBinding currentType = this;
-    if (!erasure.isInterface()) {
+    if (!otherType.isInterface()) {
 		while ((currentType = currentType.superclass()) != null) {
-			if (currentType == erasure || currentType.erasure() == erasure) return currentType;
+			if (currentType == otherType || (!currentType.isTypeVariable() && currentType.erasure() == otherType)) return currentType;
 		}
 		return null;
     }
@@ -526,7 +533,7 @@
 	for (int i = 0; i <= lastPosition; i++) {
 		ReferenceBinding[] interfaces = interfacesToVisit[i];
 		for (int j = 0, length = interfaces.length; j < length; j++) {
-			if ((currentType = interfaces[j]) == erasure || currentType.erasure() == erasure)
+			if ((currentType = interfaces[j]) == otherType || (!currentType.isTypeVariable() && currentType.erasure() == otherType))
 				return currentType;
 
 			ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
@@ -602,6 +609,52 @@
 	return (modifiers & AccRestrictedAccess) != 0;
 }
 
+/**
+ * Returns true if the two types have an incompatible common supertype,
+ * e.g. List<String> and List<Integer>
+ */
+public boolean hasIncompatibleSuperType(ReferenceBinding otherType) {
+
+    if (this == otherType) return false;
+    
+    ReferenceBinding currentType = this;
+	ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[5][];
+	ReferenceBinding match;
+	int lastPosition = -1;
+	do {
+		match = otherType.findSuperTypeWithSameErasure(currentType);
+		if (match != null) {
+			if (!match.isIntersectingWith(currentType))
+					return true;
+		}
+		ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
+		if (itsInterfaces != NoSuperInterfaces) {
+			if (++lastPosition == interfacesToVisit.length)
+				System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition);
+			interfacesToVisit[lastPosition] = itsInterfaces;
+		}
+	} while ((currentType = currentType.superclass()) != null);
+			
+	for (int i = 0; i <= lastPosition; i++) {
+		ReferenceBinding[] interfaces = interfacesToVisit[i];
+		for (int j = 0, length = interfaces.length; j < length; j++) {
+			if ((currentType = interfaces[j]) == otherType) return false;
+			match = otherType.findSuperTypeWithSameErasure(currentType);
+			if (match != null) {
+				if (!match.isIntersectingWith(currentType))
+						return true;				
+			}
+			ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
+			if (itsInterfaces != NoSuperInterfaces) {
+				if (++lastPosition == interfacesToVisit.length)
+					System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition);
+				interfacesToVisit[lastPosition] = itsInterfaces;
+			}
+		}
+	}
+	return false;
+}
+
 /* Answer true if the receiver implements anInterface or is identical to anInterface.
 * If searchHierarchy is true, then also search the receiver's superclasses.
 *
@@ -661,9 +714,6 @@
 public boolean isAnnotationType() {
 	return (modifiers & AccAnnotation) != 0;
 }
-public final boolean isAnonymousType() {
-	return (tagBits & IsAnonymousType) != 0;
-}
 public final boolean isBinaryBinding() {
 	return (tagBits & IsBinaryBinding) != 0;
 }
@@ -694,14 +744,23 @@
 			// check compatibility with capture of ? super X
 			if (otherType.isCapture()) {
 				CaptureBinding otherCapture = (CaptureBinding) otherType;
-				if (otherCapture.lowerBound != null) {
-					return this.isCompatibleWith(otherCapture.lowerBound);
+				TypeBinding otherLowerBound;
+				if ((otherLowerBound = otherCapture.lowerBound) != null) {
+					if (otherLowerBound.isArrayType()) return false;
+					return this.isCompatibleWith(otherLowerBound);
 				}
 			}
 		case Binding.GENERIC_TYPE :
 		case Binding.TYPE :
 		case Binding.PARAMETERIZED_TYPE :
 		case Binding.RAW_TYPE :
+			switch (this.kind()) {
+				case Binding.GENERIC_TYPE :
+				case Binding.PARAMETERIZED_TYPE :
+				case Binding.RAW_TYPE :
+					if (this.erasure() == otherType.erasure())
+						return false; // should have passed equivalence check above if same erasure
+			}
 			ReferenceBinding otherReferenceType = (ReferenceBinding) otherType;
 			if (otherReferenceType.isInterface()) // could be annotation type
 				return implementsInterface(otherReferenceType, true);
@@ -737,18 +796,6 @@
 	return (modifiers & AccInterface) != 0;
 }
 	
-public final boolean isPartOfRawType() {
-	ReferenceBinding current = this;
-	do {
-		if (current.isRawType())
-			return true;
-		// no static type
-		if (isStatic()) 
-			break;
-	} while ((current = current.enclosingType()) != null);
-    return false;
-}
-
 /* Answer true if the receiver has private visibility
 */
 public final boolean isPrivate() {
@@ -757,8 +804,8 @@
 /* Answer true if the receiver has private visibility and is used locally
 */
 
-public final boolean isPrivateUsed() {
-	return (modifiers & AccPrivateUsed) != 0;
+public final boolean isUsed() {
+	return (modifiers & AccLocallyUsed) != 0;
 }
 /* Answer true if the receiver has protected visibility
 */
@@ -796,9 +843,39 @@
 	return false;
 }
 
+/**
+ * JLS 11.5 ensures that Throwable, Exception, RuntimeException and Error are directly connected.
+ * (Throwable<- Exception <- RumtimeException, Throwable <- Error). Thus no need to check #isCompatibleWith
+ * but rather check in type IDs so as to avoid some eager class loading for JCL writers.
+ * When 'includeSupertype' is true, answers true if the given type can be a supertype of some unchecked exception
+ * type (i.e. Throwable or Exception).
+ * @see org.eclipse.jdt.internal.compiler.lookup.TypeBinding#isUncheckedException(boolean)
+ */
+public boolean isUncheckedException(boolean includeSupertype) {
+	switch (this.id) {
+			case TypeIds.T_JavaLangError :
+			case TypeIds.T_JavaLangRuntimeException :
+				return true;
+			case TypeIds.T_JavaLangThrowable :
+			case TypeIds.T_JavaLangException :
+				return includeSupertype;
+	}
+	ReferenceBinding current = this;
+	while ((current = current.superclass()) != null) {
+		switch (current.id) {
+			case TypeIds.T_JavaLangError :
+			case TypeIds.T_JavaLangRuntimeException :
+				return true;
+			case TypeIds.T_JavaLangThrowable :
+			case TypeIds.T_JavaLangException :
+				return false;
+		}
+	}
+	return false;
+}
+
 /* Answer true if the receiver is deprecated (or any of its enclosing types)
 */
-
 public final boolean isViewedAsDeprecated() {
 	return (modifiers & (AccDeprecated | AccDeprecatedImplicitly)) != 0;
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
index 32000e8..160659a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
@@ -21,6 +21,7 @@
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.ast.*;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
 import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
 import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
@@ -176,7 +177,10 @@
 				}
 				if (substitutedArguments != originalArguments || substitutedEnclosing != originalEnclosing) {
 					identicalVariables: { // if substituted with original variables, then answer the generic type itself
-						if (substitutedEnclosing != originalEnclosing) break identicalVariables;
+						if (substitutedEnclosing != null) {
+							//if (!(substitutedEnclosing instanceof SourceTypeBinding)) break identicalVariables;
+							if (substitutedEnclosing != originalEnclosing) break identicalVariables;						
+						}
 						if (originalParameterizedType.type.isBinaryBinding()) break identicalVariables; // generic binary is never used as is, see 85262
 						TypeVariableBinding[] originalVariables = originalParameterizedType.type.typeVariables();
 						for (int i = 0, length = originalVariables.length; i < length; i++) {
@@ -215,23 +219,26 @@
 				if (!originalType.isMemberType()) break;
 				// fall thru in case enclosing is generic
 			case Binding.GENERIC_TYPE:
-				ReferenceBinding originalGenericType = (ReferenceBinding) originalType;
+				ReferenceBinding originalReferenceType = (ReferenceBinding) originalType;
 				originalEnclosing = originalType.enclosingType();
 				substitutedEnclosing = originalEnclosing;
 				if (originalEnclosing != null) {
 					substitutedEnclosing = (ReferenceBinding) substitute(substitution, originalEnclosing);
 				}
 				if (substitution.isRawSubstitution()) {
-		            return substitution.environment().createRawType(originalGenericType, substitutedEnclosing);
+		            return substitution.environment().createRawType(originalReferenceType, substitutedEnclosing);
 	            }
-			    // treat as if parameterized with its type variables
-				TypeVariableBinding[] originalVariables = originalGenericType.typeVariables();
-				int length = originalVariables.length;
-				System.arraycopy(originalVariables, 0, originalArguments = new TypeBinding[length], 0, length);
-				substitutedArguments = substitute(substitution, originalArguments);
+			    // treat as if parameterized with its type variables (non generic type gets 'null' arguments)
+				originalArguments = originalReferenceType.typeVariables();
+				if (originalArguments == NoTypeVariables) {
+					originalArguments = null;
+					substitutedArguments = null;
+				} else {
+					substitutedArguments = substitute(substitution, originalArguments);
+				}
 				if (substitutedArguments != originalArguments || substitutedEnclosing != originalEnclosing) {
 					return substitution.environment().createParameterizedType(
-							originalGenericType, substitutedArguments, substitutedEnclosing);
+							originalReferenceType, substitutedArguments, substitutedEnclosing);
 				}
 				break;
 		}
@@ -284,18 +291,6 @@
 		return null;
 	}	
 
-	/* Answer an int describing the relationship between the given type and unchecked exceptions.
-	*
-	* 	NotRelated 
-	* 	EqualOrMoreSpecific : type is known for sure to be an unchecked exception type
-	* 	MoreGeneric : type is a supertype of an actual unchecked exception type
-	*/
-	public int compareUncheckedException(ReferenceBinding type) {
-		int comparison = compareTypes(type, getJavaLangRuntimeException());
-		if (comparison != 0) return comparison;
-		return compareTypes(type, getJavaLangError());
-	}
-
 	public final CompilationUnitScope compilationUnitScope() {
 		Scope lastScope = null;
 		Scope scope = this;
@@ -307,6 +302,14 @@
 	}
 
 	/**
+	 * Finds the most specific compiler options
+	 */
+	public final CompilerOptions compilerOptions() {
+
+		return compilationUnitScope().environment.globalOptions;
+	}
+	
+	/**
 	 * Internal use only
 	 * Given a method, returns null if arguments cannot be converted to parameters.
 	 * Will answer a subsituted method in case the method was generic and type inference got triggered;
@@ -368,8 +371,9 @@
 	
 	protected boolean connectTypeVariables(TypeParameter[] typeParameters) {
 		boolean noProblems = true;
-		if (typeParameters == null || environment().options.sourceLevel < ClassFileConstants.JDK1_5) return true;
-
+		if (typeParameters == null || compilerOptions().sourceLevel < ClassFileConstants.JDK1_5) return true;
+		TypeBinding[] types = new TypeBinding[2];
+		Map invocations = new HashMap(2);
 		nextVariable : for (int i = 0, paramLength = typeParameters.length; i < paramLength; i++) {
 			TypeParameter typeParameter = typeParameters[i];
 			TypeVariableBinding typeVariable = typeParameter.binding;
@@ -412,13 +416,11 @@
 				typeVariable.superclass = superRefType;
 			} else {
 				typeVariable.superInterfaces = new ReferenceBinding[] {superRefType};
-				typeVariable.modifiers |= AccInterface;
 			}
 			typeVariable.firstBound = superRefType; // first bound used to compute erasure
-
 			TypeReference[] boundRefs = typeParameter.bounds;
 			if (boundRefs != null) {
-				for (int j = 0, k = boundRefs.length; j < k; j++) {
+				for (int j = 0, boundLength = boundRefs.length; j < boundLength; j++) {
 					typeRef = boundRefs[j];
 					superType = this.kind == METHOD_SCOPE
 						? typeRef.resolveType((BlockScope)this, false)
@@ -429,6 +431,7 @@
 						continue nextVariable;
 					}
 					typeRef.resolvedType = superType; // hold onto the problem type
+					types[0] = superType;
 					if (superType.isArrayType()) {
 						problemReporter().boundCannotBeArray(typeRef, superType);
 						continue nextVariable;
@@ -440,27 +443,55 @@
 						noProblems = false;
 						continue nextVariable;
 					}
-					if (superType.isParameterizedType()) {
-						ReferenceBinding match = typeVariable.superclass.findSuperTypeErasingTo((ReferenceBinding) superType.erasure());
-						boolean isCollision = match != null && match != superType;
-						for (int index = typeVariable.superInterfaces.length; !isCollision && --index >= 0;) {
-							ReferenceBinding temp = typeVariable.superInterfaces[index];
-							isCollision = superType != temp && superType.erasure() == temp.erasure();
-						}
-						if (isCollision) {
-							problemReporter().boundHasConflictingArguments(typeRef, superType);
-							typeVariable.tagBits |= HierarchyHasProblems;
-							noProblems = false;
-							continue nextVariable;
+					// check against superclass
+					if (typeVariable.firstBound == typeVariable.superclass) {
+						types[1] = typeVariable.superclass;
+						TypeBinding[] mecs = minimalErasedCandidates(types, invocations);
+						if (mecs != null) {
+							nextCandidate: for (int k = 0, max = mecs.length; k < max; k++) {
+								TypeBinding mec = mecs[k];
+								if (mec == null) continue nextCandidate;
+								Set invalidInvocations = (Set)invocations.get(mec);
+								int invalidSize = invalidInvocations.size();
+								if (invalidSize > 1) {
+									TypeBinding[] collisions;
+									invalidInvocations.toArray(collisions = new TypeBinding[invalidSize]);
+									problemReporter().superinterfacesCollide(collisions[0].erasure(), typeRef, collisions[1], collisions[0]); // swap collisions since mec types got swapped
+									typeVariable.tagBits |= HierarchyHasProblems;
+									noProblems = false;
+									continue nextVariable;
+								}
+							}			
 						}
 					}
+					// check against superinterfaces
 					for (int index = typeVariable.superInterfaces.length; --index >= 0;) {
-						if (superType.erasure() == typeVariable.superInterfaces[index].erasure()) {
+						ReferenceBinding previousInterface = typeVariable.superInterfaces[index];
+						if (previousInterface == superRefType) {
 							problemReporter().duplicateBounds(typeRef, superType);
 							typeVariable.tagBits |= HierarchyHasProblems;
 							noProblems = false;
 							continue nextVariable;
 						}
+						types[1] = previousInterface;
+						invocations.clear();
+						TypeBinding[] mecs = minimalErasedCandidates(types, invocations);
+						if (mecs != null) {
+							nextCandidate: for (int m = 0, max = mecs.length; m < max; m++) {
+								TypeBinding mec = mecs[m];
+								if (mec == null) continue nextCandidate;
+								Set invalidInvocations = (Set)invocations.get(mec);
+								int invalidSize = invalidInvocations.size();
+								if (invalidSize > 1) {
+									TypeBinding[] collisions;
+									invalidInvocations.toArray(collisions = new TypeBinding[invalidSize]);
+									problemReporter().superinterfacesCollide(collisions[0].erasure(), typeRef, collisions[0], collisions[1]);
+									typeVariable.tagBits |= HierarchyHasProblems;
+									noProblems = false;
+									continue nextVariable;
+								}
+							}					
+						}
 					}
 					int size = typeVariable.superInterfaces.length;
 					System.arraycopy(typeVariable.superInterfaces, 0, typeVariable.superInterfaces = new ReferenceBinding[size + 1], 0, size);
@@ -471,89 +502,6 @@
 		return noProblems;
 	}
 
-	public TypeBinding convertToRawType(TypeBinding type) {
-
-		int dimension;
-		TypeBinding originalType;
-		switch(type.kind()) {
-			case Binding.BASE_TYPE :
-			case Binding.TYPE_PARAMETER:
-			case Binding.WILDCARD_TYPE:
-			case Binding.RAW_TYPE:
-				return type;
-			case Binding.ARRAY_TYPE:
-				dimension = type.dimensions();
-				originalType = type.leafComponentType();
-				break;
-			default:
-				dimension = 0;
-				originalType = type;
-		}
-		boolean needToConvert;
-		switch (originalType.kind()) {
-			case Binding.BASE_TYPE :
-				return type;
-			case Binding.GENERIC_TYPE :
-				needToConvert = true;
-				break;
-			case Binding.PARAMETERIZED_TYPE :
-				ParameterizedTypeBinding paramType = (ParameterizedTypeBinding) originalType;
-				needToConvert = paramType.type.isGenericType(); // only recursive call to enclosing type can find parameterizedType with arguments
-				break;
-			default :
-				needToConvert = false;
-				break;
-		}
-		ReferenceBinding originalEnclosing = originalType.enclosingType();
-		TypeBinding convertedType;
-		if (originalEnclosing == null) {
-			convertedType = needToConvert ? environment().createRawType((ReferenceBinding)originalType.erasure(), null) : originalType;
-		} else {
-			ReferenceBinding convertedEnclosing;
-			switch (originalEnclosing.kind()) {
-				case Binding.GENERIC_TYPE :
-				case Binding.PARAMETERIZED_TYPE :
-					if (needToConvert || ((ReferenceBinding)originalType).isStatic()) {
-						convertedEnclosing = (ReferenceBinding) convertToRawType(originalEnclosing);
-					} else {
-						convertedEnclosing = originalEnclosing;
-					}
-					break;
-				default :
-					convertedEnclosing = originalEnclosing;
-					break;
-			}
-			if (needToConvert) {
-				convertedType = environment().createRawType((ReferenceBinding) originalType.erasure(), convertedEnclosing);
-			} else if (originalEnclosing != convertedEnclosing) {
-				convertedType = createParameterizedType((ReferenceBinding) originalType.erasure(), null, convertedEnclosing);
-			} else {
-				convertedType = originalType;
-			}
-		}
-		if (originalType != convertedType) {
-			return dimension > 0 ? (TypeBinding)createArrayType(convertedType, dimension) : convertedType;
-		}
-		return type;
-	}
-//		TypeBinding leafType = type.leafComponentType();
-//		int dimension = type.dimensions();
-//		ReferenceBinding originalEnclosing = leafType.enclosingType();
-//		ReferenceBinding convertedEnclosing = originalEnclosing;
-//		if (originalEnclosing != null && ((ReferenceBinding)leafType).isStatic()) {
-//			convertedEnclosing = (ReferenceBinding) convertToRawType(originalEnclosing);
-//		}
-//		if (leafType.isGenericType()) {
-//			type = environment().createRawType((ReferenceBinding) leafType, convertedEnclosing);
-//			if (dimension > 0) 
-//				type = createArrayType(type, dimension);
-//		} else if (originalEnclosing != convertedEnclosing) {
-//			type = createParameterizedType((ReferenceBinding)leafType, null, convertedEnclosing);
-//			if (dimension > 0) 
-//				type = createArrayType(type, dimension);
-//		}
-//	    return type;
-
 	public ArrayBinding createArrayType(TypeBinding type, int dimension) {
 		if (type.isValidBinding())
 			return environment().createArrayType(type, dimension);
@@ -561,19 +509,9 @@
 		return new ArrayBinding(type, dimension, environment());
 	}
 	
-	public ParameterizedTypeBinding createParameterizedType(ReferenceBinding genericType, TypeBinding[] arguments, ReferenceBinding enclosingType) {
-		valid: {
-			if (!genericType.isValidBinding()) break valid;
-			for (int i = 0, max = arguments == null ? 0 : arguments.length; i < max; i++)
-				if (!arguments[i].isValidBinding()) break valid;
-			return environment().createParameterizedType(genericType, arguments, enclosingType);
-		}
-		return new ParameterizedTypeBinding(genericType, arguments, enclosingType, environment());
-	}
-	
 	public TypeVariableBinding[] createTypeVariables(TypeParameter[] typeParameters, Binding declaringElement) {
 		// do not construct type variables if source < 1.5
-		if (typeParameters == null || environment().options.sourceLevel < ClassFileConstants.JDK1_5)
+		if (typeParameters == null || compilerOptions().sourceLevel < ClassFileConstants.JDK1_5)
 			return NoTypeVariables;
 
 		TypeVariableBinding[] typeVariableBindings = NoTypeVariables;
@@ -633,6 +571,25 @@
 		return null; // may answer null if no method around
 	}
 
+	/**
+	 * Returns the immediately enclosing reference context, starting from current scope parent.
+	 * If starting on a class, it will skip current class. If starting on unitScope, returns null.
+	 */
+	public ReferenceContext enclosingReferenceContext() {
+		Scope current = this;
+		while ((current = current.parent) != null) {
+			switch(current.kind) {
+				case METHOD_SCOPE :
+					return ((MethodScope) current).referenceContext;
+				case CLASS_SCOPE :
+					return ((ClassScope) current).referenceContext;
+				case COMPILATION_UNIT_SCOPE :
+					return ((CompilationUnitScope) current).referenceContext;
+			}
+		}
+		return null;
+	}
+	
 	/* Answer the receiver's enclosing source type.
 	*/
 	public final SourceTypeBinding enclosingSourceType() {
@@ -712,7 +669,7 @@
 			return (MethodBinding) found.elementAt(0); // no good match so just use the first one found
 		}
 		// no need to check for visibility - interface methods are public
-		boolean isCompliant14 = unitScope.environment.options.complianceLevel >= ClassFileConstants.JDK1_4;
+		boolean isCompliant14 = compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4;
 		if (isCompliant14)
 			return mostSpecificMethodBinding(candidates, candidatesCount, argumentTypes, invocationSite);
 		return mostSpecificInterfaceMethodBinding(candidates, candidatesCount, invocationSite);
@@ -748,7 +705,7 @@
 		CompilationUnitScope unitScope = compilationUnitScope();
 		unitScope.recordTypeReferences(argumentTypes);
 		MethodBinding exactMethod = receiverType.getExactMethod(selector, argumentTypes, unitScope);
-		if (exactMethod != null) {
+		if (exactMethod != null && exactMethod.typeVariables == NoTypeVariables) {
 			unitScope.recordTypeReferences(exactMethod.thrownExceptions);
 			// special treatment for Object.getClass() in 1.5 mode (substitute parameterized return type)
 			if (receiverType.isInterface() || exactMethod.canBeSeenBy(receiverType, invocationSite, this)) {
@@ -940,6 +897,8 @@
 		while (keepLooking) {
 			ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
 			if (itsInterfaces == null) { // needed for statically imported types which don't know their hierarchy yet
+				if (currentType.isHierarchyBeingConnected())
+					return null; // looking for an undefined member type in its own superclass ref
 				((SourceTypeBinding) currentType).scope.connectTypeHierarchy();
 				itsInterfaces = currentType.superInterfaces();
 			}
@@ -963,7 +922,7 @@
 						if (visibleMemberType == null)
 							visibleMemberType = memberType;
 						else
-							return new ProblemReferenceBinding(typeName, Ambiguous);
+							return new ProblemReferenceBinding(typeName, null, Ambiguous);
 				} else {
 					notVisible = memberType;
 				}
@@ -985,7 +944,7 @@
 							if (visibleMemberType == null) {
 								visibleMemberType = memberType;
 							} else {
-								ambiguous = new ProblemReferenceBinding(typeName, Ambiguous);
+								ambiguous = new ProblemReferenceBinding(typeName, null, Ambiguous);
 								break done;
 							}
 						} else {
@@ -1043,7 +1002,7 @@
 			currentType = getJavaLangObject();
 		}
 
-		boolean isCompliant14 = unitScope.environment.options.complianceLevel >= ClassFileConstants.JDK1_4;
+		boolean isCompliant14 = compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4;
 		// superclass lookup
 		ReferenceBinding classHierarchyStart = currentType;
 		boolean mustBePublic = receiverType.isInterface();
@@ -1053,7 +1012,7 @@
 			int currentLength = currentMethods.length;
 
 			if (isCompliant14 && (mustBePublic || matchingMethod != null || found.size > 0)) {
-				nextMethod: for (int i = 0; i < currentLength; i++) {
+				nextMethod: for (int i = 0, l = currentLength; i < l; i++) { // currentLength can be modified inside the loop
 					MethodBinding currentMethod = currentMethods[i];
 					if (mustBePublic && !currentMethod.isPublic()) { // only public methods from Object are visible to interface receiverTypes
 						currentLength--;
@@ -1068,6 +1027,8 @@
 					// BUT we can also ignore any overridden method since we already know the better match (fixes 80028)
 					if (matchingMethod != null) {
 						if (currentMethod.areParametersEqual(matchingMethod)) {
+							if (matchingMethod.typeVariables != NoTypeVariables && invocationSite.genericTypeArguments() == null)
+								continue nextMethod; // keep inherited substituted methods to detect anonymous errors
 							if (matchingMethod.hasSubstitutedParameters() && !currentMethod.original().areParametersEqual(matchingMethod.original()))
 								continue nextMethod; // keep inherited substituted methods to detect anonymous errors
 							currentLength--;
@@ -1200,7 +1161,7 @@
 		}
 
 		// check for duplicate parameterized methods
-		if (unitScope.environment.options.sourceLevel >= ClassFileConstants.JDK1_5) {
+		if (compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) {
 			for (int i = 0; i < candidatesCount; i++) {
 				MethodBinding current = candidates[i];
 				if (current instanceof ParameterizedGenericMethodBinding)
@@ -1272,7 +1233,7 @@
 			        case 'c': 
 			            if (CharOperation.equals(selector, CLONE)) {
 							return new UpdatedMethodBinding(
-								environment().options.targetJDK >= ClassFileConstants.JDK1_4 ? (TypeBinding)receiverType : (TypeBinding)object, // remember its array type for codegen purpose on target>=1.4.0
+								compilerOptions().targetJDK >= ClassFileConstants.JDK1_4 ? (TypeBinding)receiverType : (TypeBinding)object, // remember its array type for codegen purpose on target>=1.4.0
 								(methodBinding.modifiers & ~AccProtected) | AccPublic,
 								CLONE,
 								methodBinding.returnType,
@@ -1493,7 +1454,7 @@
 														NonStaticReferenceInStaticContext);
 											}
 										}
-										if (enclosingType == fieldBinding.declaringClass || environment().options.complianceLevel >= ClassFileConstants.JDK1_4) {
+										if (enclosingType == fieldBinding.declaringClass || compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4) {
 											// found a valid field in the 'immediate' scope (ie. not inherited)
 											// OR in 1.4 mode (inherited shadows enclosing)
 											if (foundField == null) {
@@ -1532,8 +1493,7 @@
 							// in order to do so, we change the flag as we exit from the type, not the method
 							// itself, because the class scope is used to retrieve the fields.
 							MethodScope enclosingMethodScope = scope.methodScope();
-							insideConstructorCall =
-								enclosingMethodScope == null ? false : enclosingMethodScope.isConstructorCall;
+							insideConstructorCall = enclosingMethodScope == null ? false : enclosingMethodScope.isConstructorCall;
 							break;
 						case COMPILATION_UNIT_SCOPE :
 							break done;
@@ -1555,7 +1515,7 @@
 					foundField = null;
 				}
 
-				if (environment().options.sourceLevel >= ClassFileConstants.JDK1_5) {
+				if (compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) {
 					// at this point the scope is a compilation unit scope & need to check for imported static fields
 					CompilationUnitScope unitScope = (CompilationUnitScope) scope;
 					ImportBinding[] imports = unitScope.imports;
@@ -1596,7 +1556,7 @@
 											if (importReference != null) importReference.used = true;
 											if (foundInImport)
 												// Answer error binding -- import on demand conflict; name found in two import on demand packages.
-												return new ProblemReferenceBinding(name, Ambiguous);
+												return new ProblemReferenceBinding(name, null, Ambiguous);
 											foundField = temp;
 											foundInImport = true;
 										}
@@ -1852,7 +1812,7 @@
 	
 								if (receiverType == methodBinding.declaringClass
 									|| (receiverType.getMethods(selector)) != NoMethods
-									|| ((fuzzyProblem == null || fuzzyProblem.problemId() != NotVisible) && environment().options.complianceLevel >= ClassFileConstants.JDK1_4)) {
+									|| ((fuzzyProblem == null || fuzzyProblem.problemId() != NotVisible) && compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4)) {
 									// found a valid method in the 'immediate' scope (ie. not inherited)
 									// OR the receiverType implemented a method with the correct name
 									// OR in 1.4 mode (inherited visible shadows enclosing)
@@ -1917,18 +1877,23 @@
 		if (foundMethod != null)
 			return foundMethod;
 
-		if (insideStaticContext && environment().options.sourceLevel >= ClassFileConstants.JDK1_5) {
+		if (insideStaticContext && compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) {
 			// at this point the scope is a compilation unit scope & need to check for imported static methods
 			CompilationUnitScope unitScope = (CompilationUnitScope) scope;
 			ImportBinding[] imports = unitScope.imports;
 			if (imports != null) {
-				int importLevel = -1; // -1 = not found, 0 = on demand match, 1 = single import match
+				MethodBinding[] visible = null;
+				boolean skipOnDemand = false; // set to true when matched static import of method name so stop looking for on demand methods
 				for (int i = 0, length = imports.length; i < length; i++) {
 					ImportBinding importBinding = imports[i];
 					if (importBinding.isStatic()) {
 						Binding resolvedImport = importBinding.resolvedImport;
 						MethodBinding possible = null;
-						if (!importBinding.onDemand && importBinding.isStatic()) {
+						if (importBinding.onDemand) {
+							if (!skipOnDemand && resolvedImport instanceof ReferenceBinding)
+								// answers closest approximation, may not check argumentTypes or visibility
+								possible = findMethod((ReferenceBinding) resolvedImport, selector, argumentTypes, invocationSite);
+						} else {
 							if (resolvedImport instanceof MethodBinding) {
 								MethodBinding staticMethod = (MethodBinding) resolvedImport;
 								if (CharOperation.equals(staticMethod.selector, selector))
@@ -1946,9 +1911,6 @@
 										possible = findMethod((ReferenceBinding) referencedType, selector, argumentTypes, invocationSite);
 								}
 							}
-						} else if (importBinding.onDemand && importLevel < 1 && resolvedImport instanceof ReferenceBinding) {
-							// answers closest approximation, may not check argumentTypes or visibility
-							possible = findMethod((ReferenceBinding) resolvedImport, selector, argumentTypes, invocationSite);
 						}
 						if (possible != null && possible != foundMethod) {
 							if (!possible.isValidBinding()) {
@@ -1961,21 +1923,25 @@
 										if (compatibleMethod.canBeSeenBy(unitScope.fPackage)) {
 											ImportReference importReference = importBinding.reference;
 											if (importReference != null) importReference.used = true;
-											int matchingImportLevel = importBinding.onDemand ? 0 : 1;
-											if (matchingImportLevel == importLevel) {
-												scope = this;
-												while (true) {
-													switch (scope.kind) {
-														case CLASS_SCOPE :
-															return new ProblemMethodBinding(selector, argumentTypes, ((ClassScope) scope).referenceContext.binding, Ambiguous);
-														case COMPILATION_UNIT_SCOPE :
-															return new ProblemMethodBinding(compatibleMethod, selector, compatibleMethod.parameters, Ambiguous);
-													}
-													scope = scope.parent;
+											if (foundMethod == null || !foundMethod.isValidBinding()) {
+												foundMethod = compatibleMethod;
+												if (!importBinding.onDemand && foundMethod.isValidBinding())
+													skipOnDemand = true;
+											} else {
+												if (!skipOnDemand && !importBinding.onDemand) {
+													visible = null; // forget previous matches from on demand imports
+													foundMethod = compatibleMethod;
+													skipOnDemand = true;
+												} else if (visible == null) {
+													visible = new MethodBinding[] {foundMethod, compatibleMethod};
+												} else {
+													int visibleLength = visible.length;
+													MethodBinding[] temp = new MethodBinding[visibleLength + 1];
+													System.arraycopy(visible, 0, temp, 0, visibleLength);
+													temp[visibleLength] = compatibleMethod;
+													visible = temp;
 												}
 											}
-											foundMethod = compatibleMethod;
-											importLevel = matchingImportLevel;
 										} else if (foundMethod == null) {
 											foundMethod = new ProblemMethodBinding(compatibleMethod, selector, compatibleMethod.parameters, NotVisible);
 										}
@@ -1987,6 +1953,8 @@
 						}
 					}
 				}
+				if (visible != null)
+					foundMethod = mostSpecificMethodBinding(visible, visible.length, argumentTypes, invocationSite);
 			}
 			if (foundMethod != null) {
 				invocationSite.setActualReceiverType(foundMethod.declaringClass);
@@ -2047,14 +2015,7 @@
 		problemReporter().isClassPathCorrect(JAVA_LANG_ENUM, referenceCompilationUnit());
 		return null; // will not get here since the above error aborts the compilation
 	}
-	public final ReferenceBinding getJavaLangError() {
-		compilationUnitScope().recordQualifiedReference(JAVA_LANG_ERROR);
-		ReferenceBinding type = environment().getType(JAVA_LANG_ERROR);
-		if (type != null) return type;
-	
-		problemReporter().isClassPathCorrect(JAVA_LANG_ERROR, referenceCompilationUnit());
-		return null; // will not get here since the above error aborts the compilation
-	}
+
 	public final ReferenceBinding getJavaLangIterable() {
 		compilationUnitScope().recordQualifiedReference(JAVA_LANG_ITERABLE);
 		ReferenceBinding type = environment().getType(JAVA_LANG_ITERABLE);
@@ -2072,15 +2033,6 @@
 		return null; // will not get here since the above error aborts the compilation
 	}
 
-	public final ReferenceBinding getJavaLangRuntimeException() {
-		compilationUnitScope().recordQualifiedReference(JAVA_LANG_RUNTIMEEXCEPTION);
-		ReferenceBinding type = environment().getType(JAVA_LANG_RUNTIMEEXCEPTION);
-		if (type != null) return type;
-	
-		problemReporter().isClassPathCorrect(JAVA_LANG_RUNTIMEEXCEPTION, referenceCompilationUnit());
-		return null; // will not get here since the above error aborts the compilation
-	}
-
 	public final ReferenceBinding getJavaLangString() {
 		compilationUnitScope().recordQualifiedReference(JAVA_LANG_STRING);
 		ReferenceBinding type = environment().getType(JAVA_LANG_STRING);
@@ -2112,7 +2064,7 @@
 	public final ReferenceBinding getMemberType(char[] typeName, ReferenceBinding enclosingType) {
 		ReferenceBinding memberType = findMemberType(typeName, enclosingType);
 		if (memberType != null) return memberType;
-		return new ProblemReferenceBinding(typeName, NotFound);
+		return new ProblemReferenceBinding(typeName, null, NotFound);
 	}
 
 	public MethodBinding getMethod(TypeBinding receiverType, char[] selector, TypeBinding[] argumentTypes, InvocationSite invocationSite) {
@@ -2174,7 +2126,7 @@
 		compilationUnitScope().recordQualifiedReference(compoundName);
 		Binding binding = getTypeOrPackage(compoundName[0], Binding.TYPE | Binding.PACKAGE);
 		if (binding == null)
-			return new ProblemReferenceBinding(compoundName[0], NotFound);
+			return new ProblemReferenceBinding(compoundName[0], null, NotFound);
 		if (!binding.isValidBinding())
 			return (ReferenceBinding) binding;
 
@@ -2187,16 +2139,18 @@
 			if (binding == null)
 				return new ProblemReferenceBinding(
 					CharOperation.subarray(compoundName, 0, currentIndex),
+					null, 
 					NotFound);
 			if (!binding.isValidBinding())
 				return new ProblemReferenceBinding(
 					CharOperation.subarray(compoundName, 0, currentIndex),
+					null, // TODO should improve
 					binding.problemId());
 			if (!(binding instanceof PackageBinding))
 				return packageBinding;
 			packageBinding = (PackageBinding) binding;
 		}
-		return new ProblemReferenceBinding(compoundName, NotFound);
+		return new ProblemReferenceBinding(compoundName, null, NotFound);
 	}
 
 	/* Answer the type binding that corresponds the given name, starting the lookup in the receiver.
@@ -2224,10 +2178,12 @@
 		if (binding == null)
 			return new ProblemReferenceBinding(
 				CharOperation.arrayConcat(packageBinding.compoundName, name),
+				null,
 				NotFound);
 		if (!binding.isValidBinding())
 			return new ProblemReferenceBinding(
 				CharOperation.arrayConcat(packageBinding.compoundName, name),
+				null, // TODO should improve
 				binding.problemId());
 
 		ReferenceBinding typeBinding = (ReferenceBinding) binding;
@@ -2256,7 +2212,7 @@
 		Binding binding =
 			getTypeOrPackage(compoundName[0], typeNameLength == 1 ? Binding.TYPE : Binding.TYPE | Binding.PACKAGE);
 		if (binding == null)
-			return new ProblemReferenceBinding(compoundName[0], NotFound);
+			return new ProblemReferenceBinding(compoundName[0], null, NotFound);
 		if (!binding.isValidBinding())
 			return (ReferenceBinding) binding;
 
@@ -2269,10 +2225,12 @@
 				if (binding == null)
 					return new ProblemReferenceBinding(
 						CharOperation.subarray(compoundName, 0, currentIndex),
+						null,
 						NotFound);
 				if (!binding.isValidBinding())
 					return new ProblemReferenceBinding(
 						CharOperation.subarray(compoundName, 0, currentIndex),
+						null, // TODO should improve
 						binding.problemId());
 				if (!(binding instanceof PackageBinding))
 					break;
@@ -2281,6 +2239,7 @@
 			if (binding instanceof PackageBinding)
 				return new ProblemReferenceBinding(
 					CharOperation.subarray(compoundName, 0, currentIndex),
+					null,
 					NotFound);
 			checkVisibility = true;
 		}
@@ -2302,11 +2261,12 @@
 					ProblemReferenceBinding problemBinding = (ProblemReferenceBinding) typeBinding;
 					return new ProblemReferenceBinding(
 						CharOperation.subarray(compoundName, 0, currentIndex),
-						problemBinding.original,
+						problemBinding.closestMatch,
 						typeBinding.problemId());
 				}
 				return new ProblemReferenceBinding(
 					CharOperation.subarray(compoundName, 0, currentIndex),
+					null, // TODO should improve
 					typeBinding.problemId());
 			}
 		}
@@ -2340,30 +2300,30 @@
 						ReferenceBinding localType = ((BlockScope) scope).findLocalType(name); // looks in this scope only
 						if (localType != null) {
 							if (foundType != null && foundType != localType)
-								return new ProblemReferenceBinding(name, InheritedNameHidesEnclosingName);
+								return new ProblemReferenceBinding(name, foundType, InheritedNameHidesEnclosingName);
 							return localType;
 						}
 						break;
 					case CLASS_SCOPE :
 						SourceTypeBinding sourceType = ((ClassScope) scope).referenceContext.binding;
-						if (sourceType.isHierarchyBeingConnected()) {
-							// type variables take precedence over the source type, ex. class X <X> extends X == class X <Y> extends Y 
+						if (scope == this && sourceType.isHierarchyBeingConnected()) {
+							// type variables take precedence over the source type, ex. class X <X> extends X == class X <Y> extends Y
+							// but not when we step out to the enclosing type
 							TypeVariableBinding typeVariable = sourceType.getTypeVariable(name);
 							if (typeVariable != null)
 								return typeVariable;
 							if (CharOperation.equals(name, sourceType.sourceName))
 								return sourceType;
-							insideStaticContext |= (sourceType.modifiers & AccStatic) != 0; // not isStatic()
+							insideStaticContext |= sourceType.isStatic();
 							break;
 						}
 						// type variables take precedence over member types
 						TypeVariableBinding typeVariable = sourceType.getTypeVariable(name);
 						if (typeVariable != null) {
 							if (insideStaticContext) // do not consider this type modifiers: access is legite within same type
-								return new ProblemReferenceBinding(name, NonStaticReferenceInStaticContext);
+								return new ProblemReferenceBinding(name, typeVariable, NonStaticReferenceInStaticContext);
 							return typeVariable;
 						}
-						insideStaticContext |= (sourceType.modifiers & AccStatic) != 0; // not isStatic()
 						if (!insideTypeAnnotation) {
 							// 6.5.5.1 - member types have precedence over top-level type in same unit
 							ReferenceBinding memberType = findMemberType(name, sourceType);
@@ -2373,20 +2333,20 @@
 										// supercedes any potential InheritedNameHidesEnclosingName problem
 										return memberType;
 									// make the user qualify the type, likely wants the first inherited type
-									return new ProblemReferenceBinding(name, InheritedNameHidesEnclosingName);
+									return new ProblemReferenceBinding(name, foundType, InheritedNameHidesEnclosingName);
 								}
 								if (memberType.isValidBinding()) {
 									if (sourceType == memberType.enclosingType()
-											|| environment().options.complianceLevel >= ClassFileConstants.JDK1_4) {
+											|| compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4) {
 										if (insideStaticContext && !memberType.isStatic() && sourceType.isGenericType())
-											return new ProblemReferenceBinding(name, NonStaticReferenceInStaticContext);
+											return new ProblemReferenceBinding(name, memberType, NonStaticReferenceInStaticContext);
 										// found a valid type in the 'immediate' scope (ie. not inherited)
 										// OR in 1.4 mode (inherited shadows enclosing)
 										if (foundType == null)
 											return memberType; 
 										// if a valid type was found, complain when another is found in an 'immediate' enclosing type (ie. not inherited)
 										if (foundType.isValidBinding() && foundType != memberType)
-											return new ProblemReferenceBinding(name, InheritedNameHidesEnclosingName);
+											return new ProblemReferenceBinding(name, foundType, InheritedNameHidesEnclosingName);
 									}
 								}
 								if (foundType == null || (foundType.problemId() == NotVisible && memberType.problemId() != NotVisible))
@@ -2395,9 +2355,10 @@
 							}
 						}
 						insideTypeAnnotation = false;
+						insideStaticContext |= sourceType.isStatic();
 						if (CharOperation.equals(sourceType.sourceName, name)) {
 							if (foundType != null && foundType != sourceType && foundType.problemId() != NotVisible)
-								return new ProblemReferenceBinding(name, InheritedNameHidesEnclosingName);
+								return new ProblemReferenceBinding(name, foundType, InheritedNameHidesEnclosingName);
 							return sourceType;
 						}
 						break;
@@ -2412,43 +2373,63 @@
 
 		// at this point the scope is a compilation unit scope
 		CompilationUnitScope unitScope = (CompilationUnitScope) scope;
-		PackageBinding currentPackage = unitScope.fPackage; 
+		HashtableOfObject typeOrPackageCache = unitScope.typeOrPackageCache;
+		if (typeOrPackageCache != null) {
+			Binding binding = (Binding) typeOrPackageCache.get(name);
+			if (binding != null) { // can also include NotFound ProblemReferenceBindings if we already know this name is not found
+				if (binding instanceof ImportBinding) { // single type import cached in faultInImports(), replace it in the cache with the type
+					ImportReference importReference = ((ImportBinding) binding).reference;
+					if (importReference != null) importReference.used = true;
+					if (binding instanceof ImportConflictBinding)
+						typeOrPackageCache.put(name, binding = ((ImportConflictBinding) binding).conflictingTypeBinding); // already know its visible
+					else
+						typeOrPackageCache.put(name, binding = ((ImportBinding) binding).resolvedImport); // already know its visible
+				}
+				if ((mask & Binding.TYPE) != 0) {
+					if (foundType != null && foundType.problemId() != NotVisible && binding.problemId() != Ambiguous)
+						return foundType; // problem type from above supercedes NotFound type but not Ambiguous import case
+					if (binding instanceof ReferenceBinding)
+						return binding; // cached type found in previous walk below
+				}
+				if ((mask & Binding.PACKAGE) != 0 && binding instanceof PackageBinding)
+					return binding; // cached package found in previous walk below
+			}
+		}
+
 		// ask for the imports + name
 		if ((mask & Binding.TYPE) != 0) {
-			// check single type imports.
-
 			ImportBinding[] imports = unitScope.imports;
-			if (imports != null) {
-				HashtableOfObject typeImports = unitScope.resolvedSingeTypeImports;
-				if (typeImports != null) {
-					ImportBinding typeImport = (ImportBinding) typeImports.get(name);
-					if (typeImport != null) {
-						ImportReference importReference = typeImport.reference;
-						if (importReference != null) importReference.used = true;
-						return typeImport.resolvedImport; // already know its visible
-					}
-				} else {
-					// walk all the imports since resolvedSingleTypeImports is not yet initialized
-					for (int i = 0, length = imports.length; i < length; i++) {
-						ImportBinding typeImport = imports[i];
-						if (!typeImport.onDemand) {
-							if (CharOperation.equals(typeImport.compoundName[typeImport.compoundName.length - 1], name)) {
-								Binding resolvedImport = unitScope.resolveSingleImport(typeImport);
-								if (resolvedImport != null && resolvedImport instanceof TypeBinding) {
-									ImportReference importReference = typeImport.reference;
-									if (importReference != null)
-										importReference.used = true;
-									return resolvedImport; // already know its visible
-								}
+			if (imports != null && typeOrPackageCache == null) { // walk single type imports since faultInImports() has not run yet
+				nextImport : for (int i = 0, length = imports.length; i < length; i++) {
+					ImportBinding importBinding = imports[i];
+					if (!importBinding.onDemand) {
+						if (CharOperation.equals(importBinding.compoundName[importBinding.compoundName.length - 1], name)) {
+							Binding resolvedImport = unitScope.resolveSingleImport(importBinding);
+							if (resolvedImport == null) continue nextImport;
+							if (resolvedImport instanceof MethodBinding) {
+								resolvedImport = (ReferenceBinding) getType(importBinding.compoundName, importBinding.compoundName.length);
+								if (!resolvedImport.isValidBinding()) continue nextImport;
+							}
+							if (resolvedImport instanceof TypeBinding) {
+								ImportReference importReference = importBinding.reference;
+								if (importReference != null)
+									importReference.used = true;
+								return resolvedImport; // already know its visible
 							}
 						}
 					}
 				}
 			}
+
 			// check if the name is in the current package, skip it if its a sub-package
+			PackageBinding currentPackage = unitScope.fPackage; 
 			unitScope.recordReference(currentPackage.compoundName, name);
 			Binding binding = currentPackage.getTypeOrPackage(name);
-			if (binding instanceof ReferenceBinding) return binding; // type is always visible to its own package
+			if (binding instanceof ReferenceBinding) {
+				if (typeOrPackageCache != null)
+					typeOrPackageCache.put(name, binding);
+				return binding; // type is always visible to its own package
+			}
 
 			// check on demand imports
 			if (imports != null) {
@@ -2458,18 +2439,27 @@
 					ImportBinding someImport = imports[i];
 					if (someImport.onDemand) {
 						Binding resolvedImport = someImport.resolvedImport;
-						ReferenceBinding temp = resolvedImport instanceof PackageBinding
-							? findType(name, (PackageBinding) resolvedImport, currentPackage)
-							: (someImport.isStatic()
-								? findMemberType(name, (ReferenceBinding) resolvedImport) // static imports are allowed to see inherited member types
-								: findDirectMemberType(name, (ReferenceBinding) resolvedImport));
-						if (temp != null) {
+						ReferenceBinding temp = null;
+						if (resolvedImport instanceof PackageBinding) {
+							temp = findType(name, (PackageBinding) resolvedImport, currentPackage);
+						} else if (someImport.isStatic()) {
+							temp = findMemberType(name, (ReferenceBinding) resolvedImport); // static imports are allowed to see inherited member types
+							if (temp != null && !temp.isStatic())
+								temp = null;
+						} else {
+							temp = findDirectMemberType(name, (ReferenceBinding) resolvedImport);
+						}
+						if (temp != type && temp != null) {
 							if (temp.isValidBinding()) {
 								ImportReference importReference = someImport.reference;
 								if (importReference != null) importReference.used = true;
-								if (foundInImport)
+								if (foundInImport) {
 									// Answer error binding -- import on demand conflict; name found in two import on demand packages.
-									return new ProblemReferenceBinding(name, Ambiguous);
+									temp = new ProblemReferenceBinding(name, null, Ambiguous);
+									if (typeOrPackageCache != null)
+										typeOrPackageCache.put(name, temp);
+									return temp;
+								}
 								type = temp;
 								foundInImport = true;
 							} else if (foundType == null) {
@@ -2478,19 +2468,31 @@
 						}
 					}
 				}
-				if (type != null) return type;
+				if (type != null) {
+					if (typeOrPackageCache != null)
+						typeOrPackageCache.put(name, type);
+					return type;
+				}
 			}
 		}
 
 		unitScope.recordSimpleReference(name);
 		if ((mask & Binding.PACKAGE) != 0) {
 			PackageBinding packageBinding = unitScope.environment.getTopLevelPackage(name);
-			if (packageBinding != null) return packageBinding;
+			if (packageBinding != null) {
+				if (typeOrPackageCache != null)
+					typeOrPackageCache.put(name, packageBinding);
+				return packageBinding;
+			}
 		}
 
 		// Answer error binding -- could not find name
-		if (foundType != null) return foundType; // problem type from above
-		return new ProblemReferenceBinding(name, NotFound);
+		if (foundType == null) {
+			foundType = new ProblemReferenceBinding(name, null, NotFound);
+			if (typeOrPackageCache != null && (mask & Binding.PACKAGE) != 0) // only put NotFound type in cache if you know its not a package
+				typeOrPackageCache.put(name, foundType);
+		}
+		return foundType;
 	}
 
 	// Added for code assist... NOT Public API
@@ -2516,10 +2518,12 @@
 				if (binding == null)
 					return new ProblemReferenceBinding(
 						CharOperation.subarray(compoundName, 0, currentIndex),
+						null,
 						NotFound);
 				if (!binding.isValidBinding())
 					return new ProblemReferenceBinding(
 						CharOperation.subarray(compoundName, 0, currentIndex),
+						null, // TODO should improve
 						binding.problemId());
 				if (!(binding instanceof PackageBinding))
 					break;
@@ -2529,16 +2533,8 @@
 			checkVisibility = true;
 		}
 		// binding is now a ReferenceBinding
-		ReferenceBinding qualifiedType = null;
-
 		ReferenceBinding typeBinding = (ReferenceBinding) binding;
-		if (typeBinding.isGenericType()) {
-			qualifiedType = this.environment().createRawType(typeBinding, qualifiedType);
-		} else {
-			qualifiedType = (qualifiedType != null && (qualifiedType.isRawType() || qualifiedType.isParameterizedType()))
-				? this.createParameterizedType(typeBinding, null, qualifiedType)
-				: typeBinding;
-		}
+		ReferenceBinding qualifiedType = (ReferenceBinding) this.environment().convertToRawType(typeBinding);
 
 		if (checkVisibility) // handles the fall through case
 			if (!typeBinding.canBeSeenBy(this))
@@ -2549,20 +2545,20 @@
 
 		while (currentIndex < nameLength) {
 			typeBinding = getMemberType(compoundName[currentIndex++], typeBinding);
-
+			// checks visibility
+			if (!typeBinding.isValidBinding())
+				return new ProblemReferenceBinding(
+					CharOperation.subarray(compoundName, 0, currentIndex),
+					null, // TODO should improve
+					typeBinding.problemId());
+			
 			if (typeBinding.isGenericType()) {
 				qualifiedType = this.environment().createRawType(typeBinding, qualifiedType);
 			} else {
 				qualifiedType = (qualifiedType != null && (qualifiedType.isRawType() || qualifiedType.isParameterizedType()))
-					? this.createParameterizedType(typeBinding, null, qualifiedType)
+					? this.environment().createParameterizedType(typeBinding, null, qualifiedType)
 					: typeBinding;
 			}
-
-			// checks visibility
-			if (!qualifiedType.isValidBinding())
-				return new ProblemReferenceBinding(
-					CharOperation.subarray(compoundName, 0, currentIndex),
-					qualifiedType.problemId());
 		}
 		return qualifiedType;
 	}
@@ -2636,6 +2632,7 @@
 		}
 		return trimmedResult;
 	}	
+
 	/**
 	 * Returns the immediately enclosing switchCase statement (carried by closest blockScope),
 	 */
@@ -2649,8 +2646,14 @@
 		return null;
 	}
 
-	public boolean isBoxingCompatibleWith(TypeBinding left, TypeBinding right) {
-		return left.isBaseType() != right.isBaseType() && environment().isBoxingCompatibleWith(left, right);
+	public boolean isBoxingCompatibleWith(TypeBinding expressionType, TypeBinding targetType) {
+		LookupEnvironment environment = environment();
+		if (environment.globalOptions.sourceLevel < ClassFileConstants.JDK1_5 || expressionType.isBaseType() == targetType.isBaseType())
+			return false;
+	
+		// check if autoboxed type is compatible
+		TypeBinding convertedType = environment.computeBoxingType(expressionType);
+		return convertedType == targetType || convertedType.isCompatibleWith(targetType);
 	}
 
 	/* Answer true if the scope is nested inside a given field declaration.
@@ -2769,32 +2772,41 @@
 		int length = invocations.size();
 		Iterator iter = invocations.iterator();
 		if (length == 1) return (TypeBinding) iter.next();
+
+		// if mec is an array type, intersect invocation leaf component types, then promote back to array
+		int dim = mec.dimensions();
+		mec = mec.leafComponentType();
+		
 		int argLength = mec.typeVariables().length;
 		if (argLength == 0) return mec; // should be caught by no invocation check
 
 		// infer proper parameterized type from invocations
 		TypeBinding[] bestArguments = new TypeBinding[argLength];
 		while (iter.hasNext()) {
-			TypeBinding invocation = (TypeBinding)iter.next();
-			TypeVariableBinding[] invocationVariables = invocation.typeVariables();
-			if (invocation.isGenericType()) {
-				for (int i = 0; i < argLength; i++) {
-					TypeBinding bestArgument = leastContainingTypeArgument(bestArguments[i], invocationVariables[i], (ReferenceBinding) mec, i, lubStack);
-					if (bestArgument == null) return null;
-					bestArguments[i] = bestArgument;
-				}
-			} else if (invocation.isParameterizedType()) {
-				ParameterizedTypeBinding parameterizedType = (ParameterizedTypeBinding)invocation;
-				for (int i = 0; i < argLength; i++) {
-					TypeBinding bestArgument = leastContainingTypeArgument(bestArguments[i], parameterizedType.arguments[i], (ReferenceBinding) mec, i, lubStack);
-					if (bestArgument == null) return null;
-					bestArguments[i] = bestArgument;
-				}
-			} else if (invocation.isRawType()) {
-				return invocation; // raw type is taking precedence
+			TypeBinding invocation = ((TypeBinding)iter.next()).leafComponentType();
+			switch (invocation.kind()) {
+				case Binding.GENERIC_TYPE :
+					TypeVariableBinding[] invocationVariables = invocation.typeVariables();
+					for (int i = 0; i < argLength; i++) {
+						TypeBinding bestArgument = leastContainingTypeArgument(bestArguments[i], invocationVariables[i], (ReferenceBinding) mec, i, lubStack);
+						if (bestArgument == null) return null;
+						bestArguments[i] = bestArgument;
+					}
+					break;
+				case Binding.PARAMETERIZED_TYPE :
+					ParameterizedTypeBinding parameterizedType = (ParameterizedTypeBinding)invocation;
+					for (int i = 0; i < argLength; i++) {
+						TypeBinding bestArgument = leastContainingTypeArgument(bestArguments[i], parameterizedType.arguments[i], (ReferenceBinding) mec, i, lubStack);
+						if (bestArgument == null) return null;
+						bestArguments[i] = bestArgument;
+					}
+					break;
+				case Binding.RAW_TYPE :
+					return dim == 0 ? invocation : environment().createArrayType(invocation, dim); // raw type is taking precedence
 			}
 		}
-		return createParameterizedType((ReferenceBinding) mec.erasure(), bestArguments, null);
+		TypeBinding least = environment().createParameterizedType((ReferenceBinding) mec.erasure(), bestArguments, mec.enclosingType());
+		return dim == 0 ? least : environment().createArrayType(least, dim);
 	}
 	
 	// JLS 15.12.2
@@ -2874,7 +2886,16 @@
 	}
 
 	// 15.12.2
+	/**
+	 * Returns VoidBinding if types have no intersection (e.g. 2 unrelated interfaces), or null if
+	 * no common supertype (e.g. List<String> and List<Exception>), or the intersection type if possible
+	 */
 	public TypeBinding lowerUpperBound(TypeBinding[] types) {
+		int typeLength = types.length;
+		if (typeLength == 1) {
+			TypeBinding type = types[0];
+			return type == null ? VoidBinding : type;
+		}		
 		return lowerUpperBound(types, new ArrayList(1));
 	}
 	
@@ -2895,7 +2916,7 @@
 			nextTypeCheck:	for (int j = 0; j < typeLength; j++) {
 				TypeBinding type = types[j];
 				for (int k = 0; k < lubTypeLength; k++) {
-					if (lubTypes[k] == type) continue nextTypeCheck; // type found, jump to next one
+					if (lubTypes[k] == type || lubTypes[k].isEquivalentTo(type)) continue nextTypeCheck; // type found, jump to next one 
 				}
 				continue nextLubCheck; // type not found in current lubTypes
 			}
@@ -2911,31 +2932,38 @@
 		if (length == 0) return VoidBinding;
 		int count = 0;
 		TypeBinding firstBound = null;
+		int commonDim = -1;
 		for (int i = 0; i < length; i++) {
 			TypeBinding mec = mecs[i];
 			if (mec == null) continue;
 			mec = leastContainingInvocation(mec, (Set)invocations.get(mec), lubStack);
 			if (mec == null) return null;
-			if (!mec.isInterface()) firstBound = mec;
+			int dim = mec.dimensions();
+			if (commonDim == -1) {
+				commonDim = dim;
+			} else if (dim != commonDim) { // not all types have same dimension
+				return null;
+			}
+			if (firstBound == null && !mec.leafComponentType().isInterface()) firstBound = mec.leafComponentType();
 			mecs[count++] = mec; // recompact them to the front
-
 		}
 		switch (count) {
 			case 0 : return VoidBinding;
 			case 1 : return mecs[0];
 			case 2 : 
-				if (mecs[1].id == T_JavaLangObject) return mecs[0];
-				if (mecs[0].id == T_JavaLangObject) return mecs[1];
+				if ((commonDim == 0 ? mecs[1].id : mecs[1].leafComponentType().id) == T_JavaLangObject) return mecs[0];
+				if ((commonDim == 0 ? mecs[0].id : mecs[0].leafComponentType().id) == T_JavaLangObject) return mecs[1];
 		}
 		TypeBinding[] otherBounds = new TypeBinding[count - 1];
 		int rank = 0;
 		for (int i = 0; i < count; i++) {
-			TypeBinding mec = mecs[i];
+			TypeBinding mec = commonDim == 0 ? mecs[i] : mecs[i].leafComponentType();
 			if (mec.isInterface()) {
 				otherBounds[rank++] = (ReferenceBinding)mec;
 			}
 		}
-		return environment().createWildcard(null, 0, firstBound, otherBounds, Wildcard.EXTENDS);
+		TypeBinding intersectionType = environment().createWildcard(null, 0, firstBound, otherBounds, Wildcard.EXTENDS);
+		return commonDim == 0 ? intersectionType : environment().createArrayType(intersectionType, commonDim);
 	}
 	
 	public final MethodScope methodScope() {
@@ -2956,7 +2984,7 @@
 	 * of minimal erased types, where some nulls may appear (and must simply be
 	 * ignored).
 	 */
-	private TypeBinding[] minimalErasedCandidates(TypeBinding[] types, Map allInvocations) {
+	protected TypeBinding[] minimalErasedCandidates(TypeBinding[] types, Map allInvocations) {
 		int length = types.length;
 		int indexOfFirst = -1, actualLength = 0;
 		for (int i = 0; i < length; i++) {
@@ -2970,80 +2998,125 @@
 			case 0: return NoTypes;
 			case 1: return types;
 		}
+		TypeBinding firstType = types[indexOfFirst];
+		if (firstType.isBaseType()) return null; 
 
 		// record all supertypes of type
 		// intersect with all supertypes of otherType
-		TypeBinding firstType = types[indexOfFirst];
-		TypeBinding[] superTypes;
-		int superLength;
-		if (firstType.isBaseType()) {
-			return null; 
-		} else if (firstType.isArrayType()) {
-			superLength = 4;
-			if (firstType.erasure() != firstType) {
-				ArrayList someInvocations = new ArrayList(1);
-				someInvocations.add(firstType);
-				allInvocations.put(firstType.erasure(), someInvocations);
-			}
-			superTypes = new TypeBinding[] { // inject well-known array supertypes
-					firstType.erasure(), 
-					getJavaIoSerializable(),
-					getJavaLangCloneable(),
-					getJavaLangObject(),
-			};
-		} else {
-			ArrayList typesToVisit = new ArrayList(5);
-			TypeBinding firstErasure = firstType.erasure();
-			if (firstErasure != firstType) {
-				Set someInvocations = new HashSet(1);
-				someInvocations.add(firstType);
-				allInvocations.put(firstErasure, someInvocations);
-			}
-			typesToVisit.add(firstErasure);
-			int max = 1;
-			if (firstErasure.isArrayType()) {
-				typesToVisit.add(getJavaIoSerializable());
-				typesToVisit.add(getJavaLangCloneable());
-				typesToVisit.add(getJavaLangObject());
-				max += 3;
-			}
-			ReferenceBinding currentType = (ReferenceBinding)firstType;
-			for (int i = 0; i < max; i++) {
-				TypeBinding typeToVisit = (TypeBinding) typesToVisit.get(i);
-				if (typeToVisit.isArrayType()) continue;
-				currentType = (ReferenceBinding) typeToVisit;
-				// inject super interfaces prior to superclass
-				ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
-				for (int j = 0, count = itsInterfaces.length; j < count; j++) {
-					TypeBinding itsInterface = itsInterfaces[j];
-					TypeBinding itsInterfaceErasure = itsInterface.erasure();
-					if (!typesToVisit.contains(itsInterfaceErasure)) {
-						if (itsInterfaceErasure != itsInterface) {
-							Set someInvocations = new HashSet(1);
-							someInvocations.add(itsInterface);
-							allInvocations.put(itsInterfaceErasure, someInvocations);
-						}						
-						typesToVisit.add(itsInterfaceErasure);
-						max++;
-					}
-				}
-				TypeBinding itsSuperclass = currentType.superclass();
-				if (itsSuperclass != null) {
-					TypeBinding itsSuperclassErasure = itsSuperclass.erasure();
-					if (!typesToVisit.contains(itsSuperclassErasure)) {
-						if (itsSuperclassErasure != itsSuperclass) {
-							Set someInvocations = new HashSet(1);
-							someInvocations.add(itsSuperclass);
-							allInvocations.put(itsSuperclassErasure, someInvocations);
+		ArrayList typesToVisit = new ArrayList(5);
+		
+		int dim = firstType.dimensions();
+		TypeBinding leafType = firstType.leafComponentType();
+		TypeBinding firstErasure = (leafType.isTypeVariable() || leafType.isWildcard()/*&& !leafType.isCapture()*/) ? firstType : firstType.erasure();
+		if (firstErasure != firstType) {
+			Set someInvocations = new HashSet(1);
+			someInvocations.add(firstType);
+			allInvocations.put(firstErasure, someInvocations);
+		}						
+		typesToVisit.add(firstType);
+		int max = 1;
+		ReferenceBinding currentType;
+		for (int i = 0; i < max; i++) {
+			TypeBinding typeToVisit = (TypeBinding) typesToVisit.get(i);
+			dim = typeToVisit.dimensions();
+			if (dim > 0) {
+				leafType = typeToVisit.leafComponentType();
+				switch(leafType.id) {
+					case T_JavaLangObject:
+						if (dim > 1) { // Object[][] supertype is Object[]
+							TypeBinding elementType = ((ArrayBinding)typeToVisit).elementsType();
+							if (!typesToVisit.contains(elementType)) {
+								typesToVisit.add(elementType);
+								max++;
+							}
+							continue;
 						}
-						typesToVisit.add(itsSuperclassErasure);
+						// fallthrough
+					case T_byte:
+					case T_short:
+					case T_char:
+					case T_boolean:
+					case T_int:
+					case T_long:
+					case T_float:
+					case T_double:
+						TypeBinding superType = getJavaIoSerializable();
+						if (!typesToVisit.contains(superType)) {
+							typesToVisit.add(superType);
+							max++;
+						}
+						superType = getJavaLangCloneable();
+						if (!typesToVisit.contains(superType)) {
+							typesToVisit.add(superType);
+							max++;
+						}
+						superType = getJavaLangObject();
+						if (!typesToVisit.contains(superType)) {
+							typesToVisit.add(superType);
+							max++;
+						}
+						continue;
+					
+					default:
+				}
+				typeToVisit = leafType;
+			}
+			currentType = (ReferenceBinding) typeToVisit;
+			if (currentType.isCapture()) {
+				TypeBinding firstBound = ((CaptureBinding) currentType).firstBound;
+				if (firstBound != null && firstBound.isArrayType()) {
+					TypeBinding superType = dim == 0 ? firstBound : (TypeBinding)environment().createArrayType(firstBound, dim); // recreate array if needed
+					if (!typesToVisit.contains(superType)) {
+						typesToVisit.add(superType);
 						max++;
+						TypeBinding superTypeErasure = (firstBound.isTypeVariable() || firstBound.isWildcard() /*&& !itsInterface.isCapture()*/) ? superType : superType.erasure();
+						if (superTypeErasure != superType) {
+							Set someInvocations = new HashSet(1);
+							someInvocations.add(superType);
+							allInvocations.put(superTypeErasure, someInvocations);
+						}						
+					}
+					continue;
+				}
+			}
+			// inject super interfaces prior to superclass
+			ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
+			for (int j = 0, count = itsInterfaces.length; j < count; j++) {
+				TypeBinding itsInterface = itsInterfaces[j];
+				TypeBinding superType = dim == 0 ? itsInterface : (TypeBinding)environment().createArrayType(itsInterface, dim); // recreate array if needed
+				if (!typesToVisit.contains(superType)) {
+					typesToVisit.add(superType);
+					max++;
+					TypeBinding superTypeErasure = (itsInterface.isTypeVariable() || itsInterface.isWildcard() /*&& !itsInterface.isCapture()*/) ? superType : superType.erasure();
+					if (superTypeErasure != superType) {
+						Set someInvocations = new HashSet(1);
+						someInvocations.add(superType);
+						allInvocations.put(superTypeErasure, someInvocations);
+					}						
+				}
+			}
+			TypeBinding itsSuperclass = currentType.superclass();
+			if (itsSuperclass != null) {
+				TypeBinding superType = dim == 0 ? itsSuperclass : (TypeBinding)environment().createArrayType(itsSuperclass, dim); // recreate array if needed
+				if (!typesToVisit.contains(superType)) {
+					typesToVisit.add(superType);
+					max++;
+					TypeBinding superTypeErasure = (itsSuperclass.isTypeVariable() || itsSuperclass.isWildcard() /*&& !itsSuperclass.isCapture()*/) ? superType : superType.erasure();
+					if (superTypeErasure != superType) {
+						Set someInvocations = new HashSet(1);
+						someInvocations.add(superType);
+						allInvocations.put(superTypeErasure, someInvocations);
 					}
 				}
 			}
-			superLength = typesToVisit.size();
-			superTypes = new TypeBinding[superLength];
-			typesToVisit.toArray(superTypes);
+		}
+		int superLength = typesToVisit.size();
+		TypeBinding[] erasedSuperTypes = new TypeBinding[superLength];
+		int rank = 0;
+		for (Iterator iter = typesToVisit.iterator(); iter.hasNext();) {
+			TypeBinding type = (TypeBinding)iter.next();
+			leafType = type.leafComponentType();
+			erasedSuperTypes[rank++] = (leafType.isTypeVariable() || leafType.isWildcard() /*&& !leafType.isCapture()*/) ? type : type.erasure();
 		}
 		// intersecting first type supertypes with other types' ones, nullifying non matching supertypes
 		int remaining = superLength;
@@ -3052,64 +3125,77 @@
 			if (otherType == null) continue nextOtherType;
 			if (otherType.isArrayType()) {
 				nextSuperType: for (int j = 0; j < superLength; j++) {
-					TypeBinding superType = superTypes[j];
-					if (superType == null || superType == otherType) continue nextSuperType;
-					switch (superType.id) {
-						case T_JavaIoSerializable :
-						case T_JavaLangCloneable :
-						case T_JavaLangObject :
-							continue nextSuperType;
+					TypeBinding erasedSuperType = erasedSuperTypes[j];
+					if (erasedSuperType == null || erasedSuperType == otherType) continue nextSuperType;
+					TypeBinding match;
+					if ((match = ((ArrayBinding)otherType).findSuperTypeWithSameErasure(erasedSuperType)) == null) {
+						erasedSuperTypes[j] = null;
+						if (--remaining == 0) return null;
+						continue nextSuperType;
 					}
-					superTypes[j] = null;
-					if (--remaining == 0) return null;
-					
+					// record invocation
+					Set someInvocations = (Set) allInvocations.get(erasedSuperType);
+					if (someInvocations == null) someInvocations = new HashSet(1);
+					someInvocations.add(match);
+					allInvocations.put(erasedSuperType, someInvocations);
 				}
 				continue nextOtherType;
 			}
 			ReferenceBinding otherRefType = (ReferenceBinding) otherType;
 			nextSuperType: for (int j = 0; j < superLength; j++) {
-				TypeBinding superType = superTypes[j];
-				if (superType == null) continue nextSuperType;
+				TypeBinding erasedSuperType = erasedSuperTypes[j];
+				if (erasedSuperType == null) continue nextSuperType;
 				TypeBinding match;
-				if (superType == otherType || superType.id == T_JavaLangObject && otherType.isInterface()) {
-					match = superType;
+				if (erasedSuperType == otherType || erasedSuperType.id == T_JavaLangObject && otherType.isInterface()) {
+					match = erasedSuperType;
 				} else {
-					if (superType.isArrayType()) {
+					if (erasedSuperType.isArrayType()) {
 						match = null;
 					} else {
-						match = otherRefType.findSuperTypeErasingTo((ReferenceBinding)superType);
+						match = otherRefType.findSuperTypeWithSameErasure(erasedSuperType);
 					}
 					if (match == null) { // incompatible super type
-						superTypes[j] = null;
+						erasedSuperTypes[j] = null;
 						if (--remaining == 0) return null;
 						continue nextSuperType;
 					}
 				}
 				// record invocation
-				Set someInvocations = (Set) allInvocations.get(superType);
+				Set someInvocations = (Set) allInvocations.get(erasedSuperType);
 				if (someInvocations == null) someInvocations = new HashSet(1);
 				someInvocations.add(match);
-				allInvocations.put(superType, someInvocations);
+				allInvocations.put(erasedSuperType, someInvocations);
 			}				
 		}
 		// eliminate non minimal super types
 		if (remaining > 1) {
 			nextType: for (int i = 0; i < superLength; i++) {
-				ReferenceBinding superType = (ReferenceBinding)superTypes[i];
-				if (superType == null) continue nextType;
+				TypeBinding erasedSuperType = erasedSuperTypes[i];
+				if (erasedSuperType == null) continue nextType;
 				nextOtherType: for (int j = 0; j < superLength; j++) {
 					if (i == j) continue nextOtherType;
-					ReferenceBinding otherType = (ReferenceBinding)superTypes[j];
+					TypeBinding otherType = erasedSuperTypes[j];
 					if (otherType == null) continue nextOtherType;
-					if (otherType.id == T_JavaLangObject && superType.isInterface()) continue nextOtherType;
-					if (superType.findSuperTypeErasingTo(otherType) != null) {
-						superTypes[j] = null; // discard non minimal supertype
-						remaining--;
+					if (erasedSuperType instanceof ReferenceBinding) {
+						if (otherType.id == T_JavaLangObject && erasedSuperType.isInterface()) continue nextOtherType; // keep Object for an interface
+						if (((ReferenceBinding)erasedSuperType).findSuperTypeWithSameErasure(otherType) != null) {
+							erasedSuperTypes[j] = null; // discard non minimal supertype
+							remaining--;
+						}
+					} else if (erasedSuperType.isArrayType()) {
+					if (otherType.isArrayType() // keep Object[...] for an interface array (same dimensions)
+							&& otherType.leafComponentType().id == T_JavaLangObject
+							&& otherType.dimensions() == erasedSuperType.dimensions()
+							&& erasedSuperType.leafComponentType().isInterface()) continue nextOtherType;
+						if (((ArrayBinding)erasedSuperType).findSuperTypeWithSameErasure(otherType) != null) {
+							erasedSuperTypes[j] = null; // discard non minimal supertype
+							remaining--;
+						}
 					}
 				}
 			}
 		}
-		return superTypes;
+		return erasedSuperTypes;
 	}
 	
 	// Internal use only
@@ -3195,13 +3281,14 @@
 		for (int i = 0; i < visibleSize; i++)
 			compatibilityLevels[i] = parameterCompatibilityLevel(visible[i], argumentTypes);
 
-		for (int level = 0; level <= VARARGS_COMPATIBLE; level++) {
+		for (int level = 0, max = VARARGS_COMPATIBLE; level <= max; level++) {
 			nextVisible : for (int i = 0; i < visibleSize; i++) {
 				if (compatibilityLevels[i] != level) continue nextVisible; // skip this method for now
 				MethodBinding method = visible[i];
 				TypeBinding[] params = method.tiebreakMethod().parameters;
 				for (int j = 0; j < visibleSize; j++) {
 					if (i == j || compatibilityLevels[j] != level) continue;
+					max = level; // do not examine further categories
 					MethodBinding method2 = visible[j];
 					// tiebreak generic methods using variant where type params are substituted by their erasures
 					if (!method2.tiebreakMethod().areParametersCompatibleWith(params)) {
@@ -3220,36 +3307,47 @@
 								continue; // special case to choose between 2 varargs methods when the last arg is missing or its Object[]
 						}
 						continue nextVisible;
-					} else if (method.hasSubstitutedParameters() && method.isAbstract() == method2.isAbstract()) { // must both be abstract or concrete, not one of each
-						if (method.areParametersEqual(method2)) {
-							// its possible with 2 abstract methods that one does not inherit from the other
-							// need to find their methods from the receiver type
-							MethodBinding original = method.original();
-							MethodBinding original2 = method2.original();
-							if (original.areParameterErasuresEqual(original2)) continue;
-							ReferenceBinding receiverType = (ReferenceBinding) ((MessageSend) invocationSite).actualReceiverType;
-							if (receiverType != method.declaringClass) {
-								ReferenceBinding superType = ((ReferenceBinding) receiverType.erasure()).findSuperTypeErasingTo(original.declaringClass);
-								MethodBinding[] superMethods = superType.getMethods(original.selector);
+					}
+
+					// parameterized superclasses & interfaces may be walked twice from different paths
+					if (method.original() == method2.original()) continue;
+
+					// see if method & method2 are duplicates due to the current substitution or multiple static imported methods
+					if (method.tiebreakMethod().areParametersEqual(method2.tiebreakMethod())) {
+						if (method.declaringClass == method2.declaringClass)
+							continue nextVisible; // duplicates thru substitution
+
+						MethodBinding original = method.original();
+						if (method.hasSubstitutedParameters() || original.typeVariables != NoTypeVariables) {
+							ReferenceBinding declaringClass = (ReferenceBinding) method.declaringClass.erasure();
+							ReferenceBinding superType = declaringClass.findSuperTypeWithSameErasure(method2.declaringClass.erasure());
+							if (superType == null) {
+								// accept concrete methods over abstract methods found due to the default abstract method walk
+								if (!method.isAbstract() && method2.isAbstract())
+									continue;
+								continue nextVisible;
+							}
+							MethodBinding inheritedMethod = method2;
+							MethodBinding inheritedOriginal = method2.original();
+							if (method.hasSubstitutedParameters()) { // must find inherited method with the same substituted variables
+								MethodBinding[] superMethods = superType.getMethods(inheritedMethod.selector);
 								for (int m = 0, l = superMethods.length; m < l; m++) {
-									if (superMethods[m].original() == original) {
-										original = superMethods[m];
+									if (superMethods[m].original() == inheritedOriginal) {
+										inheritedMethod = superMethods[m];
 										break;
 									}
 								}
 							}
-							if (receiverType != method2.declaringClass) {
-								ReferenceBinding superType = ((ReferenceBinding) receiverType.erasure()).findSuperTypeErasingTo(original2.declaringClass);
-								MethodBinding[] superMethods = superType.getMethods(original2.selector);
-								for (int m = 0, l = superMethods.length; m < l; m++) {
-									if (superMethods[m].original() == original2) {
-										original2 = superMethods[m];
-										break;
-									}
-								}
-							}
-							if (!original.areParametersEqual(original2))
-								continue nextVisible; // cannot be substituted from 2 different type variables
+							if (original.typeVariables != NoTypeVariables)
+								inheritedMethod = original.computeSubstitutedMethod(inheritedMethod == method2 ? inheritedOriginal : inheritedMethod, environment());
+							if (inheritedMethod == null || !original.areParametersEqual(inheritedMethod))
+								break nextVisible; // dup thru substitution, not overridden... cannot find possible match
+							// method overrides method2, accept it
+						} else if (method.isStatic() && method2.isStatic()) {
+							ReferenceBinding declaringClass = (ReferenceBinding) method.declaringClass.erasure();
+							ReferenceBinding superType = declaringClass.findSuperTypeWithSameErasure(method2.declaringClass.erasure());
+							if (superType == null)
+								continue nextVisible; // static methods from unrelated types
 						}
 					}
 				}
@@ -3287,8 +3385,7 @@
 		int paramLength = parameters.length;
 		int argLength = arguments.length;
 
-		LookupEnvironment env = environment();
-		if (env.options.sourceLevel < ClassFileConstants.JDK1_5) {
+		if (compilerOptions().sourceLevel < ClassFileConstants.JDK1_5) {
 			if (paramLength != argLength)
 				return NOT_COMPATIBLE;
 			for (int i = 0; i < argLength; i++) {
@@ -3308,11 +3405,11 @@
 				TypeBinding param = parameters[lastIndex]; // is an ArrayBinding by definition
 				TypeBinding arg = arguments[lastIndex];
 				if (param != arg) {
-					level = parameterCompatibilityLevel(arg, param, env);
+					level = parameterCompatibilityLevel(arg, param, environment());
 					if (level == NOT_COMPATIBLE) {
 						// expect X[], is it called with X
 						param = ((ArrayBinding) param).elementsType();
-						if (parameterCompatibilityLevel(arg, param, env) == NOT_COMPATIBLE)
+						if (parameterCompatibilityLevel(arg, param, environment()) == NOT_COMPATIBLE)
 							return NOT_COMPATIBLE;
 						level = VARARGS_COMPATIBLE; // varargs support needed
 					}
@@ -3322,7 +3419,7 @@
 					TypeBinding param = ((ArrayBinding) parameters[lastIndex]).elementsType();
 					for (int i = lastIndex; i < argLength; i++) {
 						TypeBinding arg = arguments[i];
-						if (param != arg && parameterCompatibilityLevel(arg, param, env) == NOT_COMPATIBLE)
+						if (param != arg && parameterCompatibilityLevel(arg, param, environment()) == NOT_COMPATIBLE)
 							return NOT_COMPATIBLE;
 					}
 				}  else if (lastIndex != argLength) { // can call foo(int i, X ... x) with foo(1) but NOT foo();
@@ -3336,7 +3433,7 @@
 			TypeBinding param = parameters[i];
 			TypeBinding arg = arguments[i];
 			if (arg != param) {
-				int newLevel = parameterCompatibilityLevel(arg, param, env);
+				int newLevel = parameterCompatibilityLevel(arg, param, environment());
 				if (newLevel == NOT_COMPATIBLE)
 					return NOT_COMPATIBLE;
 				if (newLevel > level)
@@ -3366,6 +3463,26 @@
 			unitScope = scope;
 		return ((CompilationUnitScope) unitScope).referenceContext;
 	}
+	
+	/**
+	 * Returns the nearest reference context, starting from current scope.
+	 * If starting on a class, it will return current class. If starting on unitScope, returns unit.
+	 */
+	public ReferenceContext referenceContext() {
+		Scope current = this;
+		do {
+			switch(current.kind) {
+				case METHOD_SCOPE :
+					return ((MethodScope) current).referenceContext;
+				case CLASS_SCOPE :
+					return ((ClassScope) current).referenceContext;
+				case COMPILATION_UNIT_SCOPE :
+					return ((CompilationUnitScope) current).referenceContext;
+			}
+		} while ((current = current.parent) != null);
+		return null;
+	}
+	
 	// start position in this scope - for ordering scopes vs. variables
 	int startIndex() {
 		return 0;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
index 7f164d3..e72a89c 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
@@ -80,7 +80,7 @@
 
 	tagBits |= KnowsDefaultAbstractMethods;
 	if (isClass() && isAbstract()) {
-		if (fPackage.environment.options.targetJDK >= ClassFileConstants.JDK1_2)
+		if (this.scope.compilerOptions().targetJDK >= ClassFileConstants.JDK1_2)
 			return; // no longer added for post 1.2 targets
 
 		ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[5][];
@@ -185,7 +185,7 @@
 			for (int i = 0, max = typeDecl.fields.length; i < max; i++) {
 				FieldDeclaration fieldDecl = typeDecl.fields[i];
 				if (fieldDecl.binding == existingField) {
-					if (this.scope.environment().options.complianceLevel >= ClassFileConstants.JDK1_5) {
+					if (this.scope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_5) {
 						synthField.name = CharOperation.concat(
 							synthField.name,
 							"$".toCharArray()); //$NON-NLS-1$
@@ -369,6 +369,78 @@
 	}
 	return accessMethod;
 }
+/*
+ * Add a synthetic field to handle the cache of the switch translation table for the corresponding enum type 
+ */
+public SyntheticFieldBinding addSyntheticFieldForSwitchEnum(char[] fieldName, String key) {
+	if (synthetics == null)
+		synthetics = new HashMap[4];
+	if (synthetics[FIELD_EMUL] == null)
+		synthetics[FIELD_EMUL] = new HashMap(5);
+
+	SyntheticFieldBinding synthField = (SyntheticFieldBinding) synthetics[FIELD_EMUL].get(key); //$NON-NLS-1$
+	if (synthField == null) {
+		synthField = new SyntheticFieldBinding(
+			fieldName,
+			scope.createArrayType(BaseTypes.IntBinding,1),
+			AccPrivate | AccStatic | AccSynthetic,
+			this,
+			Constant.NotAConstant,
+			synthetics[FIELD_EMUL].size());
+		synthetics[FIELD_EMUL].put(key, synthField);
+	}
+	// ensure there is not already such a field defined by the user
+	boolean needRecheck;
+	int index = 0;
+	do {
+		needRecheck = false;
+		FieldBinding existingField;
+		if ((existingField = this.getField(synthField.name, true /*resolve*/)) != null) {
+			TypeDeclaration typeDecl = scope.referenceContext;
+			for (int i = 0, max = typeDecl.fields.length; i < max; i++) {
+				FieldDeclaration fieldDecl = typeDecl.fields[i];
+				if (fieldDecl.binding == existingField) {
+					synthField.name = CharOperation.concat(
+						fieldName,
+						("_" + String.valueOf(index++)).toCharArray()); //$NON-NLS-1$
+					needRecheck = true;
+					break;
+				}
+			}
+		}
+	} while (needRecheck);
+	return synthField;
+}
+/* Add a new synthetic method the enum type. Selector can either be 'values' or 'valueOf'.
+ * char[] constants from TypeConstants must be used: TypeConstants.VALUES/VALUEOF
+*/
+public SyntheticMethodBinding addSyntheticMethodForSwitchEnum(TypeBinding enumBinding) {
+	if (synthetics == null)
+		synthetics = new HashMap[4];
+	if (synthetics[METHOD_EMUL] == null)
+		synthetics[METHOD_EMUL] = new HashMap(5);
+
+	SyntheticMethodBinding accessMethod = null;
+	char[] selector = CharOperation.concat(TypeConstants.SYNTHETIC_SWITCH_ENUM_TABLE, enumBinding.constantPoolName());
+	CharOperation.replace(selector, '/', '$');
+	final String key = new String(selector);
+	SyntheticMethodBinding[] accessors = (SyntheticMethodBinding[]) synthetics[METHOD_EMUL].get(key);
+	// first add the corresponding synthetic field
+	if (accessors == null) {
+		// then create the synthetic method
+		final SyntheticFieldBinding fieldBinding = this.addSyntheticFieldForSwitchEnum(selector, key);
+		accessMethod = new SyntheticMethodBinding(fieldBinding, this, enumBinding, selector);
+		synthetics[METHOD_EMUL].put(key, accessors = new SyntheticMethodBinding[2]);
+		accessors[0] = accessMethod;
+	} else {
+		if ((accessMethod = accessors[0]) == null) {
+			final SyntheticFieldBinding fieldBinding = this.addSyntheticFieldForSwitchEnum(selector, key);
+			accessMethod = new SyntheticMethodBinding(fieldBinding, this, enumBinding, selector);
+			accessors[0] = accessMethod;
+		}
+	}
+	return accessMethod;
+}
 /* Add a new synthetic access method for access to <targetMethod>.
  * Must distinguish access method used for super access from others (need to use invokespecial bytecode)
 	Answer the new method or the existing method if one already existed.
@@ -454,12 +526,12 @@
 		case CONSTRAINT_EQUAL :
 		case CONSTRAINT_EXTENDS :
 			equivalent = this;
-	        otherEquivalent = ((ReferenceBinding)otherType).findSuperTypeErasingTo(this);
+	        otherEquivalent = ((ReferenceBinding)otherType).findSuperTypeWithSameErasure(this);
 	        if (otherEquivalent == null) return;
 	        break;
 		case CONSTRAINT_SUPER :
         default:
-	        equivalent = this.findSuperTypeErasingTo((ReferenceBinding)(otherType.erasure()));
+	        equivalent = this.findSuperTypeWithSameErasure(otherType);
 	        if (equivalent == null) return;
 	        otherEquivalent = (ReferenceBinding) otherType;
 	        break;
@@ -500,8 +572,8 @@
 	if (this.typeVariables != NoTypeVariables) return Binding.GENERIC_TYPE;
 	return Binding.TYPE;
 }
-public char[] computeUniqueKey(boolean withAccessFlags) {
-	char[] uniqueKey = super.computeUniqueKey(withAccessFlags);
+public char[] computeUniqueKey(boolean isLeaf) {
+	char[] uniqueKey = super.computeUniqueKey(isLeaf);
 	if (uniqueKey.length == 2) return uniqueKey; // problem type's unique key is "L;"
 	int start = CharOperation.lastIndexOf('/', this.fileName) + 1;
 	int end = CharOperation.lastIndexOf('.', this.fileName);
@@ -535,7 +607,7 @@
 	// check @Deprecated annotation
 	if ((this.getAnnotationTagBits() & AnnotationDeprecated) != 0) {
 		this.modifiers |= AccDeprecated;
-	} else if ((this.modifiers & AccDeprecated) != 0 && scope != null && scope.environment().options.sourceLevel >= JDK1_5) {
+	} else if ((this.modifiers & AccDeprecated) != 0 && scope != null && scope.compilerOptions().sourceLevel >= JDK1_5) {
 		scope.problemReporter().missingDeprecatedAnnotationForType(scope.referenceContext);
 	}
 	ReferenceBinding enclosingType = this.enclosingType();
@@ -781,10 +853,11 @@
 	MethodBinding[] result = new MethodBinding[matchingMethods.size()];
 	matchingMethods.toArray(result);
 	if (!methodsAreResolved) {
+		boolean isSource15 = this.scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5;
 		for (int i = 0, length = result.length - 1; i < length; i++) {
 			MethodBinding method = result[i];
 			for (int j = length; j > i; j--) {
-				boolean paramsMatch = fPackage.environment.options.sourceLevel >= ClassFileConstants.JDK1_5
+				boolean paramsMatch = isSource15
 					? method.areParameterErasuresEqual(result[j])
 					: method.areParametersEqual(result[j]);
 				if (paramsMatch) {
@@ -820,7 +893,7 @@
 		while (accessFields.hasNext()) {
 			field = (FieldBinding) accessFields.next();
 			if (CharOperation.prefixEquals(TypeConstants.SYNTHETIC_ENCLOSING_INSTANCE_PREFIX, field.name)
-				&& ((ReferenceBinding) field.type).findSuperTypeErasingTo(targetEnclosingType) != null)
+				&& ((ReferenceBinding) field.type).findSuperTypeWithSameErasure(targetEnclosingType) != null)
 					return field;
 		}
 	}
@@ -856,9 +929,16 @@
 			if (this != otherParamType.type) 
 				return false;
 			if (!isStatic()) { // static member types do not compare their enclosing
-				ReferenceBinding enclosing = enclosingType();
-				if (enclosing != null && !enclosing.isEquivalentTo(otherParamType.enclosingType()))
-					return false;
+            	ReferenceBinding enclosing = enclosingType();
+            	if (enclosing != null) {
+            		ReferenceBinding otherEnclosing = otherParamType.enclosingType();
+            		if (otherEnclosing == null) return false;
+            		if ((otherEnclosing.tagBits & HasDirectWildcard) == 0) {
+						if (enclosing != otherEnclosing) return false;
+            		} else {
+            			if (!enclosing.isEquivalentTo(otherParamType.enclosingType())) return false;
+            		}
+            	}				
 			}
 			int length = this.typeVariables == null ? 0 : this.typeVariables.length;
 			TypeBinding[] otherArguments = otherParamType.arguments;
@@ -935,27 +1015,68 @@
 		}
 
 		// find & report collision cases
-		boolean complyTo15 = fPackage.environment.options.sourceLevel >= ClassFileConstants.JDK1_5;
+		boolean complyTo15 = this.scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5;
 		for (int i = 0, length = methods.length; i < length; i++) {
 			MethodBinding method = methods[i];
 			if (method != null) {
-				TypeBinding returnErasure = method.returnType == null ? null : method.returnType.erasure();
 				char[] selector = method.selector;
 				AbstractMethodDeclaration methodDecl = null;
 				nextMethod : for (int j = length - 1; j > i; j--) {
 					MethodBinding method2 = methods[j];
 					if (method2 == null || !CharOperation.equals(selector, method2.selector))
 						continue nextMethod;
-					if (complyTo15) {
-						if (returnErasure != (method2.returnType == null ? null : method2.returnType.erasure())) {
-							 // colllision when parameters are identical & type variable erasures match
-							if (!method.areParametersEqual(method2))
-								continue nextMethod;
-							if (method.typeVariables != NoTypeVariables && method2.typeVariables != NoTypeVariables)
-								if (!method.areTypeVariableErasuresEqual(method2))
-									continue nextMethod;
-						} else if (!method.areParameterErasuresEqual(method2)) { // colllision when parameter & return type erasures match
+					if (complyTo15 && method.returnType != null && method2.returnType != null) {
+						// 8.4.2, for collision to be detected between m1 and m2:
+						// signature(m1) == signature(m2) i.e. same arity, same type parameter count, can be substituted
+						// signature(m1) == erasure(signature(m2)) or erasure(signature(m1)) == signature(m2)
+						TypeBinding[] params1 = method.parameters;
+						TypeBinding[] params2 = method2.parameters;
+						int pLength = params1.length;
+						if (pLength != params2.length)
 							continue nextMethod;
+
+						TypeVariableBinding[] vars = method.typeVariables;
+						TypeVariableBinding[] vars2 = method2.typeVariables;
+						boolean equalTypeVars = vars == vars2;
+						MethodBinding subMethod = method2;
+						if (!equalTypeVars) {
+							MethodBinding temp = method.computeSubstitutedMethod(method2, this.scope.environment());
+							if (temp != null) {
+								equalTypeVars = true;
+								subMethod = temp;
+							}
+						}
+						boolean equalParams = method.areParametersEqual(subMethod);
+						if (equalParams && equalTypeVars) {
+							// duplicates regardless of return types
+						} else if (method.returnType.erasure() == subMethod.returnType.erasure() && (equalParams || method.areParameterErasuresEqual(method2))) {
+							// name clash for sure if not duplicates, report as duplicates
+						} else if (!equalTypeVars && vars != NoTypeVariables && vars2 != NoTypeVariables) {
+							// type variables are different so we can distinguish between methods
+							continue nextMethod;
+						} else if (pLength > 0) {
+							// check to see if the erasure of either method is equal to the other
+							int index = pLength;
+							for (; --index >= 0;) {
+								if (params1[index] != params2[index].erasure())
+									if (!params1[index].isRawType() || params1[index].erasure() != params2[index].erasure()) // want X#RAW to match X#RAW and X<T>
+										break;
+								if (params1[index] == params2[index]) {
+									TypeBinding type = params1[index].leafComponentType();
+									if (type instanceof SourceTypeBinding && type.typeVariables() != NoTypeVariables) {
+										index = pLength; // handle comparing identical source types like X<T>... its erasure is itself BUT we need to answer false
+										break;
+									}
+								}
+							}
+							if (index >= 0 && index < pLength) {
+								for (index = pLength; --index >= 0;)
+									if (params1[index].erasure() != params2[index])
+										if (!params2[index].isRawType() || params1[index].erasure() != params2[index].erasure()) // want X#RAW to match X#RAW and X<T>
+											break;
+							}
+							if (index >= 0)
+								continue nextMethod;
 						}
 					} else if (!method.areParametersEqual(method2)) { // prior to 1.5, parameter identity meant a collision case
 						continue nextMethod;
@@ -987,7 +1108,7 @@
 						failed++;
 					}
 				}
-				if (returnErasure == null && methodDecl == null) { // forget method with invalid return type... was kept to detect possible collisions
+				if (method.returnType == null && methodDecl == null) { // forget method with invalid return type... was kept to detect possible collisions
 					method.sourceMethod().binding = null;
 					methods[i] = null;
 					failed++;
@@ -1018,11 +1139,11 @@
 	if ((field.modifiers & AccUnresolved) == 0)
 		return field;
 
-	if (fPackage.environment.options.sourceLevel >= ClassFileConstants.JDK1_5) {
+	if (this.scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) {
 		if ((field.getAnnotationTagBits() & AnnotationDeprecated) != 0)
 			field.modifiers |= AccDeprecated;
 		else if ((field.modifiers & AccDeprecated) != 0)
-			scope.problemReporter().missingDeprecatedAnnotationForField(field.sourceField());
+			this.scope.problemReporter().missingDeprecatedAnnotationForField(field.sourceField());
 	}
 	if (isViewedAsDeprecated() && !field.isDeprecated())
 		field.modifiers |= AccDeprecatedImplicitly;	
@@ -1032,15 +1153,15 @@
 			continue;
 
 			MethodScope initializationScope = field.isStatic() 
-				? scope.referenceContext.staticInitializerScope 
-				: scope.referenceContext.initializerScope;
+				? this.scope.referenceContext.staticInitializerScope 
+				: this.scope.referenceContext.initializerScope;
 			FieldBinding previousField = initializationScope.initializedField;
 			try {
 				initializationScope.initializedField = field;
 				FieldDeclaration fieldDecl = fieldDecls[f];
 				TypeBinding fieldType = 
 					fieldDecl.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT
-						? this // enum constant is implicitly of declaring enum type
+						? initializationScope.environment().convertToRawType(this) // enum constant is implicitly of declaring enum type
 						: fieldDecl.type.resolveType(initializationScope, true /* check bounds*/);
 				field.type = fieldType;
 				field.modifiers &= ~AccUnresolved;
@@ -1073,11 +1194,11 @@
 	if ((method.modifiers & AccUnresolved) == 0)
 		return method;
 
-	if (fPackage.environment.options.sourceLevel >= ClassFileConstants.JDK1_5) {
+	if (this.scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) {
 		if ((method.getAnnotationTagBits() & AnnotationDeprecated) != 0)
 			method.modifiers |= AccDeprecated;
 		else if ((method.modifiers & AccDeprecated) != 0)
-			scope.problemReporter().missingDeprecatedAnnotationForMethod(method.sourceMethod());
+			this.scope.problemReporter().missingDeprecatedAnnotationForMethod(method.sourceMethod());
 	}
 	if (isViewedAsDeprecated() && !method.isDeprecated())
 		method.modifiers |= AccDeprecatedImplicitly;
@@ -1096,14 +1217,14 @@
 	if (exceptionTypes != null) {
 		int size = exceptionTypes.length;
 		method.thrownExceptions = new ReferenceBinding[size];
-		ReferenceBinding throwable = scope.getJavaLangThrowable();
+		ReferenceBinding throwable = this.scope.getJavaLangThrowable();
 		int count = 0;
 		ReferenceBinding resolvedExceptionType;
 		for (int i = 0; i < size; i++) {
 			resolvedExceptionType = (ReferenceBinding) exceptionTypes[i].resolveType(methodDecl.scope, true /* check bounds*/);
 			if (resolvedExceptionType == null)
 				continue;
-			if (resolvedExceptionType.isGenericType() || resolvedExceptionType.isParameterizedType()) {
+			if (resolvedExceptionType.isGenericType() || resolvedExceptionType.isBoundParameterizedType()) {
 				methodDecl.scope.problemReporter().invalidParameterizedExceptionType(resolvedExceptionType, exceptionTypes[i]);
 				continue;
 			}
@@ -1294,7 +1415,10 @@
 	if (isStatic() && isNestedType()) buffer.append("static "); //$NON-NLS-1$
 	if (isFinal()) buffer.append("final "); //$NON-NLS-1$
 
-	buffer.append(isInterface() ? "interface " : "class "); //$NON-NLS-1$ //$NON-NLS-2$
+	if (isEnum()) buffer.append("enum "); //$NON-NLS-1$
+	else if (isAnnotationType()) buffer.append("@interface "); //$NON-NLS-1$
+	else if (isClass()) buffer.append("class "); //$NON-NLS-1$
+	else buffer.append("interface "); //$NON-NLS-1$
 	buffer.append((compoundName != null) ? CharOperation.toString(compoundName) : "UNNAMED TYPE"); //$NON-NLS-1$
 
 	if (this.typeVariables == null) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticMethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticMethodBinding.java
index 0f10dd6..299a4ee 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticMethodBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticMethodBinding.java
@@ -18,7 +18,8 @@
 
 	public FieldBinding targetReadField;		// read access to a field
 	public FieldBinding targetWriteField;		// write access to a field
-	public MethodBinding targetMethod;	// method or constructor
+	public MethodBinding targetMethod;			// method or constructor
+	public TypeBinding targetEnumType; 			// enum type
 	
 	public int kind;
 
@@ -30,6 +31,7 @@
 	public final static int BridgeMethod = 6; // bridge method
 	public final static int EnumValues = 7; // enum #values()
 	public final static int EnumValueOf = 8; // enum #valueOf(String)
+	public final static int SwitchTable = 9; // switch table method
 
 	public int sourceStart = 0; // start position of the matching declaration
 	public int index; // used for sorting access methods in the class file
@@ -128,6 +130,59 @@
 		this.sourceStart = declaringSourceType.scope.referenceContext.sourceStart; // use the target declaring class name position instead
 	}
 
+	public SyntheticMethodBinding(FieldBinding targetField, ReferenceBinding declaringClass, TypeBinding enumBinding, char[] selector) {
+		this.modifiers = AccDefault | AccStatic | AccSynthetic;
+		this.tagBits |= TagBits.AnnotationResolved;
+		SourceTypeBinding declaringSourceType = (SourceTypeBinding) declaringClass;
+		SyntheticMethodBinding[] knownAccessMethods = declaringSourceType.syntheticMethods();
+		int methodId = knownAccessMethods == null ? 0 : knownAccessMethods.length;
+		this.index = methodId;
+		this.selector = selector;
+		this.returnType = declaringSourceType.scope.createArrayType(BaseTypes.IntBinding, 1);
+		this.parameters = NoParameters;
+		this.targetReadField = targetField;
+		this.targetEnumType = enumBinding;
+		this.kind = SwitchTable;
+		this.thrownExceptions = NoExceptions;
+		this.declaringClass = declaringSourceType;
+  
+		if (declaringSourceType.isStrictfp()) {
+			this.modifiers |= AccStrictfp;
+		}
+		// check for method collision
+		boolean needRename;
+		do {
+			check : {
+				needRename = false;
+				// check for collision with known methods
+				MethodBinding[] methods = declaringSourceType.methods;
+				for (int i = 0, length = methods.length; i < length; i++) {
+					if (CharOperation.equals(this.selector, methods[i].selector) && this.areParametersEqual(methods[i])) {
+						needRename = true;
+						break check;
+					}
+				}
+				// check for collision with synthetic accessors
+				if (knownAccessMethods != null) {
+					for (int i = 0, length = knownAccessMethods.length; i < length; i++) {
+						if (knownAccessMethods[i] == null) continue;
+						if (CharOperation.equals(this.selector, knownAccessMethods[i].selector) && this.areParametersEqual(methods[i])) {
+							needRename = true;
+							break check;
+						}
+					}
+				}
+			}
+			if (needRename) { // retry with a selector postfixed by a growing methodId
+				this.setSelector(CharOperation.concat(selector, String.valueOf(++methodId).toCharArray()));
+			}
+		} while (needRename);
+
+		// We now at this point - per construction - it is for sure an enclosing instance, we are going to
+		// show the target field type declaration location.
+		this.sourceStart = declaringSourceType.scope.referenceContext.sourceStart; // use the target declaring class name position instead
+	}
+	
 	public SyntheticMethodBinding(MethodBinding targetMethod, boolean isSuperAccess, ReferenceBinding receiverType) {
 	
 		if (targetMethod.isConstructor()) {
@@ -144,9 +199,9 @@
 		
 	    this.declaringClass = declaringClass;
 	    this.selector = overridenMethodToBridge.selector;
-	    this.modifiers = overridenMethodToBridge.modifiers | AccBridge | AccSynthetic;
+	    // amongst other, clear the AccGenericSignature, so as to ensure no remains of original inherited persist (101794)
+	    this.modifiers = (overridenMethodToBridge.modifiers | AccBridge | AccSynthetic) & ~(AccAbstract | AccNative | AccGenericSignature);
 		this.tagBits |= TagBits.AnnotationResolved;
-	    this.modifiers &= ~(AccAbstract | AccNative);
 	    this.returnType = overridenMethodToBridge.returnType;
 	    this.parameters = overridenMethodToBridge.parameters;
 	    this.thrownExceptions = overridenMethodToBridge.thrownExceptions;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java
index d525014..16525e5 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java
@@ -47,6 +47,9 @@
 	// test bit to identify if the type's hierarchy is inconsistent
 	long HierarchyHasProblems = ASTNode.Bit16;
 
+	// set for parameterized type with successfull bound check
+	long PassedBoundCheck = ASTNode.Bit23;
+	
 	// set for parameterized type NOT of the form X<?,?>
 	long IsBoundParameterizedType = ASTNode.Bit24; 
 	
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java
index eb1201d..cce5926 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java
@@ -72,7 +72,7 @@
 /**
  * Perform capture conversion on a given type (only effective on parameterized type with wildcards)
  */
-public TypeBinding capture() {
+public TypeBinding capture(Scope scope, int position) {
 	return this;
 }
 
@@ -127,6 +127,10 @@
     return signature();
 }
 public abstract PackageBinding getPackage();
+
+public final boolean isAnonymousType() {
+	return (tagBits & IsAnonymousType) != 0;
+}
 public boolean isAnnotationType() {
 	return false;
 }
@@ -190,6 +194,18 @@
 public boolean isInterface() {
 	return false;
 }
+/**
+ * Returns true if a type is intersecting with another one,
+ */
+public boolean isIntersectingWith(TypeBinding otherType) {
+    return this == otherType;
+}
+/**
+ * Returns true if the current type denotes an intersection type: Number & Comparable<?>
+ */
+public boolean isIntersectionType() {
+	return false;
+}
 public final boolean isLocalType() {
 	return (tagBits & IsLocalType) != 0;
 }
@@ -307,50 +323,251 @@
 }
 
 // JLS3: 4.5.1.1
-public boolean isTypeArgumentContainedBy(TypeBinding otherArgument) {
-	if (this == otherArgument)
+public boolean isTypeArgumentContainedBy(TypeBinding otherType) {
+	if (this == otherType)
 		return true;
-	TypeBinding lowerBound = this;
-	TypeBinding upperBound = this;
-	if (isWildcard()) {
-		WildcardBinding wildcard = (WildcardBinding) this;
-		switch(wildcard.boundKind) {
-			case Wildcard.EXTENDS :
-				upperBound = wildcard.bound;
-				lowerBound = null;
-				break;
-			case Wildcard. SUPER :
-				upperBound = wildcard.typeVariable();
-				lowerBound = wildcard.bound;
-				break;
-			case Wildcard.UNBOUND :
-				upperBound = wildcard.typeVariable();
-				lowerBound = null;
-		}
-	}
-	if (otherArgument.isWildcard()) {
-		WildcardBinding otherWildcard = (WildcardBinding) otherArgument;
-		if (otherWildcard.otherBounds != null) return false; // not a true wildcard (intersection type)
-		switch(otherWildcard.boundKind) {
-			case Wildcard.EXTENDS:
-				return upperBound != null && upperBound.isCompatibleWith(otherWildcard.bound);
-
-			case Wildcard.SUPER :
-				return lowerBound != null && otherWildcard.bound.isCompatibleWith(lowerBound);
-
-			case Wildcard.UNBOUND :
-				return true;
-		}
+	switch(otherType.kind()) {
+		// allow wildcard containment
+		case Binding.WILDCARD_TYPE :
+			TypeBinding lowerBound = this;
+			TypeBinding upperBound = this;
+			switch (this.kind()) {
+				case Binding.WILDCARD_TYPE :
+					WildcardBinding wildcard = (WildcardBinding) this;
+					switch(wildcard.boundKind) {
+						case Wildcard.EXTENDS :
+							upperBound = wildcard.bound;
+							lowerBound = null;
+							break;
+						case Wildcard. SUPER :
+							upperBound = wildcard;
+							lowerBound = wildcard.bound;
+							break;
+						case Wildcard.UNBOUND :
+							upperBound = wildcard;
+							lowerBound = null;
+					}
+					break;
+				case Binding.TYPE_PARAMETER :
+					if (this.isCapture()) {
+						CaptureBinding capture = (CaptureBinding) this;
+						if (capture.lowerBound != null) lowerBound = capture.lowerBound;
+					}
+			}
+			WildcardBinding otherWildcard = (WildcardBinding) otherType;
+			if (otherWildcard.otherBounds != null) return false; // not a true wildcard (intersection type)
+			switch(otherWildcard.boundKind) {
+				case Wildcard.EXTENDS:
+					if (otherWildcard.bound == this) return true; // ? extends T  <=  ? extends ? extends T
+					return upperBound != null && upperBound.isCompatibleWith(otherWildcard.bound);
+	
+				case Wildcard.SUPER :
+					if (otherWildcard.bound == this) return true; // ? super T  <=  ? super ? super T
+					return lowerBound != null && otherWildcard.bound.isCompatibleWith(lowerBound);
+	
+				case Wildcard.UNBOUND :
+				default:
+					return true;
+			}
+		// allow List<?> to match List<? extends Object> (and reciprocally)
+		case Binding.PARAMETERIZED_TYPE :
+			if (!this.isParameterizedType()) return false;
+			ParameterizedTypeBinding paramType = (ParameterizedTypeBinding) this;
+            ParameterizedTypeBinding otherParamType = (ParameterizedTypeBinding) otherType;
+            if (paramType.type != otherParamType.type) 
+                return false;
+            if (!paramType.isStatic()) { // static member types do not compare their enclosing
+            	ReferenceBinding enclosing = enclosingType();
+            	if (enclosing != null) {
+            		ReferenceBinding otherEnclosing = otherParamType.enclosingType();
+            		if (otherEnclosing == null) return false;
+            		if ((otherEnclosing.tagBits & HasDirectWildcard) == 0) {
+						if (enclosing != otherEnclosing) return false;
+            		} else {
+            			if (!enclosing.isEquivalentTo(otherParamType.enclosingType())) return false;
+            		}
+            	}
+            }
+            int length = paramType.arguments == null ? 0 : paramType.arguments.length;
+            TypeBinding[] otherArguments = otherParamType.arguments;
+            int otherLength = otherArguments == null ? 0 : otherArguments.length;
+            if (otherLength != length) 
+                return false;
+            nextArgument: for (int i = 0; i < length; i++) {
+            	TypeBinding argument = paramType.arguments[i];
+            	TypeBinding otherArgument = otherArguments[i];
+            	if (argument == otherArgument) 
+            		continue nextArgument;
+            	int kind = argument.kind();
+            	if (otherArgument.kind() != kind)
+            		return false;
+           		switch(kind) {
+        			case Binding.PARAMETERIZED_TYPE :
+        				if (argument.isTypeArgumentContainedBy(otherArgument)) // recurse
+	        				continue nextArgument;
+        				break;
+        			case Binding.WILDCARD_TYPE :
+        				WildcardBinding wildcard = (WildcardBinding) argument;
+        				otherWildcard = (WildcardBinding) otherArgument;
+        				switch (wildcard.boundKind) {
+        					case Wildcard.EXTENDS :
+        						// match "? extends <upperBound>" with "?"
+        						if (otherWildcard.boundKind == Wildcard.UNBOUND && wildcard.bound == wildcard.typeVariable().upperBound())
+        							continue nextArgument; 
+        						break;
+        					case Wildcard.SUPER :
+        						break;
+        					case Wildcard.UNBOUND :
+        						// match "?" with "? extends <upperBound>"
+        						if (otherWildcard.boundKind == Wildcard.EXTENDS && otherWildcard.bound == otherWildcard.typeVariable().upperBound())
+        							continue nextArgument; 
+        						break;
+        				}
+        				break;
+           		}
+           		return false;
+            }
+            return true;
 	}
 	return false;
 }
 
 /**
+ * Returns false if two given types could not intersect as argument types:
+ * List<Throwable> & List<Runnable> --> false
+ * List<? extends Throwable> & List<? extends Runnable> --> true
+ * List<? extends String> & List<? extends Runnable> --> false
+ */
+public boolean isTypeArgumentIntersecting(TypeBinding otherArgument) {
+	if (this == otherArgument)
+		return true;
+	switch (kind()) {
+		
+		// TYPE_PARAM & ANY TYPE
+		case Binding.TYPE_PARAMETER :   
+			return true;
+			
+		case Binding.WILDCARD_TYPE :
+			switch (otherArgument.kind()) {
+				
+				// WILDCARD & TYPE_PARAM
+				case Binding.TYPE_PARAMETER :
+					return true;
+					
+				// WILDCARD & WILDCARD
+				case Binding.WILDCARD_TYPE :
+					TypeBinding lowerBound1 = null;
+					TypeBinding upperBound1 = null;
+					WildcardBinding wildcard = (WildcardBinding) this;
+					switch(wildcard.boundKind) {
+						case Wildcard.EXTENDS :
+							upperBound1 = wildcard.bound;
+							break;
+						case Wildcard. SUPER :
+							lowerBound1 = wildcard.bound;
+							break;
+						case Wildcard.UNBOUND :
+					}
+				
+					TypeBinding lowerBound2 = null;
+					TypeBinding upperBound2 = null;
+					WildcardBinding otherWildcard = (WildcardBinding) otherArgument;
+					switch(otherWildcard.boundKind) {
+						case Wildcard.EXTENDS :
+							upperBound2 = otherWildcard.bound;
+							break;
+						case Wildcard. SUPER :
+							lowerBound2 = otherWildcard.bound;
+							break;
+						case Wildcard.UNBOUND :
+					}
+					if (lowerBound1 != null) {
+						if (lowerBound2 != null) {
+							return true; // Object could always be a candidate
+							
+						} else if (upperBound2 != null) {
+							return lowerBound1.isCompatibleWith(upperBound2);
+						} else {
+							return true;
+						}
+					} else if (upperBound1 != null) {
+						if (upperBound1.isTypeVariable()) return true;
+						if (lowerBound2 != null) {
+							return lowerBound2.isCompatibleWith(upperBound1);
+				
+						} else if (upperBound2 != null) {
+							if (upperBound1.isInterface()) {
+								if (upperBound2.isInterface())
+									return true;
+								if (upperBound2.isArrayType() || ((upperBound2 instanceof ReferenceBinding) && ((ReferenceBinding)upperBound2).isFinal())) {
+									return upperBound2.isCompatibleWith(upperBound1);
+								}
+								return true;
+							} else {
+								if (upperBound2.isInterface()) {
+									if (upperBound1.isArrayType() || ((upperBound1 instanceof ReferenceBinding) && ((ReferenceBinding)upperBound1).isFinal())) {
+										return upperBound1.isCompatibleWith(upperBound2);
+									}
+								} else {
+									return upperBound1.isCompatibleWith(upperBound2);									
+								}
+							}
+							return true;
+						} else {
+							return true;
+						}
+					} else {
+						return true;
+					}
+					
+				// WILDCARD & OTHER TYPE
+				default :
+					 wildcard = (WildcardBinding) this;
+					switch(wildcard.boundKind) {
+						case Wildcard.EXTENDS :
+							return otherArgument.isCompatibleWith(wildcard.bound);
+						case Wildcard. SUPER :
+							return wildcard.bound.isCompatibleWith(otherArgument);
+						case Wildcard.UNBOUND :
+						default:
+							return true;
+					}
+			}
+			
+		default:
+			switch (otherArgument.kind()) {
+
+				// OTHER TYPE & TYPE_PARAM
+				case Binding.TYPE_PARAMETER :
+					return true;
+
+				// OTHER TYPE & WILDCARD
+				case Binding.WILDCARD_TYPE :
+					WildcardBinding otherWildcard = (WildcardBinding) otherArgument;
+					switch(otherWildcard.boundKind) {
+						case Wildcard.EXTENDS :
+							return this.isCompatibleWith(otherWildcard.bound);
+						case Wildcard. SUPER :
+							return otherWildcard.bound.isCompatibleWith(this);
+						case Wildcard.UNBOUND :
+						default:
+							return true;
+					}					
+
+				// OTHER TYPE & OTHER TYPE
+				default :
+					return false;
+			}
+	}
+}
+
+/**
  * Returns true if the type was declared as a type variable
  */
 public boolean isTypeVariable() {
     return false;
 }
+
 /**
  * Returns true if wildcard type of the form '?' (no bound)
  */
@@ -359,6 +576,13 @@
 }
 
 /**
+ * Returns true if the type is a subclass of java.lang.Error or java.lang.RuntimeException
+ */
+public boolean isUncheckedException(boolean includeSupertype) {
+	return false;
+}
+
+/**
  * Returns true if the type is a wildcard
  */
 public boolean isWildcard() {
@@ -379,15 +603,18 @@
 	if (!(currentType instanceof ReferenceBinding))
 		return false;
 	
-	ReferenceBinding compatible = ((ReferenceBinding)currentType).findSuperTypeErasingTo((ReferenceBinding)targetType.erasure());
+	ReferenceBinding compatible = ((ReferenceBinding)currentType).findSuperTypeWithSameErasure(targetType);
 	if (compatible == null) 
 		return false;
-	if (!compatible.isPartOfRawType()) return false;
-	do {
-		if (compatible.isRawType() && (targetType.isBoundParameterizedType() || targetType.isGenericType())) {
+
+	while (compatible.isRawType()) {
+		if (targetType.isBoundParameterizedType() || targetType.isGenericType()) {
 			return true;
 		}
-	} while ((compatible = compatible.enclosingType()) != null && (targetType = targetType.enclosingType()) != null);
+		if (compatible.isStatic()) break;
+		if ((compatible = compatible.enclosingType()) == null) break;
+		if ((targetType = targetType.enclosingType()) == null) break;
+	}
 	return false;
 }
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java
index a154f81..c40ed9e 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java
@@ -144,6 +144,7 @@
 	// Synthetics
 	char[] INIT = "<init>".toCharArray(); //$NON-NLS-1$
 	char[] CLINIT = "<clinit>".toCharArray(); //$NON-NLS-1$
+	char[] SYNTHETIC_SWITCH_ENUM_TABLE = "$SWITCH_TABLE$".toCharArray(); //$NON-NLS-1$
 	char[] SYNTHETIC_ENUM_VALUES = "ENUM$VALUES".toCharArray(); //$NON-NLS-1$
 	char[] SYNTHETIC_ASSERT_DISABLED = "$assertionsDisabled".toCharArray(); //$NON-NLS-1$
 	char[] SYNTHETIC_CLASS = "class$".toCharArray(); //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java
index 821214e..7d43e8e 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java
@@ -40,7 +40,7 @@
 	final int T_JavaLangThrowable = 21;
 	final int T_JavaLangNoClassDefError = 22;
 	final int T_JavaLangClassNotFoundException = 23;
-	final int T_JavaIoPrintStream = 24;
+	final int T_JavaLangRuntimeException = 24;
 	final int T_JavaLangException = 25;
 
 	// wrapper types
@@ -77,7 +77,9 @@
 	final int T_JavaLangAnnotationTarget = 50;
 	final int T_JavaLangAnnotationRetentionPolicy = 51;
 	final int T_JavaLangAnnotationElementType = 52;
-	
+
+	final int T_JavaIoPrintStream = 53;
+
 	final int NoId = Integer.MAX_VALUE;
 
 	public static final int IMPLICIT_CONVERSION_MASK = 0xFF;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java
index ea3b3dc..2e94844 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java
@@ -55,50 +55,103 @@
 		boolean hasSubstitution = substitution != null;
 		if (!(argumentType instanceof ReferenceBinding || argumentType.isArrayType()))
 			return TypeConstants.MISMATCH;	
-		
-	    if (argumentType.isWildcard()) {
-	        WildcardBinding wildcard = (WildcardBinding) argumentType;
-	        switch (wildcard.boundKind) {
-	        	case Wildcard.SUPER :
-//		            if (boundCheck(substitution, wildcard.bound) != TypeConstants.OK) return TypeConstants.MISMATCH;
-//		            break;
-		            return boundCheck(substitution, wildcard.bound); // only check the lower bound
-				case Wildcard.UNBOUND :
-					if (this == wildcard.typeVariable()) 
+		// special case for re-entrant source types (selection, code assist, etc)...
+		// can request additional types during hierarchy walk that are found as source types that also 'need' to connect their hierarchy
+		if (this.superclass == null)
+			return TypeConstants.OK;
+
+		if (argumentType.isWildcard() && !argumentType.isIntersectionType()) {
+			WildcardBinding wildcard = (WildcardBinding) argumentType;
+			switch(wildcard.boundKind) {
+				case Wildcard.EXTENDS :
+					TypeBinding wildcardBound = wildcard.bound;
+					if (wildcardBound == this) 
 						return TypeConstants.OK;
-					break;	        		
-	        }
-	    }
+					ReferenceBinding superclassBound = hasSubstitution ? (ReferenceBinding)Scope.substitute(substitution, this.superclass) : this.superclass;
+					boolean isArrayBound = wildcardBound.isArrayType();
+					if (!wildcardBound.isInterface()) {
+						if (superclassBound.id != T_JavaLangObject) {
+							if (isArrayBound) {
+								if (!wildcardBound.isCompatibleWith(superclassBound))
+									return TypeConstants.MISMATCH;
+							} else {
+								ReferenceBinding match = ((ReferenceBinding)wildcardBound).findSuperTypeWithSameErasure(superclassBound);
+								if (match != null) {
+									if (!match.isIntersectingWith(superclassBound)) {
+										return TypeConstants.MISMATCH;
+									}
+								} else {
+									return TypeConstants.MISMATCH;
+								}
+							}
+						}
+					}
+					ReferenceBinding[] superInterfaceBounds = hasSubstitution ? Scope.substitute(substitution, this.superInterfaces) : this.superInterfaces;
+					int length = superInterfaceBounds.length;
+					boolean mustImplement = isArrayBound || ((ReferenceBinding)wildcardBound).isFinal();
+					for (int i = 0; i < length; i++) {
+						TypeBinding superInterfaceBound = superInterfaceBounds[i];
+						if (isArrayBound) {
+							if (!wildcardBound.isCompatibleWith(superInterfaceBound))
+									return TypeConstants.MISMATCH;
+						} else {
+							ReferenceBinding match = ((ReferenceBinding)wildcardBound).findSuperTypeWithSameErasure(superInterfaceBound);
+							if (match != null) {
+								if (!match.isIntersectingWith(superInterfaceBound)) {
+									return TypeConstants.MISMATCH;
+								}
+							} else if (mustImplement) {
+									return TypeConstants.MISMATCH; // cannot be extended further to satisfy missing bounds
+							}
+						}
+
+					}
+					break;
+					
+				case Wildcard.SUPER :
+					return boundCheck(substitution, wildcard.bound);
+					
+				case Wildcard.UNBOUND :
+					break;
+			}
+			return TypeConstants.OK;
+		}
 		boolean unchecked = false;
 		if (this.superclass.id != T_JavaLangObject) {
-			TypeBinding substitutedSuperType = hasSubstitution ? Scope.substitute(substitution, this.superclass) : this.superclass;
-			if (!argumentType.isCompatibleWith(substitutedSuperType)) {
-			    return TypeConstants.MISMATCH;
-			}
-			if (argumentType instanceof ReferenceBinding) {
-				ReferenceBinding referenceArgument = (ReferenceBinding) argumentType;
-				TypeBinding match = referenceArgument.findSuperTypeErasingTo((ReferenceBinding)substitutedSuperType.erasure());
-				if (match != null){
-					// Enum#RAW is not a substitute for <E extends Enum<E>> (86838)
-					if (match.isRawType() && (substitutedSuperType.isGenericType()||substitutedSuperType.isBoundParameterizedType()))
-						unchecked = true;
+			TypeBinding superType = this.superclass;
+			if (superType != argumentType) { // check identity before substituting (104649)
+				TypeBinding substitutedSuperType = hasSubstitution ? Scope.substitute(substitution, superType) : superType;
+				if (!argumentType.isCompatibleWith(substitutedSuperType)) {
+				    return TypeConstants.MISMATCH;
 				}
+				if (argumentType instanceof ReferenceBinding) {
+					ReferenceBinding referenceArgument = (ReferenceBinding) argumentType;
+					TypeBinding match = referenceArgument.findSuperTypeWithSameErasure(substitutedSuperType);
+					if (match != null){
+						// Enum#RAW is not a substitute for <E extends Enum<E>> (86838)
+						if (match.isRawType() && (substitutedSuperType.isGenericType()||substitutedSuperType.isBoundParameterizedType()))
+							unchecked = true;
+					}
+				} 
 			}
 		}
 	    for (int i = 0, length = this.superInterfaces.length; i < length; i++) {
-			TypeBinding substitutedSuperType = hasSubstitution ? Scope.substitute(substitution, this.superInterfaces[i]) : this.superInterfaces[i];
-			if (!argumentType.isCompatibleWith(substitutedSuperType)) {
-			    return TypeConstants.MISMATCH;
-			}
-			if (argumentType instanceof ReferenceBinding) {
-				ReferenceBinding referenceArgument = (ReferenceBinding) argumentType;
-				TypeBinding match = referenceArgument.findSuperTypeErasingTo((ReferenceBinding)substitutedSuperType.erasure());
-				if (match != null){
-					// Enum#RAW is not a substitute for <E extends Enum<E>> (86838)
-					if (match.isRawType() && (substitutedSuperType.isGenericType()||substitutedSuperType.isBoundParameterizedType()))
-						unchecked = true;
+	    	TypeBinding superType = this.superInterfaces[i];
+	    	if (superType != argumentType) { // check identity before substituting (104649)
+				TypeBinding substitutedSuperType = hasSubstitution ? Scope.substitute(substitution, superType) : superType;
+				if (!argumentType.isCompatibleWith(substitutedSuperType)) {
+				    return TypeConstants.MISMATCH;
 				}
-			}
+				if (argumentType instanceof ReferenceBinding) {
+					ReferenceBinding referenceArgument = (ReferenceBinding) argumentType;
+					TypeBinding match = referenceArgument.findSuperTypeWithSameErasure(substitutedSuperType);
+					if (match != null){
+						// Enum#RAW is not a substitute for <E extends Enum<E>> (86838)
+						if (match.isRawType() && (substitutedSuperType.isGenericType()||substitutedSuperType.isBoundParameterizedType()))
+							unchecked = true;
+					}
+				}
+	    	}
 	    }
 	    return unchecked ? TypeConstants.UNCHECKED : TypeConstants.OK;
 	}
@@ -173,17 +226,34 @@
 	}
 	/*
 	 * declaringUniqueKey : genericTypeSignature
-	 * p.X<T> { ... } --> Lp/X<TT;>;:TT;
+	 * p.X<T> { ... } --> Lp/X;:TT;
+	 * p.X { <T> void foo() {...} } --> Lp/X;.foo()V:TT;
 	 */
-	public char[] computeUniqueKey(boolean withAccessFlags) {
-		char[] declaringKey = this.declaringElement.computeUniqueKey(false/*without access flags*/);
-		int declaringLength = declaringKey.length;
-		char[] sig = genericTypeSignature();
-		int sigLength = sig.length;
-		char[] uniqueKey = new char[declaringLength + 1 + sigLength];
-		System.arraycopy(declaringKey, 0, uniqueKey, 0, declaringLength);
-		uniqueKey[declaringLength] = ':';
-		System.arraycopy(sig, 0, uniqueKey, declaringLength+1, sigLength);
+	public char[] computeUniqueKey(boolean isLeaf) {
+		StringBuffer buffer = new StringBuffer();
+		Binding declaring = this.declaringElement;
+		if (!isLeaf && declaring.kind() == Binding.METHOD) { // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=97902
+			MethodBinding methodBinding = (MethodBinding) declaring;
+			ReferenceBinding declaringClass = methodBinding.declaringClass;
+			buffer.append(declaringClass.computeUniqueKey(false/*not a leaf*/));
+			buffer.append(':');
+			MethodBinding[] methods = declaringClass.methods();
+			if (methods != null)
+				for (int i = 0, length = methods.length; i < length; i++) {
+					MethodBinding binding = methods[i];
+					if (binding == methodBinding) {
+						buffer.append(i);
+						break;
+					}
+				}
+		} else {
+			buffer.append(declaring.computeUniqueKey(false/*not a leaf*/));
+			buffer.append(':');			
+		}
+		buffer.append(genericTypeSignature());
+		int length = buffer.length();
+		char[] uniqueKey = new char[length];
+		buffer.getChars(0, length, uniqueKey, 0);
 		return uniqueKey;
 	}
 	/**
@@ -199,93 +269,6 @@
 	    return this.superclass; // java/lang/Object
 	}	
 
-/**
- * Find supertype which erases to a given well-known type, or null if not found
- * (using id avoids triggering the load of well-known type: 73740)
- * NOTE: only works for erasures of well-known types, as random other types may share
- * same id though being distincts.
- * Override super-method since erasure() is answering firstBound (first supertype) already
- */
-public ReferenceBinding findSuperTypeErasingTo(int erasureId, boolean erasureIsClass) {
-
-//    if (this.id == erasureId) return this; // no ID for type variable
-    ReferenceBinding currentType = this;
-    // iterate superclass to avoid recording interfaces if searched supertype is class
-    if (erasureIsClass) {
-		while ((currentType = currentType.superclass()) != null) { 
-			if (currentType.id == erasureId || currentType.erasure().id == erasureId) return currentType;
-		}    
-		return null;
-    }
-	ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[5][];
-	int lastPosition = -1;
-	do {
-		ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
-		if (itsInterfaces != NoSuperInterfaces) {
-			if (++lastPosition == interfacesToVisit.length)
-				System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition);
-			interfacesToVisit[lastPosition] = itsInterfaces;
-		}
-	} while ((currentType = currentType.superclass()) != null);
-			
-	for (int i = 0; i <= lastPosition; i++) {
-		ReferenceBinding[] interfaces = interfacesToVisit[i];
-		for (int j = 0, length = interfaces.length; j < length; j++) {
-			if ((currentType = interfaces[j]).id == erasureId || currentType.erasure().id == erasureId)
-				return currentType;
-
-			ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
-			if (itsInterfaces != NoSuperInterfaces) {
-				if (++lastPosition == interfacesToVisit.length)
-					System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition);
-				interfacesToVisit[lastPosition] = itsInterfaces;
-			}
-		}
-	}
-	return null;
-}
-/**
- * Find supertype which erases to a given type, or null if not found
- * Override super-method since erasure() is answering firstBound (first supertype) already
- */
-public ReferenceBinding findSuperTypeErasingTo(ReferenceBinding erasure) {
-
-    if (this == erasure) return this;
-    ReferenceBinding currentType = this;
-    if (!erasure.isInterface()) {
-		while ((currentType = currentType.superclass()) != null) {
-			if (currentType == erasure || currentType.erasure() == erasure) return currentType;
-		}
-		return null;
-    }
-	ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[5][];
-	int lastPosition = -1;
-	do {
-		ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
-		if (itsInterfaces != NoSuperInterfaces) {
-			if (++lastPosition == interfacesToVisit.length)
-				System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition);
-			interfacesToVisit[lastPosition] = itsInterfaces;
-		}
-	} while ((currentType = currentType.superclass()) != null);
-			
-	for (int i = 0; i <= lastPosition; i++) {
-		ReferenceBinding[] interfaces = interfacesToVisit[i];
-		for (int j = 0, length = interfaces.length; j < length; j++) {
-			if ((currentType = interfaces[j]) == erasure || currentType.erasure() == erasure)
-				return currentType;
-
-			ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
-			if (itsInterfaces != NoSuperInterfaces) {
-				if (++lastPosition == interfacesToVisit.length)
-					System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition);
-				interfacesToVisit[lastPosition] = itsInterfaces;
-			}
-		}
-	}
-	return null;
-}
-	
 	/**
 	 * T::Ljava/util/Map;:Ljava/io/Serializable;
 	 * T:LY<TT;>
@@ -326,13 +309,57 @@
 		}
 		return false;
 	}
+	
+	/**
+	 * Returns true if the 2 variables are playing exact same role: they have
+	 * the same bounds, providing one is substituted with the other: <T1 extends
+	 * List<T1>> is interchangeable with <T2 extends List<T2>>.
+	 */
+	public boolean isInterchangeableWith(final LookupEnvironment environment, final TypeVariableBinding otherVariable) {
+		if (this == otherVariable)
+			return true;
+		int length = this.superInterfaces.length;
+		if (length != otherVariable.superInterfaces.length)
+			return false;
+
+		identical: {
+			if (this.superclass != otherVariable.superclass) {
+				if (this.superclass.erasure() != otherVariable.superclass.erasure())
+					return false; // no way it can match after substitution
+				break identical;
+			}
+			for (int i = 0; i < length; i++) {
+				if (this.superInterfaces[i] != otherVariable.superInterfaces[i]) {
+					if (this.superInterfaces[i].erasure() != otherVariable.superInterfaces[i].erasure())
+						return false; // no way it can match after substitution
+					break identical;
+				}
+			}
+			return true;
+		}
+		// need substitutions
+		Substitution subst = new Substitution() {
+			public LookupEnvironment environment() { return environment; }
+			public boolean isRawSubstitution() { return false; }
+			public TypeBinding substitute(TypeVariableBinding typeVariable) {
+				return typeVariable == otherVariable ? TypeVariableBinding.this : typeVariable;
+			}
+		};
+		if (this.superclass != Scope.substitute(subst, otherVariable.superclass))
+			return false;
+		for (int i = 0; i < length; i++)
+			if (this.superInterfaces[i] != Scope.substitute(subst, otherVariable.superInterfaces[i]))
+				return false;
+		return true;
+	}
+	
 	/**
 	 * Returns true if the type was declared as a type variable
 	 */
 	public boolean isTypeVariable() {
 	    return true;
 	}
-	
+
 	/** 
 	 * Returns the original type variable for a given variable.
 	 * Only different from receiver for type variables of generic methods of parameterized types
@@ -430,4 +457,13 @@
 		buffer.append('>');
 		return buffer.toString();
 	}	
+	/**
+	 * Upper bound doesn't perform erasure
+	 */
+	public TypeBinding upperBound() {
+	    if (this.firstBound != null) {
+			return this.firstBound;
+	    }
+	    return this.superclass; // java/lang/Object
+	}		
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/UnresolvedReferenceBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/UnresolvedReferenceBinding.java
index bef72ed..0cd1f6e 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/UnresolvedReferenceBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/UnresolvedReferenceBinding.java
@@ -49,17 +49,7 @@
 		}
 	}
 	if (convertGenericToRawType) {
-		boolean rawEnclosing = false;
-		ReferenceBinding targetEnclosingType = targetType.enclosingType();
-		if (targetEnclosingType != null && targetEnclosingType.isGenericType()) { // convert to raw type since wasn't parameterized
-			rawEnclosing = true;
-			targetEnclosingType = environment.createRawType(targetEnclosingType, targetEnclosingType.enclosingType());
-		}
-		if (targetType.isGenericType()) { // raw reference to generic ?
-		    return environment.createRawType(targetType, targetEnclosingType);
-		} else if (rawEnclosing) {
-			return environment.createParameterizedType(targetType, null, targetEnclosingType);
-		}
+		targetType = (ReferenceBinding) environment.convertToRawType(targetType);
 	}
 	return targetType;
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/WildcardBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/WildcardBinding.java
index eeb487c..3e60bd7 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/WildcardBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/WildcardBinding.java
@@ -80,6 +80,7 @@
 		// cannot be asked per construction
 		return false;
 	}
+	
 	/**
 	 * Collect the substitutes into a map for certain type variables inside the receiver type
 	 * e.g.   Collection<T>.collectSubstitutes(Collection<List<X>>, Map), will populate Map with: T --> List<X>
@@ -262,15 +263,25 @@
 		}
 	}
 	
-	public char[] computeUniqueKey(boolean withAccessFlags) {
+	/*
+	 * genericTypeKey *|+|- [boundKey]
+	 * p.X<T> { X<?> ... } --> Lp/X<TT;>;*
+	 */
+	public char[] computeUniqueKey(boolean isLeaf) {
+		char[] genericTypeKey = this.genericType.computeUniqueKey(false/*not a leaf*/);
+		char[] wildCardKey;
         switch (this.boundKind) {
             case Wildcard.UNBOUND : 
-                return WILDCARD_STAR;
+                wildCardKey = WILDCARD_STAR;
+                break;
             case Wildcard.EXTENDS :
-                return CharOperation.concat(WILDCARD_PLUS, this.bound.computeUniqueKey(false/*without access flags*/));
+                wildCardKey = CharOperation.concat(WILDCARD_PLUS, this.bound.computeUniqueKey(false/*not a leaf*/));
+                break;
 			default: // SUPER
-			    return CharOperation.concat(WILDCARD_MINUS, this.bound.computeUniqueKey(false/*without access flags*/));
+			    wildCardKey = CharOperation.concat(WILDCARD_MINUS, this.bound.computeUniqueKey(false/*not a leaf*/));
+				break;
         }
+        return CharOperation.concat(genericTypeKey, wildCardKey);
        }
 	
 	/**
@@ -320,8 +331,7 @@
 			this.fPackage = someGenericType.getPackage();
 		}
 		if (someBound != null) {
-		    if (someBound.isTypeVariable())
-		        this.tagBits |= HasTypeVariable;
+			this.tagBits |= someBound.tagBits & HasTypeVariable;
 		}
 	}
 
@@ -338,7 +348,14 @@
         }
         return false;
     }
-
+    
+    /**
+     * Returns true if the current type denotes an intersection type: Number & Comparable<?>
+     */
+    public boolean isIntersectionType() {
+    	return this.otherBounds != null;
+    }
+    
     /**
 	 * Returns true if the type is a wildcard
 	 */
@@ -467,6 +484,30 @@
 
 		return this.superclass;
     }
+    
+    public ReferenceBinding superclass2() {
+		if (this.superclass == null) {
+			TypeBinding superType = (this.boundKind == Wildcard.EXTENDS && !this.bound.isInterface()) 
+				? this.bound
+				: null;
+			this.superclass = superType instanceof ReferenceBinding && !superType.isInterface()
+				? (ReferenceBinding) superType
+				: environment.getType(JAVA_LANG_OBJECT);
+			
+//			TypeBinding superType = null;
+//			if (this.boundKind == Wildcard.EXTENDS && !this.bound.isInterface()) {
+//				superType = this.bound;
+//			} else {
+//				TypeVariableBinding variable = this.typeVariable();
+//				if (variable != null) superType = variable.firstBound;
+//			}
+//			this.superclass = superType instanceof ReferenceBinding && !superType.isInterface()
+//				? (ReferenceBinding) superType
+//				: environment.getType(JAVA_LANG_OBJECT);
+		}
+
+		return this.superclass;
+    }
     /* (non-Javadoc)
      * @see org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding#superInterfaces()
      */
@@ -498,13 +539,38 @@
         return this.superInterfaces;
     }
 
+    public ReferenceBinding[] superInterfaces2() {
+        if (this.superInterfaces == null) {
+        	if (this.boundKind == Wildcard.EXTENDS) {
+        		if (this.bound.isInterface()) {
+        			if (this.otherBounds != null) {
+						// augment super interfaces with the wildcard otherBounds (interfaces per construction)
+						int otherLength = this.otherBounds.length;
+						System.arraycopy(this.otherBounds, 0, this.superInterfaces = new ReferenceBinding[otherLength+1], 1, otherLength);
+						this.superInterfaces[0] = (ReferenceBinding) this.bound;
+        			} else {
+        				this.superInterfaces = new ReferenceBinding[] { (ReferenceBinding) this.bound };
+        			}
+        		} else if (this.otherBounds != null) {
+					int otherLength = this.otherBounds.length;
+        			System.arraycopy(this.otherBounds, 0, this.superInterfaces = new ReferenceBinding[otherLength], 0, otherLength);
+        		} else {
+        			this.superInterfaces = NoSuperInterfaces;
+        		}
+        	} else { 
+        		this.superInterfaces = NoSuperInterfaces;
+        	}
+        }
+        return this.superInterfaces;
+    }
+
 	public void swapUnresolved(UnresolvedReferenceBinding unresolvedType, ReferenceBinding resolvedType, LookupEnvironment env) {
 		boolean affected = false;
 		if (this.genericType == unresolvedType) {
 			this.genericType = resolvedType; // no raw conversion
 			affected = true;
 		} else if (this.bound == unresolvedType) {
-			this.bound = resolvedType.isGenericType() ? env.createRawType(resolvedType, resolvedType.enclosingType()) : resolvedType;
+			this.bound = env.convertToRawType(resolvedType);
 			affected = true;
 		}
 		if (affected) 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/messages.properties b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/messages.properties
similarity index 100%
rename from org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/messages.properties
rename to org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/messages.properties
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/AbstractCommentParser.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/AbstractCommentParser.java
index e1a39ff..b411ffa 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/AbstractCommentParser.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/AbstractCommentParser.java
@@ -853,7 +853,7 @@
 		// Report problem
 		this.currentTokenType = -1;
 		end = hasMultiLines ? this.lineEnd: this.scanner.getCurrentTokenEndPosition();
-		while (readToken() != TerminalTokens.TokenNameWHITESPACE) {
+		while ((token=readToken()) != TerminalTokens.TokenNameWHITESPACE && token != TerminalTokens.TokenNameEOF) {
 			this.currentTokenType = -1;
 			end = hasMultiLines ? this.lineEnd: this.scanner.getCurrentTokenEndPosition();
 		}
@@ -883,7 +883,7 @@
 		// Scan tokens
 		int primitiveToken = -1;
 		nextToken : for (int iToken = 0; ; iToken++) {
-			int token = readToken();
+			int token = readTokenSafely();
 			switch (token) {
 				case TerminalTokens.TokenNameIdentifier :
 					if (((iToken % 2) > 0)) { // identifiers must be odd tokens
@@ -957,9 +957,10 @@
 			// Get reference tokens
 			nextToken : while (this.index < this.scanner.eofPosition) {
 				previousPosition = this.index;
-				int token = readToken();
+				int token = readTokenSafely();
 				switch (token) {
-					case TerminalTokens.TokenNameStringLiteral : // @see "string"
+				case TerminalTokens.TokenNameStringLiteral : // @see "string"
+						if (typeRef != null) break nextToken;
 						consumeToken();
 						int start = this.scanner.getCurrentTokenStartPosition();
 						if (this.tagValue == TAG_VALUE_VALUE) {
@@ -981,6 +982,7 @@
 						if (this.reportProblems) this.sourceParser.problemReporter().javadocUnexpectedText(this.scanner.currentPosition, this.lineEnd);
 						return false;
 					case TerminalTokens.TokenNameLESS : // @see "<a href="URL#Value">label</a>
+						if (typeRef != null) break nextToken;
 						consumeToken();
 						start = this.scanner.getCurrentTokenStartPosition();
 						if (parseHref()) {
@@ -1014,6 +1016,11 @@
 							}
 							return false;
 						}
+						char[] currentError = this.scanner.getCurrentIdentifierSource();
+						if (currentError.length>0 && currentError[0] == '"') {
+							if (this.reportProblems) this.sourceParser.problemReporter().javadocInvalidReference(this.scanner.getCurrentTokenStartPosition(), getTokenEndPosition());
+							return false;
+						}
 						break nextToken;
 					case TerminalTokens.TokenNameIdentifier :
 						if (typeRef == null) {
@@ -1270,6 +1277,21 @@
 		consumeToken();
 		return token;
 	}
+
+	/*
+	 * Read token without throwing any InvalidInputException exception.
+	 * Returns TerminalTokens.TokenNameERROR instead.
+	 */
+	protected int readTokenSafely() {
+		int token = TerminalTokens.TokenNameERROR;
+		try {
+			token = readToken();
+		}
+		catch (InvalidInputException iie) {
+			// token is already set to error
+		}
+		return token;
+	}
 	
 	/*
 	 * Refresh start position and length of an inline tag.
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/JavadocParser.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/JavadocParser.java
index e6e3388..18cf1c8 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/JavadocParser.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/JavadocParser.java
@@ -318,6 +318,54 @@
 			case TerminalTokens.TokenNameIdentifier:
 			case TerminalTokens.TokenNamereturn:
 			case TerminalTokens.TokenNamethrows:
+			case TerminalTokens.TokenNameabstract:
+			case TerminalTokens.TokenNameassert:
+			case TerminalTokens.TokenNameboolean:
+			case TerminalTokens.TokenNamebreak:
+			case TerminalTokens.TokenNamebyte:
+			case TerminalTokens.TokenNamecase:
+			case TerminalTokens.TokenNamecatch:
+			case TerminalTokens.TokenNamechar:
+			case TerminalTokens.TokenNameclass:
+			case TerminalTokens.TokenNamecontinue:
+			case TerminalTokens.TokenNamedefault:
+			case TerminalTokens.TokenNamedo:
+			case TerminalTokens.TokenNamedouble:
+			case TerminalTokens.TokenNameelse:
+			case TerminalTokens.TokenNameextends:
+			case TerminalTokens.TokenNamefalse:
+			case TerminalTokens.TokenNamefinal:
+			case TerminalTokens.TokenNamefinally:
+			case TerminalTokens.TokenNamefloat:
+			case TerminalTokens.TokenNamefor:
+			case TerminalTokens.TokenNameif:
+			case TerminalTokens.TokenNameimplements:
+			case TerminalTokens.TokenNameimport:
+			case TerminalTokens.TokenNameinstanceof:
+			case TerminalTokens.TokenNameint:
+			case TerminalTokens.TokenNameinterface:
+			case TerminalTokens.TokenNamelong:
+			case TerminalTokens.TokenNamenative:
+			case TerminalTokens.TokenNamenew:
+			case TerminalTokens.TokenNamenull:
+			case TerminalTokens.TokenNamepackage:
+			case TerminalTokens.TokenNameprivate:
+			case TerminalTokens.TokenNameprotected:
+			case TerminalTokens.TokenNamepublic:
+			case TerminalTokens.TokenNameshort:
+			case TerminalTokens.TokenNamestatic:
+			case TerminalTokens.TokenNamestrictfp:
+			case TerminalTokens.TokenNamesuper:
+			case TerminalTokens.TokenNameswitch:
+			case TerminalTokens.TokenNamesynchronized:
+			case TerminalTokens.TokenNamethis:
+			case TerminalTokens.TokenNamethrow:
+			case TerminalTokens.TokenNametransient:
+			case TerminalTokens.TokenNametrue:
+			case TerminalTokens.TokenNametry:
+			case TerminalTokens.TokenNamevoid:
+			case TerminalTokens.TokenNamevolatile:
+			case TerminalTokens.TokenNamewhile:
 				validTag= true;
 		}
 		tagNameToken: while (token != TerminalTokens.TokenNameEOF && this.index < this.scanner.eofPosition) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java
index 626e32a..770b5ee 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java
@@ -703,6 +703,11 @@
 	// javadoc support
 	this.javadocParser = new JavadocParser(this);	
 }
+protected void annotationRecoveryCheckPoint(int start, int end) {
+	if(this.lastCheckPoint > start && this.lastCheckPoint < end) {
+		this.lastCheckPoint = end + 1;
+	}
+}
 public void arrayInitializer(int length) {
 	//length is the size of the array Initializer
 	//expressionPtr points on the last elt of the arrayInitializer, 
@@ -1037,7 +1042,11 @@
 	}
 }
 protected void consumeAnnotationName() {
-	// nothing to do
+	if(this.currentElement != null) {
+		int start = this.intStack[this.intPtr];
+		int end = (int) (this.identifierPositionStack[this.identifierPtr] & 0x00000000FFFFFFFFL);
+		annotationRecoveryCheckPoint(start, end);
+	}
 }
 protected void consumeAnnotationTypeDeclaration() {
 	int length;
@@ -1070,6 +1079,8 @@
 	if (this.currentElement != null) {
 		this.restartRecovery = true; // used to avoid branching back into the regular automaton		
 	}
+	// flush the comments related to the annotation type header
+	this.scanner.commentPtr = -1;
 }
 protected void consumeAnnotationTypeDeclarationHeaderName() {
 	// consumeAnnotationTypeDeclarationHeader ::= Modifiers '@' PushModifiers interface Identifier
@@ -1245,7 +1256,8 @@
 	arrayInitializer(this.expressionLengthStack[this.expressionLengthPtr--]);
 }
 protected void consumeArrayTypeWithTypeArgumentsName() {
-	this.intStack[this.intPtr] += this.identifierLengthStack[this.identifierLengthPtr];
+	this.genericsIdentifiersLengthStack[this.genericsIdentifiersLengthPtr] += this.identifierLengthStack[this.identifierLengthPtr];
+	pushOnGenericsLengthStack(0); // handle type arguments
 }
 protected void consumeAssertStatement() {
 	// AssertStatement ::= 'assert' Expression ':' Expression ';'
@@ -1733,6 +1745,9 @@
 	// ClassBodyDeclarationsopt ::= NestedType ClassBodyDeclarations
 	this.nestedType-- ;
 }
+protected void consumeAnnotationTypeMemberDeclarationsopt() {
+	this.nestedType-- ;
+}
 protected void consumeClassBodyopt() {
 	// ClassBodyopt ::= $empty
 	pushOnAstStack(null);
@@ -2575,6 +2590,10 @@
 
 	anonymousType.bodyStart = this.scanner.currentPosition;	
 	this.listLength = 0; // will be updated when reading super-interfaces
+	
+	// flush the comments related to the anonymous
+	this.scanner.commentPtr = -1;
+	
 	// recovery
 	if (this.currentElement != null){ 
 		this.lastCheckPoint = anonymousType.bodyStart;		
@@ -3128,10 +3147,9 @@
 		pushOnExpressionStack(fr);
 	} else {
 		//optimize push/pop
-		if ((fr.receiver = this.expressionStack[this.expressionPtr]).isThis()) {
-			//fieldreference begins at the this
-			fr.sourceStart = fr.receiver.sourceStart;
-		}
+		fr.receiver = this.expressionStack[this.expressionPtr];
+		//fieldreference begins at the receiver
+		fr.sourceStart = fr.receiver.sourceStart;
 		this.expressionStack[this.expressionPtr] = fr;
 	}
 }
@@ -3280,7 +3298,8 @@
 	// Will be consume by a getTypeRefence call
 }
 protected void consumeGenericTypeNameArrayType() {
-	pushOnGenericsLengthStack(0); // handle type arguments
+	// nothing to do
+	// Will be consume by a getTypeRefence call
 }
 protected void consumeImportDeclaration() {
 	// SingleTypeImportDeclaration ::= SingleTypeImportDeclarationName ';'
@@ -4189,6 +4208,11 @@
 	}
 	normalAnnotation.declarationSourceEnd = this.rParenPos;
 	pushOnExpressionStack(normalAnnotation);
+	
+	if(this.currentElement != null) {
+		annotationRecoveryCheckPoint(normalAnnotation.sourceStart, normalAnnotation.declarationSourceEnd);
+	}
+	
 	if(options.sourceLevel < ClassFileConstants.JDK1_5 &&
 			this.lastErrorEndPositionBeforeRecovery < this.scanner.currentPosition) {
 		this.problemReporter().invalidUsageOfAnnotation(normalAnnotation);
@@ -4230,7 +4254,11 @@
 	this.realBlockStack[this.realBlockPtr] = 0;
 }
 protected void consumePackageComment() {
-	// do nothing
+	// get possible comment for syntax since 1.5
+	if(options.sourceLevel >= ClassFileConstants.JDK1_5) {
+		checkComment();
+		resetModifiers();
+	}
 }
 protected void consumePackageDeclaration() {
 	// PackageDeclaration ::= 'package' Name ';'
@@ -4238,6 +4266,8 @@
 	stored in the identifier stack. */
 
 	ImportReference impt = this.compilationUnit.currentPackage;
+	this.compilationUnit.javadoc = this.javadoc;
+	this.javadoc = null;
 	// flush comments defined prior to import statements
 	impt.declarationEnd = this.endStatementPosition;
 	impt.declarationSourceEnd = this.flushCommentsDefinedPriorTo(impt.declarationSourceEnd);
@@ -4273,6 +4303,11 @@
 	//this.endPosition is just before the ;
 	impt.declarationSourceStart = this.intStack[this.intPtr--];
 
+	// get possible comment source start
+	if(this.javadoc != null) {
+		impt.declarationSourceStart = this.javadoc.sourceStart;
+	}
+
 	// recovery
 	if (this.currentElement != null){
 		this.lastCheckPoint = impt.declarationSourceEnd+1;
@@ -4315,6 +4350,10 @@
 		intPtr--; // we don't need the position of the 'package keyword
 	} else {
 		impt.declarationSourceStart = this.intStack[this.intPtr--];
+		// get possible comment source start
+		if (this.javadoc != null) {
+			impt.declarationSourceStart = this.javadoc.sourceStart;
+		}
 	}
 		
 	if (this.currentToken == TokenNameSEMICOLON){
@@ -6050,6 +6089,10 @@
 		    consumeEmptyAnnotationTypeMemberDeclarationsopt() ;  
 			break;
  
+    case 651 : if (DEBUG) { System.out.println("AnnotationTypeMemberDeclarationsopt ::= NestedType..."); }  //$NON-NLS-1$
+		    consumeAnnotationTypeMemberDeclarationsopt() ;  
+			break;
+ 
     case 653 : if (DEBUG) { System.out.println("AnnotationTypeMemberDeclarations ::=..."); }  //$NON-NLS-1$
 		    consumeAnnotationTypeMemberDeclarations() ;  
 			break;
@@ -6170,6 +6213,12 @@
 	this.expressionLengthPtr--;
 	singleMemberAnnotation.declarationSourceEnd = this.rParenPos;
 	pushOnExpressionStack(singleMemberAnnotation);
+	
+	
+	if(this.currentElement != null) {
+		annotationRecoveryCheckPoint(singleMemberAnnotation.sourceStart, singleMemberAnnotation.declarationSourceEnd);
+	}
+	
 	if(options.sourceLevel < ClassFileConstants.JDK1_5 &&
 			this.lastErrorEndPositionBeforeRecovery < this.scanner.currentPosition) {
 		this.problemReporter().invalidUsageOfAnnotation(singleMemberAnnotation);
@@ -6878,11 +6927,12 @@
 			this.endPosition = this.scanner.startPosition;
 			this.endStatementPosition = this.scanner.currentPosition - 1;
 			break;
+		case TokenNameLBRACE :
+			this.endStatementPosition = this.scanner.currentPosition - 1;
 		case TokenNamePLUS :
 		case TokenNameMINUS :
 		case TokenNameNOT :
 		case TokenNameTWIDDLE :
-		case TokenNameLBRACE :
 			this.endPosition = this.scanner.startPosition;
 			break;
 		case TokenNamePLUS_PLUS :
@@ -8040,7 +8090,7 @@
 	this.scanner.recordLineSeparator = false;
 }
 public void goForMemberValue() {
-	//tells the scanner to go for a memeber value parsing
+	//tells the scanner to go for a member value parsing
 
 	this.firstToken = TokenNameOR_OR;
 	this.scanner.recordLineSeparator = true; // recovery goals must record line separators
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/ParserBasicInformation.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/ParserBasicInformation.java
index b277b64..01bf9a2 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/ParserBasicInformation.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/ParserBasicInformation.java
@@ -16,20 +16,20 @@
 
 	int ERROR_SYMBOL = 110,
 		MAX_NAME_LENGTH = 41,
-		NUM_STATES = 953,
+		NUM_STATES = 955,
 
 		NT_OFFSET = 110,
 		SCOPE_UBOUND = 131,
 		SCOPE_SIZE = 132,
-		LA_STATE_OFFSET = 12568,
+		LA_STATE_OFFSET = 12619,
 		MAX_LA = 1,
 		NUM_RULES = 691,
 		NUM_TERMINALS = 110,
 		NUM_NON_TERMINALS = 306,
 		NUM_SYMBOLS = 416,
-		START_STATE = 1045,
+		START_STATE = 1466,
 		EOFT_SYMBOL = 66,
 		EOLT_SYMBOL = 66,
-		ACCEPT_ACTION = 12567,
-		ERROR_ACTION = 12568;
+		ACCEPT_ACTION = 12618,
+		ERROR_ACTION = 12619;
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredField.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredField.java
index 91f1751..867857e 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredField.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredField.java
@@ -133,9 +133,7 @@
 					typeDeclaration.declarationSourceEnd = this.fieldDeclaration.declarationSourceEnd;
 					typeDeclaration.bodyEnd = this.fieldDeclaration.declarationSourceEnd;
 				}
-				if (recoveredType.preserveContent){
-					recoveredType.updatedTypeDeclaration();
-				}
+				recoveredType.updatedTypeDeclaration();
 			}
 		}
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredMethod.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredMethod.java
index 193ac00..12c96d4 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredMethod.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredMethod.java
@@ -318,8 +318,8 @@
  * is about to disappear because of restarting recovery
  */
 public void updateFromParserState(){
-
-	if(this.bodyStartsAtHeaderEnd()){
+	// if parent is null then recovery already occured in diet parser.
+	if(this.bodyStartsAtHeaderEnd() && this.parent != null){
 		Parser parser = this.parser();
 		/* might want to recover arguments or thrown exceptions */
 		if (parser.listLength > 0 && parser.astLengthPtr > 0){ // awaiting interface type references
@@ -375,19 +375,28 @@
 				// to compute bodyStart, and thus used to set next checkpoint.
 				int count;
 				for (count = 0; count < argLength; count++){
-					Argument argument = (Argument)parser.astStack[argStart+count];
-					/* cannot be an argument if non final */
-					char[][] argTypeName = argument.type.getTypeName();
-					if ((argument.modifiers & ~AccFinal) != 0
-						|| (argTypeName.length == 1
-							&& CharOperation.equals(argTypeName[0], VoidBinding.sourceName()))){
+					ASTNode aNode = parser.astStack[argStart+count];
+					if(aNode instanceof Argument) {
+						Argument argument = (Argument)aNode;
+						/* cannot be an argument if non final */
+						char[][] argTypeName = argument.type.getTypeName();
+						if ((argument.modifiers & ~AccFinal) != 0
+							|| (argTypeName.length == 1
+								&& CharOperation.equals(argTypeName[0], VoidBinding.sourceName()))){
+							parser.astLengthStack[parser.astLengthPtr] = count; 
+							parser.astPtr = argStart+count-1; 
+							parser.listLength = count;
+							parser.currentToken = 0;
+							break;
+						}
+						if (needUpdateRParenPos) parser.rParenPos = argument.sourceEnd + 1;
+					} else {
 						parser.astLengthStack[parser.astLengthPtr] = count; 
 						parser.astPtr = argStart+count-1; 
 						parser.listLength = count;
 						parser.currentToken = 0;
 						break;
 					}
-					if (needUpdateRParenPos) parser.rParenPos = argument.sourceEnd + 1;
 				}
 				if (parser.listLength > 0 && parser.astLengthPtr > 0){
 					
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredType.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredType.java
index 15c475b..0be747a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredType.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredType.java
@@ -45,7 +45,12 @@
 public RecoveredType(TypeDeclaration typeDeclaration, RecoveredElement parent, int bracketBalance){
 	super(typeDeclaration, parent, bracketBalance);
 	this.typeDeclaration = typeDeclaration;
-	this.foundOpeningBrace = !bodyStartsAtHeaderEnd();
+	if(typeDeclaration.allocation != null && typeDeclaration.allocation.type == null) {
+		// an enum constant body can not exist if there is no opening brace
+		this.foundOpeningBrace = true;
+	} else {
+		this.foundOpeningBrace = !bodyStartsAtHeaderEnd();
+	}
 	this.insideEnumConstantPart = typeDeclaration.kind() == IGenericType.ENUM_DECL;
 	if(this.foundOpeningBrace) {
 		this.bracketBalance++;
@@ -414,7 +419,8 @@
  */
 public void updateFromParserState(){
 
-	if(this.bodyStartsAtHeaderEnd()){
+	// anymous type and enum constant doesn't need to be updated
+	if(this.bodyStartsAtHeaderEnd() && typeDeclaration.allocation == null){
 		Parser parser = this.parser();
 		/* might want to recover implemented interfaces */
 		// protection for bugs 15142
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java
index feb4892..97b1754 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java
@@ -908,6 +908,8 @@
 					if (this.currentPosition > this.eofPosition)
 						return TokenNameEOF;
 				}
+				if (this.currentPosition > this.eofPosition)
+					return TokenNameEOF;
 				if (checkIfUnicode) {
 					isWhiteSpace = jumpOverUnicodeWhiteSpace();
 					offset = this.currentPosition - offset;
@@ -956,12 +958,7 @@
 					this.withoutUnicodePtr = 0;
 				}
 			}
-			//little trick to get out in the middle of a source compuation
-			if (this.currentPosition > this.eofPosition)
-				return TokenNameEOF;
-
 			// ---------Identify the next token-------------
-
 			switch (this.currentCharacter) {
 				case '@' :
 /*					if (this.sourceLevel >= ClassFileConstants.JDK1_5) {
@@ -2388,11 +2385,6 @@
 	}
 	this.commentPtr = -1; // reset comment stack
 	this.foundTaskCount = 0;
-	
-//	// if resetTo is used with being > than end.
-//	if (begin > this.eofPosition) {
-//		begin = this.eofPosition;
-//	}
 }
 
 public final void scanEscapeCharacter() throws InvalidInputException {
@@ -3359,20 +3351,30 @@
 	this.containsAssertKeyword = false;
 	this.linePtr = -1;	
 }
-
 /*
  * Should be used if a parse (usually a diet parse) has already been performed on the unit, 
  * so as to get the already computed line end positions.
  */
-public final void setSource(CompilationResult compilationResult) {
-	char[] contents = compilationResult.compilationUnit.getContents();
-	setSource(contents);
+public final void setSource(char[] contents, CompilationResult compilationResult) {
+	if (contents == null) {
+		char[] cuContents = compilationResult.compilationUnit.getContents();
+		setSource(cuContents);
+	} else {
+		setSource(contents);
+	}
 	int[] lineSeparatorPositions = compilationResult.lineSeparatorPositions;
 	if (lineSeparatorPositions != null) {
 		this.lineEnds = lineSeparatorPositions;
 		this.linePtr = lineSeparatorPositions.length - 1;
 	}
 }
+/*
+ * Should be used if a parse (usually a diet parse) has already been performed on the unit, 
+ * so as to get the already computed line end positions.
+ */
+public final void setSource(CompilationResult compilationResult) {
+	setSource(null, compilationResult);
+}
 public String toString() {
 	if (this.startPosition == this.source.length)
 		return "EOF\n\n" + new String(this.source); //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/TerminalTokens.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/TerminalTokens.java
index f161000..df8f7da 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/TerminalTokens.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/TerminalTokens.java
@@ -51,7 +51,7 @@
 		TokenNameelse = 103,
 		TokenNameenum = 98,
 		TokenNameextends = 99,
-		TokenNamefalse = 45,
+		TokenNamefalse = 44,
 		TokenNamefinal = 57,
 		TokenNamefinally = 104,
 		TokenNamefloat = 36,
@@ -66,7 +66,7 @@
 		TokenNamelong = 38,
 		TokenNamenative = 58,
 		TokenNamenew = 43,
-		TokenNamenull = 46,
+		TokenNamenull = 45,
 		TokenNamepackage = 96,
 		TokenNameprivate = 59,
 		TokenNameprotected = 60,
@@ -82,17 +82,17 @@
 		TokenNamethrow = 82,
 		TokenNamethrows = 105,
 		TokenNametransient = 63,
-		TokenNametrue = 47,
+		TokenNametrue = 46,
 		TokenNametry = 83,
 		TokenNamevoid = 40,
 		TokenNamevolatile = 64,
 		TokenNamewhile = 73,
-		TokenNameIntegerLiteral = 48,
-		TokenNameLongLiteral = 49,
-		TokenNameFloatingPointLiteral = 50,
-		TokenNameDoubleLiteral = 51,
-		TokenNameCharacterLiteral = 52,
-		TokenNameStringLiteral = 53,
+		TokenNameIntegerLiteral = 47,
+		TokenNameLongLiteral = 48,
+		TokenNameFloatingPointLiteral = 49,
+		TokenNameDoubleLiteral = 50,
+		TokenNameCharacterLiteral = 51,
+		TokenNameStringLiteral = 52,
 		TokenNamePLUS_PLUS = 10,
 		TokenNameMINUS_MINUS = 11,
 		TokenNameEQUAL_EQUAL = 18,
@@ -139,7 +139,7 @@
 		TokenNameCOMMA = 30,
 		TokenNameDOT = 3,
 		TokenNameEQUAL = 71,
-		TokenNameAT = 44,
+		TokenNameAT = 53,
 		TokenNameELLIPSIS = 107,
 		TokenNameEOF = 66,
 		TokenNameERROR = 110;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser1.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser1.rsc
index f08b9bf..12d3ef8 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser1.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser1.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser12.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser12.rsc
index cf0228a..cf2a204 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser12.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser12.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser13.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser13.rsc
index 35baf52..6438e80 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser13.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser13.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser14.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser14.rsc
index d62f283..9dccdac 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser14.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser14.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser15.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser15.rsc
index 9a18dbc..92f5d61 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser15.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser15.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser16.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser16.rsc
index 5e93598..79a6cb6 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser16.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser16.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser17.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser17.rsc
index 1365bda..0969339 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser17.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser17.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser18.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser18.rsc
index 856d1a0..dcdc0b5 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser18.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser18.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser19.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser19.rsc
index 927a29e..fb9d761 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser19.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser19.rsc
@@ -1 +1 @@
-ggFFFEEhAAA!FfAeAIE	JJE!EEbGG_!H!!!!!,
\ No newline at end of file
+ggFFFEEhAAA!FfAeAIE	JJE!EEbGG_!H!!!!!5
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser2.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser2.rsc
index f088262..81f119f 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser2.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser2.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser3.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser3.rsc
index 920127b..5cd9763 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser3.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser3.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser4.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser4.rsc
index d383385..d484da8 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser4.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser4.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser5.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser5.rsc
index 355084e..baae381 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser5.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser5.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser6.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser6.rsc
index 0000f7c..ad2c407 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser6.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser6.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser7.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser7.rsc
index c79761e..eef9e8f 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser7.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser7.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser8.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser8.rsc
index 5379910..4404e1b 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser8.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser8.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser9.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser9.rsc
index 4a50e3d..7ebae37 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser9.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser9.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
index 849818e..fc509f1 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
@@ -24,6 +24,14 @@
 import org.eclipse.jdt.internal.compiler.util.Messages;
 
 public class ProblemReporter extends ProblemHandler implements ProblemReasons {
+
+	/** These constants will be defined on IProblem in 3.2 branch, but are only internal in 3.1 maintenance
+	 * stream so as not to compromise source compatibility with 3.1.0.
+	 */
+	/** @since 3.2 */
+	private final static int JavadocNonStaticTypeFromStaticInvocation = IProblem.Javadoc + IProblem.Internal + 468;
+	/** @since 3.2 */ 
+	private final static int EnumStaticFieldInInInitializerContext = IProblem.FieldRelated + 762;
 	
 	public ReferenceContext referenceContext;
 	
@@ -314,14 +322,6 @@
 		location.sourceStart,
 		location.sourceEnd);
 }
-public void boundHasConflictingArguments(ASTNode location, TypeBinding type) {
-	this.handle(
-		IProblem.BoundHasConflictingArguments,
-		new String[] {new String(type.readableName())},
-		new String[] {new String(type.shortReadableName())},
-		location.sourceStart,
-		location.sourceEnd);
-}
 public void boundMustBeAnInterface(ASTNode location, TypeBinding type) {
 	this.handle(
 		IProblem.BoundMustBeAnInterface,
@@ -376,8 +376,8 @@
 		new String[] {
 			(field.declaringClass == null ? "array" : new String(field.declaringClass.shortReadableName())), //$NON-NLS-1$
 			new String(field.shortReadableName())},
-		location.sourceStart,
-		location.sourceEnd);
+		fieldSourceStart(field, location),
+		fieldSourceEnd(field, location));
 }
 public void cannotAssignToFinalLocal(LocalVariableBinding local, ASTNode location) {
 	String[] arguments = new String[] { new String(local.readableName())};
@@ -489,13 +489,13 @@
 		exceptionType.sourceStart,
 		exceptionType.sourceEnd);
 }
-public void cannotUseQualifiedEnumConstantInCaseLabel(Reference reference, FieldBinding field) {
+public void cannotUseQualifiedEnumConstantInCaseLabel(Reference location, FieldBinding field) {
 	this.handle(
 			IProblem.IllegalQualifiedEnumConstantLabel,
 			new String[]{ String.valueOf(field.declaringClass.readableName()), String.valueOf(field.name) },
 			new String[]{ String.valueOf(field.declaringClass.shortReadableName()), String.valueOf(field.name) },
-			reference.sourceStart,
-			reference.sourceEnd);	
+			fieldSourceStart(field, location),
+			fieldSourceEnd(field, location)); 
 }
 public void cannotUseSuperInCodeSnippet(int start, int end) {
 	this.handle(
@@ -559,197 +559,13 @@
  * falls into:
  *		Error | Warning | Ignore
  */
-public int computeSeverity(int problemId){
+public int computeSeverity(int problemID){
 
-	// severity can have been preset on the problem
-//	if ((problem.severity & Fatal) != 0){
-//		return Error;
-//	}
-
-	// if not then check whether it is a configurable problem
-	switch(problemId){
-
-		case IProblem.MaskedCatch : 
-			return this.options.getSeverity(CompilerOptions.MaskedCatchBlock);
-
-		case IProblem.UnusedImport :
-			return this.options.getSeverity(CompilerOptions.UnusedImport);
-			
-		case IProblem.MethodButWithConstructorName :
-			return this.options.getSeverity(CompilerOptions.MethodWithConstructorName);
-		
-		case IProblem.OverridingNonVisibleMethod :
-			return this.options.getSeverity(CompilerOptions.OverriddenPackageDefaultMethod);
-
-		case IProblem.IncompatibleReturnTypeForNonInheritedInterfaceMethod :
-		case IProblem.IncompatibleExceptionInThrowsClauseForNonInheritedInterfaceMethod :
-			return this.options.getSeverity(CompilerOptions.IncompatibleNonInheritedInterfaceMethod);
-
-		case IProblem.OverridingDeprecatedMethod :				
-		case IProblem.UsingDeprecatedType :				
-		case IProblem.UsingDeprecatedMethod :
-		case IProblem.UsingDeprecatedConstructor :
-		case IProblem.UsingDeprecatedField :
-			return this.options.getSeverity(CompilerOptions.UsingDeprecatedAPI);
-		
-		case IProblem.LocalVariableIsNeverUsed :
-			return this.options.getSeverity(CompilerOptions.UnusedLocalVariable);
-		
-		case IProblem.ArgumentIsNeverUsed :
-			return this.options.getSeverity(CompilerOptions.UnusedArgument);
-
-		case IProblem.NoImplicitStringConversionForCharArrayExpression :
-			return this.options.getSeverity(CompilerOptions.NoImplicitStringConversion);
-
-		case IProblem.NeedToEmulateFieldReadAccess :
-		case IProblem.NeedToEmulateFieldWriteAccess :
-		case IProblem.NeedToEmulateMethodAccess :
-		case IProblem.NeedToEmulateConstructorAccess :			
-			return this.options.getSeverity(CompilerOptions.AccessEmulation);
-
-		case IProblem.NonExternalizedStringLiteral :
-			return this.options.getSeverity(CompilerOptions.NonExternalizedString);
-
-		case IProblem.UseAssertAsAnIdentifier :
-			return this.options.getSeverity(CompilerOptions.AssertUsedAsAnIdentifier);
-		case IProblem.UseEnumAsAnIdentifier :
-			return this.options.getSeverity(CompilerOptions.EnumUsedAsAnIdentifier);
-
-		case IProblem.NonStaticAccessToStaticMethod :
-		case IProblem.NonStaticAccessToStaticField :
-			return this.options.getSeverity(CompilerOptions.NonStaticAccessToStatic);
-
-		case IProblem.IndirectAccessToStaticMethod :
-		case IProblem.IndirectAccessToStaticField :
-		case IProblem.IndirectAccessToStaticType :
-			return this.options.getSeverity(CompilerOptions.IndirectStaticAccess);
-
-		case IProblem.AssignmentHasNoEffect:
-			return this.options.getSeverity(CompilerOptions.NoEffectAssignment);
-
-		case IProblem.UnusedPrivateConstructor:
-		case IProblem.UnusedPrivateMethod:
-		case IProblem.UnusedPrivateField:
-		case IProblem.UnusedPrivateType:
-			return this.options.getSeverity(CompilerOptions.UnusedPrivateMember);
-
+	switch (problemID) {
 		case IProblem.Task :
-			return Warning;			
-
-		case IProblem.LocalVariableHidingLocalVariable:
-		case IProblem.LocalVariableHidingField:
-		case IProblem.ArgumentHidingLocalVariable:
-		case IProblem.ArgumentHidingField:
-			return this.options.getSeverity(CompilerOptions.LocalVariableHiding);
-
-		case IProblem.FieldHidingLocalVariable:
-		case IProblem.FieldHidingField:
-			return this.options.getSeverity(CompilerOptions.FieldHiding);
-
-		case IProblem.TypeParameterHidingType:
-			return this.options.getSeverity(CompilerOptions.TypeParameterHiding);
+ 		case IProblem.VarargsConflict :
+			return ProblemSeverities.Warning;
 			
-		case IProblem.PossibleAccidentalBooleanAssignment:
-			return this.options.getSeverity(CompilerOptions.AccidentalBooleanAssign);
-
-		case IProblem.SuperfluousSemicolon:
-		case IProblem.EmptyControlFlowStatement:
-			return this.options.getSeverity(CompilerOptions.EmptyStatement);
-
-		case IProblem.UndocumentedEmptyBlock:
-			return this.options.getSeverity(CompilerOptions.UndocumentedEmptyBlock);
-			
-		case IProblem.UnnecessaryCast:
-		case IProblem.UnnecessaryInstanceof:
-			return this.options.getSeverity(CompilerOptions.UnnecessaryTypeCheck);
-			
-		case IProblem.FinallyMustCompleteNormally:
-			return this.options.getSeverity(CompilerOptions.FinallyBlockNotCompleting);
-			
-		case IProblem.UnusedMethodDeclaredThrownException:
-		case IProblem.UnusedConstructorDeclaredThrownException:
-			return this.options.getSeverity(CompilerOptions.UnusedDeclaredThrownException);
-
-		case IProblem.UnqualifiedFieldAccess:
-			return this.options.getSeverity(CompilerOptions.UnqualifiedFieldAccess);
-		
-		case IProblem.UnnecessaryElse:
-			return this.options.getSeverity(CompilerOptions.UnnecessaryElse);
-
-		case IProblem.UnsafeRawConstructorInvocation:
-		case IProblem.UnsafeRawMethodInvocation:
-		case IProblem.UnsafeTypeConversion:
-		case IProblem.UnsafeRawFieldAssignment:
-		case IProblem.UnsafeGenericCast:
-		case IProblem.UnsafeReturnTypeOverride:
-		case IProblem.UnsafeRawGenericMethodInvocation:
-		case IProblem.UnsafeRawGenericConstructorInvocation:
-			return this.options.getSeverity(CompilerOptions.UncheckedTypeOperation);
-
-		case IProblem.MissingOverrideAnnotation:
-			return this.options.getSeverity(CompilerOptions.MissingOverrideAnnotation);
-			
-		case IProblem.FieldMissingDeprecatedAnnotation:
-		case IProblem.MethodMissingDeprecatedAnnotation:
-		case IProblem.TypeMissingDeprecatedAnnotation:
-			return this.options.getSeverity(CompilerOptions.MissingDeprecatedAnnotation);
-			
-		case IProblem.FinalBoundForTypeVariable:
-		    return this.options.getSeverity(CompilerOptions.FinalParameterBound);
-
-		case IProblem.MissingSerialVersion:
-			return this.options.getSeverity(CompilerOptions.MissingSerialVersion);
-		
-		case IProblem.ForbiddenReference:
-			return this.options.getSeverity(CompilerOptions.ForbiddenReference);
-
-		case IProblem.DiscouragedReference:
-			return this.options.getSeverity(CompilerOptions.DiscouragedReference);
-
-		case IProblem.MethodVarargsArgumentNeedCast :
-		case IProblem.ConstructorVarargsArgumentNeedCast :
-			return this.options.getSeverity(CompilerOptions.VarargsArgumentNeedCast);
-
-		case IProblem.LocalVariableCannotBeNull :
-		case IProblem.LocalVariableCanOnlyBeNull :
-			return this.options.getSeverity(CompilerOptions.NullReference);
-			
-		case IProblem.BoxingConversion :
-		case IProblem.UnboxingConversion :
-			return this.options.getSeverity(CompilerOptions.Autoboxing);
-
-		case IProblem.MissingEnumConstantCase :
-			return this.options.getSeverity(CompilerOptions.IncompleteEnumSwitch);
-			
-		case IProblem.VarargsConflict :
-			return Warning;
-			
-		case IProblem.AnnotationTypeUsedAsSuperInterface :
-			return this.options.getSeverity(CompilerOptions.AnnotationSuperInterface);
-			
-		/*
-		 * Javadoc syntax errors
-		 */
-		case IProblem.JavadocUnexpectedTag:
-		case IProblem.JavadocDuplicateReturnTag:
-		case IProblem.JavadocInvalidThrowsClass:
-		case IProblem.JavadocInvalidReference:
-		case IProblem.JavadocInvalidParamTagName:
-		case IProblem.JavadocInvalidParamTagTypeParameter:
-		case IProblem.JavadocMalformedSeeReference:
-		case IProblem.JavadocInvalidSeeHref:
-		case IProblem.JavadocInvalidSeeArgs:
-		case IProblem.JavadocInvalidTag:
-		case IProblem.JavadocUnterminatedInlineTag:
-		case IProblem.JavadocMissingHashCharacter:
-		case IProblem.JavadocEmptyReturnTag:
-		case IProblem.JavadocUnexpectedText:
-			if (this.options.docCommentSupport) {
-				return this.options.getSeverity(CompilerOptions.InvalidJavadoc);
-			} else {
-				return ProblemSeverities.Ignore;
-			}
-
 		/*
 		 * Javadoc tags resolved references errors
 		 */
@@ -759,7 +575,7 @@
 		case IProblem.JavadocInvalidThrowsClassName:
 		case IProblem.JavadocDuplicateThrowsClassName:
 		case IProblem.JavadocMissingThrowsClassName:
-		case IProblem.JavadocMissingReference:
+		case IProblem.JavadocMissingSeeReference:
 		case IProblem.JavadocInvalidValueReference:
 		case IProblem.JavadocUndefinedField:
 		case IProblem.JavadocAmbiguousField:
@@ -777,6 +593,7 @@
 		case IProblem.JavadocInheritedMethodHidesEnclosingName:
 		case IProblem.JavadocInheritedFieldHidesEnclosingName:
 		case IProblem.JavadocInheritedNameHidesEnclosingTypeName:
+		case ProblemReporter.JavadocNonStaticTypeFromStaticInvocation: // internal problem ID in 3.1 maintenance branch
 		case IProblem.JavadocGenericMethodTypeArgumentMismatch:
 		case IProblem.JavadocNonGenericMethod:
 		case IProblem.JavadocIncorrectArityForParameterizedMethod:
@@ -787,11 +604,10 @@
 		case IProblem.JavadocIncorrectArityForParameterizedConstructor:
 		case IProblem.JavadocParameterizedConstructorArgumentTypeMismatch:
 		case IProblem.JavadocTypeArgumentsForRawGenericConstructor:
-			if (this.options.docCommentSupport && this.options.reportInvalidJavadocTags) {
-				return this.options.getSeverity(CompilerOptions.InvalidJavadoc);
+			if (!this.options.reportInvalidJavadocTags) {
+				return ProblemSeverities.Ignore;		
 			}
-			return ProblemSeverities.Ignore;
-
+			break;
 		/*
 		 * Javadoc invalid tags due to deprecated references
 		 */
@@ -799,11 +615,10 @@
 		case IProblem.JavadocUsingDeprecatedConstructor:
 		case IProblem.JavadocUsingDeprecatedMethod:
 		case IProblem.JavadocUsingDeprecatedType:
-			if (this.options.docCommentSupport && this.options.reportInvalidJavadocTags && this.options.reportInvalidJavadocTagsDeprecatedRef) {
-				return this.options.getSeverity(CompilerOptions.InvalidJavadoc);
+			if (!(this.options.reportInvalidJavadocTags && this.options.reportInvalidJavadocTagsDeprecatedRef)) {
+				return ProblemSeverities.Ignore;
 			}
-			return ProblemSeverities.Ignore;
-
+			break;
 		/*
 		 * Javadoc invalid tags due to non-visible references
 		 */
@@ -811,37 +626,18 @@
 		case IProblem.JavadocNotVisibleConstructor:
 		case IProblem.JavadocNotVisibleMethod:
 		case IProblem.JavadocNotVisibleType:
-			if (this.options.docCommentSupport && this.options.reportInvalidJavadocTags && this.options.reportInvalidJavadocTagsNotVisibleRef) {
-				return this.options.getSeverity(CompilerOptions.InvalidJavadoc);
+			if (!(this.options.reportInvalidJavadocTags && this.options.reportInvalidJavadocTagsNotVisibleRef)) {
+				return ProblemSeverities.Ignore;			
 			}
-			return ProblemSeverities.Ignore;
-
-		/*
-		 * Javadoc missing tags errors
-		 */
-		case IProblem.JavadocMissingParamTag:
-		case IProblem.JavadocMissingReturnTag:
-		case IProblem.JavadocMissingThrowsTag:
-			if (this.options.docCommentSupport) {
-				return this.options.getSeverity(CompilerOptions.MissingJavadocTags);
-			} else {
-				return ProblemSeverities.Ignore;
-			}
-
-		/*
-		 * Missing Javadoc errors
-		 */
-		case IProblem.JavadocMissing:
-			if (this.options.docCommentSupport) {
-				return this.options.getSeverity(CompilerOptions.MissingJavadocComments);
-			} else {
-				return ProblemSeverities.Ignore;
-			}
-			
-		// by default problems are errors.
-		default:
-			return Error;
+			break;
 	}
+	long irritant = getIrritant(problemID);
+	if (irritant != 0) {
+		if ((problemID & IProblem.Javadoc) != 0 && !this.options.docCommentSupport) 
+			return ProblemSeverities.Ignore;
+		return this.options.getSeverity(irritant);
+	}
+	return Error;
 }
 public void conditionalArgumentsIncompatibleTypes(ConditionalExpression expression, TypeBinding trueType, TypeBinding falseType) {
 	this.handle(
@@ -928,8 +724,8 @@
 		IProblem.UsingDeprecatedField,
 		new String[] {new String(field.declaringClass.readableName()), new String(field.name)},
 		new String[] {new String(field.declaringClass.shortReadableName()), new String(field.name)},
-		location.sourceStart,
-		location.sourceEnd);
+		fieldSourceStart(field, location),
+		fieldSourceEnd(field, location));
 }
 public void deprecatedMethod(MethodBinding method, ASTNode location) {
 	if (method.isConstructor()) {
@@ -1062,8 +858,8 @@
 		IProblem.DuplicateBlankFinalFieldInitialization,
 		arguments,
 		arguments,
-		reference.sourceStart,
-		reference.sourceEnd);
+		fieldSourceStart(field, reference),
+		fieldSourceEnd(field, reference));
 }
 public void duplicateInitializationOfFinalLocal(LocalVariableBinding local, ASTNode location) {
 	String[] arguments = new String[] { new String(local.readableName())};
@@ -1176,7 +972,7 @@
 		typeDecl.sourceStart,
 		typeDecl.sourceEnd);
 }
-public void duplicateSuperinterface(SourceTypeBinding type, TypeDeclaration typeDecl, ReferenceBinding superType) {
+public void duplicateSuperinterface(SourceTypeBinding type, TypeReference reference, ReferenceBinding superType) {
 	this.handle(
 		IProblem.DuplicateSuperInterface,
 		new String[] {
@@ -1185,17 +981,18 @@
 		new String[] {
 			new String(superType.shortReadableName()),
 			new String(type.sourceName())},
-		typeDecl.sourceStart,
-		typeDecl.sourceEnd);
+		reference.sourceStart,
+		reference.sourceEnd);
 }
 public void duplicateTargetInTargetAnnotation(TypeBinding annotationType, NameReference reference) {
-	String name = 	new String(reference.fieldBinding().name);
+	FieldBinding field = reference.fieldBinding();
+	String name = 	new String(field.name);
 	this.handle(
 		IProblem.DuplicateTargetInTargetAnnotation,
 		new String[] { name, new String(annotationType.readableName())},
 		new String[] {	name, new String(annotationType.shortReadableName())},
-		reference.sourceStart,
-		reference.sourceEnd);
+		fieldSourceStart(field, reference),
+		fieldSourceEnd(field, reference)); 
 }
 public void duplicateTypeParameterInType(TypeParameter typeParameter) {
 	this.handle(
@@ -1243,13 +1040,21 @@
 		method.sourceStart(),
 		method.sourceEnd());
 }
+public void enumStaticFieldUsedDuringInitialization(FieldBinding field, ASTNode location) {
+	this.handle(
+		ProblemReporter.EnumStaticFieldInInInitializerContext, // internal problem ID in 3.1 maintenance branch
+		new String[] {new String(field.declaringClass.readableName()), new String(field.name)},
+		new String[] {new String(field.declaringClass.shortReadableName()), new String(field.name)},
+		fieldSourceStart(field, location),
+		fieldSourceEnd(field, location));
+}
 public void enumSwitchCannotTargetField(Reference reference, FieldBinding field) {
 	this.handle(
 			IProblem.EnumSwitchCannotTargetField,
 			new String[]{ String.valueOf(field.declaringClass.readableName()), String.valueOf(field.name) },
 			new String[]{ String.valueOf(field.declaringClass.shortReadableName()), String.valueOf(field.name) },
-			reference.sourceStart,
-			reference.sourceEnd);	
+			fieldSourceStart(field, reference),
+			fieldSourceEnd(field, reference)); 
 }
 public void errorNoMethodFor(MessageSend messageSend, TypeBinding recType, TypeBinding[] params) {
 	StringBuffer buffer = new StringBuffer();
@@ -1327,7 +1132,8 @@
 			fieldDecl.sourceEnd);
 	}
 }
-private int fieldLocation(FieldBinding field, ASTNode node) {
+
+private int fieldSourceEnd(FieldBinding field, ASTNode node) {
 	if (node instanceof QualifiedNameReference) {
 		QualifiedNameReference ref = (QualifiedNameReference) node;
 		FieldBinding[] bindings = ref.otherBindings;
@@ -1338,6 +1144,14 @@
 	}
 	return node.sourceEnd;
 }
+private int fieldSourceStart(FieldBinding field, ASTNode node) {
+	if (node instanceof FieldReference) {
+		FieldReference fieldReference = (FieldReference) node;
+		return (int) (fieldReference.nameSourcePosition >> 32);
+	}
+	return node.sourceStart;
+}
+
 public void fieldsOrThisBeforeConstructorInvocation(ThisReference reference) {
 	this.handle(
 		IProblem.ThisSuperDuringConstructorInvocation,
@@ -1406,6 +1220,238 @@
 		typeDecl.superclass.sourceStart,
 		typeDecl.superclass.sourceEnd);
 }
+public static long getIrritant(int problemID) {
+	switch(problemID){
+
+		case IProblem.MaskedCatch : 
+			return CompilerOptions.MaskedCatchBlock;
+
+		case IProblem.UnusedImport :
+			return CompilerOptions.UnusedImport;
+			
+		case IProblem.MethodButWithConstructorName :
+			return CompilerOptions.MethodWithConstructorName;
+		
+		case IProblem.OverridingNonVisibleMethod :
+			return CompilerOptions.OverriddenPackageDefaultMethod;
+
+		case IProblem.IncompatibleReturnTypeForNonInheritedInterfaceMethod :
+		case IProblem.IncompatibleExceptionInThrowsClauseForNonInheritedInterfaceMethod :
+			return CompilerOptions.IncompatibleNonInheritedInterfaceMethod;
+
+		case IProblem.OverridingDeprecatedMethod :				
+		case IProblem.UsingDeprecatedType :				
+		case IProblem.UsingDeprecatedMethod :
+		case IProblem.UsingDeprecatedConstructor :
+		case IProblem.UsingDeprecatedField :
+			return CompilerOptions.UsingDeprecatedAPI;
+		
+		case IProblem.LocalVariableIsNeverUsed :
+			return CompilerOptions.UnusedLocalVariable;
+		
+		case IProblem.ArgumentIsNeverUsed :
+			return CompilerOptions.UnusedArgument;
+
+		case IProblem.NoImplicitStringConversionForCharArrayExpression :
+			return CompilerOptions.NoImplicitStringConversion;
+
+		case IProblem.NeedToEmulateFieldReadAccess :
+		case IProblem.NeedToEmulateFieldWriteAccess :
+		case IProblem.NeedToEmulateMethodAccess :
+		case IProblem.NeedToEmulateConstructorAccess :			
+			return CompilerOptions.AccessEmulation;
+
+		case IProblem.NonExternalizedStringLiteral :
+			return CompilerOptions.NonExternalizedString;
+
+		case IProblem.UseAssertAsAnIdentifier :
+			return CompilerOptions.AssertUsedAsAnIdentifier;
+			
+		case IProblem.UseEnumAsAnIdentifier :
+			return CompilerOptions.EnumUsedAsAnIdentifier;
+
+		case IProblem.NonStaticAccessToStaticMethod :
+		case IProblem.NonStaticAccessToStaticField :
+			return CompilerOptions.NonStaticAccessToStatic;
+
+		case IProblem.IndirectAccessToStaticMethod :
+		case IProblem.IndirectAccessToStaticField :
+		case IProblem.IndirectAccessToStaticType :
+			return CompilerOptions.IndirectStaticAccess;
+
+		case IProblem.AssignmentHasNoEffect:
+			return CompilerOptions.NoEffectAssignment;
+
+		case IProblem.UnusedPrivateConstructor:
+		case IProblem.UnusedPrivateMethod:
+		case IProblem.UnusedPrivateField:
+		case IProblem.UnusedPrivateType:
+			return CompilerOptions.UnusedPrivateMember;
+
+		case IProblem.LocalVariableHidingLocalVariable:
+		case IProblem.LocalVariableHidingField:
+		case IProblem.ArgumentHidingLocalVariable:
+		case IProblem.ArgumentHidingField:
+			return CompilerOptions.LocalVariableHiding;
+
+		case IProblem.FieldHidingLocalVariable:
+		case IProblem.FieldHidingField:
+			return CompilerOptions.FieldHiding;
+
+		case IProblem.TypeParameterHidingType:
+			return CompilerOptions.TypeParameterHiding;
+			
+		case IProblem.PossibleAccidentalBooleanAssignment:
+			return CompilerOptions.AccidentalBooleanAssign;
+
+		case IProblem.SuperfluousSemicolon:
+		case IProblem.EmptyControlFlowStatement:
+			return CompilerOptions.EmptyStatement;
+
+		case IProblem.UndocumentedEmptyBlock:
+			return CompilerOptions.UndocumentedEmptyBlock;
+			
+		case IProblem.UnnecessaryCast:
+		case IProblem.UnnecessaryInstanceof:
+			return CompilerOptions.UnnecessaryTypeCheck;
+			
+		case IProblem.FinallyMustCompleteNormally:
+			return CompilerOptions.FinallyBlockNotCompleting;
+			
+		case IProblem.UnusedMethodDeclaredThrownException:
+		case IProblem.UnusedConstructorDeclaredThrownException:
+			return CompilerOptions.UnusedDeclaredThrownException;
+
+		case IProblem.UnqualifiedFieldAccess:
+			return CompilerOptions.UnqualifiedFieldAccess;
+		
+		case IProblem.UnnecessaryElse:
+			return CompilerOptions.UnnecessaryElse;
+
+		case IProblem.UnsafeRawConstructorInvocation:
+		case IProblem.UnsafeRawMethodInvocation:
+		case IProblem.UnsafeTypeConversion:
+		case IProblem.UnsafeRawFieldAssignment:
+		case IProblem.UnsafeGenericCast:
+		case IProblem.UnsafeReturnTypeOverride:
+		case IProblem.UnsafeRawGenericMethodInvocation:
+		case IProblem.UnsafeRawGenericConstructorInvocation:
+			return CompilerOptions.UncheckedTypeOperation;
+
+		case IProblem.MissingOverrideAnnotation:
+			return CompilerOptions.MissingOverrideAnnotation;
+			
+		case IProblem.FieldMissingDeprecatedAnnotation:
+		case IProblem.MethodMissingDeprecatedAnnotation:
+		case IProblem.TypeMissingDeprecatedAnnotation:
+			return CompilerOptions.MissingDeprecatedAnnotation;
+			
+		case IProblem.FinalBoundForTypeVariable:
+		    return CompilerOptions.FinalParameterBound;
+
+		case IProblem.MissingSerialVersion:
+			return CompilerOptions.MissingSerialVersion;
+		
+		case IProblem.ForbiddenReference:
+			return CompilerOptions.ForbiddenReference;
+
+		case IProblem.DiscouragedReference:
+			return CompilerOptions.DiscouragedReference;
+
+		case IProblem.MethodVarargsArgumentNeedCast :
+		case IProblem.ConstructorVarargsArgumentNeedCast :
+			return CompilerOptions.VarargsArgumentNeedCast;
+
+		case IProblem.LocalVariableCannotBeNull :
+		case IProblem.LocalVariableCanOnlyBeNull :
+			return CompilerOptions.NullReference;
+			
+		case IProblem.BoxingConversion :
+		case IProblem.UnboxingConversion :
+			return CompilerOptions.Autoboxing;
+
+		case IProblem.MissingEnumConstantCase :
+			return CompilerOptions.IncompleteEnumSwitch;
+			
+		case IProblem.AnnotationTypeUsedAsSuperInterface :
+			return CompilerOptions.AnnotationSuperInterface;
+			
+		case IProblem.UnhandledWarningToken :
+			return CompilerOptions.UnhandledWarningToken;
+			
+		case IProblem.JavadocUnexpectedTag:
+		case IProblem.JavadocDuplicateReturnTag:
+		case IProblem.JavadocInvalidThrowsClass:
+		case IProblem.JavadocInvalidSeeReference:
+		case IProblem.JavadocInvalidParamTagName:
+		case IProblem.JavadocInvalidParamTagTypeParameter:
+		case IProblem.JavadocMalformedSeeReference:
+		case IProblem.JavadocInvalidSeeHref:
+		case IProblem.JavadocInvalidSeeArgs:
+		case IProblem.JavadocInvalidTag:
+		case IProblem.JavadocUnterminatedInlineTag:
+		case IProblem.JavadocMissingHashCharacter:
+		case IProblem.JavadocEmptyReturnTag:
+		case IProblem.JavadocUnexpectedText:
+		case IProblem.JavadocInvalidParamName:
+		case IProblem.JavadocDuplicateParamName:
+		case IProblem.JavadocMissingParamName:
+		case IProblem.JavadocInvalidThrowsClassName:
+		case IProblem.JavadocDuplicateThrowsClassName:
+		case IProblem.JavadocMissingThrowsClassName:
+		case IProblem.JavadocMissingSeeReference:
+		case IProblem.JavadocInvalidValueReference:
+		case IProblem.JavadocUndefinedField:
+		case IProblem.JavadocAmbiguousField:
+		case IProblem.JavadocUndefinedConstructor:
+		case IProblem.JavadocAmbiguousConstructor:
+		case IProblem.JavadocUndefinedMethod:
+		case IProblem.JavadocAmbiguousMethod:
+		case IProblem.JavadocAmbiguousMethodReference:
+		case IProblem.JavadocParameterMismatch:
+		case IProblem.JavadocUndefinedType:
+		case IProblem.JavadocAmbiguousType:
+		case IProblem.JavadocInternalTypeNameProvided:
+		case IProblem.JavadocNoMessageSendOnArrayType:
+		case IProblem.JavadocNoMessageSendOnBaseType:
+		case IProblem.JavadocInheritedMethodHidesEnclosingName:
+		case IProblem.JavadocInheritedFieldHidesEnclosingName:
+		case IProblem.JavadocInheritedNameHidesEnclosingTypeName:
+		case ProblemReporter.JavadocNonStaticTypeFromStaticInvocation:  // internal problem ID in 3.1 maintenance branch
+		case IProblem.JavadocGenericMethodTypeArgumentMismatch:
+		case IProblem.JavadocNonGenericMethod:
+		case IProblem.JavadocIncorrectArityForParameterizedMethod:
+		case IProblem.JavadocParameterizedMethodArgumentTypeMismatch:
+		case IProblem.JavadocTypeArgumentsForRawGenericMethod:
+		case IProblem.JavadocGenericConstructorTypeArgumentMismatch:
+		case IProblem.JavadocNonGenericConstructor:
+		case IProblem.JavadocIncorrectArityForParameterizedConstructor:
+		case IProblem.JavadocParameterizedConstructorArgumentTypeMismatch:
+		case IProblem.JavadocTypeArgumentsForRawGenericConstructor:
+		case IProblem.JavadocNotVisibleField:
+		case IProblem.JavadocNotVisibleConstructor:
+		case IProblem.JavadocNotVisibleMethod:
+		case IProblem.JavadocNotVisibleType:
+			return CompilerOptions.InvalidJavadoc;
+			
+		case IProblem.JavadocUsingDeprecatedField:
+		case IProblem.JavadocUsingDeprecatedConstructor:
+		case IProblem.JavadocUsingDeprecatedMethod:
+		case IProblem.JavadocUsingDeprecatedType:
+			return CompilerOptions.InvalidJavadoc | CompilerOptions.UsingDeprecatedAPI;
+
+		case IProblem.JavadocMissingParamTag:
+		case IProblem.JavadocMissingReturnTag:
+		case IProblem.JavadocMissingThrowsTag:
+			return CompilerOptions.MissingJavadocTags;
+
+		case IProblem.JavadocMissing:
+			return CompilerOptions.MissingJavadocComments;
+	}
+	return 0;
+	
+}
+
 // use this private API when the compilation unit result can be found through the
 // reference context. Otherwise, use the other API taking a problem and a compilation result
 // as arguments
@@ -2074,8 +2120,8 @@
 		IProblem.IndirectAccessToStaticField,
 		new String[] {new String(field.declaringClass.readableName()), new String(field.name)},
 		new String[] {new String(field.declaringClass.shortReadableName()), new String(field.name)},
-		location.sourceStart,
-		fieldLocation(field, location));
+		fieldSourceStart(field, location),
+		fieldSourceEnd(field, location));
 }
 public void indirectAccessToStaticMethod(ASTNode location, MethodBinding method) {
 	this.handle(
@@ -2281,24 +2327,27 @@
 			problemConstructor = (ProblemMethodBinding) targetConstructor;
 			ParameterizedGenericMethodBinding substitutedConstructor = (ParameterizedGenericMethodBinding) problemConstructor.closestMatch;
 			shownConstructor = substitutedConstructor.original();
-			TypeBinding typeArgument = targetConstructor.parameters[0];
-			TypeVariableBinding typeParameter = (TypeVariableBinding) targetConstructor.parameters[1];
+			int augmentedLength = problemConstructor.parameters.length;
+			TypeBinding inferredTypeArgument = problemConstructor.parameters[augmentedLength-2];
+			TypeVariableBinding typeParameter = (TypeVariableBinding) problemConstructor.parameters[augmentedLength-1];
+			TypeBinding[] invocationArguments = new TypeBinding[augmentedLength-2]; // remove extra info from the end
+			System.arraycopy(problemConstructor.parameters, 0, invocationArguments, 0, augmentedLength-2);
 			this.handle(
 				IProblem.GenericConstructorTypeArgumentMismatch,
 				new String[] { 
 				        new String(shownConstructor.declaringClass.sourceName()),
 				        typesAsString(shownConstructor.isVarargs(), shownConstructor.parameters, false), 
 				        new String(shownConstructor.declaringClass.readableName()), 
-				        typesAsString(substitutedConstructor.isVarargs(), substitutedConstructor.parameters, false), 
-				        new String(typeArgument.readableName()), 
+				        typesAsString(false, invocationArguments, false), 
+				        new String(inferredTypeArgument.readableName()), 
 				        new String(typeParameter.sourceName), 
 				        parameterBoundAsString(typeParameter, false) },
 				new String[] { 
 				        new String(shownConstructor.declaringClass.sourceName()),
 				        typesAsString(shownConstructor.isVarargs(), shownConstructor.parameters, true), 
 				        new String(shownConstructor.declaringClass.shortReadableName()), 
-				        typesAsString(substitutedConstructor.isVarargs(), substitutedConstructor.parameters, true), 
-				        new String(typeArgument.shortReadableName()), 
+				        typesAsString(false, invocationArguments, true), 
+				        new String(inferredTypeArgument.shortReadableName()), 
 				        new String(typeParameter.sourceName), 
 				        parameterBoundAsString(typeParameter, true) },
 				sourceStart,
@@ -2453,6 +2502,7 @@
 public void invalidField(FieldReference fieldRef, TypeBinding searchedType) {
 	int id = IProblem.UndefinedField;
 	FieldBinding field = fieldRef.binding;
+	final int sourceStart= (int) (fieldRef.nameSourcePosition >> 32);
 	switch (field.problemId()) {
 		case NotFound :
 			id = IProblem.UndefinedField;
@@ -2462,8 +2512,13 @@
 */
 			break;
 		case NotVisible :
-			id = IProblem.NotVisibleField;
-			break;
+			this.handle(
+				IProblem.NotVisibleField,
+				new String[] {new String(fieldRef.token), new String(field.declaringClass.readableName())},
+				new String[] {new String(fieldRef.token), new String(field.declaringClass.shortReadableName())},
+				sourceStart,
+				fieldRef.sourceEnd);			
+			return;
 		case Ambiguous :
 			id = IProblem.AmbiguousField;
 			break;
@@ -2496,7 +2551,7 @@
 		id,
 		arguments,
 		arguments,
-		fieldRef.sourceStart,
+		sourceStart,
 		fieldRef.sourceEnd);
 }
 public void invalidField(NameReference nameRef, FieldBinding field) {
@@ -2506,8 +2561,15 @@
 			id = IProblem.UndefinedField;
 			break;
 		case NotVisible :
-			id = IProblem.NotVisibleField;
-			break;
+			char[] name = field.readableName();
+			name = CharOperation.lastSegment(name, '.');
+			this.handle(
+				IProblem.NotVisibleField,
+				new String[] {new String(name), new String(field.declaringClass.readableName())},
+				new String[] {new String(name), new String(field.declaringClass.shortReadableName())},
+				nameRef.sourceStart,
+				nameRef.sourceEnd);				
+			return;
 		case Ambiguous :
 			id = IProblem.AmbiguousField;
 			break;
@@ -2576,8 +2638,14 @@
 */
 			break;
 		case NotVisible :
-			id = IProblem.NotVisibleField;
-			break;
+			String fieldName = new String(nameRef.tokens[index]);
+			this.handle(
+				IProblem.NotVisibleField,
+				new String[] {fieldName, new String(field.declaringClass.readableName())},
+				new String[] {fieldName, new String(field.declaringClass.shortReadableName())},
+				nameRef.sourceStart, 
+				(int) nameRef.sourcePositions[index]);				
+			return;
 		case Ambiguous :
 			id = IProblem.AmbiguousField;
 			break;
@@ -2629,13 +2697,9 @@
 			if (problemMethod.closestMatch != null) {
 			    	shownMethod = problemMethod.closestMatch;
 					String closestParameterTypeNames = typesAsString(shownMethod.isVarargs(), shownMethod.parameters, false);
-					String parameterTypeNames = typesAsString(method.isVarargs(), method.parameters, false);
+					String parameterTypeNames = typesAsString(false, problemMethod.parameters, false);
 					String closestParameterTypeShortNames = typesAsString(shownMethod.isVarargs(), shownMethod.parameters, true);
-					String parameterTypeShortNames = typesAsString(method.isVarargs(), method.parameters, true);
-					if (closestParameterTypeShortNames.equals(parameterTypeShortNames)){
-						closestParameterTypeShortNames = closestParameterTypeNames;
-						parameterTypeShortNames = parameterTypeNames;
-					}
+					String parameterTypeShortNames = typesAsString(false, problemMethod.parameters, true);
 					this.handle(
 						IProblem.ParameterMismatch,
 						new String[] {
@@ -2686,24 +2750,27 @@
 			problemMethod = (ProblemMethodBinding) method;
 			ParameterizedGenericMethodBinding substitutedMethod = (ParameterizedGenericMethodBinding) problemMethod.closestMatch;
 			shownMethod = substitutedMethod.original();
-			TypeBinding typeArgument = method.parameters[0];
-			TypeVariableBinding typeParameter = (TypeVariableBinding) method.parameters[1];
+			int augmentedLength = problemMethod.parameters.length;
+			TypeBinding inferredTypeArgument = problemMethod.parameters[augmentedLength-2];
+			TypeVariableBinding typeParameter = (TypeVariableBinding) problemMethod.parameters[augmentedLength-1];
+			TypeBinding[] invocationArguments = new TypeBinding[augmentedLength-2]; // remove extra info from the end
+			System.arraycopy(problemMethod.parameters, 0, invocationArguments, 0, augmentedLength-2);
 			this.handle(
 				IProblem.GenericMethodTypeArgumentMismatch,
 				new String[] { 
 				        new String(shownMethod.selector),
 				        typesAsString(shownMethod.isVarargs(), shownMethod.parameters, false), 
 				        new String(shownMethod.declaringClass.readableName()), 
-				        typesAsString(substitutedMethod.isVarargs(), substitutedMethod.parameters, false), 
-				        new String(typeArgument.readableName()), 
+				        typesAsString(false, invocationArguments, false), 
+				        new String(inferredTypeArgument.readableName()), 
 				        new String(typeParameter.sourceName), 
 				        parameterBoundAsString(typeParameter, false) },
 				new String[] { 
 				        new String(shownMethod.selector),
 				        typesAsString(shownMethod.isVarargs(), shownMethod.parameters, true), 
 				        new String(shownMethod.declaringClass.shortReadableName()), 
-				        typesAsString(substitutedMethod.isVarargs(), substitutedMethod.parameters, true), 
-				        new String(typeArgument.shortReadableName()), 
+				        typesAsString(false, invocationArguments, true), 
+				        new String(inferredTypeArgument.shortReadableName()), 
 				        new String(typeParameter.sourceName), 
 				        parameterBoundAsString(typeParameter, true) },
 				(int) (messageSend.nameSourcePosition >>> 32),
@@ -2892,7 +2959,7 @@
 			id = IProblem.InheritedTypeHidesEnclosingName;
 			break;
 		case NonStaticReferenceInStaticContext :
-			id = IProblem.TypeVariableReferenceFromStaticContext;
+			id = IProblem.NonStaticTypeFromStaticInvocation;
 		    break;
 		case IllegalSuperTypeVariable : 
 		    id = IProblem.IllegalTypeVariableSuperReference;
@@ -3242,24 +3309,29 @@
 			problemConstructor = (ProblemMethodBinding) targetConstructor;
 			ParameterizedGenericMethodBinding substitutedConstructor = (ParameterizedGenericMethodBinding) problemConstructor.closestMatch;
 			shownConstructor = substitutedConstructor.original();
-			TypeBinding typeArgument = targetConstructor.parameters[0];
-			TypeVariableBinding typeParameter = (TypeVariableBinding) targetConstructor.parameters[1];
+			
+			int augmentedLength = problemConstructor.parameters.length;
+			TypeBinding inferredTypeArgument = problemConstructor.parameters[augmentedLength-2];
+			TypeVariableBinding typeParameter = (TypeVariableBinding) problemConstructor.parameters[augmentedLength-1];
+			TypeBinding[] invocationArguments = new TypeBinding[augmentedLength-2]; // remove extra info from the end
+			System.arraycopy(problemConstructor.parameters, 0, invocationArguments, 0, augmentedLength-2);
+			
 			this.handle(
 				IProblem.JavadocGenericConstructorTypeArgumentMismatch,
 				new String[] { 
 				        new String(shownConstructor.declaringClass.sourceName()),
 				        typesAsString(shownConstructor.isVarargs(), shownConstructor.parameters, false), 
 				        new String(shownConstructor.declaringClass.readableName()), 
-				        typesAsString(substitutedConstructor.isVarargs(), substitutedConstructor.parameters, false), 
-				        new String(typeArgument.readableName()), 
+				        typesAsString(false, invocationArguments, false), 
+				        new String(inferredTypeArgument.readableName()), 
 				        new String(typeParameter.sourceName), 
 				        parameterBoundAsString(typeParameter, false) },
 				new String[] { 
 				        new String(shownConstructor.declaringClass.sourceName()),
 				        typesAsString(shownConstructor.isVarargs(), shownConstructor.parameters, true), 
 				        new String(shownConstructor.declaringClass.shortReadableName()), 
-				        typesAsString(substitutedConstructor.isVarargs(), substitutedConstructor.parameters, true), 
-				        new String(typeArgument.shortReadableName()), 
+				        typesAsString(false, invocationArguments, true), 
+				        new String(inferredTypeArgument.shortReadableName()), 
 				        new String(typeParameter.sourceName), 
 				        parameterBoundAsString(typeParameter, true) },
 				sourceStart,
@@ -3372,9 +3444,6 @@
 		case Ambiguous :
 			id = IProblem.JavadocAmbiguousField;
 			break;
-		case InheritedNameHidesEnclosingName :
-			id = IProblem.JavadocInheritedFieldHidesEnclosingName;
-			break;
 		case NoError : // 0
 		default :
 			needImplementation(); // want to fail to see why we were here...
@@ -3437,31 +3506,31 @@
 		case Ambiguous :
 			id = IProblem.JavadocAmbiguousMethod;
 			break;
-		case InheritedNameHidesEnclosingName :
-			id = IProblem.JavadocInheritedMethodHidesEnclosingName;
-			break;
 		case ParameterBoundMismatch :
 			problemMethod = (ProblemMethodBinding) method;
 			ParameterizedGenericMethodBinding substitutedMethod = (ParameterizedGenericMethodBinding) problemMethod.closestMatch;
 			shownMethod = substitutedMethod.original();
-			TypeBinding typeArgument = method.parameters[0];
-			TypeVariableBinding typeParameter = (TypeVariableBinding) method.parameters[1];
+			int augmentedLength = problemMethod.parameters.length;
+			TypeBinding inferredTypeArgument = problemMethod.parameters[augmentedLength-2];
+			TypeVariableBinding typeParameter = (TypeVariableBinding) problemMethod.parameters[augmentedLength-1];
+			TypeBinding[] invocationArguments = new TypeBinding[augmentedLength-2]; // remove extra info from the end
+			System.arraycopy(problemMethod.parameters, 0, invocationArguments, 0, augmentedLength-2);
 			this.handle(
 				IProblem.JavadocGenericMethodTypeArgumentMismatch,
 				new String[] { 
 				        new String(shownMethod.selector),
 				        typesAsString(shownMethod.isVarargs(), shownMethod.parameters, false), 
 				        new String(shownMethod.declaringClass.readableName()), 
-				        typesAsString(substitutedMethod.isVarargs(), substitutedMethod.parameters, false), 
-				        new String(typeArgument.readableName()), 
+				        typesAsString(false, invocationArguments, false), 
+				        new String(inferredTypeArgument.readableName()), 
 				        new String(typeParameter.sourceName), 
 				        parameterBoundAsString(typeParameter, false) },
 				new String[] { 
 				        new String(shownMethod.selector),
 				        typesAsString(shownMethod.isVarargs(), shownMethod.parameters, true), 
 				        new String(shownMethod.declaringClass.shortReadableName()), 
-				        typesAsString(substitutedMethod.isVarargs(), substitutedMethod.parameters, true), 
-				        new String(typeArgument.shortReadableName()), 
+				        typesAsString(false, invocationArguments, true), 
+				        new String(inferredTypeArgument.shortReadableName()), 
 				        new String(typeParameter.sourceName), 
 				        parameterBoundAsString(typeParameter, true) },
 				(int) (messageSend.nameSourcePosition >>> 32),
@@ -3566,7 +3635,7 @@
 	this.handle(IProblem.JavadocInvalidParamTagTypeParameter, NoArgument, NoArgument, sourceStart, sourceEnd);
 }
 public void javadocInvalidReference(int sourceStart, int sourceEnd) {
-	this.handle(IProblem.JavadocInvalidReference, NoArgument, NoArgument, sourceStart, sourceEnd);
+	this.handle(IProblem.JavadocInvalidSeeReference, NoArgument, NoArgument, sourceStart, sourceEnd);
 }
 public void javadocInvalidSeeReferenceArgs(int sourceStart, int sourceEnd) {
 	this.handle(IProblem.JavadocInvalidSeeArgs, NoArgument, NoArgument, sourceStart, sourceEnd);
@@ -3605,6 +3674,9 @@
 			case InheritedNameHidesEnclosingName :
 				id = IProblem.JavadocInheritedNameHidesEnclosingTypeName;
 				break;
+			case NonStaticReferenceInStaticContext :
+				id = ProblemReporter.JavadocNonStaticTypeFromStaticInvocation; // internal problem ID in 3.1 maintenance branch
+			    break;
 			case NoError : // 0
 			default :
 				needImplementation(); // want to fail to see why we were here...
@@ -3656,7 +3728,7 @@
 }
 public void javadocMissingReference(int sourceStart, int sourceEnd, int modifiers){
 	if (javadocVisibility(this.options.reportInvalidJavadocTagsVisibility, modifiers))
-		this.handle(IProblem.JavadocMissingReference, NoArgument, NoArgument, sourceStart, sourceEnd);
+		this.handle(IProblem.JavadocMissingSeeReference, NoArgument, NoArgument, sourceStart, sourceEnd);
 }
 public void javadocMissingReturnTag(int sourceStart, int sourceEnd, int modifiers){
 	boolean overriding = (modifiers & (CompilerModifiers.AccImplementing|CompilerModifiers.AccOverriding)) != 0;
@@ -3954,8 +4026,8 @@
 			: IProblem.NeedToEmulateFieldWriteAccess,
 		new String[] {new String(field.declaringClass.readableName()), new String(field.name)},
 		new String[] {new String(field.declaringClass.shortReadableName()), new String(field.name)},
-		location.sourceStart,
-		location.sourceEnd);
+		fieldSourceStart(field, location),
+		fieldSourceEnd(field, location));
 }
 public void needToEmulateMethodAccess(
 	MethodBinding method, 
@@ -4075,8 +4147,8 @@
 		IProblem.NonStaticAccessToStaticField,
 		new String[] {new String(field.declaringClass.readableName()), new String(field.name)},
 		new String[] {new String(field.declaringClass.shortReadableName()), new String(field.name)},
-		location.sourceStart,
-		fieldLocation(field, location));
+		fieldSourceStart(field, location),
+		fieldSourceEnd(field, location));
 }
 public void nonStaticAccessToStaticMethod(ASTNode location, MethodBinding method) {
 	this.handle(
@@ -4773,8 +4845,8 @@
 		IProblem.NonStaticFieldFromStaticInvocation,
 		arguments,
 		arguments,
-		location.sourceStart,
-		fieldLocation(field, location)); 
+		fieldSourceStart(field,location),
+		fieldSourceEnd(field, location)); 
 }
 public void staticInheritedMethodConflicts(SourceTypeBinding type, MethodBinding concreteMethod, MethodBinding[] abstractMethods) {
 	this.handle(
@@ -4840,13 +4912,13 @@
 		superInterfaceRef.sourceStart,
 		superInterfaceRef.sourceEnd);
 }
-public void superinterfacesCollide(ReferenceBinding type, TypeDeclaration typeDecl, ReferenceBinding superType, ReferenceBinding inheritedSuperType) {
+public void superinterfacesCollide(TypeBinding type, ASTNode decl, TypeBinding superType, TypeBinding inheritedSuperType) {
 	this.handle(
 		IProblem.SuperInterfacesCollide,
 		new String[] {new String(superType.readableName()), new String(inheritedSuperType.readableName()), new String(type.sourceName())},
 		new String[] {new String(superType.shortReadableName()), new String(inheritedSuperType.shortReadableName()), new String(type.sourceName())},
-		typeDecl.sourceStart,
-		typeDecl.sourceEnd);
+		decl.sourceStart,
+		decl.sourceEnd);
 }
 public void superTypeCannotUseWildcard(SourceTypeBinding type, TypeReference superclass, TypeBinding superTypeBinding) {
 	String name = new String(type.sourceName());
@@ -5076,14 +5148,14 @@
 		location.sourceStart,
 		location.sourceEnd);
 }
-public void uninitializedBlankFinalField(FieldBinding binding, ASTNode location) {
-	String[] arguments = new String[] {new String(binding.readableName())};
+public void uninitializedBlankFinalField(FieldBinding field, ASTNode location) {
+	String[] arguments = new String[] {new String(field.readableName())};
 	this.handle(
 		IProblem.UninitializedBlankFinalField,
 		arguments,
 		arguments,
-		location.sourceStart,
-		fieldLocation(binding, location));
+		fieldSourceStart(field, location),
+		fieldSourceEnd(field, location));
 }
 public void uninitializedLocalVariable(LocalVariableBinding binding, ASTNode location) {
 	String[] arguments = new String[] {new String(binding.readableName())};
@@ -5171,6 +5243,15 @@
 		statement.sourceStart,
 		statement.sourceEnd);
 }
+public void unhandledWarningToken(Expression token) {
+	String[] arguments = new String[] { token.constant.stringValue() };
+	this.handle(
+		IProblem.UnhandledWarningToken,
+		arguments,
+		arguments,
+		token.sourceStart,
+		token.sourceEnd);
+}
 public void unresolvableReference(NameReference nameRef, Binding binding) {
 	int severity = Error;
 /* also need to check that the searchedType is the receiver type
@@ -5214,15 +5295,15 @@
 		castExpression.sourceStart,
 		castExpression.sourceEnd);
 }
-public void unsafeRawFieldAssignment(FieldBinding rawField, TypeBinding expressionType, ASTNode location) {
+public void unsafeRawFieldAssignment(FieldBinding field, TypeBinding expressionType, ASTNode location) {
 	this.handle(
 		IProblem.UnsafeRawFieldAssignment,
 		new String[] { 
-		        new String(expressionType.readableName()), new String(rawField.name), new String(rawField.declaringClass.readableName()), new String(rawField.declaringClass.erasure().readableName()) },
+		        new String(expressionType.readableName()), new String(field.name), new String(field.declaringClass.readableName()), new String(field.declaringClass.erasure().readableName()) },
 		new String[] { 
-		        new String(expressionType.shortReadableName()), new String(rawField.name), new String(rawField.declaringClass.shortReadableName()), new String(rawField.declaringClass.erasure().shortReadableName()) },
-		location.sourceStart,
-		location.sourceEnd);    
+		        new String(expressionType.shortReadableName()), new String(field.name), new String(field.declaringClass.shortReadableName()), new String(field.declaringClass.erasure().shortReadableName()) },
+		fieldSourceStart(field,location),
+		fieldSourceEnd(field, location)); 
 }
 public void unsafeRawGenericMethodInvocation(ASTNode location, MethodBinding rawMethod) {
     if (rawMethod.isConstructor()) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
index 70fc600..7565007 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
@@ -15,7 +15,7 @@
 4 = The type {0} is ambiguous
 5 = The type {0} is deprecated
 6 = The nested type {0} cannot be referenced using its binary name
-7 = The private type {0} is never used locally
+7 = The type {0} is never used locally
 
 15 = Incompatible operand types {0} and {1}
 16 = Incompatible conditional operand types {0} and {1}
@@ -57,13 +57,13 @@
 68 = Too many array dimensions. Maximum is 255
 69 = The code of constructor {0}({1}) is exceeding the 65535 bytes limit
 70 = {0} cannot be resolved or is not a field
-71 = The field {0} is not visible
+71 = The field {1}.{0} is not visible
 72 = The field {0} is ambiguous
 73 = The field {0}.{1} is deprecated
 74 = Cannot make a static reference to the non-static field {0}
 75 = Cannot reference a field before it is defined
 76 = The static field {0}.{1} should be accessed in a static way
-77 = The private field {0}.{1} is never read locally
+77 = The field {0}.{1} is never read locally
 78 = The static field {0}.{1} should be accessed directly
 79 = Unqualified access to the field {0}.{1} 
 80 = The final field {0}.{1} cannot be assigned
@@ -96,14 +96,14 @@
 115 = The method {1}({2}) in the type {0} is not applicable for the arguments ({3})
 116 = Cannot invoke {1}({2}) on the array type {0}
 117 = The static method {1}({2}) from the type {0} should be accessed in a static way
-118 = The private method {1}({2}) from the type {0} is never used locally
+118 = The method {1}({2}) from the type {0} is never used locally
 119 = The static method {1}({2}) from the type {0} should be accessed directly 
 
 130 = The constructor {0}({1}) is undefined
 131 = The constructor {0}({1}) is not visible
 132 = The constructor {0}({1}) is ambiguous
 133 = The constructor {0}({1}) is deprecated
-134 = The private constructor {0}({1}) is never used locally
+134 = The constructor {0}({1}) is never used locally
 135 = Cannot refer to an instance field {0} while explicitly invoking a constructor
 136 = Cannot refer to an instance method while explicitly invoking a constructor
 137 = Recursive constructor invocation {0}({1})
@@ -359,6 +359,7 @@
 460 = Empty block should be documented
 
 ### DOC 
+468 = Cannot make a static reference to the non-static type variable {0}
 469 = Invalid param tag type parameter name
 470 = Unexpected tag
 471 = Missing tag for parameter {0}
@@ -403,18 +404,18 @@
 510 = The type {0} is defined in an inherited type and an enclosing scope
 511 = {0} is an ambiguous method reference or is not a field
 512 = Missing closing brace for inline tag
-513 = Missing #: "{0}"
-514 = Malformed reference (missing end space separator)
-515 = Missing return type description
-516 = Only static field reference is allowed for @value tag
-517 = Unexpected text
-518 = Invalid param tag name
-519 = Javadoc: 
+513 = Malformed reference (missing end space separator)
+514 = Javadoc: 
+515 = Missing #: "{0}"
+516 = Missing return type description
+517 = Only static field reference is allowed for @value tag
+518 = Unexpected text
+519 = Invalid param tag name
 
 ### GENERICS
 520 = Duplicate type parameter {0}
 521 = Cannot refer to the type parameter {0} as a supertype
-522 = Cannot make a static reference to the type parameter {0}
+522 = Cannot make a static reference to the non-static type {0}
 523 = The type java.lang.Object cannot be declared as a generic
 524 = The type {0} is not generic; it cannot be parameterized with arguments <{1}>
 525 = Incorrect number of arguments for type {0}; it cannot be parameterized with arguments <{1}>
@@ -435,8 +436,8 @@
 540 = Bound mismatch: The constructor {0}({1}) of type {2} is not applicable for the arguments ({3}). The wildcard parameter {5} has no lower bound, and may actually be more restrictive than argument {4}
 541 = Bound mismatch: The method {0}({1}) of type {2} is not applicable for the arguments ({3}). The wildcard parameter {5} has no lower bound, and may actually be more restrictive than argument {4}
 542 = Bound mismatch: Cannot assign expression of type {0} to wildcard type {1}. The wildcard type has no lower bound, and may actually be more restrictive than expression type
-543 = Bound mismatch: The generic method {0}({1}) of type {2} is not applicable for the arguments ({3}) since the type {4} is not a valid substitute for the bounded parameter <{5} extends {6}>
-544 = Bound mismatch: The generic constructor {0}({1}) of type {2} is not applicable for the arguments ({3}) since the type {4} is not a valid substitute for the bounded parameter <{5} extends {6}>
+543 = Bound mismatch: The generic method {0}({1}) of type {2} is not applicable for the arguments ({3}). The inferred type {4} is not a valid substitute for the bounded parameter <{5} extends {6}>
+544 = Bound mismatch: The generic constructor {0}({1}) of type {2} is not applicable for the arguments ({3}). The inferred type {4} is not a valid substitute for the bounded parameter <{5} extends {6}>
 545 = Type safety: The cast from {0} to {1} is actually checking against the erased type {2}
 546 = Cannot perform instanceof check against parameterized type {0}. Use instead its raw form {1} since generic type information will be erased at runtime
 547 = Cannot perform instanceof check against type parameter {0}. Use instead its erasure {1} since generic type information will be erased at runtime
@@ -456,7 +457,7 @@
 561 = The member type {0}<{1}> must be qualified with a parameterized type, since it is not static
 562 = The member type {0} must be parameterized, since it is qualified with a parameterized type
 563 = The member type {0} cannot be qualified with a parameterized type, since it is static. Remove arguments from qualifying type {1}
-564 = Bound conflict: {0} is inherited with conflicting arguments
+###[obsolete] 564 = Bound conflict: {0} is inherited with conflicting arguments
 565 = Duplicate methods named {0} with the parameters ({2}) and ({3}) are defined by the type {1}
 566 = Cannot allocate the member type {0} using a parameterized compound name; use its simple name and an enclosing instance of type {1}
 567 = Duplicate bound {0}
@@ -511,6 +512,7 @@
 628 = The deprecated field {0}.{1} should be annotated with @Deprecated
 629 = The deprecated method {0}({1}) of type {2} should be annotated with @Deprecated
 630 = The deprecated type {0} should be annotated with @Deprecated
+631 = Unhandled warning token {0}
 
 ### CORRUPTED BINARIES
 700 = The class file {0} contains a signature ''{1}'' ill-formed at position {2}
@@ -532,6 +534,7 @@
 759 = The field {0}.{1} cannot be referenced from an enum case label; only enum constants can be used in enum switch
 760 = Illegal modifier for the enum constructor; only private is permitted.
 761 = The enum constant {0}.{1} has no corresponding case label
+762 = Cannot refer to the static enum field {0}.{1} within an initializer
 
 ### VARARGS
 800 = Extended dimensions are illegal for a variable argument
@@ -540,12 +543,12 @@
 803 = Varargs methods should only override other varargs methods unlike {2}.{0}({1}) and {4}.{0}({3})
 
 ### GENERIC JAVADOC
-850 = Bound mismatch: The generic method {0}({1}) of type {2} is not applicable for the arguments ({3}) since the type {4} is not a valid substitute for the bounded parameter <{5} extends {6}>
+850 = Bound mismatch: The generic method {0}({1}) of type {2} is not applicable for the arguments ({3}). The inferred type {4} is not a valid substitute for the bounded parameter <{5} extends {6}>
 851 = The method {0}({1}) of type {2} is not generic; it cannot be parameterized with arguments <{3}>
 852 = Incorrect number of type arguments for generic method <{3}>{0}({1}) of type {2}; it cannot be parameterized with arguments <{4}>
 853 = The parameterized method <{3}>{0}({1}) of type {2} is not applicable for the arguments ({4})
 854 = The method {0}({1}) of raw type {2} is no longer generic; it cannot be parameterized with arguments <{3}>
-855 = Bound mismatch: The generic constructor {0}({1}) of type {2} is not applicable for the arguments ({3}) since the type {4} is not a valid substitute for the bounded parameter <{5} extends {6}>
+855 = Bound mismatch: The generic constructor {0}({1}) of type {2} is not applicable for the arguments ({3}). The inferred type {4} is not a valid substitute for the bounded parameter <{5} extends {6}>
 856 = The constructor {0}({1}) of type {2} is not generic; it cannot be parameterized with arguments <{3}>
 857 = Incorrect number of type arguments for generic constructor <{3}>{0}({1}) of type {2}; it cannot be parameterized with arguments <{4}>
 858 = The parameterized constructor <{3}>{0}({1}) of type {2} is not applicable for the arguments ({4})
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Messages.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Messages.java
index 67c23f7..9adcdf5 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Messages.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Messages.java
@@ -71,7 +71,7 @@
 	private static String[] nlSuffixes;
 	private static final String EXTENSION = ".properties"; //$NON-NLS-1$
 
-	private static final String BUNDLE_NAME = "org.eclipse.jdt.internal.compiler.util.messages";//$NON-NLS-1$
+	private static final String BUNDLE_NAME = "org.eclipse.jdt.internal.compiler.messages";//$NON-NLS-1$
 
 	private Messages() {
 		// Do not instantiate
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Util.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Util.java
index 63cb886..a43f75b 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Util.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Util.java
@@ -29,7 +29,6 @@
 
 	private static final int DEFAULT_READING_SIZE = 8192;
 	public static String LINE_SEPARATOR = System.getProperty("line.separator"); //$NON-NLS-1$
-	public static char[] LINE_SEPARATOR_CHARS = LINE_SEPARATOR.toCharArray();
 	
 	/**
 	 * Returns the given bytes as a char array using a given encoding (null means platform default).
diff --git a/org.eclipse.jdt.core/component.xml b/org.eclipse.jdt.core/component.xml
new file mode 100644
index 0000000..c0ce337
--- /dev/null
+++ b/org.eclipse.jdt.core/component.xml
@@ -0,0 +1,308 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<component xmlns="http://eclipse.org/component"
+   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+   xsi:schemaLocation="http://eclipse.org/component ../component.xsd "
+   name="org.eclipse.jdt.core">
+ <plugin id="org.eclipse.jdt.core" />
+
+ <package name="org.eclipse.jdt.core">
+   <type name="BindingKey" subclass="false" />
+   <type name="BufferChangedEvent" subclass="false" instantiate="false"/>
+   <type name="ClasspathContainerInitializer" instantiate="false"/>
+   <type name="ClasspathVariableInitializer" instantiate="false"/>
+   <type name="CompletionContext" subclass="false" instantiate="false"/>
+   <type name="CompletionProposal" subclass="false" instantiate="false"/>
+   <type name="CompletionRequestor" instantiate="false"/>
+   <type name="CompletionRequestorAdapter"/>
+   <type name="CorrectionEngine" subclass="false"/>
+   <type name="ElementChangedEvent" subclass="false" instantiate="false"/>
+   <type name="Flags" subclass="false" instantiate="false"/>
+   <type name="IAccessRule"/>
+   <type name="IBuffer"/>
+   <type name="IBufferChangedListener"/>
+   <type name="IBufferFactory"/>
+   <type name="IClassFile" implement="false"/>
+   <type name="IClasspathAttribute" implement="false"/>
+   <type name="IClasspathContainer" implement="false"/>
+   <type name="IClasspathEntry" implement="false"/>
+   <type name="ICodeAssist" implement="false"/>
+   <type name="ICodeCompletionRequestor"/>
+   <type name="ICodeFormatter" implement="false"/>
+   <type name="ICompilationUnit" implement="false"/>
+   <type name="ICompletionRequestor"/>
+   <type name="ICorrectionRequestor" implement="false"/>
+   <type name="IElementChangedListener"/>
+   <type name="IField" implement="false"/>
+   <type name="IImportContainer" implement="false"/>
+   <type name="IImportDeclaration" implement="false"/>
+   <type name="IInitializer" implement="false"/>
+   <type name="IJavaElement" implement="false"/>
+   <type name="IJavaElementDelta" implement="false"/>
+   <type name="IJavaModel" implement="false"/>
+   <type name="IJavaModelMarker" implement="false"/>
+   <type name="IJavaModelStatus" implement="false"/>
+   <type name="IJavaModelStatusConstants" implement="false"/>
+   <type name="IJavaProject" implement="false"/>
+   <type name="ILocalVariable" implement="false"/>
+   <type name="IMember" implement="false"/>
+   <type name="IMethod" implement="false"/>
+   <type name="IOpenable" implement="false"/>
+   <type name="IPackageDeclaration" implement="false"/>
+   <type name="IPackageFragment" implement="false"/>
+   <type name="IPackageFragmentRoot" implement="false"/>
+   <type name="IParent" implement="false"/>
+   <type name="IProblemRequestor"/>
+   <type name="IRegion" implement="false"/>
+   <type name="ISourceManipulation" implement="false"/>
+   <type name="ISourceRange" implement="false"/>
+   <type name="ISourceReference" implement="false"/>
+   <type name="IType" implement="false"/>
+   <type name="ITypeHierarchy" implement="false"/>
+   <type name="ITypeHierarchyChangedListener"/>
+   <type name="ITypeParameter" implement="false"/>
+   <type name="IWorkingCopy" implement="false"/>
+   <type name="JavaConventions" subclass="false" instantiate="false"/>
+   <type name="JavaCore" subclass="false" instantiate="false"/>
+   <type name="JavaModelException" subclass="false" instantiate="false"/>
+   <type name="NamingConventions" subclass="false" instantiate="false"/>
+   <type name="Signature" subclass="false" instantiate="false"/>
+   <type name="ToolFactory" subclass="false" instantiate="false"/>
+   <type name="WorkingCopyOwner" instantiate="false"/>
+ </package>
+ <package name="org.eclipse.jdt.core.compiler">
+   <type name="IScanner" implement="false"/>
+   <type name="ITerminalSymbols" implement="false"/>
+   <type name="CharOperation" subclass="false" instantiate="false"/>
+   <type name="InvalidInputException" subclass="false" instantiate="false"/>
+   <type name="IProblem" implement="false"/>
+ </package>
+ <package name="org.eclipse.jdt.core.dom">
+   <type name="AbstractTypeDeclaration" instantiate="false"/>
+   <type name="Annotation" instantiate="false"/>
+   <type name="AnnotationTypeDeclaration" instantiate="false"/>
+   <type name="AnnotationTypeMemberDeclaration" instantiate="false"/>
+   <type name="AnonymousClassDeclaration" instantiate="false"/>
+   <type name="ArrayAccess" instantiate="false"/>
+   <type name="ArrayCreation" instantiate="false"/>
+   <type name="ArrayInitializer" instantiate="false"/>
+   <type name="ArrayType" instantiate="false"/>
+   <type name="AssertStatement" instantiate="false"/>
+   <type name="Assignment" instantiate="false"/>
+   <type name="AST" subclass="false" instantiate="false"/>
+   <type name="ASTConverter" reference="false"/>
+   <type name="ASTMatcher"/>
+   <type name="ASTNode" instantiate="false"/>
+   <type name="ASTParser" instantiate="false"/>
+   <type name="ASTRequestor" instantiate="false"/>
+   <type name="ASTSyntaxErrorPropagator" reference="false"/>
+   <type name="ASTVisitor"/>
+   <type name="BindingComparator" reference="false"/>
+   <type name="BindingResolver" reference="false"/>
+   <type name="Block" instantiate="false"/>
+   <type name="BlockComment" subclass="false" instantiate="false"/>
+   <type name="BodyDeclaration" instantiate="false"/>
+   <type name="BooleanLiteral" instantiate="false"/>
+   <type name="BreakStatement" instantiate="false"/>
+   <type name="CastExpression" instantiate="false"/>
+   <type name="CatchClause" instantiate="false"/>
+   <type name="CharacterLiteral" instantiate="false"/>
+   <type name="ChildListPropertyDescriptor" subclass="false" instantiate="false"/>
+   <type name="ChildPropertyDescriptor" subclass="false" instantiate="false"/>
+   <type name="ClassInstanceCreation" instantiate="false"/>
+   <type name="Comment" instantiate="false"/>
+   <type name="CompilationUnit" instantiate="false"/>
+   <type name="CompilationUnitResolver" reference="false"/>
+   <type name="ConditionalExpression" instantiate="false"/>
+   <type name="ConstructorInvocation" instantiate="false"/>
+   <type name="ContinueStatement" instantiate="false"/>
+   <type name="DefaultASTVisitor" reference="false"/>
+   <type name="DefaultBindingResolver" reference="false"/>
+   <type name="DefaultCommentMapper" reference="false"/>
+   <type name="DocCommentParser" reference="false"/>
+   <type name="DoStatement" instantiate="false"/>
+   <type name="EmptyStatement" instantiate="false"/>
+   <type name="EnhancedForStatement" instantiate="false"/>
+   <type name="EnumConstantDeclaration" instantiate="false"/>
+   <type name="EnumDeclaration" instantiate="false"/>
+   <type name="Expression" instantiate="false"/>
+   <type name="ExpressionStatement" instantiate="false"/>
+   <type name="FieldAccess" instantiate="false"/>
+   <type name="FieldDeclaration" instantiate="false"/>
+   <type name="ForStatement" instantiate="false"/>
+   <type name="IBinding" instantiate="false" implement="false"/>
+   <type name="IDocElement" reference="false"/>
+   <type name="IExtendedModifier" instantiate="false"/>
+   <type name="IfStatement" instantiate="false"/>
+   <type name="IMethodBinding" instantiate="false" implement="false"/>
+   <type name="ImportDeclaration" instantiate="false"/>
+   <type name="InfixExpression" instantiate="false"/>
+   <type name="Initializer" instantiate="false"/>
+   <type name="InstanceofExpression" instantiate="false"/>
+   <type name="InternalASTRewrite" reference="false"/>
+   <type name="IPackageBinding" implement="false"/>
+   <type name="ITypeBinding" implement="false"/>
+   <type name="IVariableBinding" implement="false"/>
+   <type name="Javadoc" instantiate="false"/>
+   <type name="LabeledStatement" instantiate="false"/>
+   <type name="LineComment" instantiate="false" subclass="false"/>
+   <type name="MarkerAnnotation" instantiate="false"/>
+   <type name="MemberRef" instantiate="false"/>
+   <type name="MemberValuePair" instantiate="false"/>
+   <type name="Message" instantiate="false"/>
+   <type name="MethodBinding" reference="false"/>
+   <type name="MethodDeclaration" instantiate="false"/>
+   <type name="MethodInvocation" instantiate="false"/>
+   <type name="MethodRef" instantiate="false"/>
+   <type name="MethodRefParameter" instantiate="false"/>
+   <type name="Modifier" instantiate="false" subclass="false"/>
+   <type name="NaiveASTFlattener" reference="false"/>
+   <type name="Name" instantiate="false"/>
+   <type name="NodeEventHandler" reference="false"/>
+   <type name="NodeSearcher" reference="false"/>
+   <type name="NormalAnnotation" instantiate="false"/>
+   <type name="NullLiteral" instantiate="false"/>
+   <type name="NumberLiteral" instantiate="false"/>
+   <type name="PackageBinding" reference="false"/>
+   <type name="PackageDeclaration" instantiate="false"/>
+   <type name="ParameterizedType" instantiate="false"/>
+   <type name="ParenthesizedExpression" instantiate="false"/>
+   <type name="PostfixExpression" instantiate="false"/>
+   <type name="PrefixExpression" instantiate="false"/>
+   <type name="PrimitiveType" instantiate="false"/>
+   <type name="QualifiedName" instantiate="false"/>
+   <type name="QualifiedType" instantiate="false"/>
+   <type name="ReturnStatement" instantiate="false"/>
+   <type name="SimpleName" instantiate="false"/>
+   <type name="SimplePropertyDescriptor" subclass="false" instantiate="false"/>
+   <type name="SimpleType" instantiate="false"/>
+   <type name="SingleMemberAnnotation" instantiate="false"/>
+   <type name="SingleVariableDeclaration" instantiate="false"/>
+   <type name="Statement" instantiate="false"/>
+   <type name="StringLiteral" instantiate="false"/>
+   <type name="StructuralPropertyDescriptor" subclass="false" instantiate="false"/>
+   <type name="SuperConstructorInvocation" instantiate="false"/>
+   <type name="SuperFieldAccess" instantiate="false"/>
+   <type name="SuperMethodInvocation" instantiate="false"/>
+   <type name="SwitchCase" instantiate="false"/>
+   <type name="SwitchStatement" instantiate="false"/>
+   <type name="SynchronizedStatement" instantiate="false"/>
+   <type name="TagElement" instantiate="false" subclass="false"/>
+   <type name="TextElement" instantiate="false" subclass="false"/>
+   <type name="ThisExpression" instantiate="false"/>
+   <type name="ThrowStatement" instantiate="false"/>
+   <type name="TryStatement" instantiate="false"/>
+   <type name="Type" instantiate="false"/>
+   <type name="TypeBinding" reference="false"/>
+   <type name="TypeDeclaration" instantiate="false"/>
+   <type name="TypeDeclarationStatement" instantiate="false"/>
+   <type name="TypeLiteral" instantiate="false"/>
+   <type name="TypeParameter" instantiate="false"/>
+   <type name="VariableBinding" reference="false"/>
+   <type name="VariableDeclaration" instantiate="false"/>
+   <type name="VariableDeclarationExpression" instantiate="false"/>
+   <type name="VariableDeclarationFragment" instantiate="false"/>
+   <type name="VariableDeclarationStatement" instantiate="false"/>
+   <type name="WhileStatement" instantiate="false"/>
+   <type name="WildcardType" instantiate="false"/>
+ </package>
+ <package name="org.eclipse.jdt.core.dom.rewrite">
+   <type name="ASTRewrite" subclass="false" instantiate="false"/>
+   <type name="ITrackedNodePosition" implement="false"/>
+   <type name="ListRewrite" subclass="false"/>
+   <type name="TargetSourceRangeComputer"/> 
+ </package>
+ <package name="org.eclipse.jdt.core.eval">
+   <type name="ICodeSnippetRequestor"/>
+   <type name="IEvaluationContext" implement="false"/>
+   <type name="IGlobalVariable" implement="false"/>   
+ </package>
+ <package name="org.eclipse.jdt.core.formatter">
+   <type name="CodeFormatter"/>
+   <type name="DefaultCodeFormatterConstants" subclass="false" instantiate="false"/>
+ </package>
+ <package name="org.eclipse.jdt.core.jdom">
+   <type name="DOMException"/>
+   <type name="DOMFactory" subclass="false"/>
+   <type name="IDOMCompilationUnit" implement="false"/>
+   <type name="IDOMFactory" implement="false"/>
+   <type name="IDOMField" implement="false"/>
+   <type name="IDOMImport" implement="false"/>
+   <type name="IDOMInitializer" implement="false"/>
+   <type name="IDOMMember" implement="false"/>
+   <type name="IDOMMethod" implement="false"/>
+   <type name="IDOMNode" implement="false"/>
+   <type name="IDOMPackage" implement="false"/>
+   <type name="IDOMType" implement="false"/> 
+ </package>
+ <package name="org.eclipse.jdt.core.search">
+   <type name="FieldDeclarationMatch"/>
+   <type name="FieldReferenceMatch"/>
+   <type name="IJavaSearchConstants" implement="false"/>
+   <type name="IJavaSearchResultCollector"/>
+   <type name="IJavaSearchScope"/>
+   <type name="ISearchPattern"/>
+   <type name="ITypeNameRequestor"/>
+   <type name="LocalVariableDeclarationMatch"/>
+   <type name="LocalVariableReferenceMatch"/>
+   <type name="MethodDeclarationMatch"/>
+   <type name="MethodReferenceMatch"/>
+   <type name="PackageDeclarationMatch"/>
+   <type name="PackageReferenceMatch"/>
+   <type name="SearchDocument" instantiate="false"/>
+   <type name="SearchEngine" subclass="false"/>
+   <type name="SearchMatch"/>
+   <type name="SearchParticipant" instantiate="false"/>
+   <type name="SearchPattern" instantiate="false"/>
+   <type name="SearchRequestor" instantiate="false"/>
+   <type name="TypeDeclarationMatch"/>
+   <type name="TypeNameRequestor" instantiate="false"/>
+   <type name="TypeParameterDeclarationMatch"/>
+   <type name="TypeParameterReferenceMatch"/>
+   <type name="TypeReferenceMatch"/>
+ </package>
+ <package name="org.eclipse.jdt.core.util">
+   <type name="ByteCodeVisitorAdapter"/>
+   <type name="ClassFileBytesDisassembler"/>
+   <type name="ClassFormatException"/>
+   <type name="CompilationUnitSorter" subclass="false" instantiate="false"/>
+   <type name="IAnnotation"/>
+   <type name="IAnnotationComponent"/>
+   <type name="IAnnotationComponentValue"/>
+   <type name="IAnnotationDefaultAttribute"/>
+   <type name="IAttributeNamesConstants" implement="false"/>
+   <type name="IBytecodeVisitor" implement="false"/>
+   <type name="IClassFileAttribute"/>
+   <type name="IClassFileDisassembler"/>
+   <type name="IClassFileReader"/>
+   <type name="ICodeAttribute"/>
+   <type name="IConstantPool"/>
+   <type name="IConstantPoolConstant" implement="false"/>
+   <type name="IConstantPoolEntry"/>
+   <type name="IConstantValueAttribute"/>
+   <type name="IEnclosingMethodAttribute"/>
+   <type name="IExceptionAttribute"/>
+   <type name="IExceptionTableEntry"/>
+   <type name="IFieldInfo"/>
+   <type name="IInnerClassesAttribute"/>
+   <type name="IInnerClassesAttributeEntry"/>
+   <type name="ILineNumberAttribute"/>
+   <type name="ILocalVariableAttribute"/>
+   <type name="ILocalVariableTableEntry"/>
+   <type name="ILocalVariableTypeTableAttribute"/>
+   <type name="ILocalVariableTypeTableEntry"/>
+   <type name="IMethodInfo"/>
+   <type name="IModifierConstants" implement="false"/>
+   <type name="IOpcodeMnemonics" implement="false"/>
+   <type name="IParameterAnnotation"/>
+   <type name="IRuntimeInvisibleAnnotationsAttribute"/>
+   <type name="IRuntimeInvisibleParameterAnnotationsAttribute"/>
+   <type name="IRuntimeVisibleAnnotationsAttribute"/>
+   <type name="IRuntimeVisibleParameterAnnotationsAttribute"/>
+   <type name="ISignatureAttribute"/>
+   <type name="ISourceAttribute"/>
+   <type name="IVerificationTypeInfo"/>
+   <type name="OpcodeStringValues" subclass="false" instantiate="false"/>
+ </package>
+ 
+<component-depends unrestricted="true"/>
+</component>
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java
index 254116f..3d460c4 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java
@@ -58,6 +58,7 @@
 	protected AST ast;
 	protected Comment[] commentsTable;
 	char[] compilationUnitSource;
+	int compilationUnitSourceLength;
 	protected DocCommentParser docParser;
 	// comments
 	protected boolean insideComments;
@@ -360,8 +361,6 @@
 			setModifiers(initializer, oldInitializer);
 			initializer.setSourceRange(oldInitializer.declarationSourceStart, oldInitializer.sourceEnd - oldInitializer.declarationSourceStart + 1);
 			// The javadoc comment is now got from list store in compilation unit declaration
-//			setJavaDocComment(initializer);
-//			initializer.setJavadoc(convert(oldInitializer.javadoc));
 			convert(oldInitializer.javadoc, initializer);
 			bodyDeclarations.add(initializer);
 			return;
@@ -550,11 +549,14 @@
 		}
 		
 		// The javadoc comment is now got from list store in compilation unit declaration
-		convert(methodDeclaration.javadoc, methodDecl);
 		if (this.resolveBindings) {
 			recordNodes(methodDecl, methodDeclaration);
 			recordNodes(methodName, methodDeclaration);
-			methodDecl.resolveBinding();
+			if (methodDecl.resolveBinding() != null) {
+				convert(methodDeclaration.javadoc, methodDecl);
+			}
+		} else {
+			convert(methodDeclaration.javadoc, methodDecl);
 		}
 		return methodDecl;
 	}	
@@ -761,7 +763,7 @@
 			int previousSearchStart = end;
 			ArrayType componentType = (ArrayType) type.getParent();
 			for (int i = 0; i < dimensionsLength; i++) {
-				previousSearchStart = retrieveRightBracketPosition(previousSearchStart + 1, this.compilationUnitSource.length);
+				previousSearchStart = retrieveRightBracketPosition(previousSearchStart + 1, this.compilationUnitSourceLength);
 				componentType.setSourceRange(start, previousSearchStart - start + 1);
 				componentType = (ArrayType) componentType.getParent();
 			}
@@ -817,7 +819,7 @@
 			assertStatement.setMessage(convert(exceptionArgument));
 		}
 		int start = statement.sourceStart;
-		int sourceEnd = retrieveEndingSemiColonPosition(end, this.compilationUnitSource.length);
+		int sourceEnd = retrieveEndingSemiColonPosition(end, this.compilationUnitSourceLength);
 		assertStatement.setSourceRange(start, sourceEnd - start + 1);
 		return assertStatement;
 	}
@@ -1122,8 +1124,16 @@
 	
 	public CompilationUnit convert(org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration unit, char[] source) {
 		this.compilationUnitSource = source;
-		this.scanner.setSource(unit.compilationResult);
+		this.compilationUnitSourceLength = source.length;
+		this.scanner.setSource(source, unit.compilationResult);
 		CompilationUnit compilationUnit = new CompilationUnit(this.ast);
+
+		// Parse comments
+		int[][] comments = unit.comments;
+		if (comments != null) {
+			buildCommentsTable(compilationUnit, comments);
+		}
+
 		// handle the package declaration immediately
 		// There is no node corresponding to the package declaration
 		if (this.resolveBindings) {
@@ -1141,12 +1151,6 @@
 			}
 		}
 
-		// Parse comments
-		int[][] comments = unit.comments;
-		if (comments != null) {
-			buildCommentsTable(compilationUnit, comments);
-		}
-
 		org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] types = unit.types;
 		if (types != null) {
 			int typesLength = types.length;
@@ -1168,11 +1172,12 @@
 		int problemLength = unit.compilationResult.problemCount;
 		if (problemLength != 0) {
 			IProblem[] resizedProblems = null;
-			final IProblem[] problems = unit.compilationResult.problems;
-			if (problems.length == problemLength) {
+			final IProblem[] problems = unit.compilationResult.getProblems();
+			final int realProblemLength=problems.length;
+			if (realProblemLength == problemLength) {
 				resizedProblems = problems;
 			} else {
-				System.arraycopy(problems, 0, (resizedProblems = new IProblem[problemLength]), 0, problemLength);
+				System.arraycopy(problems, 0, (resizedProblems = new IProblem[realProblemLength]), 0, realProblemLength);
 			}
 			ASTSyntaxErrorPropagator syntaxErrorPropagator = new ASTSyntaxErrorPropagator(resizedProblems);
 			compilationUnit.accept(syntaxErrorPropagator);
@@ -1227,6 +1232,9 @@
 				break;
 		}
 		assignment.setRightHandSide(convert(expression.expression));
+		if (this.resolveBindings) {
+			recordNodes(assignment, expression);
+		}
 		return assignment;
 	}
 
@@ -1323,11 +1331,13 @@
 		} else {
 			enumConstantDeclaration.setSourceRange(declarationSourceStart, declarationSourceEnd - declarationSourceStart + 1);
 		}
+		setModifiers(enumConstantDeclaration, enumConstant);
 		if (this.resolveBindings) {
 			recordNodes(enumConstantDeclaration, enumConstant);
 			recordNodes(typeName, enumConstant);
 			enumConstantDeclaration.resolveVariable();
 		}
+		convert(enumConstant.javadoc, enumConstantDeclaration);
 		return enumConstantDeclaration;
 	}
 
@@ -1744,6 +1754,29 @@
 			}
 		}
 	}
+
+	public void convert(org.eclipse.jdt.internal.compiler.ast.Javadoc javadoc, PackageDeclaration packageDeclaration) {
+		if (ast.apiLevel == AST.JLS3 && packageDeclaration.getJavadoc() == null) {
+			if (javadoc != null) {
+				if (this.commentMapper == null || !this.commentMapper.hasSameTable(this.commentsTable)) {
+					this.commentMapper = new DefaultCommentMapper(this.commentsTable);
+				}
+				Comment comment = this.commentMapper.getComment(javadoc.sourceStart);
+				if (comment != null && comment.isDocComment() && comment.getParent() == null) {
+					Javadoc docComment = (Javadoc) comment;
+					if (this.resolveBindings) {
+						recordNodes(docComment, javadoc);
+						// resolve member and method references binding
+						Iterator tags = docComment.tags().listIterator();
+						while (tags.hasNext()) {
+							recordNodes(javadoc, (TagElement) tags.next());
+						}
+					}
+					packageDeclaration.setJavadoc(docComment);
+				}
+			}
+		}
+	}
 	
 	public LabeledStatement convert(org.eclipse.jdt.internal.compiler.ast.LabeledStatement statement) {
 		LabeledStatement labeledStatement = new LabeledStatement(this.ast);
@@ -2621,6 +2654,8 @@
 		if (this.resolveBindings) {
 			recordNodes(packageDeclaration, importReference);
 		}
+		// Set javadoc
+		convert(compilationUnitDeclaration.javadoc, packageDeclaration);
 		return packageDeclaration;
 	}
 	
@@ -2660,15 +2695,18 @@
 		VariableDeclarationFragment variableDeclarationFragment = convertToVariableDeclarationFragment(fieldDecl);
 		final FieldDeclaration fieldDeclaration = new FieldDeclaration(this.ast);
 		fieldDeclaration.fragments().add(variableDeclarationFragment);
+		IVariableBinding binding = null;
 		if (this.resolveBindings) {
 			recordNodes(variableDeclarationFragment, fieldDecl);
-			variableDeclarationFragment.resolveBinding();
+			binding = variableDeclarationFragment.resolveBinding();
 		}
 		fieldDeclaration.setSourceRange(fieldDecl.declarationSourceStart, fieldDecl.declarationEnd - fieldDecl.declarationSourceStart + 1);
 		Type type = convertType(fieldDecl.type);
 		setTypeForField(fieldDeclaration, type, variableDeclarationFragment.getExtraDimensions());
 		setModifiers(fieldDeclaration, fieldDecl);
-		convert(fieldDecl.javadoc, fieldDeclaration);
+		if (!(this.resolveBindings && binding == null)) {
+			convert(fieldDecl.javadoc, fieldDeclaration);
+		}
 		return fieldDeclaration;
 	}
 
@@ -2777,7 +2815,13 @@
 		name.internalSetIdentifier(new String(localDeclaration.name));
 		name.setSourceRange(localDeclaration.sourceStart, localDeclaration.sourceEnd - localDeclaration.sourceStart + 1);
 		variableDeclarationFragment.setName(name);
-		int end = retrievePositionBeforeNextCommaOrSemiColon(localDeclaration.sourceEnd, this.compilationUnitSource.length);
+		int start = localDeclaration.sourceEnd;
+		if (localDeclaration.initialization != null) {
+			final Expression expression = convert(localDeclaration.initialization);
+			variableDeclarationFragment.setInitializer(expression);
+			start = expression.getStartPosition() + expression.getLength();
+		}
+		int end = retrievePositionBeforeNextCommaOrSemiColon(start, localDeclaration.declarationSourceEnd);
 		if (end == -1) {
 			if (localDeclaration.initialization != null) {
 				variableDeclarationFragment.setSourceRange(localDeclaration.sourceStart, localDeclaration.initialization.sourceEnd - localDeclaration.sourceStart + 1);
@@ -2787,10 +2831,7 @@
 		} else {
 			variableDeclarationFragment.setSourceRange(localDeclaration.sourceStart, end - localDeclaration.sourceStart + 1);
 		}
-		if (localDeclaration.initialization != null) {
-			variableDeclarationFragment.setInitializer(convert(localDeclaration.initialization));
-		}
-		variableDeclarationFragment.setExtraDimensions(retrieveExtraDimension(localDeclaration.sourceEnd + 1, this.compilationUnitSource.length));
+		variableDeclarationFragment.setExtraDimensions(retrieveExtraDimension(localDeclaration.sourceEnd + 1, this.compilationUnitSourceLength));
 		if (this.resolveBindings) {
 			recordNodes(variableDeclarationFragment, localDeclaration);
 			recordNodes(name, localDeclaration);
@@ -2820,11 +2861,15 @@
 			final Wildcard wildcard = (Wildcard) typeReference;
 			final WildcardType wildcardType = new WildcardType(this.ast);
 			if (wildcard.bound != null) {
-				wildcardType.setBound(convertType(wildcard.bound), wildcard.kind == Wildcard.EXTENDS);
+				final Type bound = convertType(wildcard.bound);
+				wildcardType.setBound(bound, wildcard.kind == Wildcard.EXTENDS);
+				int start = wildcard.sourceStart;
+				wildcardType.setSourceRange(start, bound.getStartPosition() + bound.getLength() - start);
+			} else {
+				final int start = wildcard.sourceStart;
+				final int end = wildcard.sourceEnd;
+				wildcardType.setSourceRange(start, end - start + 1);
 			}
-			int start = wildcard.sourceStart;
-			int end = wildcard.sourceEnd;
-			wildcardType.setSourceRange(start, end - start + 1);
 			if (this.resolveBindings) {
 				recordNodes(wildcardType, typeReference);
 			}
@@ -3069,7 +3114,7 @@
 				if (this.resolveBindings) {
 					completeRecord((ArrayType) type, typeReference);
 				}
-				int end = retrieveEndOfDimensionsPosition(sourceStart+length, this.compilationUnitSource.length);
+				int end = retrieveEndOfDimensionsPosition(sourceStart+length, this.compilationUnitSourceLength);
 				if (end != -1) {
 					type.setSourceRange(sourceStart, end - sourceStart + 1);
 				} else {
@@ -3637,7 +3682,7 @@
 	 * @return int the dimension found, -1 if none
 	 */
 	protected int retrieveClosingAngleBracketPosition(int start) {
-		this.scanner.resetTo(start, this.scanner.eofPosition);
+		this.scanner.resetTo(start, this.compilationUnitSourceLength);
 		this.scanner.returnOnlyGreater = true;
 		try {
 			int token;
@@ -3665,7 +3710,7 @@
 		int start = node.getStartPosition();
 		int length = node.getLength();
 		int end = start + length;
-		this.scanner.resetTo(end, this.compilationUnitSource.length);
+		this.scanner.resetTo(end, this.compilationUnitSourceLength);
 		try {
 			int token;
 			while ((token = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) {
@@ -3812,6 +3857,7 @@
 					case TerminalTokens.TokenNameint:
 					case TerminalTokens.TokenNamelong:
 					case TerminalTokens.TokenNameshort:
+					case TerminalTokens.TokenNameboolean:
 						return this.scanner.currentPosition - 1;
 				}
 			}
@@ -3856,14 +3902,15 @@
 			int token;
 			while ((token = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) {
 				switch(token) {
-					case TerminalTokens.TokenNameRBRACKET://166 
+					case TerminalTokens.TokenNameLBRACKET:
+					case TerminalTokens.TokenNameCOMMENT_BLOCK:
+					case TerminalTokens.TokenNameCOMMENT_JAVADOC:
+					case TerminalTokens.TokenNameCOMMENT_LINE:
+						break;
+					case TerminalTokens.TokenNameRBRACKET://166
 						dimensions++;
 						break;
-					case TerminalTokens.TokenNameLBRACE ://90						
-					case TerminalTokens.TokenNameCOMMA ://90
-					case TerminalTokens.TokenNameEQUAL ://167
-					case TerminalTokens.TokenNameSEMICOLON ://64
-					case TerminalTokens.TokenNameRPAREN : //86
+					default:
 						return dimensions;
 				}
 			}
@@ -3953,7 +4000,7 @@
 	}
 
 	protected int retrieveProperRightBracketPosition(int bracketNumber, int start) {
-		this.scanner.resetTo(start, this.compilationUnitSource.length);
+		this.scanner.resetTo(start, this.compilationUnitSourceLength);
 		try {
 			int token, count = 0;
 			while ((token = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) {
@@ -4043,7 +4090,7 @@
 		int length = node.getLength();
 		int end = start + length;
 		int count = 0;
-		this.scanner.resetTo(end, this.compilationUnitSource.length);
+		this.scanner.resetTo(end, this.compilationUnitSourceLength);
 		try {
 			int token;
 			while ((token = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) {
@@ -4140,7 +4187,6 @@
 		try {
 			int token;
 			int indexInAnnotations = 0;
-			int eofPosition = this.scanner.eofPosition;
 			while ((token = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) {
 				IExtendedModifier modifier = null;
 				switch(token) {
@@ -4182,7 +4228,7 @@
 						if (annotations != null && indexInAnnotations < annotations.length) {
 							org.eclipse.jdt.internal.compiler.ast.Annotation annotation = annotations[indexInAnnotations++];
 							modifier = convert(annotation);
-							this.scanner.resetTo(annotation.declarationSourceEnd + 1, eofPosition);
+							this.scanner.resetTo(annotation.declarationSourceEnd + 1, this.compilationUnitSourceLength);
 						}
 						break;
 					case TerminalTokens.TokenNameCOMMENT_BLOCK :
@@ -4207,6 +4253,20 @@
 		this.setModifiers(enumDeclaration, enumDeclaration2.annotations);
 	}
 	
+	protected void setModifiers(EnumConstantDeclaration enumConstantDeclaration, org.eclipse.jdt.internal.compiler.ast.FieldDeclaration fieldDeclaration) {
+		switch(this.ast.apiLevel) {
+			case AST.JLS2_INTERNAL :
+				enumConstantDeclaration.internalSetModifiers(fieldDeclaration.modifiers & CompilerModifiers.AccJustFlag);
+				if (fieldDeclaration.annotations != null) {
+					enumConstantDeclaration.setFlags(enumConstantDeclaration.getFlags() | ASTNode.MALFORMED);
+				}
+				break;
+			case AST.JLS3 :
+				this.scanner.resetTo(fieldDeclaration.declarationSourceStart, fieldDeclaration.sourceStart);
+				this.setModifiers(enumConstantDeclaration, fieldDeclaration.annotations);
+		}
+	}
+	
 	/**
 	 * @param fieldDeclaration
 	 * @param fieldDecl
@@ -4319,8 +4379,15 @@
 								if (annotations != null && indexInAnnotations < annotations.length) {
 									org.eclipse.jdt.internal.compiler.ast.Annotation annotation = annotations[indexInAnnotations++];
 									modifier = convert(annotation);
-									this.scanner.resetTo(annotation.declarationSourceEnd + 1, this.scanner.eofPosition);
+									this.scanner.resetTo(annotation.declarationSourceEnd + 1, this.compilationUnitSourceLength);
 								}
+								break;
+							case TerminalTokens.TokenNameCOMMENT_BLOCK :
+							case TerminalTokens.TokenNameCOMMENT_LINE :
+							case TerminalTokens.TokenNameCOMMENT_JAVADOC :
+								break;
+							default :
+								return;
 						}
 						if (modifier != null) {
 							variableDecl.modifiers().add(modifier);
@@ -4387,8 +4454,15 @@
 							if (annotations != null && indexInAnnotations < annotations.length) {
 								org.eclipse.jdt.internal.compiler.ast.Annotation annotation = annotations[indexInAnnotations++];
 								modifier = convert(annotation);
-								this.scanner.resetTo(annotation.declarationSourceEnd + 1, this.scanner.eofPosition);
+								this.scanner.resetTo(annotation.declarationSourceEnd + 1, this.compilationUnitSourceLength);
 							}
+							break;
+						case TerminalTokens.TokenNameCOMMENT_BLOCK :
+						case TerminalTokens.TokenNameCOMMENT_LINE :
+						case TerminalTokens.TokenNameCOMMENT_JAVADOC :
+							break;
+						default :
+							return;
 					}
 					if (modifier != null) {
 						variableDecl.modifiers().add(modifier);
@@ -4482,8 +4556,15 @@
 								if (annotations != null && indexInAnnotations < annotations.length) {
 									org.eclipse.jdt.internal.compiler.ast.Annotation annotation = annotations[indexInAnnotations++];
 									modifier = convert(annotation);
-									this.scanner.resetTo(annotation.declarationSourceEnd + 1, this.scanner.eofPosition);
+									this.scanner.resetTo(annotation.declarationSourceEnd + 1, this.compilationUnitSourceLength);
 								}
+								break;
+							case TerminalTokens.TokenNameCOMMENT_BLOCK :
+							case TerminalTokens.TokenNameCOMMENT_LINE :
+							case TerminalTokens.TokenNameCOMMENT_JAVADOC :
+								break;
+							default :
+								return;
 						}
 						if (modifier != null) {
 							variableDeclarationExpression.modifiers().add(modifier);
@@ -4556,8 +4637,15 @@
 								if (annotations != null && indexInAnnotations < annotations.length) {
 									org.eclipse.jdt.internal.compiler.ast.Annotation annotation = annotations[indexInAnnotations++];
 									modifier = convert(annotation);
-									this.scanner.resetTo(annotation.declarationSourceEnd + 1, this.scanner.eofPosition);
+									this.scanner.resetTo(annotation.declarationSourceEnd + 1, this.compilationUnitSourceLength);
 								}
+								break;
+							case TerminalTokens.TokenNameCOMMENT_BLOCK :
+							case TerminalTokens.TokenNameCOMMENT_LINE :
+							case TerminalTokens.TokenNameCOMMENT_JAVADOC :
+								break;
+							default :
+								return;
 						}
 						if (modifier != null) {
 							variableDeclarationStatement.modifiers().add(modifier);
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTParser.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTParser.java
index ba7e715..88dc2ef 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTParser.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTParser.java
@@ -224,13 +224,28 @@
 	   
 	/**
 	 * Sets the compiler options to be used when parsing.
-     * <p>
-     * The compiler options default to {@link JavaCore#getOptions()}.
-     * </p>
+	 * <p>
+	 * Note that {@link #setSource(IClassFile)},
+	 * {@link #setSource(ICompilationUnit)},
+	 * and {@link #setProject(IJavaProject)} reset the compiler options
+	 * based on the Java project. In other cases, compiler options default
+	 * to {@link JavaCore#getOptions()}. In either case, and especially
+	 * in the latter, the caller should carefully weight the consequences of
+	 * allowing compiler options to be defaulted as opposed to being
+	 * explicitly specified for the <code>ASTParser</code> instance.
+	 * For instance, there is a compiler option called "Source Compatibility Mode"
+	 * which determines which JDK level the source code is expected to meet.
+	 * If you specify "1.4", then "assert" is treated as a keyword and disallowed
+	 * as an identifier; if you specify "1.3", then "assert" is allowed as an
+	 * identifier. So this particular setting has a major bearing on what is
+	 * considered syntactically legal. By explicitly specifying the setting,
+	 * the client control exactly how the parser works. On the other hand,
+	 * allowing default settings means the parsing behaves like other JDT tools.
+	 * </p>
 	 * 
 	 * @param options the table of options (key type: <code>String</code>;
 	 * value type: <code>String</code>), or <code>null</code>
-     * to set it back to the default
+	 * to set it back to the default
 	 */
 	public void setCompilerOptions(Map options) {
 	   if (options == null) {
@@ -522,21 +537,24 @@
 	}
 	
 	/**
-     * Sets the Java project used when resolving bindings.
-     * This method automatically sets the compiler
-     * options based on the given project:
-     * <pre>
-     * setCompilerOptions(project.getOptions(true));
-     * </pre>
-     * This setting is used in conjunction with <code>setSource(char[])</code>.
-     * For the purposes of resolving bindings, types declared in the
+	 * Sets the Java project used when resolving bindings.
+	 * This method automatically sets the compiler
+	 * options based on the given project:
+	 * <pre>
+	 * setCompilerOptions(project.getOptions(true));
+	 * </pre>
+	 * See {@link #setCompilerOptions(Map)} for a discussion of
+	 * the pros and cons of using these options vs specifying 
+	 * compiler options explicitly.
+	 * This setting is used in conjunction with <code>setSource(char[])</code>.
+	 * For the purposes of resolving bindings, types declared in the
 	 * source string will hide types by the same name available
-     * through the classpath of the given project.
-     * Defaults to none (<code>null</code>).
-     * 
+	 * through the classpath of the given project.
+	 * Defaults to none (<code>null</code>).
+	 * 
 	 * @param project the Java project used to resolve names, or 
 	 *    <code>null</code> if none
-     */
+	 */
 	public void setProject(IJavaProject project) {
 		this.project = project;
 		if (project != null) {
@@ -870,8 +888,9 @@
 	 * @see ASTNode#getLength()
 	 */
 	private ASTNode internalCreateASTForKind() {
-		ASTConverter converter = new ASTConverter(this.compilerOptions, false, null);
+		final ASTConverter converter = new ASTConverter(this.compilerOptions, false, null);
 		converter.compilationUnitSource = this.rawSource;
+		converter.compilationUnitSourceLength = this.rawSource.length;
 		converter.scanner.setSource(this.rawSource);
 		
 		AST ast = AST.newAST(this.apiLevel);
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BindingComparator.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BindingComparator.java
index fbd5b2e..c97210d 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BindingComparator.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BindingComparator.java
@@ -10,6 +10,8 @@
  *******************************************************************************/
 package org.eclipse.jdt.core.dom;
 
+import java.util.HashSet;
+
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.env.IConstants;
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
@@ -61,21 +63,21 @@
 	 * @param declaringElement2
 	 * @return true if both parameters are equals, false otherwise
 	 */
-	static boolean isEqual(Binding declaringElement, Binding declaringElement2, boolean checkTypeVariables) {
+	static boolean isEqual(Binding declaringElement, Binding declaringElement2, HashSet visitedTypes) {
 		if (declaringElement instanceof org.eclipse.jdt.internal.compiler.lookup.TypeBinding) {
 			if (!(declaringElement2 instanceof org.eclipse.jdt.internal.compiler.lookup.TypeBinding)){
 				return false;
 			}
 			return isEqual((org.eclipse.jdt.internal.compiler.lookup.TypeBinding) declaringElement,
 					(org.eclipse.jdt.internal.compiler.lookup.TypeBinding) declaringElement2,
-					checkTypeVariables);
+					visitedTypes);
 		} else if (declaringElement instanceof org.eclipse.jdt.internal.compiler.lookup.MethodBinding) {
 			if (!(declaringElement2 instanceof org.eclipse.jdt.internal.compiler.lookup.MethodBinding)) {
 				return false;
 			}
 			return isEqual((org.eclipse.jdt.internal.compiler.lookup.MethodBinding) declaringElement,
 					(org.eclipse.jdt.internal.compiler.lookup.MethodBinding) declaringElement2,
-					checkTypeVariables);
+					visitedTypes);
 		} else if (declaringElement instanceof VariableBinding) {
 			if (!(declaringElement2 instanceof VariableBinding)) {
 				return false;
@@ -104,23 +106,19 @@
 	
 	static boolean isEqual(org.eclipse.jdt.internal.compiler.lookup.MethodBinding methodBinding,
 			org.eclipse.jdt.internal.compiler.lookup.MethodBinding methodBinding2) {
-		return isEqual(methodBinding, methodBinding2, true);
+		return isEqual(methodBinding, methodBinding2, new HashSet());
 	}
 			
 	static boolean isEqual(org.eclipse.jdt.internal.compiler.lookup.MethodBinding methodBinding,
 			org.eclipse.jdt.internal.compiler.lookup.MethodBinding methodBinding2,
-			boolean checkTypeVariables) {
-		if (checkTypeVariables) {
-			if (!isEqual(methodBinding.typeVariables, methodBinding2.typeVariables, true)
-					|| !isEqual(methodBinding.parameters, methodBinding2.parameters, true)) {
-				return false;
-			}
-		}
+			HashSet visitedTypes) {
 		return (methodBinding == null && methodBinding2 == null)
 			|| (CharOperation.equals(methodBinding.selector, methodBinding2.selector)
-				&& isEqual(methodBinding.returnType, methodBinding2.returnType, checkTypeVariables) 
-				&& isEqual(methodBinding.thrownExceptions, methodBinding2.thrownExceptions, checkTypeVariables)
-				&& isEqual(methodBinding.declaringClass, methodBinding2.declaringClass, true));
+				&& isEqual(methodBinding.returnType, methodBinding2.returnType, visitedTypes) 
+				&& isEqual(methodBinding.thrownExceptions, methodBinding2.thrownExceptions, visitedTypes)
+				&& isEqual(methodBinding.declaringClass, methodBinding2.declaringClass, visitedTypes)
+				&& isEqual(methodBinding.typeVariables, methodBinding2.typeVariables, visitedTypes)
+				&& isEqual(methodBinding.parameters, methodBinding2.parameters, visitedTypes));
 	}
 
 	static boolean isEqual(VariableBinding variableBinding, VariableBinding variableBinding2) {
@@ -131,10 +129,11 @@
 	}
 
 	static boolean isEqual(FieldBinding fieldBinding, FieldBinding fieldBinding2) {
+		HashSet visitedTypes = new HashSet();
 		return (fieldBinding.modifiers & CompilerModifiers.AccJustFlag) == (fieldBinding2.modifiers & CompilerModifiers.AccJustFlag)
 				&& CharOperation.equals(fieldBinding.name, fieldBinding2.name)
-				&& isEqual(fieldBinding.type, fieldBinding2.type, true)
-				&& isEqual(fieldBinding.declaringClass, fieldBinding2.declaringClass, true);
+				&& isEqual(fieldBinding.type, fieldBinding2.type, visitedTypes)
+				&& isEqual(fieldBinding.declaringClass, fieldBinding2.declaringClass, visitedTypes);
 	}
 
 	/**
@@ -143,14 +142,14 @@
 	 * @return true if both parameters are equals, false otherwise
 	 */
 	static boolean isEqual(org.eclipse.jdt.internal.compiler.lookup.TypeBinding[] bindings, org.eclipse.jdt.internal.compiler.lookup.TypeBinding[] otherBindings) {
-		return isEqual(bindings, otherBindings, true);
+		return isEqual(bindings, otherBindings, new HashSet());
 	}
 	/**
 	 * @param bindings
 	 * @param otherBindings
 	 * @return true if both parameters are equals, false otherwise
 	 */
-	static boolean isEqual(org.eclipse.jdt.internal.compiler.lookup.TypeBinding[] bindings, org.eclipse.jdt.internal.compiler.lookup.TypeBinding[] otherBindings, boolean checkTypeVariables) {
+	static boolean isEqual(org.eclipse.jdt.internal.compiler.lookup.TypeBinding[] bindings, org.eclipse.jdt.internal.compiler.lookup.TypeBinding[] otherBindings, HashSet visitedTypes) {
 		if (bindings == null) {
 			return otherBindings == null;
 		} else if (otherBindings == null) {
@@ -162,20 +161,19 @@
 				return false;
 			}
 			for (int i = 0; i < length; i++) {
-				if (!isEqual(bindings[i], otherBindings[i], checkTypeVariables)) {
+				if (!isEqual(bindings[i], otherBindings[i], visitedTypes)) {
 					return false;
 				}
 			}
 			return true;
 		}
 	}
-	// TODO (olivier) should optimize to use switch(binding.kind()) & modifier bitmask comparisons
-	static boolean isEqual(org.eclipse.jdt.internal.compiler.lookup.TypeBinding typeBinding, org.eclipse.jdt.internal.compiler.lookup.TypeBinding typeBinding2, boolean checkTypeVariables) {
+	static boolean isEqual(org.eclipse.jdt.internal.compiler.lookup.TypeBinding typeBinding, org.eclipse.jdt.internal.compiler.lookup.TypeBinding typeBinding2, HashSet visitedTypes) {
 		if (typeBinding == typeBinding2)
 			return true;
 		if (typeBinding == null || typeBinding2 == null)
 			return false;
-		
+
 		switch (typeBinding.kind()) {
 			case Binding.BASE_TYPE :
 				if (!typeBinding2.isBaseType()) {
@@ -188,7 +186,7 @@
 					return false;
 				}
 				return typeBinding.dimensions() == typeBinding2.dimensions()
-						&& isEqual(typeBinding.leafComponentType(), typeBinding2.leafComponentType(), checkTypeVariables);
+						&& isEqual(typeBinding.leafComponentType(), typeBinding2.leafComponentType(), visitedTypes);
 				
 			case Binding.PARAMETERIZED_TYPE :
 				if (!typeBinding2.isParameterizedType()) {
@@ -196,14 +194,10 @@
 				}
 				ParameterizedTypeBinding parameterizedTypeBinding = (ParameterizedTypeBinding) typeBinding;
 				ParameterizedTypeBinding parameterizedTypeBinding2 = (ParameterizedTypeBinding) typeBinding2;
-				if (checkTypeVariables) {
-					if (!isEqual(parameterizedTypeBinding.arguments, parameterizedTypeBinding2.arguments, false)) {
-						return false;
-					}
-				}
 				return CharOperation.equals(parameterizedTypeBinding.compoundName, parameterizedTypeBinding2.compoundName)
 					&& (parameterizedTypeBinding.modifiers & (CompilerModifiers.AccJustFlag | IConstants.AccInterface | IConstants.AccEnum | IConstants.AccAnnotation))
-							== (parameterizedTypeBinding2.modifiers & (CompilerModifiers.AccJustFlag | IConstants.AccInterface | IConstants.AccEnum | IConstants.AccAnnotation));
+							== (parameterizedTypeBinding2.modifiers & (CompilerModifiers.AccJustFlag | IConstants.AccInterface | IConstants.AccEnum | IConstants.AccAnnotation))
+					&& isEqual(parameterizedTypeBinding.arguments, parameterizedTypeBinding2.arguments, visitedTypes);
 							
 			case Binding.WILDCARD_TYPE :
 				if (!typeBinding2.isWildcard()) {
@@ -211,10 +205,13 @@
 				}
 				WildcardBinding wildcardBinding = (WildcardBinding) typeBinding;
 				WildcardBinding wildcardBinding2 = (WildcardBinding) typeBinding2;
-				return isEqual(wildcardBinding.bound, wildcardBinding2.bound, checkTypeVariables)
+				return isEqual(wildcardBinding.bound, wildcardBinding2.bound, visitedTypes)
 					&& wildcardBinding.boundKind == wildcardBinding2.boundKind;
 				
 			case Binding.TYPE_PARAMETER :
+				if (visitedTypes.contains(typeBinding)) return true;
+				visitedTypes.add(typeBinding);
+				
 				if (!(typeBinding2.isTypeVariable())) {
 					return false;
 				}
@@ -224,18 +221,16 @@
 					}
 					CaptureBinding captureBinding = (CaptureBinding) typeBinding;
 					CaptureBinding captureBinding2 = (CaptureBinding) typeBinding2;
-					return isEqual(captureBinding.wildcard, captureBinding2.wildcard, checkTypeVariables);
+					return captureBinding.position == captureBinding2.position
+						&& isEqual(captureBinding.wildcard, captureBinding2.wildcard, visitedTypes)
+						&& isEqual(captureBinding.sourceType, captureBinding2.sourceType, visitedTypes);
 				}
 				TypeVariableBinding typeVariableBinding = (TypeVariableBinding) typeBinding;
 				TypeVariableBinding typeVariableBinding2 = (TypeVariableBinding) typeBinding2;
-				if (checkTypeVariables) {
-					return CharOperation.equals(typeVariableBinding.sourceName, typeVariableBinding2.sourceName)
-						&& isEqual(typeVariableBinding.declaringElement, typeVariableBinding2.declaringElement, false)
-						&& isEqual(typeVariableBinding.superclass(), typeVariableBinding2.superclass(), true)
-						&& isEqual(typeVariableBinding.superInterfaces(), typeVariableBinding2.superInterfaces(), true);
-				} else {
-					return CharOperation.equals(typeVariableBinding.sourceName, typeVariableBinding2.sourceName);
-				}
+				return CharOperation.equals(typeVariableBinding.sourceName, typeVariableBinding2.sourceName)
+					&& isEqual(typeVariableBinding.declaringElement, typeVariableBinding2.declaringElement, visitedTypes)
+					&& isEqual(typeVariableBinding.superclass(), typeVariableBinding2.superclass(), visitedTypes)
+					&& isEqual(typeVariableBinding.superInterfaces(), typeVariableBinding2.superInterfaces(), visitedTypes);
 			
 			case Binding.GENERIC_TYPE :
 				if (!typeBinding2.isGenericType()) {
@@ -243,14 +238,10 @@
 				}
 				ReferenceBinding referenceBinding = (ReferenceBinding) typeBinding;
 				ReferenceBinding referenceBinding2 = (ReferenceBinding) typeBinding2;
-				if (checkTypeVariables) {
-					if (!isEqual(referenceBinding.typeVariables(), referenceBinding2.typeVariables(), true)) {
-						return false;
-					}
-				}
 				return CharOperation.equals(referenceBinding.compoundName, referenceBinding2.compoundName)
 					&& (referenceBinding.modifiers & (CompilerModifiers.AccJustFlag | IConstants.AccInterface | IConstants.AccEnum | IConstants.AccAnnotation))
-							== (referenceBinding2.modifiers & (CompilerModifiers.AccJustFlag | IConstants.AccInterface | IConstants.AccEnum | IConstants.AccAnnotation));
+							== (referenceBinding2.modifiers & (CompilerModifiers.AccJustFlag | IConstants.AccInterface | IConstants.AccEnum | IConstants.AccAnnotation))
+					&& isEqual(referenceBinding.typeVariables(), referenceBinding2.typeVariables(), visitedTypes);
 		
 			case Binding.RAW_TYPE :
 			default :
@@ -274,6 +265,6 @@
 	 * @return true if both parameters are equals, false otherwise
 	 */
 	static boolean isEqual(org.eclipse.jdt.internal.compiler.lookup.TypeBinding typeBinding, org.eclipse.jdt.internal.compiler.lookup.TypeBinding typeBinding2) {
-		return isEqual(typeBinding, typeBinding2, true);
+		return isEqual(typeBinding, typeBinding2, new HashSet());
 	}
 }
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ClassInstanceCreation.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ClassInstanceCreation.java
index 8463185..90b390b 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ClassInstanceCreation.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ClassInstanceCreation.java
@@ -445,7 +445,7 @@
 	 * deprecation warnings.
 	 * @since 3.1
 	 */
-	/*package*/ public void internalSetName(Name name) {
+	/*package*/ void internalSetName(Name name) {
 	    supportedOnlyIn2();
 		if (name == null) {
 			throw new IllegalArgumentException();
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnit.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnit.java
index 5306d06..b8f0cd5 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnit.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnit.java
@@ -380,7 +380,7 @@
 	 *    a <code>VariableDeclarationFragment</code> in a 
 	 *    <code>VariableDeclarationStatement</code> or 
 	 *    <code>VariableDeclarationExpression</code></li>
-	 * <li>methods - a <code>MethodDeclaration</code> </li>
+	 * <li>method - a <code>MethodDeclaration</code> </li>
 	 * <li>constructor - a <code>MethodDeclaration</code> </li>
      * <li>annotation type - an <code>AnnotationTypeDeclaration</code></li>
      * <li>annotation type member - an <code>AnnotationTypeMemberDeclaration</code></li>
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnitResolver.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnitResolver.java
index 3e5898d..17828bb 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnitResolver.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnitResolver.java
@@ -16,6 +16,7 @@
 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.IJavaElement;
 import org.eclipse.jdt.core.IJavaProject;
@@ -85,6 +86,8 @@
 	DefaultBindingResolver.BindingTables bindingTables;
 	
 	boolean hasCompilationAborted;
+	
+	private IProgressMonitor monitor;
 
 	/**
 	 * Answer a new CompilationUnitVisitor using the given name environment and compiler options.
@@ -126,10 +129,12 @@
 		IErrorHandlingPolicy policy,
 		Map settings,
 		ICompilerRequestor requestor,
-		IProblemFactory problemFactory) {
+		IProblemFactory problemFactory,
+		IProgressMonitor monitor) {
 
 		super(environment, policy, settings, requestor, problemFactory, false);
 		this.hasCompilationAborted = false;
+		this.monitor =monitor;
 	}
 	
 	/*
@@ -181,6 +186,7 @@
 				this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/);
 				addCompilationUnit(sourceUnit, parsedUnit);
 				this.requestedSources.put(unitResult.getFileName(), sourceUnit);
+				worked(1);
 			} finally {
 				sourceUnits[i] = null; // no longer hold onto the unit
 			}
@@ -207,16 +213,12 @@
 				} 
 					
 			} else {
-				if (!resolver.hasTypeName()) {
-					// package binding key
-					char[] pkgName = CharOperation.concatWith(resolver.compoundName(), '.');
-					this.requestedKeys.put(pkgName, resolver);
-				} else {
-					// base type binding or binary binding
-					char[] key = resolver.getKey().toCharArray();
-					this.requestedKeys.put(key, resolver);
-				}
+				char[] key = resolver.hasTypeName() 
+					? resolver.getKey().toCharArray() // binary binding
+					: CharOperation.concatWith(resolver.compoundName(), '.'); // package binding or base type binding
+				this.requestedKeys.put(key, resolver);
 			}
+			worked(1);
 		}
 		
 		// binding resolution
@@ -319,40 +321,47 @@
 	}	
 	
 	public static void parse(ICompilationUnit[] compilationUnits, ASTRequestor astRequestor, int apiLevel, Map options, IProgressMonitor monitor) {
-		CompilerOptions compilerOptions = new CompilerOptions(options);
-		Parser parser = new CommentRecorderParser(
-			new ProblemReporter(
-					DefaultErrorHandlingPolicies.proceedWithAllProblems(), 
-					compilerOptions, 
-					new DefaultProblemFactory()),
-			false);
-		for (int i = 0, length = compilationUnits.length; i < length; i++) {
-			org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit = (org.eclipse.jdt.internal.compiler.env.ICompilationUnit) compilationUnits[i];
-			CompilationResult compilationResult = new CompilationResult(sourceUnit, 0, 0, compilerOptions.maxProblemsPerUnit);
-			CompilationUnitDeclaration compilationUnitDeclaration = parser.dietParse(sourceUnit, compilationResult);
-			
-			if (compilationUnitDeclaration.ignoreMethodBodies) {
-				compilationUnitDeclaration.ignoreFurtherInvestigation = true;
-				// if initial diet parse did not work, no need to dig into method bodies.
-				continue; 
+		try {
+			CompilerOptions compilerOptions = new CompilerOptions(options);
+			Parser parser = new CommentRecorderParser(
+				new ProblemReporter(
+						DefaultErrorHandlingPolicies.proceedWithAllProblems(), 
+						compilerOptions, 
+						new DefaultProblemFactory()),
+				false);
+			int length = compilationUnits.length;
+			if (monitor != null) monitor.beginTask("", length); //$NON-NLS-1$
+			for (int i = 0; i < length; i++) {
+				org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit = (org.eclipse.jdt.internal.compiler.env.ICompilationUnit) compilationUnits[i];
+				CompilationResult compilationResult = new CompilationResult(sourceUnit, 0, 0, compilerOptions.maxProblemsPerUnit);
+				CompilationUnitDeclaration compilationUnitDeclaration = parser.dietParse(sourceUnit, compilationResult);
+				
+				if (compilationUnitDeclaration.ignoreMethodBodies) {
+					compilationUnitDeclaration.ignoreFurtherInvestigation = true;
+					// if initial diet parse did not work, no need to dig into method bodies.
+					continue; 
+				}
+				
+				//fill the methods bodies in order for the code to be generated
+				//real parse of the method....
+				parser.scanner.setSource(compilationResult);
+				org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] types = compilationUnitDeclaration.types;
+				if (types != null) {
+					for (int j = types.length; --j >= 0;)
+						types[j].parseMethod(parser, compilationUnitDeclaration);
+				}
+				
+				// convert AST
+				CompilationUnit node = convert(compilationUnitDeclaration, sourceUnit.getContents(), apiLevel, options, false/*don't resolve binding*/, null/*no owner needed*/, null/*no binding table needed*/, monitor);
+				node.setJavaElement(compilationUnits[i]);
+				
+				// accept AST
+				astRequestor.acceptAST(compilationUnits[i], node);
+				
+				if (monitor != null) monitor.worked(1);
 			}
-			
-			//fill the methods bodies in order for the code to be generated
-			//real parse of the method....
-			parser.scanner.setSource(compilationResult);
-			org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] types = compilationUnitDeclaration.types;
-			if (types != null) {
-				for (int j = types.length; --j >= 0;)
-					types[j].parseMethod(parser, compilationUnitDeclaration);
-			}
-			
-			// convert AST
-			CompilationUnit node = convert(compilationUnitDeclaration, sourceUnit.getContents(), apiLevel, options, false/*don't resolve binding*/, null/*no owner needed*/, null/*no binding table needed*/, monitor);
-			node.setJavaElement(compilationUnits[i]);
-			
-			
-			// accept AST
-			astRequestor.acceptAST(compilationUnits[i], node);
+		} finally {
+			if (monitor != null) monitor.done();
 		}
 	}
 	
@@ -428,6 +437,10 @@
 		CancelableNameEnvironment environment = null;
 		CancelableProblemFactory problemFactory = null;
 		try {
+			if (monitor != null) {
+				int amountOfWork = (compilationUnits.length + bindingKeys.length) * 2; // 1 for beginToCompile, 1 for resolve
+				monitor.beginTask("", amountOfWork); //$NON-NLS-1$
+			}
 			environment = new CancelableNameEnvironment(((JavaProject) javaProject), owner, monitor);
 			problemFactory = new CancelableProblemFactory(monitor);
 			CompilationUnitResolver resolver =
@@ -436,9 +449,10 @@
 					getHandlingPolicy(),
 					options,
 					getRequestor(),
-					problemFactory);
+					problemFactory, 
+					monitor);
 
-			resolver.resolve(compilationUnits, bindingKeys, requestor, apiLevel, options, owner, monitor);
+			resolver.resolve(compilationUnits, bindingKeys, requestor, apiLevel, options, owner);
 			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$
@@ -447,6 +461,7 @@
 			// project doesn't exist -> simple parse without resolving
 			parse(compilationUnits, requestor, apiLevel, options, monitor);
 		} finally {
+			if (monitor != null) monitor.done();
 			if (environment != null) {
 				environment.monitor = null; // don't hold a reference to this external object
 			}
@@ -476,7 +491,8 @@
 					getHandlingPolicy(),
 					options,
 					getRequestor(),
-					problemFactory);
+					problemFactory, 
+					monitor);
 
 			unit = 
 				resolver.resolve(
@@ -631,7 +647,7 @@
 		}
 	}
 
-	private void resolve(ICompilationUnit[] compilationUnits, String[] bindingKeys, ASTRequestor astRequestor, int apiLevel, Map compilerOptions, WorkingCopyOwner owner, IProgressMonitor monitor) {
+	private void resolve(ICompilationUnit[] compilationUnits, String[] bindingKeys, ASTRequestor astRequestor, int apiLevel, Map compilerOptions, WorkingCopyOwner owner) {
 	
 		// temporararily connect ourselves to the ASTResolver - must disconnect when done
 		astRequestor.compilationUnitResolver = this;
@@ -653,7 +669,7 @@
 					if (this.requestedKeys.containsKey(fileName) || this.requestedSources.containsKey(fileName)) {
 						super.process(unit, i); // this.process(...) is optimized to not process already known units
 						
-						ICompilationUnit source = (ICompilationUnit) this.requestedSources.removeKey(fileName);
+						ICompilationUnit source = (ICompilationUnit) this.requestedSources.get(fileName);
 						if (source != null) {
 							// convert AST
 							CompilationResult compilationResult = unit.compilationResult;
@@ -661,7 +677,7 @@
 							char[] contents = sourceUnit.getContents();
 							AST ast = AST.newAST(apiLevel);
 							ast.setDefaultNodeFlag(ASTNode.ORIGINAL);
-							ASTConverter converter = new ASTConverter(compilerOptions, true/*need to resolve bindings*/, monitor);
+							ASTConverter converter = new ASTConverter(compilerOptions, true/*need to resolve bindings*/, this.monitor);
 							BindingResolver resolver = new DefaultBindingResolver(unit.scope, owner, this.bindingTables);
 							ast.setBindingResolver(resolver);
 							converter.setAST(ast);
@@ -673,17 +689,25 @@
 							
 							// pass it to requestor
 							astRequestor.acceptAST(source, compilationUnit);
+							
+							worked(1);
 						} 
 						
-						Object key = this.requestedKeys.removeKey(fileName);
+						Object key = this.requestedKeys.get(fileName);
 						if (key instanceof BindingKeyResolver) {
 							reportBinding(key, astRequestor, owner, unit);
+							worked(1);
 						} else if (key instanceof ArrayList) {
 							Iterator iterator = ((ArrayList) key).iterator();
 							while (iterator.hasNext()) {
 								reportBinding(iterator.next(), astRequestor, owner, unit);
+								worked(1);
 							}
 						}
+						
+						// remove at the end so that we don't resolve twice if a source and a key for the same file name have been requested
+						this.requestedSources.removeKey(fileName);
+						this.requestedKeys.removeKey(fileName);
 					} else {
 						if (unit.scope != null)
 							unit.scope.faultInTypes(); // still force resolution of signatures, so clients can query DOM AST
@@ -706,7 +730,10 @@
 				IBinding binding = compilerBinding == null ? null : resolver.getBinding(compilerBinding);
 				// pass it to requestor
 				astRequestor.acceptBinding(((BindingKeyResolver) this.requestedKeys.valueTable[j]).getKey(), binding);
+				worked(1);
 			}
+		} catch (OperationCanceledException e) {
+			throw e;
 		} catch (AbortCompilation e) {
 			this.handleInternalException(e, unit);
 		} catch (Error e) {
@@ -857,4 +884,12 @@
 			analyzeCode, 
 			generateCode);
 	}
+	
+	private void worked(int work) {
+		if (this.monitor != null) {
+			if (this.monitor.isCanceled())
+				throw new OperationCanceledException();
+			this.monitor.worked(work);
+		}
+	}
 }
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultBindingResolver.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultBindingResolver.java
index 710b694..fd3e24b 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultBindingResolver.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultBindingResolver.java
@@ -281,7 +281,7 @@
 				case ProblemReasons.NonStaticReferenceInStaticContext :
 					if (referenceBinding instanceof ProblemReferenceBinding) {
 						ProblemReferenceBinding problemReferenceBinding = (ProblemReferenceBinding) referenceBinding;
-						Binding binding2 = problemReferenceBinding.original;
+						Binding binding2 = problemReferenceBinding.closestMatch;
 						if (binding2 != null && binding2 instanceof org.eclipse.jdt.internal.compiler.lookup.TypeBinding) {
 							TypeBinding binding = (TypeBinding) this.bindingTables.compilerBindingsToASTBindings.get(binding2);
 							if (binding != null) {
@@ -310,13 +310,15 @@
 	synchronized IVariableBinding getVariableBinding(org.eclipse.jdt.internal.compiler.lookup.VariableBinding variableBinding) {
  		if (variableBinding != null) {
 	 		if (variableBinding.isValidBinding()) {
-				IVariableBinding binding = (IVariableBinding) this.bindingTables.compilerBindingsToASTBindings.get(variableBinding);
-				if (binding != null) {
+	 			if (variableBinding.type != null) {
+					IVariableBinding binding = (IVariableBinding) this.bindingTables.compilerBindingsToASTBindings.get(variableBinding);
+					if (binding != null) {
+						return binding;
+					}
+					binding = new VariableBinding(this, variableBinding);
+					this.bindingTables.compilerBindingsToASTBindings.put(variableBinding, binding);
 					return binding;
-				}
-				binding = new VariableBinding(this, variableBinding);
-				this.bindingTables.compilerBindingsToASTBindings.put(variableBinding, binding);
-				return binding;
+	 			}
 	 		} else {
 				/*
 				 * http://dev.eclipse.org/bugs/show_bug.cgi?id=24449
@@ -956,13 +958,15 @@
 									if (declaringClass != null) {
 										FieldBinding exactBinding = declaringClass.getField(tokens[tokens.length - 1], true /*resolve*/);
 										if (exactBinding != null) {
-											IVariableBinding variableBinding = (IVariableBinding) this.bindingTables.compilerBindingsToASTBindings.get(exactBinding);
-											if (variableBinding != null) {
+											if (exactBinding.type != null) {
+												IVariableBinding variableBinding = (IVariableBinding) this.bindingTables.compilerBindingsToASTBindings.get(exactBinding);
+												if (variableBinding != null) {
+													return variableBinding;
+												}
+												variableBinding = new VariableBinding(this, exactBinding);
+												this.bindingTables.compilerBindingsToASTBindings.put(exactBinding, variableBinding);
 												return variableBinding;
 											}
-											variableBinding = new VariableBinding(this, exactBinding);
-											this.bindingTables.compilerBindingsToASTBindings.put(exactBinding, variableBinding);
-											return variableBinding;
 										}
 									}
 									break;
@@ -1101,13 +1105,15 @@
 									ReferenceBinding declaringClass = problemFieldBinding.declaringClass;
 									FieldBinding exactBinding = declaringClass.getField(problemFieldBinding.name, true /*resolve*/);
 									if (exactBinding != null) {
-										IVariableBinding variableBinding2 = (IVariableBinding) this.bindingTables.compilerBindingsToASTBindings.get(exactBinding);
-										if (variableBinding2 != null) {
+										if (exactBinding.type != null) {
+											IVariableBinding variableBinding2 = (IVariableBinding) this.bindingTables.compilerBindingsToASTBindings.get(exactBinding);
+											if (variableBinding2 != null) {
+												return variableBinding2;
+											}
+											variableBinding2 = new VariableBinding(this, exactBinding);
+											this.bindingTables.compilerBindingsToASTBindings.put(exactBinding, variableBinding2);
 											return variableBinding2;
 										}
-										variableBinding2 = new VariableBinding(this, exactBinding);
-										this.bindingTables.compilerBindingsToASTBindings.put(exactBinding, variableBinding2);
-										return variableBinding2;
 									}
 									break;
 							}
@@ -1486,9 +1492,9 @@
 			} else if ("java.lang.Exception".equals(name)) {//$NON-NLS-1$
 				return this.getTypeBinding(this.scope.getType(TypeConstants.JAVA_LANG_EXCEPTION, 3));
 			} else if ("java.lang.RuntimeException".equals(name)) {//$NON-NLS-1$
-				return this.getTypeBinding(this.scope.getJavaLangRuntimeException());
+				return this.getTypeBinding(this.scope.getType(TypeConstants.JAVA_LANG_RUNTIMEEXCEPTION, 3));
 			} else if ("java.lang.Error".equals(name)) {//$NON-NLS-1$
-				return this.getTypeBinding(this.scope.getJavaLangError());
+				return this.getTypeBinding(this.scope.getType(TypeConstants.JAVA_LANG_ERROR, 3));
 			} else if ("java.lang.Class".equals(name)) {//$NON-NLS-1$ 
 				return this.getTypeBinding(this.scope.getJavaLangClass());
 			} else if ("java.lang.Cloneable".equals(name)) {//$NON-NLS-1$ 
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ITypeBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ITypeBinding.java
index 7e0e506..80c9b23 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ITypeBinding.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ITypeBinding.java
@@ -146,11 +146,16 @@
 	 * classes) is the innermost class or interface containing the expression
 	 * or statement in which this type is declared.
 	 * </p>
-	 * <p>The declaring class of a type variable is the class in which the type variable
-	 * is declared if it is declared on a type. It returns <code>null</code> otherwise.
+	 * <p>The declaring class of a type variable is the class in which the type 
+	 * variable is declared if it is declared on a type. It returns 
+	 * <code>null</code> otherwise.
+	 * </p>
+	 * <p>The declaring class of a capture binding is the innermost class or
+	 * interface containing the expression or statement in which this capture is 
+	 * declared.
 	 * </p>
 	 * <p>Array types, primitive types, the null type, top-level types,
-	 * wildcard types, and capture bindings have no declaring class.
+	 * wildcard types have no declaring class.
 	 * </p>
 	 * 
 	 * @return the binding of the type that declares this type, or
@@ -178,6 +183,7 @@
 	 * 
 	 * @return the binding of the method that declares this type, or
 	 * <code>null</code> if none
+	 * @since 3.1
 	 */
 	public IMethodBinding getDeclaringMethod();
 
@@ -215,7 +221,11 @@
 	 * if it has bounds and java.lang.Object if it does not.</li>
 	 * <li>For captures ({@link #isCapture()})
 	 * - returns the binding for the erasure of the leftmost bound
-	 * if it has bounds and java.lang.Object if it does not.</li>	 
+	 * if it has bounds and java.lang.Object if it does not.</li>
+	 * <li>For array types ({@link #isArray()}) - returns an array type of
+	 * the same dimension ({@link #getDimensions()}) as this type
+	 * binding for which the element type is the erasure of the element type
+	 * ({@link #getElementType()}) of this type binding.</li>
 	 * <li>For all other type bindings - returns the identical binding.</li>
 	 * </ul>
 	 *
@@ -445,11 +455,14 @@
 	public ITypeBinding[] getTypeArguments();
 	
 	/**
-	 * Returns the type bounds of this type variable or capture.
+	 * Returns the declared type bounds of this type variable or capture. If the
+	 * variable or the capture had no explicit bound, then it returns an empty list.
      * <p>
-     * Note that the first type bound is always a class type. If the type
-     * variable does not explicitly declare a class type bound, the first
-     * type bound will be the binding for <code>java.lang.Object</code>.
+     * Note that per construction, it can only contain one class or array type, 
+     * at most, and then it is located in first position.
+     * </p>
+     * Also note that array type bound may only occur in the case of a capture
+     * binding, e.g. <code>capture-of ? extends Object[]</code>
      * </p>
 	 *
 	 * @return the list of type bindings for this type variable or capture,
@@ -581,7 +594,11 @@
 	 * Returns whether this type is cast compatible with the given type,
 	 * as specified in section 5.5 of <em>The Java Language 
 	 * Specification, Third Edition</em> (JLS3).
-	 * 
+	 * <p>
+	 * NOTE: The cast compatibility check performs backwards. 
+	 * When testing whether type B can be cast to type A, one would use:
+	 * <code>A.isCastCompatible(B)</code>
+	 * </p>
 	 * @param type the type to check compatibility against
 	 * @return <code>true</code> if this type is cast compatible with the
 	 * given type, and <code>false</code> otherwise
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/InternalASTRewrite.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/InternalASTRewrite.java
index 6b20808..1d6b034 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/InternalASTRewrite.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/InternalASTRewrite.java
@@ -209,7 +209,17 @@
 	
 	
 	void postCloneNodeEvent(ASTNode node, ASTNode clone) {
-		this.clonedNodes.put(clone, node);
+		if(node.ast == root.ast && clone.ast == root.ast) {
+			if((node.getFlags() & ASTNode.ORIGINAL) != 0) {
+				this.clonedNodes.put(clone, node);
+			} else {
+				// node can be a cloned node
+				Object original = this.clonedNodes.get(node);
+				if(original != null) {
+					this.clonedNodes.put(clone, original);
+				}
+			}
+		}
 		this.cloneDepth--;
 	}
 	
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodBinding.java
index 7ed6eb1..c0b6804 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodBinding.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodBinding.java
@@ -28,6 +28,7 @@
 import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
 import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
 import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
+import org.eclipse.jdt.internal.core.JavaElement;
 import org.eclipse.jdt.internal.core.Member;
 import org.eclipse.jdt.internal.core.util.Util;
 
@@ -155,8 +156,15 @@
 		}
 		return this.exceptionTypes;
 	}
-
+	
 	public IJavaElement getJavaElement() {
+		JavaElement element = getUnresolvedJavaElement();
+		if (element == null)
+			return null;
+		return element.resolved(this.binding);
+	}
+
+	private JavaElement getUnresolvedJavaElement() {
 		IType declaringType = (IType) getDeclaringClass().getJavaElement();
 		if (declaringType == null) return null;
 		if (!(this.resolver instanceof DefaultBindingResolver)) return null;
@@ -171,20 +179,22 @@
 					Type type = parameter.getType();
 					String typeSig = Util.getSignature(type);
 					int arrayDim = parameter.getExtraDimensions();
-					if (parameter.isVarargs())
+					if (parameter.getAST().apiLevel() >= AST.JLS3 && parameter.isVarargs()) {
 						arrayDim++;
-					if (arrayDim > 0)
+					}
+					if (arrayDim > 0) {
 						typeSig = Signature.createArraySignature(typeSig, arrayDim);
+					}
 					parameterSignatures.add(typeSig);
 				}
 				int parameterCount = parameterSignatures.size();
 				String[] parameters = new String[parameterCount];
 				parameterSignatures.toArray(parameters);
-				return declaringType.getMethod(getName(), parameters);
+				return (JavaElement) declaringType.getMethod(getName(), parameters);
 			} else {
 				// annotation type member declaration
 				AnnotationTypeMemberDeclaration typeMemberDeclaration = (AnnotationTypeMemberDeclaration) node;
-				return declaringType.getMethod(typeMemberDeclaration.getName().getIdentifier(), new String[0]); // annotation type members don't have parameters
+				return (JavaElement) declaringType.getMethod(typeMemberDeclaration.getName().getIdentifier(), new String[0]); // annotation type members don't have parameters
 			}
 		} else {
 			// case of method not in the created AST, or a binary method
@@ -198,7 +208,7 @@
 			}
 			IMethod result = declaringType.getMethod(selector, parameterSignatures);
 			if (declaringType.isBinary())
-				return result;
+				return (JavaElement) result;
 			IMethod[] methods = null;
 			try {
 				methods = declaringType.getMethods();
@@ -209,7 +219,7 @@
 			IMethod[] candidates = Member.findMethods(result, methods);
 			if (candidates == null || candidates.length == 0)
 				return null;
-			return candidates[0];
+			return (JavaElement) candidates[0];
 		}
 	}
 	
@@ -379,16 +389,25 @@
 	/* (non-Javadoc)
 	 * @see IMethodBinding#overrides(IMethodBinding)
 	 */
-	public boolean overrides(IMethodBinding method) {
-		org.eclipse.jdt.internal.compiler.lookup.MethodBinding otherCompilerBinding = ((MethodBinding) method).binding;
-		if (this.binding == otherCompilerBinding) 
+	public boolean overrides(IMethodBinding overridenMethod) {
+		org.eclipse.jdt.internal.compiler.lookup.MethodBinding overridenCompilerBinding = ((MethodBinding) overridenMethod).binding;
+		if (this.binding == overridenCompilerBinding) 
 			return false;
-		if (!this.binding.declaringClass.isCompatibleWith(otherCompilerBinding.declaringClass))
+		if (!CharOperation.equals(this.binding.selector, overridenCompilerBinding.selector))
 			return false;
-		LookupEnvironment lookupEnvironment = this.resolver.lookupEnvironment();
-		if (lookupEnvironment == null) return false;
-		MethodVerifier methodVerifier = lookupEnvironment.methodVerifier();
-		return methodVerifier.doesMethodOverride(this.binding, otherCompilerBinding);
+		ReferenceBinding match = this.binding.declaringClass.findSuperTypeWithSameErasure(overridenCompilerBinding.declaringClass);
+		if (match == null) return false;
+		
+		org.eclipse.jdt.internal.compiler.lookup.MethodBinding[] superMethods = match.methods();
+		for (int i = 0, length = superMethods.length; i < length; i++) {
+			if (superMethods[i].original() == overridenCompilerBinding) {
+				LookupEnvironment lookupEnvironment = this.resolver.lookupEnvironment();
+				if (lookupEnvironment == null) return false;
+				MethodVerifier methodVerifier = lookupEnvironment.methodVerifier();
+				return methodVerifier.doesMethodOverride(this.binding, superMethods[i]);
+			}
+		}
+		return false;
 	}
 
 	/* 
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeBinding.java
index 81c376d..66f96de 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeBinding.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeBinding.java
@@ -50,6 +50,7 @@
 import org.eclipse.jdt.internal.compiler.lookup.WildcardBinding;
 import org.eclipse.jdt.internal.compiler.util.Util;
 import org.eclipse.jdt.internal.core.ClassFile;
+import org.eclipse.jdt.internal.core.JavaElement;
 
 /**
  * Internal implementation of type bindings.
@@ -277,7 +278,7 @@
 			}
 		} else if (this.binding.isTypeVariable()) {
 			TypeVariableBinding typeVariableBinding = (TypeVariableBinding) this.binding;
-			Binding declaringElement = typeVariableBinding.declaringElement;
+			Binding declaringElement = typeVariableBinding.isCapture() ? ((CaptureBinding) typeVariableBinding).sourceType : typeVariableBinding.declaringElement;
 			if (declaringElement instanceof ReferenceBinding) {
 				try {
 					return this.resolver.getTypeBinding((ReferenceBinding)declaringElement);
@@ -366,23 +367,39 @@
 	}
 	
 	public IJavaElement getJavaElement() {
-		if (this.binding == null) 
+		JavaElement element = getUnresolvedJavaElement();
+		if (element == null)
 			return null;
-		switch (this.binding.kind()) {
+		return element.resolved(this.binding);
+	}
+	
+	private JavaElement getUnresolvedJavaElement() {
+		return getUnresolvedJavaElement(this.binding);
+	}
+	private JavaElement getUnresolvedJavaElement(org.eclipse.jdt.internal.compiler.lookup.TypeBinding typeBinding ) {
+		if (typeBinding == null) 
+			return null;
+		switch (typeBinding.kind()) {
 			case Binding.ARRAY_TYPE :
+				typeBinding = ((ArrayBinding) typeBinding).leafComponentType();
+				return getUnresolvedJavaElement(typeBinding);
 			case Binding.BASE_TYPE :
+			case Binding.WILDCARD_TYPE :
 				return null;
+			default :
+				if (typeBinding.isCapture()) 
+					return null;
 		}
 		ReferenceBinding referenceBinding;
-		if (this.binding.isParameterizedType() || this.binding.isRawType())
-			referenceBinding = (ReferenceBinding) this.binding.erasure();
+		if (typeBinding.isParameterizedType() || typeBinding.isRawType())
+			referenceBinding = (ReferenceBinding) typeBinding.erasure();
 		else
-			referenceBinding = (ReferenceBinding) this.binding;
+			referenceBinding = (ReferenceBinding) typeBinding;
 		char[] fileName = referenceBinding.getFileName();
 		if (Util.isClassFileName(fileName)) {
 			ClassFile classFile = (ClassFile) getClassFile(fileName);
 			if (classFile == null) return null;
-			return classFile.getType();
+			return (JavaElement) classFile.getType();
 		}
 		if (referenceBinding.isLocalType() || referenceBinding.isAnonymousType()) {
 			// local or anonymous type
@@ -393,7 +410,7 @@
 			ASTNode node = (ASTNode) bindingResolver.bindingsToAstNodes.get(this);
 			// must use getElementAt(...) as there is no back pointer to the defining method (scope is null after resolution has ended)
 			try {
-				return cu.getElementAt(node.getStartPosition());
+				return (JavaElement) cu.getElementAt(node.getStartPosition());
 			} catch (JavaModelException e) {
 				// does not exist
 				return null;
@@ -406,11 +423,11 @@
 			if (declaringElement instanceof MethodBinding) {
 				declaringTypeBinding = this.resolver.getMethodBinding((MethodBinding) declaringElement);
 				IMethod declaringMethod = (IMethod) declaringTypeBinding.getJavaElement();
-				return declaringMethod.getTypeParameter(typeVariableName);
+				return (JavaElement) declaringMethod.getTypeParameter(typeVariableName);
 			} else {
 				declaringTypeBinding = this.resolver.getTypeBinding((org.eclipse.jdt.internal.compiler.lookup.TypeBinding) declaringElement);
 				IType declaringType = (IType) declaringTypeBinding.getJavaElement();
-				return declaringType.getTypeParameter(typeVariableName);
+				return (JavaElement) declaringType.getTypeParameter(typeVariableName);
 			}
 		} else {
 			if (fileName == null) return null; // case of a WilCardBinding that doesn't have a corresponding Java element
@@ -420,12 +437,12 @@
 				// top level type
 				ICompilationUnit cu = getCompilationUnit(fileName);
 				if (cu == null) return null;
-				return cu.getType(new String(referenceBinding.sourceName()));
+				return (JavaElement) cu.getType(new String(referenceBinding.sourceName()));
 			} else {
 				// member type
 				IType declaringType = (IType) declaringTypeBinding.getJavaElement();
 				if (declaringType == null) return null;
-				return declaringType.getType(new String(referenceBinding.sourceName()));
+				return (JavaElement) declaringType.getType(new String(referenceBinding.sourceName()));
 			}
 		}
 	}
@@ -769,22 +786,29 @@
 	public ITypeBinding[] getTypeBounds() {
 		if (this.binding instanceof TypeVariableBinding) {
 			TypeVariableBinding typeVariableBinding = (TypeVariableBinding) this.binding;
-			int boundsNumber = 0;
-			ReferenceBinding superclass = typeVariableBinding.superclass();
-			if (superclass != null) {
-				boundsNumber++;
+			ReferenceBinding varSuperclass = typeVariableBinding.superclass();
+			org.eclipse.jdt.internal.compiler.lookup.TypeBinding firstClassOrArrayBound = typeVariableBinding.firstBound;
+			int boundsLength = 0;
+			if (firstClassOrArrayBound != null) {
+				if (firstClassOrArrayBound == varSuperclass) {
+					boundsLength++;
+				} else if (firstClassOrArrayBound.isArrayType()) { // capture of ? extends/super arrayType
+					boundsLength++;
+				} else {
+					firstClassOrArrayBound = null;
+				}
 			}
 			ReferenceBinding[] superinterfaces = typeVariableBinding.superInterfaces();
 			int superinterfacesLength = 0;
 			if (superinterfaces != null) {
 				superinterfacesLength = superinterfaces.length;
-				boundsNumber += superinterfacesLength;
+				boundsLength += superinterfacesLength;
 			}
-			if (boundsNumber != 0) {
-				ITypeBinding[] typeBounds = new ITypeBinding[boundsNumber];
+			if (boundsLength != 0) {
+				ITypeBinding[] typeBounds = new ITypeBinding[boundsLength];
 				int boundsIndex = 0;
-				if (superclass != null) {
-					typeBounds[boundsIndex++] = this.resolver.getTypeBinding(superclass);
+				if (firstClassOrArrayBound != null) {
+					typeBounds[boundsIndex++] = this.resolver.getTypeBinding(firstClassOrArrayBound);
 				}
 				if (superinterfaces != null) {
 					for (int i = 0; i < superinterfacesLength; i++, boundsIndex++) {
@@ -894,14 +918,17 @@
 		};
 		Scope scope = this.resolver.scope();
 		if (scope == null) return false;
-		return expression.checkCastTypesCompatibility(scope, this.binding, ((TypeBinding) type).binding, null);
+		org.eclipse.jdt.internal.compiler.lookup.TypeBinding expressionType = ((TypeBinding) type).binding;
+		// simulate capture in case checked binding did not properly get extracted from a reference
+		expressionType = expressionType.capture(scope, 0);
+		return expression.checkCastTypesCompatibility(scope, this.binding, expressionType, null);
 	}
 
 	/*
 	 * @see ITypeBinding#isClass()
 	 */
 	public boolean isClass() {
-		return this.binding.isClass() && !this.binding.isTypeVariable();
+		return this.binding.isClass() && !this.binding.isTypeVariable() && !this.binding.isWildcard();
 	}
 
 	/*
@@ -961,6 +988,28 @@
 			} else {
 				return !referenceBinding.isBinaryBinding();
 			}
+		} else if (isTypeVariable()) {
+			final TypeVariableBinding typeVariableBinding = (TypeVariableBinding) this.binding;
+			final Binding declaringElement = typeVariableBinding.declaringElement;
+			if (declaringElement instanceof MethodBinding) {
+				MethodBinding methodBinding = (MethodBinding) declaringElement;
+				return !methodBinding.declaringClass.isBinaryBinding();
+			} else {
+				final org.eclipse.jdt.internal.compiler.lookup.TypeBinding typeBinding = (org.eclipse.jdt.internal.compiler.lookup.TypeBinding) declaringElement;
+				if (typeBinding instanceof ReferenceBinding) {
+					return !((ReferenceBinding) typeBinding).isBinaryBinding();
+				} else if (typeBinding instanceof ArrayBinding) {
+					final ArrayBinding arrayBinding = (ArrayBinding) typeBinding;
+					final org.eclipse.jdt.internal.compiler.lookup.TypeBinding leafComponentType = arrayBinding.leafComponentType;
+					if (leafComponentType instanceof ReferenceBinding) {
+						return !((ReferenceBinding) leafComponentType).isBinaryBinding();
+					}
+				}
+			}
+			
+		} else if (isCapture()) {
+			CaptureBinding captureBinding = (CaptureBinding) this.binding;
+			return !captureBinding.sourceType.isBinaryBinding();
 		}
 		return false;
 	}
@@ -969,7 +1018,7 @@
 	 * @see ITypeBinding#isInterface()
 	 */
 	public boolean isInterface() {
-		return this.binding.isInterface();
+		return this.binding.isInterface() && !this.binding.isTypeVariable() && !this.binding.isWildcard();
 	}
 
 	/*
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableBinding.java
index 17532f0..6e4fa9c 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableBinding.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableBinding.java
@@ -125,13 +125,20 @@
 	 * @see IBinding#getJavaElement()
 	 */
 	public IJavaElement getJavaElement() {
+		JavaElement element = getUnresolvedJavaElement();
+		if (element == null)
+			return null;
+		return element.resolved(this.binding);
+	}
+	
+	private JavaElement getUnresolvedJavaElement() {
 		if (isField()) {
 			// field
 			FieldBinding fieldBinding = (FieldBinding) this.binding;
 			if (fieldBinding.declaringClass == null) return null; // arraylength
 			IType declaringType = (IType) getDeclaringClass().getJavaElement();
 			if (declaringType == null) return null;
-			return declaringType.getField(getName());
+			return (JavaElement) declaringType.getField(getName());
 		}
 		// local variable
 		IMethodBinding declaringMethod = getDeclaringMethod();
@@ -153,9 +160,9 @@
 		} else {
 			nameStart =  localVar.getStartPosition();
 			nameLength = localVar.getLength();
-			VariableDeclarationStatement statement = (VariableDeclarationStatement) localVar.getParent();
-			sourceStart = statement.getStartPosition();
-			sourceLength = statement.getLength();
+			ASTNode node = localVar.getParent();
+			sourceStart = node.getStartPosition();
+			sourceLength = node.getLength();
 		}
 		char[] typeSig = this.binding.type.genericTypeSignature();
 		return new LocalVariable(method, localVar.getName().getIdentifier(), sourceStart, sourceStart+sourceLength-1, nameStart, nameStart+nameLength-1, new String(typeSig));
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ASTRewrite.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ASTRewrite.java
index 0c5e848..9cd1c5b 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ASTRewrite.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ASTRewrite.java
@@ -178,10 +178,14 @@
 		if (rootNode != null) {
 			//validateASTNotModified(rootNode);
 			
-			getRewriteEventStore().markMovedNodesRemoved();
+			TargetSourceRangeComputer sourceRangeComputer= getExtendedSourceRangeComputer();
+			
+			this.eventStore.prepareMovedNodes(sourceRangeComputer);
 
-			ASTRewriteAnalyzer visitor= new ASTRewriteAnalyzer(document, result, this.eventStore, this.nodeStore, options, getExtendedSourceRangeComputer());
+			ASTRewriteAnalyzer visitor= new ASTRewriteAnalyzer(document, result, this.eventStore, this.nodeStore, options, sourceRangeComputer);
 			rootNode.accept(visitor); // throws IllegalArgumentException
+			
+			this.eventStore.revertMovedNodes();
 		}
 		return result;
 	}
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ListRewrite.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ListRewrite.java
index 540603b..9aa2b12 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ListRewrite.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ListRewrite.java
@@ -13,19 +13,18 @@
 import java.util.Collections;
 import java.util.List;
 
-import org.eclipse.text.edits.TextEditGroup;
-
 import org.eclipse.jdt.core.dom.ASTNode;
+import org.eclipse.jdt.core.dom.Block;
 import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor;
 import org.eclipse.jdt.core.dom.FieldDeclaration;
 import org.eclipse.jdt.core.dom.Statement;
 import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor;
-
 import org.eclipse.jdt.internal.core.dom.rewrite.ListRewriteEvent;
 import org.eclipse.jdt.internal.core.dom.rewrite.NodeInfoStore;
 import org.eclipse.jdt.internal.core.dom.rewrite.RewriteEvent;
 import org.eclipse.jdt.internal.core.dom.rewrite.RewriteEventStore;
 import org.eclipse.jdt.internal.core.dom.rewrite.RewriteEventStore.CopySourceInfo;
+import org.eclipse.text.edits.TextEditGroup;
 
 /**
  * For describing manipulations to a child list property of an AST node.
@@ -290,18 +289,19 @@
 	}
 	
 	
-	private ASTNode createTargetNode(ASTNode first, ASTNode last, boolean isMove) {
+	private ASTNode createTargetNode(ASTNode first, ASTNode last, boolean isMove, ASTNode replacingNode, TextEditGroup editGroup) {
 		if (first == null || last == null) {
 			throw new IllegalArgumentException();
 		}
-		//validateIsInsideAST(node);
-		CopySourceInfo info= getRewriteStore().markAsRangeCopySource(this.parent, this.childProperty, first, last, isMove);
-	
+
 		NodeInfoStore nodeStore= this.rewriter.getNodeStore();
 		ASTNode placeholder= nodeStore.newPlaceholderNode(first.getNodeType()); // revisit: could use list type
 		if (placeholder == null) {
 			throw new IllegalArgumentException("Creating a target node is not supported for nodes of type" + first.getClass().getName()); //$NON-NLS-1$
 		}
+		
+		Block internalPlaceHolder= nodeStore.createCollapsePlaceholder();
+		CopySourceInfo info= getRewriteStore().createRangeCopy(this.parent, this.childProperty, first, last, isMove, internalPlaceHolder, replacingNode, editGroup);
 		nodeStore.markAsCopyTarget(placeholder, info);
 		
 		return placeholder;		
@@ -318,14 +318,16 @@
 	 * @param first the node that starts the range
 	 * @param last the node that ends the range
 	 * @return the new placeholder node
-	 * @throws IllegalArgumentException if the node is null, or if the node
-	 * is not part of this rewriter's AST
+	 * @throws IllegalArgumentException An exception is thrown if the first or last node
+	 * are <code>null</code>, if a node is not a child of the current list or if the first node
+	 * is not before the last node. An <code>IllegalArgumentException</code> is
+	 * also thrown if the copied range is overlapping with an other moved or copied range. 
 	 */
 	public final ASTNode createCopyTarget(ASTNode first, ASTNode last) {
 		if (first == last) {
 			return this.rewriter.createCopyTarget(first);
 		} else {
-			return createTargetNode(first, last, false);
+			return createTargetNode(first, last, false, null, null);
 		}
 	}
 	
@@ -340,16 +342,47 @@
 	 * @param first the node that starts the range
 	 * @param last the node that ends the range
 	 * @return the new placeholder node
-	 * @throws IllegalArgumentException if the node is null, or if the node
-	 * is not part of this rewriter's AST
+	 * @throws IllegalArgumentException An exception is thrown if the first or last node
+	 * are <code>null</code>, if a node is not a child of the current list or if the first node
+	 * is not before the last node. An <code>IllegalArgumentException</code> is
+	 * also thrown if the moved range is overlapping with an other moved or copied range. 
 	 * 
 	 * @since 3.1
 	 */
 	public final ASTNode createMoveTarget(ASTNode first, ASTNode last) {
+		return createMoveTarget(first, last, null, null);
+	}
+	
+	/**
+	 * Creates and returns a placeholder node for a move of a range of nodes of the
+	 * current list. The moved nodes can optionally be replaced by a specified node.
+	 * 
+	 * The placeholder node can either be inserted as new or used to replace an
+	 * existing node. When the document is rewritten, a copy of the source code 
+	 * for the given node range is inserted into the output document at the position
+	 * corresponding to the placeholder (indentation is adjusted).
+	 * 
+	 * @param first the node that starts the range
+	 * @param last the node that ends the range
+	 * @param replacingNode a node that is set at the location of the moved nodes
+	 * or <code>null</code> to remove all nodes
+	 * @param editGroup the edit group in which to collect the corresponding
+	 * text edits fro a replace, or <code>null</code> if ungrouped
+	 * @return the new placeholder node
+	 * @throws IllegalArgumentException An exception is thrown if the first or
+	 * last node are <code>null</code>, if a node is not a child of the current list or
+	 * if the first node is not before the last node. An <code>IllegalArgumentException
+	 * </code> is also thrown if the moved range is overlapping with an other moved
+	 * or copied range. 
+	 * 
+	 * @since 3.1
+	 */
+	public final ASTNode createMoveTarget(ASTNode first, ASTNode last, ASTNode replacingNode, TextEditGroup editGroup) {
 		if (first == last) {
+			replace(first, replacingNode, editGroup);
 			return this.rewriter.createMoveTarget(first);
 		} else {
-			return createTargetNode(first, last, true);
+			return createTargetNode(first, last, true, replacingNode, editGroup);
 		}
 	}
 	
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/TargetSourceRangeComputer.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/TargetSourceRangeComputer.java
index 2c24289..1104552 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/TargetSourceRangeComputer.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/TargetSourceRangeComputer.java
@@ -125,9 +125,11 @@
 	 * that should be replaced (or deleted)
 	 */
 	public SourceRange computeSourceRange(ASTNode node) {
-		CompilationUnit cu = (CompilationUnit) node.getRoot();
-		return new SourceRange(
-				cu.getExtendedStartPosition(node),
-				cu.getExtendedLength(node));
+		ASTNode root= node.getRoot();
+		if (root instanceof CompilationUnit) {
+			CompilationUnit cu= (CompilationUnit) root;
+			return new SourceRange(cu.getExtendedStartPosition(node), cu.getExtendedLength(node));
+		}
+		return new SourceRange(node.getStartPosition(), node.getLength());
 	}
 }
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/package.html b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/package.html
new file mode 100644
index 0000000..2f568ac
--- /dev/null
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/package.html
@@ -0,0 +1,18 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <meta name="Author" content="IBM">
+   <title>Package-level Javadoc</title>
+</head>
+<body>
+The Java DOM/AST rewrite is the set of classes that are used to make changes to an existing DOM/AST tree.
+
+<h2>
+Package Specification</h2>
+
+<p>This package contains the Java DOM/AST classes used to make changes to an existing DOM/AST tree.
+The principal classes are {@link org.eclipse.jdt.core.dom.rewrite.ASTRewrite ASTRewrite} and
+{@link org.eclipse.jdt.core.dom.rewrite.ListRewrite ListRewrite}.</p>
+</body>
+</html>
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java
index 81f09de..957af20 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java
@@ -114,41 +114,33 @@
 	}
 	
 	/**
-	 * Returns the extended source range computer for this AST rewriter.
+	 * Returns the extended source range for a node.
 	 * 
-	 * @return an extended source range computer (never null)
+	 * @return an extended source range (never null)
 	 * @since 3.1
 	 */
-	private TargetSourceRangeComputer getExtendedSourceRangeComputer() {
-		return this.extendedSourceRangeComputer;
-	}
-	
 	final SourceRange getExtendedRange(ASTNode node) {
-		return getExtendedSourceRangeComputer().computeSourceRange(node);
+		if (this.eventStore.isRangeCopyPlaceholder(node)) {
+			return new SourceRange(node.getStartPosition(), node.getLength());
+		}
+		return this.extendedSourceRangeComputer.computeSourceRange(node);
 	}
 	
 	final int getExtendedOffset(ASTNode node) {
-		return getExtendedSourceRangeComputer().computeSourceRange(node).getStartPosition();
+		return getExtendedRange(node).getStartPosition();
 	}
 	
 	final int getExtendedEnd(ASTNode node) {
-		TargetSourceRangeComputer.SourceRange range =
-			getExtendedSourceRangeComputer().computeSourceRange(node);
+		TargetSourceRangeComputer.SourceRange range= getExtendedRange(node);
 		return range.getStartPosition() + range.getLength();
 	}
 	
 	final TextEdit getCopySourceEdit(CopySourceInfo info) {
 		TextEdit edit= (TextEdit) this.sourceCopyInfoToEdit.get(info);
 		if (edit == null) {
-			int start, end;
-			if (info.getStartNode() == info.getEndNode()) {
-				SourceRange range= getExtendedRange(info.getStartNode());
-				start= range.getStartPosition();
-				end= start + range.getLength();
-			} else {
-				start= getExtendedOffset(info.getStartNode());
-				end= getExtendedEnd(info.getEndNode());
-			}
+			SourceRange range= getExtendedRange(info.getNode());
+			int start= range.getStartPosition();
+			int end= start + range.getLength();
 			if (info.isMove) {
 				MoveSourceEdit moveSourceEdit= new MoveSourceEdit(start, end - start);
 				moveSourceEdit.setTargetEdit(new MoveTargetEdit(0));
@@ -284,32 +276,18 @@
 		if (property.isChildProperty() && node != null) {
 			return doVisit((ASTNode) node);
 		} else if (property.isChildListProperty()) {
-			boolean hasRangeCopySources= this.eventStore.hasRangeCopySources(parent, property);
-			return doVisitList((List) node, offset, hasRangeCopySources);
+			return doVisitList((List) node, offset);
 		}
 		return offset;
 	}
 	
-	private int doVisitList(List list, int offset, boolean hasRangeCopySources) {
-		if (hasRangeCopySources) {
-			// list with copy source ranges
-			Stack nodeRangeEndStack= new Stack();
-			int endPos= offset;
-			for (Iterator iter= list.iterator(); iter.hasNext();) {
-				ASTNode curr= ((ASTNode) iter.next());
-				doCopySourcePreVisit(this.eventStore.getRangeCopySources(curr), nodeRangeEndStack);
-				endPos= doVisit(curr);
-				doCopySourcePostVisit(curr, nodeRangeEndStack);
-			}
-			return endPos;
-		} else {
-			int endPos= offset;
-			for (Iterator iter= list.iterator(); iter.hasNext();) {
-				ASTNode curr= ((ASTNode) iter.next());
-				endPos= doVisit(curr);
-			}
-			return endPos;
+	private int doVisitList(List list, int offset) {
+		int endPos= offset;
+		for (Iterator iter= list.iterator(); iter.hasNext();) {
+			ASTNode curr= ((ASTNode) iter.next());
+			endPos= doVisit(curr);
 		}
+		return endPos;
 	}
 	
 	final void voidVisit(ASTNode node) {
@@ -321,42 +299,20 @@
 		if (property.isChildProperty() && node != null) {
 			voidVisit((ASTNode) node);
 		} else if (property.isChildListProperty()) {
-			boolean hasRangeCopySources= this.eventStore.hasRangeCopySources(parent, property);
-			voidVisitList((List) node, hasRangeCopySources);
+			voidVisitList((List) node);
 		}
 	}
 	
-	private void voidVisitList(List list, boolean hasRangeCopySources) {
-		if (hasRangeCopySources) {
-			// list with copy source ranges
-			Stack nodeRangeEndStack= new Stack();
-			for (Iterator iter= list.iterator(); iter.hasNext();) {
-				ASTNode curr= ((ASTNode) iter.next());
-				doCopySourcePreVisit(this.eventStore.getRangeCopySources(curr), nodeRangeEndStack);
-				doVisit(curr);
-				doCopySourcePostVisit(curr, nodeRangeEndStack);
-			}
-		} else {
-			for (Iterator iter= list.iterator(); iter.hasNext();) {
-				doVisit(((ASTNode) iter.next()));
-			}
+	private void voidVisitList(List list) {
+		for (Iterator iter= list.iterator(); iter.hasNext();) {
+			doVisit(((ASTNode) iter.next()));
 		}
 	}
 	
 	private final boolean doVisitUnchangedChildren(ASTNode parent) {
 		List properties= parent.structuralPropertiesForType();
 		for (int i= 0; i < properties.size(); i++) {
-			StructuralPropertyDescriptor property= (StructuralPropertyDescriptor) properties.get(i);
-			if (property.isChildProperty()) {
-				ASTNode child= (ASTNode) parent.getStructuralProperty(property);
-				if (child != null) {
-					voidVisit(child);
-				}
-			} else if (property.isChildListProperty()) {
-				List list= (List) parent.getStructuralProperty(property);
-				boolean hasRangeCopySources= this.eventStore.hasRangeCopySources(parent, property);
-				voidVisitList(list, hasRangeCopySources);
-			}
+			voidVisit(parent, (StructuralPropertyDescriptor) properties.get(i));
 		}
 		return false;
 	}
@@ -409,12 +365,14 @@
 		
 		protected RewriteEvent[] list;
 		
-		private Stack copyRangeEndStack;
-		
 		protected final ASTNode getOriginalNode(int index) {
 			return (ASTNode) this.list[index].getOriginalValue();
 		}
 		
+		protected final ASTNode getNewNode(int index) {
+			return (ASTNode) this.list[index].getNewValue();
+		}
+		
 		protected String getSeparatorString(int nodeIndex) {
 			return this.contantSeparator;
 		}
@@ -422,7 +380,7 @@
 		protected int getInitialIndent() {
 			return getIndent(this.startPos);
 		}
-		
+				
 		protected int getNodeIndent(int nodeIndex) {
 			ASTNode node= getOriginalNode(nodeIndex);
 			if (node == null) {
@@ -465,8 +423,6 @@
 			this.startPos= offset;
 			this.list= getEvent(parent, property).getChildren();
 			
-			initCopyRangeChecks(parent, property);
-			
 			int total= this.list.length;
 			if (total == 0) {
 				return this.startPos;
@@ -543,17 +499,13 @@
 					if (i > lastNonDelete && separatorState == EXISTING) {
 						// is last, remove previous separator: split delete to allow range copies
 						doTextRemove(prevEnd, currPos - prevEnd, editGroup); // remove separator
-						checkForRangeStart(node);
 						doTextRemoveAndVisit(currPos, currEnd - currPos, node, editGroup); // remove node
-						checkForRangeEnd(node);
 						currPos= currEnd;
 						prevEnd= currEnd;
 					} else {
 						// remove element and next separator
 						int end= getStartOfNextNode(nextIndex, currEnd); // start of next
-						checkForRangeStart(node);
 						doTextRemoveAndVisit(currPos, currEnd - currPos, node, getEditGroup(currEvent)); // remove node
-						checkForRangeEnd(node);
 						doTextRemove(currEnd, end - currEnd, editGroup); // remove separator
 						currPos= end;
 						prevEnd= currEnd;
@@ -566,17 +518,13 @@
 						
 						TextEditGroup editGroup= getEditGroup(currEvent);
 						ASTNode changed= (ASTNode) currEvent.getNewValue();
-						checkForRangeStart(node);
 						doTextRemoveAndVisit(currPos, currEnd - currPos, node, editGroup);
 						doTextInsert(currPos, changed, getNodeIndent(i), true, editGroup);
-						checkForRangeEnd(node);
 						
 						prevEnd= currEnd;
 					} else { // is unchanged
 						ASTNode node= (ASTNode) currEvent.getOriginalValue();
-						checkForRangeStart(node);
 						voidVisit(node);
-						checkForRangeEnd(node);
 					}
 					if (i == lastNonInsert) { // last node or next nodes are all inserts
 						separatorState= NONE;
@@ -600,23 +548,6 @@
 			return currPos;
 		}
 		
-		private void initCopyRangeChecks(ASTNode parent, StructuralPropertyDescriptor property) {
-			if (ASTRewriteAnalyzer.this.eventStore.hasRangeCopySources(parent, property)) {
-				this.copyRangeEndStack= new Stack();
-			}
-		}
-
-		private void checkForRangeStart(ASTNode node) {
-			if (this.copyRangeEndStack != null) {
-				doCopySourcePreVisit(ASTRewriteAnalyzer.this.eventStore.getRangeCopySources(node), this.copyRangeEndStack);
-			}
-		}
-		
-		private void checkForRangeEnd(ASTNode node) {
-			if (this.copyRangeEndStack != null) {
-				doCopySourcePostVisit(node, this.copyRangeEndStack);
-			}
-		}
 	}
 				
 	private int rewriteRequiredNode(ASTNode parent, StructuralPropertyDescriptor property) {
@@ -917,7 +848,7 @@
 		return listRewriter.rewriteList(parent, property, insertPos, leadString.toString());
 	}
 	
-	private int rewriteOptionalTypeParameters(ASTNode parent, StructuralPropertyDescriptor property, int offset, String keyword, boolean adjustOnNext) {
+	private int rewriteOptionalTypeParameters(ASTNode parent, StructuralPropertyDescriptor property, int offset, String keyword, boolean adjustOnNext, boolean needsSpaceOnRemoveAll) {
 		int pos= offset;
 		RewriteEvent event= getEvent(parent, property);
 		if (event != null && event.getChangeKind() != RewriteEvent.UNCHANGED) {
@@ -929,13 +860,18 @@
 				}
 				boolean isAllRemoved= !isAllInserted && isAllOfKind(children, RewriteEvent.REMOVED);
 				if (isAllRemoved) { // all removed: set start to left bracket
-					pos= getScanner().getTokenStartOffset(ITerminalSymbols.TokenNameLESS, pos);
+					int posBeforeOpenBracket= getScanner().getTokenStartOffset(ITerminalSymbols.TokenNameLESS, pos);
+					if (posBeforeOpenBracket != pos) {
+						needsSpaceOnRemoveAll= false;
+					}
+					pos= posBeforeOpenBracket;
 				}
 				pos= new ListRewriter().rewriteList(parent, property, pos, String.valueOf('<'), ", "); //$NON-NLS-1$ //$NON-NLS-2$
 				if (isAllRemoved) { // all removed: remove right and space up to next element
 					int endPos= getScanner().getTokenEndOffset(ITerminalSymbols.TokenNameGREATER, pos); // set pos to '>'
 					endPos= getScanner().getNextStartOffset(endPos, false);
-					doTextRemove(pos, endPos - pos, getEditGroup(children[children.length - 1]));
+					String replacement= needsSpaceOnRemoveAll ? String.valueOf(' ') : new String();
+					doTextReplace(pos, endPos - pos, replacement, getEditGroup(children[children.length - 1]));
 					return endPos;
 				} else if (isAllInserted) {
 					doTextInsert(pos, String.valueOf('>' + keyword), getEditGroup(children[children.length - 1]));
@@ -1109,7 +1045,7 @@
 				String destIndentString=  this.formatter.getIndentString(getCurrentLine(formatted, offset));
 				if (data instanceof CopyPlaceholderData) { // replace with a copy/move target
 					CopySourceInfo copySource= ((CopyPlaceholderData) data).copySource;
-					int srcIndentLevel= getIndent(copySource.getStartNode().getStartPosition());
+					int srcIndentLevel= getIndent(copySource.getNode().getStartPosition());
 					TextEdit sourceEdit= getCopySourceEdit(copySource);
 					doTextCopy(sourceEdit, insertOffset, srcIndentLevel, destIndentString, editGroup);
 					currPos= offset + curr.length; // continue to insert after the replaced string
@@ -1201,6 +1137,27 @@
 		}
 	}
 	
+	private class ModifierRewriter extends ListRewriter {
+		
+		private final Prefix annotationSeparation;
+
+		public ModifierRewriter(Prefix annotationSeparation) {
+			this.annotationSeparation= annotationSeparation;
+		}
+		
+		/* (non-Javadoc)
+		 * @see org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.ListRewriter#getSeparatorString(int)
+		 */
+		protected String getSeparatorString(int nodeIndex) {
+			ASTNode curr= getNewNode(nodeIndex);
+			if (curr instanceof Annotation) {
+				return this.annotationSeparation.getPrefix(getNodeIndent(nodeIndex + 1));
+			}
+			return super.getSeparatorString(nodeIndex);
+		}
+	}
+	
+	
 	private int rewriteModifiers2(ASTNode node, ChildListPropertyDescriptor property, int pos) {
 		RewriteEvent event= getEvent(node, property);
 		if (event == null || event.getChangeKind() == RewriteEvent.UNCHANGED) {
@@ -1217,7 +1174,8 @@
 				handleException(e);
 			}
 		}
-		int endPos= rewriteNodeList(node, property, pos, "", " "); //$NON-NLS-1$ //$NON-NLS-2$
+		
+		int endPos= new ModifierRewriter(this.formatter.ANNOTATION_SEPARATION).rewriteList(node, property, pos, "", " "); //$NON-NLS-1$ //$NON-NLS-2$
 
 		if (isAllInsert) {
 			doTextInsert(endPos, " ", getEditGroup(children[children.length - 1])); //$NON-NLS-1$
@@ -1297,7 +1255,7 @@
 				TextEdit edit= getCopySourceEdit(curr);
 				addEdit(edit);
 				this.currentEdit= edit;
-				nodeEndStack.push(curr.getEndNode());
+				nodeEndStack.push(curr.getNode());
 			}
 		}
 	}
@@ -1368,7 +1326,7 @@
 		pos= rewriteRequiredNode(node, TypeDeclaration.NAME_PROPERTY);
 		
 		if (apiLevel >= AST.JLS3) {
-			pos= rewriteOptionalTypeParameters(node, TypeDeclaration.TYPE_PARAMETERS_PROPERTY, pos, "", false); //$NON-NLS-1$
+			pos= rewriteOptionalTypeParameters(node, TypeDeclaration.TYPE_PARAMETERS_PROPERTY, pos, "", false, true); //$NON-NLS-1$
 		}
 		
 		// superclass
@@ -1486,7 +1444,7 @@
 			rewriteModifiers(node, MethodDeclaration.MODIFIERS_PROPERTY, pos);
 		} else {
 			pos= rewriteModifiers2(node, MethodDeclaration.MODIFIERS2_PROPERTY, pos);
-			pos= rewriteOptionalTypeParameters(node, MethodDeclaration.TYPE_PARAMETERS_PROPERTY, pos, " ", true); //$NON-NLS-1$
+			pos= rewriteOptionalTypeParameters(node, MethodDeclaration.TYPE_PARAMETERS_PROPERTY, pos, " ", true, pos != node.getStartPosition()); //$NON-NLS-1$
 		}
 		
 		boolean isConstructorChange= isChanged(node, MethodDeclaration.CONSTRUCTOR_PROPERTY);
@@ -1846,7 +1804,7 @@
 			if (isChanged(node, ClassInstanceCreation.TYPE_ARGUMENTS_PROPERTY)) {
 				try {
 					pos= getScanner().getTokenEndOffset(ITerminalSymbols.TokenNamenew, pos); //after 'new'
-					rewriteOptionalTypeParameters(node, ClassInstanceCreation.TYPE_ARGUMENTS_PROPERTY, pos, " ", true); //$NON-NLS-1$
+					rewriteOptionalTypeParameters(node, ClassInstanceCreation.TYPE_ARGUMENTS_PROPERTY, pos, " ", true, true); //$NON-NLS-1$
 				} catch (CoreException e) {
 					handleException(e);
 				}
@@ -1904,7 +1862,7 @@
 		}
 		int pos= node.getStartPosition();
 		if (node.getAST().apiLevel() >= AST.JLS3) {
-			pos= rewriteOptionalTypeParameters(node, ConstructorInvocation.TYPE_ARGUMENTS_PROPERTY, pos, "", false); //$NON-NLS-1$
+			pos= rewriteOptionalTypeParameters(node, ConstructorInvocation.TYPE_ARGUMENTS_PROPERTY, pos, "", false, false); //$NON-NLS-1$
 		}
 		try {
 			pos= getScanner().getTokenEndOffset(ITerminalSymbols.TokenNameLPAREN, pos);
@@ -2278,7 +2236,7 @@
 		
 		int pos= rewriteOptionalQualifier(node, MethodInvocation.EXPRESSION_PROPERTY, node.getStartPosition());
 		if (node.getAST().apiLevel() >= AST.JLS3) {
-			pos= rewriteOptionalTypeParameters(node, MethodInvocation.TYPE_ARGUMENTS_PROPERTY, pos, "", false); //$NON-NLS-1$
+			pos= rewriteOptionalTypeParameters(node, MethodInvocation.TYPE_ARGUMENTS_PROPERTY, pos, "", false, false); //$NON-NLS-1$
 		}
 
 		pos= rewriteRequiredNode(node, MethodInvocation.NAME_PROPERTY);
@@ -2501,7 +2459,7 @@
 		int pos= rewriteOptionalQualifier(node, SuperConstructorInvocation.EXPRESSION_PROPERTY, node.getStartPosition());
 
 		if (node.getAST().apiLevel() >= AST.JLS3) {
-			pos= rewriteOptionalTypeParameters(node, SuperConstructorInvocation.TYPE_ARGUMENTS_PROPERTY, pos, "", false); //$NON-NLS-1$
+			pos= rewriteOptionalTypeParameters(node, SuperConstructorInvocation.TYPE_ARGUMENTS_PROPERTY, pos, "", false, false); //$NON-NLS-1$
 		}
 		
 		if (isChanged(node, SuperConstructorInvocation.ARGUMENTS_PROPERTY)) {
@@ -2545,7 +2503,7 @@
 			if (isChanged(node, SuperMethodInvocation.TYPE_ARGUMENTS_PROPERTY)) {
 				try {
 					pos= getScanner().getTokenEndOffset(ITerminalSymbols.TokenNameDOT, pos);
-					rewriteOptionalTypeParameters(node, SuperMethodInvocation.TYPE_ARGUMENTS_PROPERTY, pos, "", false); //$NON-NLS-1$
+					rewriteOptionalTypeParameters(node, SuperMethodInvocation.TYPE_ARGUMENTS_PROPERTY, pos, "", false, false); //$NON-NLS-1$
 				} catch (CoreException e) {
 					handleException(e);
 				}
@@ -2884,52 +2842,45 @@
 		int changeKind= getChangeKind(node, TagElement.TAG_NAME_PROPERTY);
 		switch (changeKind) {
 			case RewriteEvent.INSERTED: {
-			    String newTagName= '@' + (String) getNewValue(node, TagElement.TAG_NAME_PROPERTY);
+			    String newTagName= (String) getNewValue(node, TagElement.TAG_NAME_PROPERTY);
 				doTextInsert(node.getStartPosition(), newTagName, getEditGroup(node, TagElement.TAG_NAME_PROPERTY));
 				break;
 			}
 			case RewriteEvent.REMOVED: {
-			    String oldTag= (String) getOriginalValue(node, TagElement.TAG_NAME_PROPERTY);
-			    int tagEnd= findTagNameStart(node)  + oldTag.length();
-			    doTextRemove(node.getStartPosition(), tagEnd - node.getStartPosition(), getEditGroup(node, TagElement.TAG_NAME_PROPERTY));
+			    doTextRemove(node.getStartPosition(), findTagNameEnd(node) - node.getStartPosition(), getEditGroup(node, TagElement.TAG_NAME_PROPERTY));
 			    break;
 			}
 			case RewriteEvent.REPLACED: {
 			    String newTagName= (String) getNewValue(node, TagElement.TAG_NAME_PROPERTY);
-		    	String oldTag= (String) getOriginalValue(node, TagElement.TAG_NAME_PROPERTY);
-		    	int tagStart= findTagNameStart(node);
-		    	doTextReplace(tagStart, oldTag.length(), newTagName, getEditGroup(node, TagElement.TAG_NAME_PROPERTY));
+		    	doTextReplace(node.getStartPosition(), findTagNameEnd(node) - node.getStartPosition(), newTagName, getEditGroup(node, TagElement.TAG_NAME_PROPERTY));
 			    break;
 			}
 		}
 				
 		if (isChanged(node, TagElement.FRAGMENTS_PROPERTY)) {
 			// eval position after name
-			int startOffset= node.getStartPosition();
-            String oldTag= (String) getOriginalValue(node, TagElement.TAG_NAME_PROPERTY);
-            if (oldTag != null) {
-                startOffset= findTagNameStart(node) + oldTag.length();
-            }
-            
-            rewriteNodeList(node, TagElement.FRAGMENTS_PROPERTY, startOffset, " ", " ");  //$NON-NLS-1$//$NON-NLS-2$
+			int endOffset= findTagNameEnd(node);
+            rewriteNodeList(node, TagElement.FRAGMENTS_PROPERTY, endOffset, " ", " ");  //$NON-NLS-1$//$NON-NLS-2$
 		} else {
 			voidVisit(node, TagElement.FRAGMENTS_PROPERTY);
 		}
 		return false;
 	}
 		
-	private int findTagNameStart(ASTNode tagNode) {
-	    try {
-	        IDocument doc = getDocument();
-	        int i= tagNode.getStartPosition();
-	        int end= i + tagNode.getLength();
-	        while (i < end && !Character.isJavaIdentifierStart(doc.getChar(i))) {
-	            i++;
-	        }
-	        return i;
-	    } catch (BadLocationException e) {
-	        handleException(e);
-	    }
+	private int findTagNameEnd(TagElement tagNode) {
+		if (tagNode.getTagName() != null) {
+		    try {
+		        IDocument doc = getDocument();
+		        int len= doc.getLength();
+		        int i= tagNode.getStartPosition();
+		        while (i < len && !Indents.isIndentChar(doc.getChar(i))) {
+		            i++;
+		        }
+		        return i;
+		    } catch (BadLocationException e) {
+		        handleException(e);
+		    }
+		}
 	    return tagNode.getStartPosition();
 	}
 		
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFormatter.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFormatter.java
index c0a105f..ffb0621 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFormatter.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFormatter.java
@@ -334,8 +334,8 @@
 					code= CodeFormatter.K_COMPILATION_UNIT;
 					break;
 				case ASTNode.JAVADOC:
-					suffix= "void foo();"; //$NON-NLS-1$
-					code= CodeFormatter.K_CLASS_BODY_DECLARATIONS;
+					suffix= "\nclass A {}"; //$NON-NLS-1$
+					code= CodeFormatter.K_COMPILATION_UNIT;
 					break;
 				case ASTNode.CATCH_CLAUSE:
 					prefix= "try {}"; //$NON-NLS-1$
@@ -365,8 +365,27 @@
 				case ASTNode.METHOD_REF_PARAMETER:
 				case ASTNode.TAG_ELEMENT:
 				case ASTNode.TEXT_ELEMENT:
-					// Javadoc formatting not yet supported:
-				    return null;
+					// javadoc formatting disabled due to bug 93644
+					return null; 
+
+//				wiat for bug 93644 
+//				case ASTNode.MEMBER_REF:
+//				case ASTNode.METHOD_REF:
+//					prefix= "/**\n * @see "; //$NON-NLS-1$
+//					suffix= "\n*/"; //$NON-NLS-1$
+//					code= CodeFormatter.K_JAVA_DOC;
+//					break;
+//				case ASTNode.METHOD_REF_PARAMETER:
+//					prefix= "/**\n * @see A#foo("; //$NON-NLS-1$
+//					suffix= ")\n*/"; //$NON-NLS-1$
+//					code= CodeFormatter.K_JAVA_DOC;
+//					break;
+//				case ASTNode.TAG_ELEMENT:
+//				case ASTNode.TEXT_ELEMENT:
+//					prefix= "/**\n * "; //$NON-NLS-1$
+//					suffix= "\n*/"; //$NON-NLS-1$
+//					code= CodeFormatter.K_JAVA_DOC;
+//					break;
 				default:
 					//Assert.isTrue(false, "Node type not covered: " + node.getClass().getName()); //$NON-NLS-1$
 					return null;
@@ -375,6 +394,7 @@
 		
 		String concatStr= prefix + str + suffix;
 		TextEdit edit= ToolFactory.createCodeFormatter(options).format(code, concatStr, prefix.length(), str.length(), indentationLevel, lineSeparator);
+		
 		if (prefix.length() > 0) {
 			edit= shifEdit(edit, prefix.length());
 		}		
@@ -554,7 +574,8 @@
 	public final Prefix WILDCARD_SUPER= new FormattingPrefix("A<? super B> a;", "? super B" , CodeFormatter.K_CLASS_BODY_DECLARATIONS); //$NON-NLS-1$ //$NON-NLS-2$
 
 	public final Prefix FIRST_ENUM_CONST= new FormattingPrefix("enum E { X;}", "{ X" , CodeFormatter.K_COMPILATION_UNIT); //$NON-NLS-1$ //$NON-NLS-2$
-	
+	public final Prefix ANNOTATION_SEPARATION= new FormattingPrefix("@A @B class C {}", "A @" , CodeFormatter.K_COMPILATION_UNIT); //$NON-NLS-1$ //$NON-NLS-2$
+
 	public final BlockContext IF_BLOCK_WITH_ELSE= new BlockFormattingPrefixSuffix("if (true)", "else{}", 8); //$NON-NLS-1$ //$NON-NLS-2$
 	public final BlockContext IF_BLOCK_NO_ELSE= new BlockFormattingPrefix("if (true)", 8); //$NON-NLS-1$ //$NON-NLS-2$
 	public final BlockContext ELSE_AFTER_STATEMENT= new BlockFormattingPrefix("if (true) foo(); else ", 15); //$NON-NLS-1$ //$NON-NLS-2$
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/RewriteEventStore.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/RewriteEventStore.java
index 1445334..c6dda3e 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/RewriteEventStore.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/RewriteEventStore.java
@@ -10,23 +10,12 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.dom.rewrite;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashSet;
-import java.util.IdentityHashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.eclipse.text.edits.TextEditGroup;
+import java.util.*;
 
 import org.eclipse.jdt.core.Signature;
-
-import org.eclipse.jdt.core.dom.ASTNode;
-import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor;
+import org.eclipse.jdt.core.dom.*;
+import org.eclipse.jdt.core.dom.rewrite.TargetSourceRangeComputer;
+import org.eclipse.text.edits.TextEditGroup;
 
 
 /**
@@ -37,8 +26,8 @@
 	
 
 	public final class PropertyLocation {
-		private ASTNode parent;
-		private StructuralPropertyDescriptor property;
+		private final ASTNode parent;
+		private final StructuralPropertyDescriptor property;
 		
 		public PropertyLocation(ASTNode parent, StructuralPropertyDescriptor property) {
 			this.parent= parent;
@@ -52,6 +41,19 @@
 		public StructuralPropertyDescriptor getProperty() {
 			return this.property;
 		}
+		
+		public boolean equals(Object obj) {
+			if (obj != null && obj.getClass().equals(this.getClass())) {
+				PropertyLocation other= (PropertyLocation) obj;
+				return other.getParent().equals(getParent()) && other.getProperty().equals(getProperty());
+			}
+			return false;
+		}
+		
+		public int hashCode() {
+			return getParent().hashCode() + getProperty().hashCode();
+		}
+		
 	}
 	
 	/**
@@ -92,19 +94,60 @@
 		}
 	}
 	
-	public static class CopySourceInfo {
-		public final ASTNode parent;
-		public final StructuralPropertyDescriptor childProperty;
-		private final ASTNode first;
-		private final ASTNode last;
+	public static class CopySourceInfo implements Comparable {
+		public final PropertyLocation location; // can be null, only used to mark as removed on move
+		private final ASTNode node;
 		public final boolean isMove;
 		
-		public CopySourceInfo(ASTNode parent, StructuralPropertyDescriptor childProperty, ASTNode first, ASTNode last, boolean isMove) {
-			this.parent= parent;
-			this.childProperty= childProperty;
+		public CopySourceInfo(PropertyLocation location, ASTNode node, boolean isMove) {
+			this.location= location;
+			this.node= node;
+			this.isMove= isMove;
+		}
+		
+		public ASTNode getNode() {
+			return this.node;
+		}
+		
+		public int compareTo(Object o2) {
+			CopySourceInfo r2= (CopySourceInfo) o2;
+		
+			int startDiff= this.getNode().getStartPosition() - r2.getNode().getStartPosition();
+			if (startDiff != 0) {
+				return startDiff; // insert before if start node is first
+			}
+
+			if (r2.isMove != this.isMove) {
+				return this.isMove ? -1 : 1; // first move then copy
+			}
+			return 0;
+		}
+		
+		public String toString() {
+			StringBuffer buf= new StringBuffer();
+			if (this.isMove) {
+				buf.append("move source: "); //$NON-NLS-1$
+			} else {
+				buf.append("copy source: "); //$NON-NLS-1$
+			}
+			buf.append(this.node);
+			return buf.toString();
+		}
+	}
+	
+	private static class NodeRangeInfo implements Comparable {
+		private final ASTNode first;
+		private final ASTNode last;
+		public final CopySourceInfo copyInfo; // containing the internal placeholder and the 'isMove' flag
+		public final ASTNode replacingNode;
+		public final TextEditGroup editGroup;
+		
+		public NodeRangeInfo(ASTNode parent, StructuralPropertyDescriptor childProperty, ASTNode first, ASTNode last, CopySourceInfo copyInfo, ASTNode replacingNode, TextEditGroup editGroup) {
 			this.first= first;
 			this.last= last;
-			this.isMove= isMove;
+			this.copyInfo= copyInfo;
+			this.replacingNode= replacingNode;
+			this.editGroup= editGroup;
 		}
 		
 		public ASTNode getStartNode() {
@@ -114,39 +157,59 @@
 		public ASTNode getEndNode() {
 			return this.last;
 		}
-
+		
+		public boolean isMove() {
+			return this.copyInfo.isMove;
+		}
+		
+		public Block getInternalPlaceholder() {
+			return (Block) this.copyInfo.getNode();
+		}
+				
+		public int compareTo(Object o2) {
+			NodeRangeInfo r2= (NodeRangeInfo) o2;
+		
+			int startDiff= this.getStartNode().getStartPosition() - r2.getStartNode().getStartPosition();
+			if (startDiff != 0) {
+				return startDiff; // insert before if start node is first
+			}
+			int endDiff= this.getEndNode().getStartPosition() - r2.getEndNode().getStartPosition();
+			if (endDiff != 0) {
+				return -endDiff; // insert before if length is longer
+			}
+			if (r2.isMove() != this.isMove()) {
+				return this.isMove() ? -1 : 1; // first move then copy
+			}
+			return 0;
+		}
+		
+		public void updatePlaceholderSourceRanges(TargetSourceRangeComputer sourceRangeComputer) {
+			TargetSourceRangeComputer.SourceRange startRange= sourceRangeComputer.computeSourceRange(getStartNode());
+			TargetSourceRangeComputer.SourceRange endRange= sourceRangeComputer.computeSourceRange(getEndNode());
+			int startPos= startRange.getStartPosition();
+			int endPos= endRange.getStartPosition() + endRange.getLength();
+			
+			Block internalPlaceholder= getInternalPlaceholder();
+			internalPlaceholder.setSourceRange(startPos, endPos - startPos);
+		}
+		
 		public String toString() {
 			StringBuffer buf= new StringBuffer();
 			if (this.first != this.last) {
 				buf.append("range ");  //$NON-NLS-1$
 			}
-			if (this.isMove) {
+			if (isMove()) {
 				buf.append("move source: "); //$NON-NLS-1$
 			} else {
 				buf.append("copy source: "); //$NON-NLS-1$
 			}
 			buf.append(this.first);
-			if (this.first != this.last) {
-				buf.append(" - "); //$NON-NLS-1$
-				buf.append(this.last);
-			}
+			buf.append(" - "); //$NON-NLS-1$
+			buf.append(this.last);
 			return buf.toString();
 		}
-	}
 
-	public static class CopySourceInfoSorter implements Comparator {
 
-		public int compare(Object o1, Object o2) {
-			CopySourceInfo e1= (CopySourceInfo) o1;
-			CopySourceInfo e2= (CopySourceInfo) o2;
-			if (e1.isMove) {
-				return -1;
-			} else if (e2.isMove) {
-				return 1;
-			}
-			return e2.getEndNode().getStartPosition() - e1.getEndNode().getStartPosition();
-		}
-	
 	}
 	
 	/**
@@ -166,8 +229,8 @@
 			} else {
 				this.sourceNodeIter= Collections.EMPTY_LIST.iterator();
 			}
-			if (RewriteEventStore.this.rangeCopySources != null) {
-				this.rangeNodeIter= RewriteEventStore.this.rangeCopySources.iterator();
+			if (RewriteEventStore.this.nodeRangeInfos != null) {
+				this.rangeNodeIter= RewriteEventStore.this.nodeRangeInfos.keySet().iterator();
 			} else {
 				this.rangeNodeIter= Collections.EMPTY_LIST.iterator();
 			}
@@ -193,10 +256,10 @@
 				return ((EventHolder) this.eventIter.next()).parent;
 			}
 			if (this.sourceNodeIter.hasNext()) {
-				return ((CopySourceInfo) this.sourceNodeIter.next()).getStartNode();
+				return ((CopySourceInfo) this.sourceNodeIter.next()).getNode();
 			}
 			if (this.rangeNodeIter.hasNext()) {
-				return ((CopySourceInfo) this.rangeNodeIter.next()).parent;
+				return ((PropertyLocation) this.rangeNodeIter.next()).getParent();
 			}
 			return this.trackedNodeIter.next();
 		}
@@ -223,11 +286,11 @@
 	/** Maps events to group descriptions */
 	private Map editGroups;
 		
-	/** Stores which nodes are source of a copy or move (list of CopyRangeSourceInfo)*/
+	/** Stores which nodes are source of a copy or move (list of CopySourceInfo)*/
 	List nodeCopySources;
 	
-	/** Stores which node ranges that are source of a copy or move (list of CopyRangeSourceInfo)*/
-	List rangeCopySources;
+	/** Stores node ranges that are used to copy or move (map of <PropertyLocation, CopyRangeInfo>)*/
+	Map nodeRangeInfos;
 	
 	/** Stores which nodes are tracked and the corresponding edit group*/
 	Map trackedNodes;
@@ -238,6 +301,8 @@
 	
 	/** optional mapper to allow fix already modified AST trees */
 	private INodePropertyMapper nodePropertyMapper;
+	
+	private static final String INTERNAL_PLACEHOLDER_PROPERTY= "rewrite_internal_placeholder"; //$NON-NLS-1$
 		
 	public RewriteEventStore() {
 		this.events= new ArrayList();
@@ -250,6 +315,7 @@
 		
 		this.nodePropertyMapper= null;
 		this.nodeCopySources= null;
+		this.nodeRangeInfos= null;
 	}
 	
 	/**
@@ -485,8 +551,8 @@
 		setTrackedNodeData(node, editGroup);
 	}	
 	
-	public final CopySourceInfo markAsCopySource(ASTNode parent, StructuralPropertyDescriptor property, ASTNode node, boolean isMove) {
-		CopySourceInfo copySource= new CopySourceInfo(parent, property, node, node, isMove);
+	private final CopySourceInfo createCopySourceInfo(PropertyLocation location, ASTNode node, boolean isMove) {
+		CopySourceInfo copySource= new CopySourceInfo(location, node, isMove);
 		
 		if (this.nodeCopySources == null) {
 			this.nodeCopySources= new ArrayList();
@@ -495,69 +561,19 @@
 		return copySource;
 	}
 	
-	public final CopySourceInfo markAsRangeCopySource(ASTNode parent, StructuralPropertyDescriptor property, ASTNode first, ASTNode last, boolean isMove) {
-		CopySourceInfo copySource= new CopySourceInfo(parent, property, first, last, isMove);
-		assertNoOverlap(copySource);
+	public final CopySourceInfo markAsCopySource(ASTNode parent, StructuralPropertyDescriptor property, ASTNode node, boolean isMove) {
+		return createCopySourceInfo(new PropertyLocation(parent, property), node, isMove);
+	}
+	
+	public final boolean isRangeCopyPlaceholder(ASTNode node) {
+		return node.getProperty(INTERNAL_PLACEHOLDER_PROPERTY) != null;
+	}
+	
+	public final CopySourceInfo createRangeCopy(ASTNode parent, StructuralPropertyDescriptor childProperty, ASTNode first, ASTNode last, boolean isMove, ASTNode internalPlaceholder, ASTNode replacingNode, TextEditGroup editGroup) {
+		CopySourceInfo copyInfo= createCopySourceInfo(null, internalPlaceholder, isMove);
+		internalPlaceholder.setProperty(INTERNAL_PLACEHOLDER_PROPERTY, internalPlaceholder);
 		
-		if (this.rangeCopySources == null) {
-			this.rangeCopySources= new ArrayList();
-		}
-		this.rangeCopySources.add(copySource);
-		return copySource;
-	}
-	
-	
-	public CopySourceInfo[] getNodeCopySources(ASTNode node) {
-		if (this.nodeCopySources == null) {
-			return null;
-		}
-		return internalGetCopySources(this.nodeCopySources, node);
-	}
-	
-	public CopySourceInfo[] getRangeCopySources(ASTNode node) {
-		if (this.rangeCopySources == null) {
-			return null;
-		}
-		return internalGetCopySources(this.rangeCopySources, node);
-	}
-	
-	public boolean hasRangeCopySources(ASTNode parent, StructuralPropertyDescriptor property) {
-		if (this.rangeCopySources == null) {
-			return false;
-		}
-		for (int i= 0; i < this.rangeCopySources.size(); i++) {
-			CopySourceInfo curr= (CopySourceInfo) this.rangeCopySources.get(i);
-			if (curr.parent == parent && curr.childProperty == property) {
-				return true;
-			}
-		}
-		return false;
-	}
-	
-	public CopySourceInfo[] internalGetCopySources(List copySources, ASTNode node) {
-		ArrayList res= new ArrayList(3);
-		for (int i= 0; i < copySources.size(); i++) {
-			CopySourceInfo curr= (CopySourceInfo) copySources.get(i);
-			if (curr.getStartNode() == node) {
-				res.add(curr);
-			}
-		}
-		if (res.isEmpty()) {
-			return null;
-		}
-		CopySourceInfo[] arr= (CopySourceInfo[]) res.toArray(new CopySourceInfo[res.size()]);
-		if (arr.length > 1) {
-			Arrays.sort(arr, new CopySourceInfoSorter());
-		}
-		return arr;
-	}
-	
-	
-	private void assertNoOverlap(CopySourceInfo copySource) {
-		ASTNode parent= copySource.parent;
-		StructuralPropertyDescriptor childProperty= copySource.childProperty;
-		ASTNode first= copySource.getStartNode();
-		ASTNode last= copySource.getEndNode();
+		NodeRangeInfo copyRangeInfo= new NodeRangeInfo(parent, childProperty, first, last, copyInfo, replacingNode, editGroup);
 		
 		ListRewriteEvent listEvent= getListEvent(parent, childProperty, true);
 		
@@ -573,46 +589,197 @@
 		if (indexFirst > indexLast) {
 			throw new IllegalArgumentException("Start node must be before end node"); //$NON-NLS-1$
 		}
-		if (this.rangeCopySources != null) {
-			for (Iterator iter= this.rangeCopySources.iterator(); iter.hasNext();) {
-				CopySourceInfo info= (CopySourceInfo) iter.next();
-				if (info.parent == parent && info.childProperty == childProperty) {
-					int currStart= listEvent.getIndex(first, ListRewriteEvent.BOTH);
-					int currEnd= listEvent.getIndex(first, ListRewriteEvent.BOTH);
-					if (currStart < indexFirst && currEnd < indexLast && currEnd >= indexFirst
-							|| currStart > indexFirst && currStart <= currEnd && currEnd > indexLast) {
-						throw new IllegalArgumentException("Range overlapps with an existing copy or move range"); //$NON-NLS-1$ 
-					}
-				}
+		
+		if (this.nodeRangeInfos == null) {
+			this.nodeRangeInfos= new HashMap();
+		}
+		PropertyLocation loc= new PropertyLocation(parent, childProperty);
+		List innerList= (List) this.nodeRangeInfos.get(loc);
+		if (innerList == null) {
+			innerList= new ArrayList(2);
+			this.nodeRangeInfos.put(loc, innerList);
+		} else {
+			assertNoOverlap(listEvent, indexFirst, indexLast, innerList);
+		}
+		innerList.add(copyRangeInfo);
+		
+		
+		return copyInfo;
+	}
+	
+	public CopySourceInfo[] getNodeCopySources(ASTNode node) {
+		if (this.nodeCopySources == null) {
+			return null;
+		}
+		return internalGetCopySources(this.nodeCopySources, node);
+	}
+	
+	
+	public CopySourceInfo[] internalGetCopySources(List copySources, ASTNode node) {
+		ArrayList res= new ArrayList(3);
+		for (int i= 0; i < copySources.size(); i++) {
+			CopySourceInfo curr= (CopySourceInfo) copySources.get(i);
+			if (curr.getNode() == node) {
+				res.add(curr);
+			}
+		}
+		if (res.isEmpty()) {
+			return null;
+		}
+		
+		CopySourceInfo[] arr= (CopySourceInfo[]) res.toArray(new CopySourceInfo[res.size()]);
+		Arrays.sort(arr);
+		return arr;
+	}
+	
+	
+	private void assertNoOverlap(ListRewriteEvent listEvent, int indexFirst, int indexLast, List innerList) {
+		for (Iterator iter= innerList.iterator(); iter.hasNext();) {
+			NodeRangeInfo curr= (NodeRangeInfo) iter.next();
+			int currStart= listEvent.getIndex(curr.getStartNode(), ListRewriteEvent.BOTH);
+			int currEnd= listEvent.getIndex(curr.getEndNode(), ListRewriteEvent.BOTH);
+			if (currStart < indexFirst && currEnd < indexLast && currEnd >= indexFirst
+					|| currStart > indexFirst && currStart <= currEnd && currEnd > indexLast) {
+				throw new IllegalArgumentException("Range overlapps with an existing copy or move range"); //$NON-NLS-1$ 
 			}
 		}
 	}
 	
+	public void prepareMovedNodes(TargetSourceRangeComputer sourceRangeComputer) {
+		if (this.nodeCopySources != null) {
+			prepareSingleNodeCopies();
+		}
+		
+		if (this.nodeRangeInfos != null) {
+			prepareNodeRangeCopies(sourceRangeComputer);
+		}
+	}
+	
+	public void revertMovedNodes() {
+		if (this.nodeRangeInfos != null) {
+			removeMoveRangePlaceholders();
+		}
+	}
+	
+	private void removeMoveRangePlaceholders() {
+		for (Iterator iter= this.nodeRangeInfos.entrySet().iterator(); iter.hasNext();) {
+			Map.Entry entry= (Map.Entry) iter.next();
+			Set placeholders= new HashSet(); // collect all placeholders
+			List rangeInfos= (List) entry.getValue(); // list of CopySourceRange
+			for (int i= 0; i < rangeInfos.size(); i++) {
+				placeholders.add(((NodeRangeInfo) rangeInfos.get(i)).getInternalPlaceholder());
+			}
+			
+			PropertyLocation loc= (PropertyLocation) entry.getKey();
+			
+			RewriteEvent[] children= getListEvent(loc.getParent(), loc.getProperty(), true).getChildren();
+			List revertedChildren= new ArrayList();
+			revertListWithRanges(children, placeholders, revertedChildren);
+			RewriteEvent[] revertedChildrenArr= (RewriteEvent[]) revertedChildren.toArray(new RewriteEvent[revertedChildren.size()]);
+			addEvent(loc.getParent(), loc.getProperty(), new ListRewriteEvent(revertedChildrenArr)); // replace the current edits
+		}	
+	}
+	
+	private void revertListWithRanges(RewriteEvent[] childEvents, Set placeholders, List revertedChildren) {
+		for (int i= 0; i < childEvents.length; i++) {
+			RewriteEvent event= childEvents[i];
+			ASTNode node= (ASTNode) event.getOriginalValue();
+			if (placeholders.contains(node)) {
+				RewriteEvent[] placeholderChildren= getListEvent(node, Block.STATEMENTS_PROPERTY, false).getChildren();
+				revertListWithRanges(placeholderChildren, placeholders, revertedChildren);
+			} else {
+				revertedChildren.add(event);
+			}
+		}
+	}
+
+	private void prepareNodeRangeCopies(TargetSourceRangeComputer sourceRangeComputer) {
+		for (Iterator iter= this.nodeRangeInfos.entrySet().iterator(); iter.hasNext();) {
+			Map.Entry entry= (Map.Entry) iter.next();
+			List rangeInfos= (List) entry.getValue(); // list of CopySourceRange
+			Collections.sort(rangeInfos); // sort by start index, length, move or copy
+			
+			PropertyLocation loc= (PropertyLocation) entry.getKey();
+			RewriteEvent[] children= getListEvent(loc.getParent(), loc.getProperty(), true).getChildren();
+			
+			RewriteEvent[] newChildren= processListWithRanges(rangeInfos, children, sourceRangeComputer);
+			addEvent(loc.getParent(), loc.getProperty(), new ListRewriteEvent(newChildren)); // replace the current edits
+		}		
+	}
+
+	private RewriteEvent[] processListWithRanges(List rangeInfos, RewriteEvent[] childEvents, TargetSourceRangeComputer sourceRangeComputer) {
+		List newChildEvents= new ArrayList(childEvents.length);
+		NodeRangeInfo topInfo= null;
+		Stack newChildrenStack= new Stack();
+		Stack topInfoStack= new Stack();
+
+		Iterator rangeInfoIterator= rangeInfos.iterator();
+		NodeRangeInfo nextInfo= (NodeRangeInfo) rangeInfoIterator.next();
+		
+		for (int k= 0; k < childEvents.length; k++) {
+			RewriteEvent event= childEvents[k];
+			ASTNode node= (ASTNode) event.getOriginalValue();
+			// check for ranges and add a placeholder for them
+			while (nextInfo != null && node == nextInfo.getStartNode()) { // is this child the beginning of a range?
+				nextInfo.updatePlaceholderSourceRanges(sourceRangeComputer);
+				
+				Block internalPlaceholder= nextInfo.getInternalPlaceholder();
+				RewriteEvent newEvent;
+				if (nextInfo.isMove()) {
+					newEvent= new NodeRewriteEvent(internalPlaceholder, nextInfo.replacingNode); // remove or replace
+				} else {
+					newEvent= new NodeRewriteEvent(internalPlaceholder, internalPlaceholder); // unchanged
+				}
+				newChildEvents.add(newEvent);
+				if (nextInfo.editGroup != null) {
+					setEventEditGroup(newEvent, nextInfo.editGroup);
+				}
+				
+				newChildrenStack.push(newChildEvents);
+				topInfoStack.push(topInfo);
+				
+				newChildEvents= new ArrayList(childEvents.length);
+				topInfo= nextInfo;
+				
+				nextInfo= rangeInfoIterator.hasNext() ? (NodeRangeInfo) rangeInfoIterator.next() : null;
+			}
+			
+			newChildEvents.add(event);
+
+			while (topInfo != null && node == topInfo.getEndNode()) {
+				RewriteEvent[] placeholderChildEvents= (RewriteEvent[]) newChildEvents.toArray(new RewriteEvent[newChildEvents.size()]);
+				Block internalPlaceholder= topInfo.getInternalPlaceholder();
+				addEvent(internalPlaceholder, Block.STATEMENTS_PROPERTY, new ListRewriteEvent(placeholderChildEvents));
+				
+				newChildEvents= (List) newChildrenStack.pop();
+				topInfo= (NodeRangeInfo) topInfoStack.pop();
+			}
+		}
+		return (RewriteEvent[]) newChildEvents.toArray(new RewriteEvent[newChildEvents.size()]);
+	}
+
 	/**
 	 * Make sure all moved nodes are marked as removed or replaced.
 	 */
-	public void markMovedNodesRemoved() {
-		if (this.nodeCopySources == null) {
-			return;
-		}
+	private void prepareSingleNodeCopies() {
 		for (int i= 0; i < this.nodeCopySources.size(); i++) {
 			CopySourceInfo curr= (CopySourceInfo) this.nodeCopySources.get(i);
-			if (curr.isMove) {
-				doMarkMovedAsRemoved(curr);
+			if (curr.isMove && curr.location != null) {
+				doMarkMovedAsRemoved(curr, curr.location.getParent(), curr.location.getProperty());
 			}
 		}
 		
 	}
 	
-	private void doMarkMovedAsRemoved(CopySourceInfo curr) {
-		if (curr.childProperty.isChildListProperty()) {
-			ListRewriteEvent event= getListEvent(curr.parent, curr.childProperty, true);
-			int index= event.getIndex(curr.getStartNode(), ListRewriteEvent.OLD);
+	private void doMarkMovedAsRemoved(CopySourceInfo curr, ASTNode parent, StructuralPropertyDescriptor childProperty) {
+		if (childProperty.isChildListProperty()) {
+			ListRewriteEvent event= getListEvent(parent, childProperty, true);
+			int index= event.getIndex(curr.getNode(), ListRewriteEvent.OLD);
 			if (index != -1 && event.getChangeKind(index) == RewriteEvent.UNCHANGED) {
 				event.setNewValue(null, index);
 			}
 		} else {
-			NodeRewriteEvent event= getNodeEvent(curr.parent, curr.childProperty, true);
+			NodeRewriteEvent event= getNodeEvent(parent, childProperty, true);
 			if (event.getChangeKind() == RewriteEvent.UNCHANGED) {
 				event.setNewValue(null);
 			}
@@ -665,4 +832,6 @@
 	public static boolean isNewNode(ASTNode node) {
 		return (node.getFlags() & ASTNode.ORIGINAL) == 0;
 	}
+
+
 }
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/TrackedNodePosition.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/TrackedNodePosition.java
index 253b478..ffa702c 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/TrackedNodePosition.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/TrackedNodePosition.java
@@ -15,6 +15,7 @@
 
 import org.eclipse.jdt.core.dom.ASTNode;
 import org.eclipse.jdt.core.dom.rewrite.ITrackedNodePosition;
+import org.eclipse.jface.text.IRegion;
 
 /**
  *
@@ -36,7 +37,11 @@
 		if (this.group.isEmpty()) {
 			return this.node.getStartPosition();
 		}
-		return TextEdit.getCoverage(this.group.getTextEdits()).getOffset();
+		IRegion coverage= TextEdit.getCoverage(this.group.getTextEdits());
+		if (coverage == null) {
+			return this.node.getStartPosition();
+		}
+		return coverage.getOffset();
 	}
 
 	/* (non-Javadoc)
@@ -46,6 +51,10 @@
 		if (this.group.isEmpty()) {
 			return this.node.getLength();
 		}
-		return TextEdit.getCoverage(this.group.getTextEdits()).getLength();
+		IRegion coverage= TextEdit.getCoverage(this.group.getTextEdits());
+		if (coverage == null) {
+			return this.node.getLength();
+		}
+		return coverage.getLength();
 	}
 }
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetClassFile.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetClassFile.java
index 501ecec..c1939b8 100644
--- a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetClassFile.java
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetClassFile.java
@@ -49,7 +49,7 @@
 	this.header[this.headerOffset++] = (byte) (0xCAFEBABEL >> 8);
 	this.header[this.headerOffset++] = (byte) (0xCAFEBABEL >> 0);
 
-	this.targetJDK = this.referenceBinding.scope.environment().options.targetJDK;
+	this.targetJDK = this.referenceBinding.scope.compilerOptions().targetJDK;
 	this.header[this.headerOffset++] = (byte) (targetJDK >> 8); // minor high
 	this.header[this.headerOffset++] = (byte) (targetJDK >> 0); // minor low
 	this.header[this.headerOffset++] = (byte) (targetJDK >> 24); // major high
@@ -108,7 +108,7 @@
 			this.contents[this.contentsOffset++] = (byte) interfaceIndex;
 		}
 	}
-	this.produceDebugAttributes = this.referenceBinding.scope.environment().options.produceDebugAttributes;
+	this.produceDebugAttributes = this.referenceBinding.scope.compilerOptions().produceDebugAttributes;
 	this.innerClassesBindings = new ReferenceBinding[INNER_CLASSES_SIZE];
 	this.creatingProblemType = creatingProblemType;
 	this.codeStream = new CodeSnippetCodeStream(this);
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetEvaluator.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetEvaluator.java
index d68a9ee..854d920 100644
--- a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetEvaluator.java
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetEvaluator.java
@@ -126,6 +126,7 @@
 				this.context,
 				getMapper().startPosOffset,
 				getMapper().startPosOffset + this.codeSnippet.length - 1);
+		((CodeSnippetParser) compiler.parser).lineSeparatorLength = this.context.lineSeparator.length();
 		// Initialize the compiler's lookup environment with the already compiled super classes
 		IBinaryType binary = this.context.getRootCodeSnippetBinary();
 		if (binary != null) {
@@ -180,7 +181,8 @@
 			this.context.localVariableNames, 
 			this.context.localVariableTypeNames, 
 			this.context.localVariableModifiers, 
-			this.context.declaringTypeName			
+			this.context.declaringTypeName,
+			this.context.lineSeparator
 		);
 
 	}
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetFieldReference.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetFieldReference.java
index f93863a..336b15c 100644
--- a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetFieldReference.java
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetFieldReference.java
@@ -232,7 +232,7 @@
 		}
 		codeStream.generateConstant(postIncrement.expression.constant, this.implicitConversion);
 		codeStream.sendOperator(postIncrement.operator, this.codegenBinding.type.id);
-		codeStream.generateImplicitConversion(postIncrement.assignmentImplicitConversion);
+		codeStream.generateImplicitConversion(postIncrement.preAssignImplicitConversion);
 		fieldStore(codeStream, this.codegenBinding, null, false);
 	} else {
 		this.receiver.generateCode(currentScope, codeStream, !(isStatic = this.codegenBinding.isStatic()));
@@ -280,7 +280,7 @@
 
 		codeStream.generateConstant(postIncrement.expression.constant, this.implicitConversion);
 		codeStream.sendOperator(postIncrement.operator, this.codegenBinding.type.id);
-		codeStream.generateImplicitConversion(postIncrement.assignmentImplicitConversion);
+		codeStream.generateImplicitConversion(postIncrement.preAssignImplicitConversion);
 		((CodeSnippetCodeStream) codeStream).generateEmulatedWriteAccessForField(this.codegenBinding);
 	}
 }
@@ -315,7 +315,7 @@
 			&& this.binding.declaringClass != null // array.length
 			&& !this.binding.isConstantValue()) {
 	
-		CompilerOptions options = currentScope.environment().options;
+		CompilerOptions options = currentScope.compilerOptions();
 		if ((options.targetJDK >= ClassFileConstants.JDK1_2
 				&& (options.complianceLevel >= ClassFileConstants.JDK1_4 || !receiver.isImplicitThis() || !this.codegenBinding.isStatic())
 				&& this.binding.declaringClass.id != T_JavaLangObject) // no change for Object fields
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetMessageSend.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetMessageSend.java
index 82214f8..767b2bf 100644
--- a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetMessageSend.java
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetMessageSend.java
@@ -10,6 +10,9 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.eval;
 
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.ast.CastExpression;
+import org.eclipse.jdt.internal.compiler.ast.Expression;
 import org.eclipse.jdt.internal.compiler.ast.MessageSend;
 import org.eclipse.jdt.internal.compiler.ast.NameReference;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
@@ -68,11 +71,7 @@
 			this.receiver.generateCode(currentScope, codeStream, !isStatic);
 		}
 		// generate arguments
-		if (this.arguments != null) {
-			for (int i = 0, max = this.arguments.length; i < max; i++) {
-				this.arguments[i].generateCode(currentScope, codeStream, true);
-			}
-		}
+		generateArguments(binding, arguments, currentScope, codeStream);
 		// actual message invocation
 		if (isStatic) {
 			codeStream.invokestatic(this.codegenBinding);
@@ -140,24 +139,25 @@
 		}
 	}
 	// operation on the returned value
-	if (valueRequired) {
+	if (valueRequired){
 		// implicit conversion if necessary
-		codeStream.generateImplicitConversion(this.implicitConversion);
+		if (this.valueCast != null) 
+			codeStream.checkcast(this.valueCast);
+		codeStream.generateImplicitConversion(implicitConversion);
 	} else {
 		// pop return value if any
-		switch (this.codegenBinding.returnType.id) {
+		switch(binding.returnType.id){
 			case T_long :
 			case T_double :
 				codeStream.pop2();
 				break;
 			case T_void :
 				break;
-			default :
+			default:
 				codeStream.pop();
 		}
 	}
-	// TODO (philippe) need to revise codegen to include genericCast
-	codeStream.recordPositionsFrom(pc, this.sourceStart);
+	codeStream.recordPositionsFrom(pc, (int)(this.nameSourcePosition >>> 32)); // highlight selector
 }
 public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
 
@@ -181,7 +181,7 @@
 	// and not from Object or implicit static method call.	
 	if (this.binding.declaringClass != this.actualReceiverType
 			&& !this.actualReceiverType.isArrayType()) {
-		CompilerOptions options = currentScope.environment().options;
+		CompilerOptions options = currentScope.compilerOptions();
 		if ((options.targetJDK >= ClassFileConstants.JDK1_2
 				&& (options.complianceLevel >= ClassFileConstants.JDK1_4 || !receiver.isImplicitThis() || !this.codegenBinding.isStatic())
 				&& this.binding.declaringClass.id != T_JavaLangObject) // no change for Object methods
@@ -199,22 +199,58 @@
 	// Base type promotion
 
 	this.constant = NotAConstant;
-	this.actualReceiverType = this.receiver.resolveType(scope); 
+	boolean receiverCast = false, argsContainCast = false; 
+	if (this.receiver instanceof CastExpression) {
+		this.receiver.bits |= IgnoreNeedForCastCheckMASK; // will check later on
+		receiverCast = true;
+	}
+	this.actualReceiverType = receiver.resolveType(scope); 
+	if (receiverCast && this.actualReceiverType != null) {
+		 // due to change of declaring class with receiver type, only identity cast should be notified
+		if (((CastExpression)this.receiver).expression.resolvedType == this.actualReceiverType) { 
+			scope.problemReporter().unnecessaryCast((CastExpression)this.receiver);		
+		}
+	}
+	// resolve type arguments (for generic constructor call)
+	if (this.typeArguments != null) {
+		int length = this.typeArguments.length;
+		boolean argHasError = false; // typeChecks all arguments
+		this.genericTypeArguments = new TypeBinding[length];
+		for (int i = 0; i < length; i++) {
+			if ((this.genericTypeArguments[i] = this.typeArguments[i].resolveType(scope, true /* check bounds*/)) == null) {
+				argHasError = true;
+			}
+		}
+		if (argHasError) {
+			return null;
+		}
+	}
 	// will check for null after args are resolved
 	TypeBinding[] argumentTypes = NoParameters;
 	if (this.arguments != null) {
 		boolean argHasError = false; // typeChecks all arguments 
 		int length = this.arguments.length;
 		argumentTypes = new TypeBinding[length];
-		for (int i = 0; i < length; i++)
+		for (int i = 0; i < length; i++) {
+			Expression argument = arguments[i];
+			if (argument instanceof CastExpression) {
+				argument.bits |= IgnoreNeedForCastCheckMASK; // will check later on
+				argsContainCast = true;
+			}
 			if ((argumentTypes[i] = this.arguments[i].resolveType(scope)) == null)
 				argHasError = true;
-		if (argHasError)
+		}
+		if (argHasError) {
+			if(actualReceiverType instanceof ReferenceBinding) {
+				// record any selector match, for clients who may still need hint about possible method match
+				this.binding = scope.findMethod((ReferenceBinding)actualReceiverType, selector, new TypeBinding[]{}, this);
+			}			
 			return null;
+		}
 	}
-	if (this.actualReceiverType == null) 
+	if (this.actualReceiverType == null) {
 		return null;
-
+	}
 	// base type cannot receive any message
 	if (this.actualReceiverType.isBaseType()) {
 		scope.problemReporter().errorNoMethodFor(this, this.actualReceiverType, argumentTypes);
@@ -274,28 +310,44 @@
 	}
 	if (!this.binding.isStatic()) {
 		// the "receiver" must not be a type, in other words, a NameReference that the TC has bound to a Type
-		if (this.receiver instanceof NameReference) {
-			if ((((NameReference) this.receiver).bits & Binding.TYPE) != 0) {
-				scope.problemReporter().mustUseAStaticMethod(this, this.binding);
-				return null;
+		if (receiver instanceof NameReference 
+				&& (((NameReference) receiver).bits & Binding.TYPE) != 0) {
+			scope.problemReporter().mustUseAStaticMethod(this, binding);
+		} else {
+			// compute generic cast if necessary
+			TypeBinding receiverErasure = this.actualReceiverType.erasure();
+			if (receiverErasure instanceof ReferenceBinding) {
+				ReferenceBinding match = ((ReferenceBinding)receiverErasure).findSuperTypeWithSameErasure(this.binding.declaringClass);
+				if (match == null) {
+					this.actualReceiverType = this.binding.declaringClass; // handle indirect inheritance thru variable secondary bound
+				}
 			}
+			receiver.computeConversion(scope, this.actualReceiverType, this.actualReceiverType);
 		}
 	}
-	if (this.arguments != null)
-		for (int i = 0; i < this.arguments.length; i++)
-			this.arguments[i].computeConversion(scope, this.binding.parameters[i], argumentTypes[i]);
+	checkInvocationArguments(scope, this.receiver, actualReceiverType, binding, this.arguments, argumentTypes, argsContainCast, this);
 
 	//-------message send that are known to fail at compile time-----------
-	if (this.binding.isAbstract()) {
-		if (this.receiver.isSuper()) {
-			scope.problemReporter().cannotDireclyInvokeAbstractMethod(this, this.binding);
-			return null;
+	if (binding.isAbstract()) {
+		if (receiver.isSuper()) {
+			scope.problemReporter().cannotDireclyInvokeAbstractMethod(this, binding);
 		}
 		// abstract private methods cannot occur nor abstract static............
 	}
-	if (isMethodUseDeprecated(this.binding, scope))
-		scope.problemReporter().deprecatedMethod(this.binding, this);
+	if (isMethodUseDeprecated(binding, scope))
+		scope.problemReporter().deprecatedMethod(binding, this);
 
-	return this.resolvedType = this.binding.returnType;
+	// from 1.5 compliance on, array#clone() returns the array type (but binding still shows Object)
+	if (actualReceiverType.isArrayType() 
+			&& this.binding.parameters == NoParameters 
+			&& scope.compilerOptions().complianceLevel >= JDK1_5 
+			&& CharOperation.equals(this.binding.selector, CLONE)) {
+		this.resolvedType = actualReceiverType;
+	} else {
+		TypeBinding returnType = this.binding.returnType;
+		if (returnType != null) returnType = returnType.capture(scope, this.sourceEnd);
+		this.resolvedType = returnType;
+	}
+	return this.resolvedType;
 }
 }
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetParser.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetParser.java
index 19034b9..3a20f88 100644
--- a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetParser.java
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetParser.java
@@ -17,18 +17,18 @@
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
 import org.eclipse.jdt.internal.compiler.parser.Parser;
 import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
-import org.eclipse.jdt.internal.compiler.util.Util;
 
 /**
  * A parser for code snippets.
  */
 public class CodeSnippetParser extends Parser implements EvaluationConstants {
 	int codeSnippetStart, codeSnippetEnd;
-	boolean hasRecoveredOnExpression;
-	int problemCountBeforeRecovery = 0;
-	int lastStatement = -1; // end of last top level statement
-
 	EvaluationContext evaluationContext;
+	boolean hasRecoveredOnExpression;
+	int lastStatement = -1; // end of last top level statement
+	int lineSeparatorLength;
+
+	int problemCountBeforeRecovery = 0;
 /**
  * Creates a new code snippet parser.
  */
@@ -145,6 +145,11 @@
 	/* recovery */
 	recordLastStatementIfNeeded();
 }
+protected void consumeEnhancedForStatement() {
+	super.consumeEnhancedForStatement();
+	/* recovery */
+	recordLastStatementIfNeeded();	
+}
 protected void consumeExpressionStatement() {
 	super.consumeExpressionStatement();
 	/* recovery */
@@ -245,6 +250,7 @@
 	/* recovery */
 	recordLastStatementIfNeeded();
 }
+
 /**
  * In case emulating local variables, wrap the (recovered) statements inside a 
  * try statement so as to achieve local state commiting (copy local vars back to fields).
@@ -338,7 +344,7 @@
 	// MethodInvocation ::= Name '(' ArgumentListopt ')'
 
 	if (this.scanner.startPosition >= this.codeSnippetStart
-		&& this.scanner.startPosition <= this.codeSnippetEnd + 1 + Util.LINE_SEPARATOR_CHARS.length // 14838
+		&& this.scanner.startPosition <= this.codeSnippetEnd + 1 + this.lineSeparatorLength // 14838
 		&& isTopLevelType()) {
 			
 		// when the name is only an identifier...we have a message send to "this" (implicit)
@@ -374,12 +380,11 @@
 	m.receiver = new CodeSnippetSuperReference(m.sourceStart, this.endPosition, this.evaluationContext);
 	pushOnExpressionStack(m);
 }
-
 protected void consumePrimaryNoNewArrayThis() {
 	// PrimaryNoNewArray ::= 'this'
 
 	if (this.scanner.startPosition >= this.codeSnippetStart
-		&& this.scanner.startPosition <= this.codeSnippetEnd + 1 + Util.LINE_SEPARATOR_CHARS.length // 14838
+		&& this.scanner.startPosition <= this.codeSnippetEnd + 1 + this.lineSeparatorLength // 14838
 		&& isTopLevelType()) {
 		pushOnExpressionStack(
 			new CodeSnippetThisReference(this.intStack[this.intPtr--], this.endPosition, this.evaluationContext, false));
@@ -443,7 +448,7 @@
 	// returned value intercepted by code snippet 
 	// support have to be defined at toplevel only
 	if ((this.hasRecoveredOnExpression
-			|| (this.scanner.startPosition >= this.codeSnippetStart && this.scanner.startPosition <= this.codeSnippetEnd+1+Util.LINE_SEPARATOR_CHARS.length /* 14838*/))
+			|| (this.scanner.startPosition >= this.codeSnippetStart && this.scanner.startPosition <= this.codeSnippetEnd+1+this.lineSeparatorLength /* 14838*/))
 		&& this.expressionLengthStack[this.expressionLengthPtr] != 0
 		&& isTopLevelType()) {
 		this.expressionLengthPtr--;
@@ -566,7 +571,7 @@
 	/* build a (unspecified) NameReference which may be qualified*/
 
 	if (this.scanner.startPosition >= this.codeSnippetStart 
-		&& this.scanner.startPosition <= this.codeSnippetEnd+1+Util.LINE_SEPARATOR_CHARS.length /*14838*/){
+		&& this.scanner.startPosition <= this.codeSnippetEnd+1+this.lineSeparatorLength /*14838*/){
 		int length;
 		NameReference ref;
 		if ((length = this.identifierLengthStack[this.identifierLengthPtr--]) == 1) {
@@ -604,7 +609,7 @@
 	look for that it is not a type reference */
 
 	if (this.scanner.startPosition >= this.codeSnippetStart 
-		&& this.scanner.startPosition <= this.codeSnippetEnd+1+Util.LINE_SEPARATOR_CHARS.length /*14838*/){
+		&& this.scanner.startPosition <= this.codeSnippetEnd+1+this.lineSeparatorLength /*14838*/){
 		int length;
 		NameReference ref;
 		if ((length = this.identifierLengthStack[this.identifierLengthPtr--]) == 1) {
@@ -675,10 +680,11 @@
  * Records the scanner position if we're parsing a top level type.
  */
 private void recordLastStatementIfNeeded() {
-	if ((isTopLevelType()) && (this.scanner.startPosition <= this.codeSnippetEnd+Util.LINE_SEPARATOR_CHARS.length /*14838*/)) {
+	if ((isTopLevelType()) && (this.scanner.startPosition <= this.codeSnippetEnd+this.lineSeparatorLength /*14838*/)) {
 		this.lastStatement = this.scanner.startPosition;
 	}
 }
+
 protected void reportSyntaxErrors(boolean isDietParse, int oldFirstToken) {
 	if (!isDietParse) {
 		this.scanner.initialPosition = this.lastStatement;
@@ -687,7 +693,6 @@
 	}
 	super.reportSyntaxErrors(isDietParse, oldFirstToken);
 }
-
 /*
  * A syntax error was detected. If a method is being parsed, records the number of errors and
  * attempts to restart from the last statement by going for an expression.
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetQualifiedNameReference.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetQualifiedNameReference.java
index caa1c50..7e23576 100644
--- a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetQualifiedNameReference.java
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetQualifiedNameReference.java
@@ -237,7 +237,7 @@
 		}
 		codeStream.generateConstant(postIncrement.expression.constant, this.implicitConversion);
 		codeStream.sendOperator(postIncrement.operator, lastFieldBinding.type.id);
-		codeStream.generateImplicitConversion(postIncrement.assignmentImplicitConversion);
+		codeStream.generateImplicitConversion(postIncrement.preAssignImplicitConversion);
 		
 		fieldStore(codeStream, lastFieldBinding, null, false);
 	} else {
@@ -273,7 +273,7 @@
 		}
 		codeStream.generateConstant(postIncrement.expression.constant, this.implicitConversion);
 		codeStream.sendOperator(postIncrement.operator, lastFieldBinding.type.id);
-		codeStream.generateImplicitConversion(postIncrement.assignmentImplicitConversion);
+		codeStream.generateImplicitConversion(postIncrement.preAssignImplicitConversion);
 		((CodeSnippetCodeStream) codeStream).generateEmulatedWriteAccessForField(lastFieldBinding);
 	}
 }
@@ -524,7 +524,7 @@
 				&& !lastReceiverType.isArrayType()
 				&& fieldBinding.declaringClass != null // array.length
 				&& !fieldBinding.isConstantValue()) {
-			CompilerOptions options = currentScope.environment().options;
+			CompilerOptions options = currentScope.compilerOptions();
 			if ((options.targetJDK >= ClassFileConstants.JDK1_2
 					&& (options.complianceLevel >= ClassFileConstants.JDK1_4 || (index < 0 ? fieldBinding != binding : index > 0) || this.indexOfFirstFieldBinding > 1 || !fieldBinding.isStatic())
 					&& fieldBinding.declaringClass.id != T_JavaLangObject) // no change for Object fields
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetScope.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetScope.java
index b2512b2..c581a9d 100644
--- a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetScope.java
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetScope.java
@@ -556,13 +556,16 @@
 			invocationSite.setFieldIndex(currentIndex);
  			if (binding == null) {
 	 			if (currentIndex == length) // must be a type if its the last name, otherwise we have no idea if its a package or type
-					return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, currentIndex), NotFound);
+					return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, currentIndex), null, NotFound);
 				else
 					return new ProblemBinding(CharOperation.subarray(compoundName, 0, currentIndex), NotFound);
  			}
  			if (binding instanceof ReferenceBinding) {
 	 			if (!binding.isValidBinding())
-					return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, currentIndex), binding.problemId());
+					return new ProblemReferenceBinding(
+									CharOperation.subarray(compoundName, 0, currentIndex), 
+									null, // TODO should improve
+									binding.problemId());
 	 			if (!this.canBeSeenByForCodeSnippet((ReferenceBinding) binding, receiverType))
 					return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, currentIndex), (ReferenceBinding) binding, NotVisible);
 	 			break foundType;
@@ -571,7 +574,7 @@
 		}
 
 		// It is illegal to request a PACKAGE from this method.
-		return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, currentIndex), NotFound);
+		return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, currentIndex), null, NotFound);
 	}
 
 	// know binding is now a ReferenceBinding
@@ -581,19 +584,22 @@
 		invocationSite.setFieldIndex(currentIndex);
 		if ((binding = findFieldForCodeSnippet(typeBinding, nextName, invocationSite)) != null) {
 			if (!binding.isValidBinding())
-				return new ProblemFieldBinding(((FieldBinding)binding).declaringClass, CharOperation.subarray(compoundName, 0, currentIndex), binding.problemId());
+				return new ProblemFieldBinding((FieldBinding)binding, CharOperation.subarray(compoundName, 0, currentIndex), binding.problemId());
 			break; // binding is now a field
 		}
 		if ((binding = findMemberType(nextName, typeBinding)) == null)
 			return new ProblemBinding(CharOperation.subarray(compoundName, 0, currentIndex), typeBinding, NotFound);
 		 if (!binding.isValidBinding())
-			return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, currentIndex), binding.problemId());
+			return new ProblemReferenceBinding(
+								CharOperation.subarray(compoundName, 0, currentIndex), 
+								null, // TODO should improve
+								binding.problemId());
 	}
 
 	if ((mask & Binding.FIELD) != 0 && (binding instanceof FieldBinding)) { // was looking for a field and found a field
 		FieldBinding field = (FieldBinding) binding;
 		if (!field.isStatic())
-			return new ProblemFieldBinding(field.declaringClass, CharOperation.subarray(compoundName, 0, currentIndex), NonStaticReferenceInStaticContext);
+			return new ProblemFieldBinding(field, CharOperation.subarray(compoundName, 0, currentIndex), NonStaticReferenceInStaticContext);
 		return binding;
 	}
 	if ((mask & Binding.TYPE) != 0 && (binding instanceof ReferenceBinding)) { // was looking for a type and found a type
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetSingleNameReference.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetSingleNameReference.java
index e73168b..c5ce8fe 100644
--- a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetSingleNameReference.java
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetSingleNameReference.java
@@ -110,13 +110,16 @@
 	// optimizing assignment like: i = i + 1 or i = 1 + i
 	if (assignment.expression.isCompactableOperation()) {
 		BinaryExpression operation = (BinaryExpression) assignment.expression;
+		int operator = (operation.bits & OperatorMASK) >> OperatorSHIFT;
 		SingleNameReference variableReference;
 		if ((operation.left instanceof SingleNameReference) && ((variableReference = (SingleNameReference) operation.left).binding == this.binding)) {
 			// i = i + value, then use the variable on the right hand side, since it has the correct implicit conversion
-			variableReference.generateCompoundAssignment(currentScope, codeStream, this.syntheticAccessors == null ? null : this.syntheticAccessors[WRITE], operation.right, (operation.bits & OperatorMASK) >> OperatorSHIFT, operation.left.implicitConversion /*should be equivalent to no conversion*/, valueRequired);
+			variableReference.generateCompoundAssignment(currentScope, codeStream, this.syntheticAccessors == null ? null : this.syntheticAccessors[WRITE], operation.right, operator, operation.implicitConversion, valueRequired);
+			if (valueRequired) {
+				codeStream.generateImplicitConversion(assignment.implicitConversion);
+			}
 			return;
 		}
-		int operator = (operation.bits & OperatorMASK) >> OperatorSHIFT;
 		if ((operation.right instanceof SingleNameReference)
 			&& ((operator == PLUS) || (operator == MULTIPLY)) // only commutative operations
 			&& ((variableReference = (SingleNameReference) operation.right).binding == this.binding)
@@ -124,7 +127,10 @@
 			&& (((operation.left.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) != T_JavaLangString) // exclude string concatenation which would occur backwards
 			&& (((operation.right.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) != T_JavaLangString)) { // exclude string concatenation which would occur backwards
 			// i = value + i, then use the variable on the right hand side, since it has the correct implicit conversion
-			variableReference.generateCompoundAssignment(currentScope, codeStream, this.syntheticAccessors == null ? null : this.syntheticAccessors[WRITE], operation.left, operator, operation.right.implicitConversion /*should be equivalent to no conversion*/, valueRequired);
+			variableReference.generateCompoundAssignment(currentScope, codeStream, this.syntheticAccessors == null ? null : this.syntheticAccessors[WRITE], operation.left, operator, operation.implicitConversion, valueRequired);
+			if (valueRequired) {
+				codeStream.generateImplicitConversion(assignment.implicitConversion);
+			}
 			return;
 		}
 	}
@@ -454,7 +460,7 @@
 				}
 				codeStream.generateConstant(postIncrement.expression.constant, this.implicitConversion);
 				codeStream.sendOperator(postIncrement.operator, fieldBinding.type.id);
-				codeStream.generateImplicitConversion(postIncrement.assignmentImplicitConversion);
+				codeStream.generateImplicitConversion(postIncrement.preAssignImplicitConversion);
 				fieldStore(codeStream, fieldBinding, null, false);
 			} else {
 				if (fieldBinding.isStatic()) {
@@ -500,7 +506,7 @@
 				}
 				codeStream.generateConstant(postIncrement.expression.constant, this.implicitConversion);
 				codeStream.sendOperator(postIncrement.operator, fieldBinding.type.id);
-				codeStream.generateImplicitConversion(postIncrement.assignmentImplicitConversion);
+				codeStream.generateImplicitConversion(postIncrement.preAssignImplicitConversion);
 				((CodeSnippetCodeStream) codeStream).generateEmulatedWriteAccessForField(fieldBinding);
 			}
 			return;
@@ -527,7 +533,7 @@
 				}
 				codeStream.generateConstant(postIncrement.expression.constant, this.implicitConversion);
 				codeStream.sendOperator(postIncrement.operator, localBinding.type.id);
-				codeStream.generateImplicitConversion(postIncrement.assignmentImplicitConversion);
+				codeStream.generateImplicitConversion(postIncrement.preAssignImplicitConversion);
 
 				codeStream.store(localBinding, false);
 			}
@@ -584,7 +590,7 @@
 		if (fieldBinding.declaringClass != this.delegateThis.type
 				&& fieldBinding.declaringClass != null // array.length
 				&& !fieldBinding.isConstantValue()) {
-			CompilerOptions options = currentScope.environment().options;
+			CompilerOptions options = currentScope.compilerOptions();
 			if ((options.targetJDK >= ClassFileConstants.JDK1_2
 					&& (options.complianceLevel >= ClassFileConstants.JDK1_4 || !fieldBinding.isStatic())
 					&& fieldBinding.declaringClass.id != T_JavaLangObject) // no change for Object fields
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetToCuMapper.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetToCuMapper.java
index b2e7dbc..c63506e 100644
--- a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetToCuMapper.java
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetToCuMapper.java
@@ -17,7 +17,6 @@
 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.compiler.util.Util;
 
 /**
  * Maps back and forth a code snippet to a compilation unit.
@@ -59,7 +58,7 @@
 /**
  * Rebuild source in presence of external local variables
  */
- public CodeSnippetToCuMapper(char[] codeSnippet, char[] packageName, char[][] imports, char[] className, char[] varClassName, char[][] localVarNames, char[][] localVarTypeNames, int[] localVarModifiers, char[] declaringTypeName) {
+ public CodeSnippetToCuMapper(char[] codeSnippet, char[] packageName, char[][] imports, char[] className, char[] varClassName, char[][] localVarNames, char[][] localVarTypeNames, int[] localVarModifiers, char[] declaringTypeName, String lineSeparator) {
 	this.codeSnippet = codeSnippet;
 	this.snippetPackageName = packageName;
 	this.snippetImports = imports;
@@ -69,16 +68,16 @@
 	this.localVarTypeNames = localVarTypeNames;
 	this.localVarModifiers = localVarModifiers;
 	this.snippetDeclaringTypeName = declaringTypeName;
-	this.buildCUSource();
+	this.buildCUSource(lineSeparator);
 }
-private void buildCUSource() {
+private void buildCUSource(String lineSeparator) {
 	StringBuffer buffer = new StringBuffer();
 
 	// package declaration
 	if (this.snippetPackageName != null && this.snippetPackageName.length != 0) {
 		buffer.append("package "); //$NON-NLS-1$
 		buffer.append(this.snippetPackageName);
-		buffer.append(";").append(Util.LINE_SEPARATOR); //$NON-NLS-1$
+		buffer.append(";").append(lineSeparator); //$NON-NLS-1$
 		this.lineNumberOffset++;
 	}
 
@@ -87,7 +86,7 @@
 	for (int i = 0; i < imports.length; i++) {
 		buffer.append("import "); //$NON-NLS-1$
 		buffer.append(imports[i]);
-		buffer.append(';').append(Util.LINE_SEPARATOR);
+		buffer.append(';').append(lineSeparator);
 		this.lineNumberOffset++;
 	}
 
@@ -105,7 +104,7 @@
 		buffer.append("."); //$NON-NLS-1$
 		buffer.append(ROOT_CLASS_NAME);
 	}
-	buffer.append(" {").append(Util.LINE_SEPARATOR); //$NON-NLS-1$
+	buffer.append(" {").append(lineSeparator); //$NON-NLS-1$
 	this.lineNumberOffset++;
 
 	if (this.snippetDeclaringTypeName != null){
@@ -113,7 +112,7 @@
 		buffer.append(this.snippetDeclaringTypeName);
 		buffer.append(" "); //$NON-NLS-1$
 		buffer.append(DELEGATE_THIS); // val$this
-		buffer.append(';').append(Util.LINE_SEPARATOR);
+		buffer.append(';').append(lineSeparator);
 		this.lineNumberOffset++;
 	}
 	// add some storage location for local variable persisted state
@@ -124,22 +123,22 @@
 			buffer.append(" "); //$NON-NLS-1$
 			buffer.append(LOCAL_VAR_PREFIX); // val$...
 			buffer.append(this.localVarNames[i]);
-			buffer.append(';').append(Util.LINE_SEPARATOR);
+			buffer.append(';').append(lineSeparator);
 			this.lineNumberOffset++;
 		}
 	}
 	// run() method declaration
-	buffer.append("public void run() throws Throwable {").append(Util.LINE_SEPARATOR); //$NON-NLS-1$
+	buffer.append("public void run() throws Throwable {").append(lineSeparator); //$NON-NLS-1$
 	this.lineNumberOffset++;
 	this.startPosOffset = buffer.length();
 	buffer.append(this.codeSnippet);
 	// a line separator is required after the code snippet source code
 	// in case the code snippet source code ends with a line comment
 	// http://dev.eclipse.org/bugs/show_bug.cgi?id=14838
-	buffer.append(Util.LINE_SEPARATOR).append('}').append(Util.LINE_SEPARATOR);
+	buffer.append(lineSeparator).append('}').append(lineSeparator);
 
 	// end of class declaration
-	buffer.append('}').append(Util.LINE_SEPARATOR);
+	buffer.append('}').append(lineSeparator);
 
 	// store result
 	int length = buffer.length();
@@ -191,9 +190,9 @@
 		}
 	};
 }
-public char[] getCUSource() {
+public char[] getCUSource(String lineSeparator) {
 	if (this.cuSource == null) {
-		buildCUSource();
+		buildCUSource(lineSeparator);
 	}
 	return this.cuSource;
 }
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/EvaluationContext.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/EvaluationContext.java
index 893caf2..8119fd0 100644
--- a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/EvaluationContext.java
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/EvaluationContext.java
@@ -15,7 +15,6 @@
 import org.eclipse.jdt.core.CompletionRequestor;
 import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.compiler.*;
-import org.eclipse.jdt.core.compiler.IProblem;
 import org.eclipse.jdt.internal.codeassist.CompletionEngine;
 import org.eclipse.jdt.internal.codeassist.ISelectionRequestor;
 import org.eclipse.jdt.internal.codeassist.SelectionEngine;
@@ -51,6 +50,7 @@
 	boolean varsChanged;
 	VariablesInfo installedVars;
 	IBinaryType codeSnippetBinary;
+	String lineSeparator;
 
 	/* do names implicitly refer to a given type */
 	char[] declaringTypeName;
@@ -72,6 +72,7 @@
 	this.varsChanged = true;
 	this.isStatic = true;
 	this.isConstructorCall = false;
+	this.lineSeparator = org.eclipse.jdt.internal.compiler.util.Util.LINE_SEPARATOR; // default value
 }
 /**
  * Returns the global variables of this evaluation context in the order they were created in.
@@ -107,14 +108,15 @@
 		this.localVariableNames, 
 		this.localVariableTypeNames, 
 		this.localVariableModifiers, 
-		this.declaringTypeName		
+		this.declaringTypeName,
+		this.lineSeparator
 	);
 	ICompilationUnit sourceUnit = new ICompilationUnit() {
 		public char[] getFileName() {
 			return CharOperation.concat(className, Util.defaultJavaExtension().toCharArray());
 		}
 		public char[] getContents() {
-			return mapper.getCUSource();
+			return mapper.getCUSource(EvaluationContext.this.lineSeparator);
 		}
 		public char[] getMainTypeName() {
 			return className;
@@ -511,14 +513,15 @@
 		this.localVariableNames, 
 		this.localVariableTypeNames, 
 		this.localVariableModifiers, 
-		this.declaringTypeName
+		this.declaringTypeName,
+		this.lineSeparator
 	);
 	ICompilationUnit sourceUnit = new ICompilationUnit() {
 		public char[] getFileName() {
 			return CharOperation.concat(className, Util.defaultJavaExtension().toCharArray());
 		}
 		public char[] getContents() {
-			return mapper.getCUSource();
+			return mapper.getCUSource(EvaluationContext.this.lineSeparator);
 		}
 		public char[] getMainTypeName() {
 			return className;
@@ -540,6 +543,12 @@
 	this.varsChanged = true; // this may change the visibility of the variable's types
 }
 /**
+ * Sets the line separator used by this evaluation context.
+ */
+public void setLineSeparator(String lineSeparator) {
+	this.lineSeparator = lineSeparator;
+}
+/**
  * Sets the dot-separated name of the package code snippets are ran into.
  * The default package name is an empty array.
  */
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/VariablesEvaluator.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/VariablesEvaluator.java
index f75da9a..b6db9b3 100644
--- a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/VariablesEvaluator.java
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/VariablesEvaluator.java
@@ -22,7 +22,6 @@
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
 import org.eclipse.jdt.internal.compiler.env.IBinaryType;
 import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
-import org.eclipse.jdt.internal.compiler.util.Util;
 
 /**
  * A variables evaluator compiles the global variables of an evaluation context and returns
@@ -190,7 +189,7 @@
 	if (packageName.length != 0) {
 		buffer.append("package "); //$NON-NLS-1$
 		buffer.append(packageName);
-		buffer.append(';').append(Util.LINE_SEPARATOR);
+		buffer.append(';').append(this.context.lineSeparator);
 		lineNumberOffset++;
 	}
 
@@ -199,7 +198,7 @@
 	for (int i = 0; i < imports.length; i++) {
 		buffer.append("import "); //$NON-NLS-1$
 		buffer.append(imports[i]);
-		buffer.append(';').append(Util.LINE_SEPARATOR);
+		buffer.append(';').append(this.context.lineSeparator);
 		lineNumberOffset++;
 	}
 
@@ -210,7 +209,7 @@
 	buffer.append(PACKAGE_NAME);
 	buffer.append("."); //$NON-NLS-1$
 	buffer.append(ROOT_CLASS_NAME);
-	buffer.append(" {").append(Util.LINE_SEPARATOR); //$NON-NLS-1$
+	buffer.append(" {").append(this.context.lineSeparator); //$NON-NLS-1$
 	lineNumberOffset++;
 	this.startPosOffset = buffer.length();
 
@@ -225,12 +224,12 @@
 		buffer.append(" "); //$NON-NLS-1$
 		char[] varName = var.name;
 		buffer.append(varName);
-		buffer.append(';').append(Util.LINE_SEPARATOR);
+		buffer.append(';').append(this.context.lineSeparator);
 		lineNumberOffset++;
 	}
 
 	// field initializations
-	buffer.append("\tstatic {").append(Util.LINE_SEPARATOR); //$NON-NLS-1$
+	buffer.append("\tstatic {").append(this.context.lineSeparator); //$NON-NLS-1$
 	lineNumberOffset++;
 	for (int i = 0; i < this.context.variableCount; i++){
 		GlobalVariable var = vars[i];
@@ -240,7 +239,7 @@
 			// Initialize with initializer if there was no previous value
 			char[] initializer = var.initializer;
 			if (initializer != null) {
-				buffer.append("\t\ttry {").append(Util.LINE_SEPARATOR); //$NON-NLS-1$
+				buffer.append("\t\ttry {").append(this.context.lineSeparator); //$NON-NLS-1$
 				lineNumberOffset++;
 				var.initializerLineStart = lineNumberOffset;
 				buffer.append("\t\t\t"); //$NON-NLS-1$
@@ -250,10 +249,10 @@
 				var.initExpressionStart = buffer.length();
 				buffer.append(initializer);
 				lineNumberOffset += numberOfCRs(initializer);
-				buffer.append(';').append(Util.LINE_SEPARATOR);
-				buffer.append("\t\t} catch (Throwable e) {").append(Util.LINE_SEPARATOR); //$NON-NLS-1$
-				buffer.append("\t\t\te.printStackTrace();").append(Util.LINE_SEPARATOR); //$NON-NLS-1$
-				buffer.append("\t\t}").append(Util.LINE_SEPARATOR); //$NON-NLS-1$
+				buffer.append(';').append(this.context.lineSeparator);
+				buffer.append("\t\t} catch (Throwable e) {").append(this.context.lineSeparator); //$NON-NLS-1$
+				buffer.append("\t\t\te.printStackTrace();").append(this.context.lineSeparator); //$NON-NLS-1$
+				buffer.append("\t\t}").append(this.context.lineSeparator); //$NON-NLS-1$
 				lineNumberOffset += 4; // 4 CRs
 			}
 		} else {
@@ -269,14 +268,14 @@
 			buffer.append(installedVars.className);
 			buffer.append("."); //$NON-NLS-1$
 			buffer.append(varName);
-			buffer.append(';').append(Util.LINE_SEPARATOR);
+			buffer.append(';').append(this.context.lineSeparator);
 			lineNumberOffset++;
 		}
 	}
-	buffer.append("\t}").append(Util.LINE_SEPARATOR); //$NON-NLS-1$
+	buffer.append("\t}").append(this.context.lineSeparator); //$NON-NLS-1$
 	
 	// end of class declaration
-	buffer.append('}').append(Util.LINE_SEPARATOR);
+	buffer.append('}').append(this.context.lineSeparator);
 
 	// return result
 	int length = buffer.length();
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/DefaultCodeFormatterConstants.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/DefaultCodeFormatterConstants.java
index 25823a2..caf50f4 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/DefaultCodeFormatterConstants.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/DefaultCodeFormatterConstants.java
@@ -808,7 +808,7 @@
 
 	/**
 	 * <pre>
-	 * FORMATTER / Option to insert a new line after the opening brace in an array initializer
+	 * FORMATTER / Option to insert a new line after an annotation
 	 *     - option id:         "org.eclipse.jdt.core.formatter.insert_new_line_after_annotation"
 	 *     - possible values:   { INSERT, DO_NOT_INSERT }
 	 *     - default:           INSERT
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/package.html b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/package.html
new file mode 100644
index 0000000..90588e9
--- /dev/null
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/package.html
@@ -0,0 +1,19 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <meta name="Author" content="IBM">
+   <title>Package-level Javadoc</title>
+</head>
+<body>
+The code formatter is the set of classes that are used to format Java code.
+
+<h2>
+Package Specification</h2>
+
+<p>This package contains classes to format Java code.
+The principal classes are {@link org.eclipse.jdt.core.formatter.CodeFormatter CodeFormatter} and
+{@link org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants DefaultCodeFormatterConstants}.
+</p>
+</body>
+</html>
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/CodeFormatterVisitor.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/CodeFormatterVisitor.java
index 2211187..028d6ea 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/CodeFormatterVisitor.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/CodeFormatterVisitor.java
@@ -311,6 +311,8 @@
 						if (currentField.declarationSourceStart == ((FieldDeclaration) previousMergedNode).declarationSourceStart) {
 							// we create a multi field declaration
 							mergedNodes.set(mergedNodes.size() - 1, new MultiFieldDeclaration(new FieldDeclaration[]{ (FieldDeclaration)previousMergedNode, currentField}));
+						} else {
+							mergedNodes.add(currentNode);
 						}
 					} else {
 						mergedNodes.add(currentNode);
@@ -1328,6 +1330,28 @@
 					if (numberOfParens > 0) {
 						manageOpeningParenthesizedExpression(currentMessageSend, numberOfParens);
 					}
+					TypeReference[] typeArguments = currentMessageSend.typeArguments;
+					if (typeArguments != null) {
+							this.scribe.printNextToken(TerminalTokens.TokenNameLESS, this.preferences.insert_space_before_opening_angle_bracket_in_type_arguments); 
+							if (this.preferences.insert_space_after_opening_angle_bracket_in_type_arguments) {
+								this.scribe.space();
+							}
+							int length = typeArguments.length;
+							for (int j = 0; j < length - 1; j++) {
+								typeArguments[j].traverse(this, scope);
+								this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_type_arguments);
+								if (this.preferences.insert_space_after_comma_in_type_arguments) {
+									this.scribe.space();
+								}				
+							}
+							typeArguments[length - 1].traverse(this, scope);
+							if (isClosingGenericToken()) {
+								this.scribe.printNextToken(CLOSING_GENERICS_EXPECTEDTOKENS, this.preferences.insert_space_before_closing_angle_bracket_in_type_arguments); 
+							}
+							if (this.preferences.insert_space_after_closing_angle_bracket_in_type_arguments) {
+								this.scribe.space();
+							}
+					}
 					ASTNode[] arguments = currentMessageSend.arguments;
 					this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier); // selector
 					this.scribe.printNextToken(TerminalTokens.TokenNameLPAREN, this.preferences.insert_space_before_opening_paren_in_method_invocation);
@@ -1486,7 +1510,7 @@
 	private void formatLocalDeclaration(LocalDeclaration localDeclaration, BlockScope scope, boolean insertSpaceBeforeComma, boolean insertSpaceAfterComma) {
 
 		if (!isMultipleLocalDeclaration(localDeclaration)) {
-			if (localDeclaration.modifiers != NO_MODIFIERS) {
+			if (localDeclaration.modifiers != NO_MODIFIERS || localDeclaration.annotations != null) {
 		        this.scribe.printComment();
 				this.scribe.printModifiers(localDeclaration.annotations, this);
 				this.scribe.space();
@@ -1987,16 +2011,15 @@
 			int token;
 			while ((token = this.localScanner.getNextToken()) != TerminalTokens.TokenNameEOF) {
 				switch(token) {
-					case TerminalTokens.TokenNameRBRACKET://166 
+					case TerminalTokens.TokenNameRBRACKET:
 						dimensions++;
 						break;
-					case TerminalTokens.TokenNameIdentifier ://90						
-					case TerminalTokens.TokenNameLBRACE ://90						
-					case TerminalTokens.TokenNameLPAREN :
-					case TerminalTokens.TokenNameCOMMA ://90
-					case TerminalTokens.TokenNameEQUAL ://167
-					case TerminalTokens.TokenNameSEMICOLON ://64
-					case TerminalTokens.TokenNameRPAREN : //86
+					case TerminalTokens.TokenNameCOMMENT_BLOCK :
+					case TerminalTokens.TokenNameCOMMENT_JAVADOC :
+					case TerminalTokens.TokenNameCOMMENT_LINE :
+					case TerminalTokens.TokenNameLBRACKET :
+						break;
+					default:
 						return dimensions;
 				}
 			}
@@ -2268,7 +2291,7 @@
 	 */
 	public boolean visit(Argument argument, BlockScope scope) {
 
-		if (argument.modifiers != NO_MODIFIERS) {
+		if (argument.modifiers != NO_MODIFIERS || argument.annotations != null) {
 	        this.scribe.printComment();
 			this.scribe.printModifiers(argument.annotations, this);
 			this.scribe.space();
@@ -2475,7 +2498,7 @@
 			if (numberOfParens > 0) {
 				manageOpeningParenthesizedExpression(arrayQualifiedTypeReference, numberOfParens);
 			}
-			this.scribe.printQualifiedReference(arrayQualifiedTypeReference.sourceEnd);
+			this.scribe.printArrayQualifiedReference(arrayQualifiedTypeReference.tokens.length, arrayQualifiedTypeReference.sourceEnd);
 			int dimensions = getDimensions();
 			if (dimensions != 0) {
 				for (int i = 0; i < dimensions; i++) {
@@ -2500,7 +2523,7 @@
 			if (numberOfParens > 0) {
 				manageOpeningParenthesizedExpression(arrayQualifiedTypeReference, numberOfParens);
 			}
-			this.scribe.printQualifiedReference(arrayQualifiedTypeReference.sourceEnd);
+			this.scribe.printArrayQualifiedReference(arrayQualifiedTypeReference.tokens.length, arrayQualifiedTypeReference.sourceEnd);
 			int dimensions = getDimensions();
 			if (dimensions != 0) {
 				for (int i = 0; i < dimensions; i++) {
@@ -3790,7 +3813,12 @@
 		if (this.preferences.insert_space_after_colon_in_labeled_statement) {
 			this.scribe.space();
 		}
-		labeledStatement.statement.traverse(this, scope);
+		final Statement statement = labeledStatement.statement;
+		statement.traverse(this, scope);
+		if (statement instanceof Expression) {
+			this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+			this.scribe.printTrailingComment();
+		}
 		return false;
 	}
 
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatter.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatter.java
index 525bd59..e27f3b7 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatter.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatter.java
@@ -333,21 +333,25 @@
 		}
 		ProbingScanner.setSource((char[]) null);
 
+		// probe for expression
 		Expression expression = this.codeSnippetParsingUtil.parseExpression(source.toCharArray(), getDefaultCompilerOptions(), true);
 		if (expression != null) {
 			return internalFormatExpression(source, indentationLevel, lineSeparator, expression, offset, length);
 		}
 
+		// probe for body declarations (fields, methods, constructors)
 		ASTNode[] bodyDeclarations = this.codeSnippetParsingUtil.parseClassBodyDeclarations(source.toCharArray(), getDefaultCompilerOptions(), true);
 		if (bodyDeclarations != null) {
 			return internalFormatClassBodyDeclarations(source, indentationLevel, lineSeparator, bodyDeclarations, offset, length);
 		}
 
+		// probe for statements
 		ConstructorDeclaration constructorDeclaration = this.codeSnippetParsingUtil.parseStatements(source.toCharArray(), getDefaultCompilerOptions(), true);
 		if (constructorDeclaration.statements != null) {
 			return internalFormatStatements(source, indentationLevel, lineSeparator, constructorDeclaration, offset, length);
 		}
 
+		// this has to be a compilation unit
 		return formatCompilationUnit(source, indentationLevel, lineSeparator, offset, length);
 	}
 }
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/Scribe.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/Scribe.java
index a42e291..c7fd854 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/Scribe.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/Scribe.java
@@ -1206,7 +1206,7 @@
 						hasModifiers = true;
 						this.print(this.scanner.getRawTokenSource(), !isFirstModifier);
 						isFirstModifier = false;
-						currentTokenStartPosition = this.scanner.getCurrentTokenStartPosition();
+						currentTokenStartPosition = this.scanner.currentPosition;
 						break;
 					case TerminalTokens.TokenNameAT :
 						hasModifiers = true;
@@ -1352,6 +1352,50 @@
 		}
 	}
 
+	public void printArrayQualifiedReference(int numberOfTokens, int sourceEnd) {
+		int currentTokenStartPosition = this.scanner.currentPosition;
+		int numberOfIdentifiers = 0;
+		try {
+			do {
+				this.printComment();
+				switch(this.currentToken = this.scanner.getNextToken()) {
+					case TerminalTokens.TokenNameEOF :
+						return;
+					case TerminalTokens.TokenNameWHITESPACE :
+						addDeleteEdit(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition());
+						currentTokenStartPosition = this.scanner.currentPosition;
+						break;
+					case TerminalTokens.TokenNameCOMMENT_BLOCK :
+					case TerminalTokens.TokenNameCOMMENT_JAVADOC :
+						this.printBlockComment(this.scanner.getRawTokenSource(), false);
+						currentTokenStartPosition = this.scanner.currentPosition;
+						break;
+					case TerminalTokens.TokenNameCOMMENT_LINE :
+						this.printCommentLine(this.scanner.getRawTokenSource());
+						currentTokenStartPosition = this.scanner.currentPosition;
+						break;
+					case TerminalTokens.TokenNameIdentifier :
+						this.print(this.scanner.getRawTokenSource(), false);
+						currentTokenStartPosition = this.scanner.currentPosition;
+						if (++ numberOfIdentifiers == numberOfTokens) {
+							this.scanner.resetTo(currentTokenStartPosition, this.scannerEndPosition - 1);
+							return;
+						}
+						break;						
+					case TerminalTokens.TokenNameDOT :
+						this.print(this.scanner.getRawTokenSource(), false);
+						currentTokenStartPosition = this.scanner.currentPosition;
+						break;
+					default:
+						this.scanner.resetTo(currentTokenStartPosition, this.scannerEndPosition - 1);
+						return;
+				}
+			} while (this.scanner.currentPosition <= sourceEnd);
+		} catch(InvalidInputException e) {
+			throw new AbortFormatting(e);
+		}
+	}
+
 	public void printQualifiedReference(int sourceEnd) {
 		int currentTokenStartPosition = this.scanner.currentPosition;
 		try {
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/comment/JavaDocRegion.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/comment/JavaDocRegion.java
index 5767dc7..e38dde6 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/comment/JavaDocRegion.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/comment/JavaDocRegion.java
@@ -197,10 +197,19 @@
 		ILineTracker tracker= new DefaultLineTracker();
 		String patch= indentation + MultiCommentLine.MULTI_COMMENT_CONTENT_PREFIX;
 
+		// remove trailing spaces
+		int i= snippet.length();
+		while (i > 0 && ' ' == snippet.charAt(i-1))
+			i--;
+		snippet= snippet.substring(0, i);
+		
 		buffer.setLength(0);
-		buffer.append(getDelimiter());
+		String lineDelimiter= getDelimiter();
+		if (lineDelimiter != null && snippet.indexOf(lineDelimiter) != 0)
+			buffer.append(lineDelimiter);
 		buffer.append(convertJava2Html(snippet));
-		buffer.append(getDelimiter());
+		if (lineDelimiter != null && snippet.lastIndexOf(lineDelimiter) != snippet.length() - lineDelimiter.length())
+			buffer.append(lineDelimiter);
 		tracker.set(buffer.toString());
 		
 		for (int line= tracker.getNumberOfLines() - 1; line > 0; line--)
diff --git a/org.eclipse.jdt.core/grammar/java_1_5.g b/org.eclipse.jdt.core/grammar/java_1_5.g
index 375240b..53e1f2a 100644
--- a/org.eclipse.jdt.core/grammar/java_1_5.g
+++ b/org.eclipse.jdt.core/grammar/java_1_5.g
@@ -1582,7 +1582,7 @@
 /.$putCase consumeEnumConstantHeaderName(); $break ./

 /:$readableName EnumConstantHeaderName:/

 

-EnumConstantHeader ::= EnumConstantHeaderName Argumentsopt

+EnumConstantHeader ::= EnumConstantHeaderName ForceNoDiet Argumentsopt RestoreDiet

 /.$putCase consumeEnumConstantHeader(); $break ./

 /:$readableName EnumConstantHeader:/

 

@@ -2050,7 +2050,8 @@
 AnnotationTypeMemberDeclarationsopt ::= $empty

 /.$putCase consumeEmptyAnnotationTypeMemberDeclarationsopt() ; $break ./

 /:$compliance 1.5:/

-AnnotationTypeMemberDeclarationsopt -> AnnotationTypeMemberDeclarations

+AnnotationTypeMemberDeclarationsopt ::= NestedType AnnotationTypeMemberDeclarations

+/.$putCase consumeAnnotationTypeMemberDeclarationsopt() ; $break ./

 /:$readableName AnnotationTypeMemberDeclarations:/

 /:$compliance 1.5:/

 

diff --git a/org.eclipse.jdt.core/jdt_core_style.css b/org.eclipse.jdt.core/jdt_core_style.css
new file mode 100644
index 0000000..f9a680a
--- /dev/null
+++ b/org.eclipse.jdt.core/jdt_core_style.css
@@ -0,0 +1,18 @@
+@charset "iso-8859-1";
+TD.title1
+{
+font-family: "Verdana", "Arial", "Helvetica";
+}												
+B.title1
+{
+font-family:"Times New Roman";
+}
+TD.title2
+{
+font-family: "Arial", "Helvetica", "sans-serif";   
+color: #8080ff
+}
+TD.title3
+{
+font-family: "Arial", "Helvetica", "sans-serif";
+}
\ No newline at end of file
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 1c7c5d2..2196a29 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
@@ -175,18 +175,6 @@
 	}
 	
 	/**
-	 * Returns the declaring type signature of the element represented by this binding key.
-	 * Returns the signature of the element if it is a type.
-	 * 
-	 * @return the declaring type signature
-	 */
-	public String getDeclaringTypeSignature() {
-		KeyToSignature keyToSignature = new KeyToSignature(this.key, KeyToSignature.DECLARING_TYPE);
-		keyToSignature.parse();
-		return keyToSignature.signature.toString();
-	}
-	
-	/**
 	 * 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,
 	 * returns an empty array.
@@ -233,11 +221,15 @@
 	}
 	
 	/**
-	 * Transforms this binding key into a signature.
+	 * Internal method.
+	 * <p>
+	 * This method transforms this binding key into a signature. 
+	 * This method is not intended to be called by clients.
+	 * </p>
 	 * 
 	 * @return the signature for this binding key
 	 */
-	public String toSignature() {
+	public String internalToSignature() {
 		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/CompletionProposal.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionProposal.java
index 9c210fb..74a3813 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
@@ -928,8 +928,8 @@
 	 * 	<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</li>
-	 * 	<li><code>METHOD_DECLARATION</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>
 	 * </ul>
@@ -947,7 +947,7 @@
 	
 	
 	/**
-	 * Sets the simple name of the method, field,
+	 * Sets the simple name of the method (type simple name for constructor), field,
 	 * member, or variable relevant in the context, or
 	 * <code>null</code> if none.
 	 * <p>
@@ -1359,37 +1359,52 @@
 			
 			switch(this.completionKind) {
 				case ANONYMOUS_CLASS_DECLARATION:
-					this.parameterNames =  this.findMethodParameterNames(
-							this.declarationPackageName,
-							this.declarationTypeName,
-							CharOperation.lastSegment(this.declarationTypeName, '.'),
-							this.parameterPackageNames,
-							this.parameterTypeNames);
+					try {
+						this.parameterNames = this.findMethodParameterNames(
+								this.declarationPackageName,
+								this.declarationTypeName,
+								CharOperation.lastSegment(this.declarationTypeName, '.'),
+								Signature.getParameterTypes(this.originalSignature == null ? this.signature : this.originalSignature));
+					} catch(IllegalArgumentException e) {
+						// protection for invalid signature
+						if(this.parameterTypeNames != null) {
+							this.parameterNames =  this.createDefaultParameterNames(this.parameterTypeNames.length);
+						} else {
+							this.parameterNames = null;
+						}
+					}
 					break;
 				case METHOD_REF:
-					this.parameterNames =  this.findMethodParameterNames(
-							this.declarationPackageName,
-							this.declarationTypeName,
-							this.name,
-							this.parameterPackageNames,
-							this.parameterTypeNames);
-					//this.parameterNames = this.findMethodParameterNames(
-					//		this.declarationSignature,
-					//		this.name,
-					//		Signature.getParameterTypes(this.getSignature()));
+					try {
+						this.parameterNames = this.findMethodParameterNames(
+								this.declarationPackageName,
+								this.declarationTypeName,
+								this.name,
+								Signature.getParameterTypes(this.originalSignature == null ? this.signature : this.originalSignature));
+					} catch(IllegalArgumentException e) {
+						// protection for invalid signature
+						if(this.parameterTypeNames != null) {
+							this.parameterNames =  this.createDefaultParameterNames(this.parameterTypeNames.length);
+						} else {
+							this.parameterNames = null;
+						}
+					}
 					break;
 				case METHOD_DECLARATION:
-					this.parameterNames =  this.findMethodParameterNames(
-							this.declarationPackageName,
-							this.declarationTypeName,
-							this.name,
-							this.parameterPackageNames,
-							this.parameterTypeNames);
-					//char[][] parameterTypes = Signature.getParameterTypes(this.getSignature();
-					///this.parameterNames = this.findMethodParameterNames(
-					//		this.declarationSignature,
-					//		this.name,
-					//		parameterTypes);
+					try {
+						this.parameterNames = this.findMethodParameterNames(
+								this.declarationPackageName,
+								this.declarationTypeName,
+								this.name,
+								Signature.getParameterTypes(this.originalSignature == null ? this.signature : this.originalSignature));
+					} catch(IllegalArgumentException e) {
+						// protection for invalid signature
+						if(this.parameterTypeNames != null) {
+							this.parameterNames =  this.createDefaultParameterNames(this.parameterTypeNames.length);
+						} else {
+							this.parameterNames = null;
+						}
+					}
 					if(this.parameterNames != null) {
 						this.updateCompletion = true;
 					}
@@ -1438,4 +1453,26 @@
 	public int getAccessibility() {
 		return this.accessibility;
 	}
+	
+	/**
+	 * Returns whether this proposal is a constructor.
+	 * <p>
+	 * This field is available for the following kinds of
+	 * completion proposals:
+	 * <ul>
+	 * <li><code>METHOD_REF</code> - return <code>true</code>
+	 * if the referenced method is a constructor</li>
+	 * 	<li><code>METHOD_DECLARATION</code> - return <code>true</code>
+	 * if the declared method is a constructor</li>
+	 * </ul>
+	 * For kinds of completion proposals, this method returns
+	 * <code>false</code>.
+	 * </p>
+	 * 
+	 * @return <code>true</code> if the proposal is a constructor.
+	 * @since 3.1
+	 */
+	public boolean isConstructor() {
+		return this.isConstructor;
+	}
 }
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 fde348e..d873606 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
@@ -14,10 +14,10 @@
 
 import org.eclipse.core.resources.*;
 import org.eclipse.jdt.core.compiler.*;
-import org.eclipse.jdt.core.compiler.InvalidInputException;
-import org.eclipse.jdt.core.compiler.IProblem;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons;
 import org.eclipse.jdt.internal.compiler.parser.*;
+import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
 import org.eclipse.jdt.internal.core.util.Messages;
 import org.eclipse.jdt.internal.core.util.Util;
 
@@ -401,4 +401,39 @@
 		String argumentsString = problemMarker.getAttribute(IJavaModelMarker.ARGUMENTS, null);
 		return Util.getProblemArgumentsFromMarker(argumentsString);
 	}	
+	
+	/**
+	 * Returns a token which can be used to suppress a given warning using 
+	 * <code>@SuppressWarnings</code> annotation, for a given problem ID 
+	 * ({@link IProblem }). If a particular problem is not suppressable, 
+	 * <code>null</code> will be returned. 
+	 * <p>
+	 * <b>Note:</b> <code>@SuppressWarnings</code> can only suppress warnings, 
+	 * which means that if some problems got promoted to ERROR using custom compiler 
+	 * settings ({@link IJavaProject#setOption(String, String)}), the 
+	 * <code>@SuppressWarnings</code> annotation will be ineffective.
+	 * </p>
+	 * <p>
+	 * <b>Note:</b> <code>@SuppressWarnings</code> can be argumented with 
+	 * <code>"all"</code> so as to suppress all possible warnings at once.
+	 * </p>
+	 * <p>
+	 * <b>Note:</b> The tokens returned are not necessarily standardized across Java 
+	 * compilers. If you were to use one of these tokens in an @SuppressWarnings 
+	 * annotation in the Java source code, the effects (if any) may vary from 
+	 * compiler to compiler.
+	 * </p>
+	 * @param problemID
+	 *         the ID of a given warning to suppress
+	 * @return a String which can be used in <code>@SuppressWarnings</code> annotation, 
+	 * or <code>null</code> if unable to suppress this warning.
+	 * @since 3.1
+	 */
+	public static String getWarningToken(int problemID){
+		long irritant = ProblemReporter.getIrritant(problemID);
+		if (irritant != 0) {
+			return CompilerOptions.warningTokenFromIrritant(irritant);
+		}
+		return null;
+	}
 }
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 c790e0d..9079343 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
@@ -31,10 +31,13 @@
  * Note this is different from inclusion and exclusion patterns on source classpath entries, 
  * where a source file that is excluded is not even compiled.
  * Files patterns look like relative file paths with wildcards and are interpreted relative 
- * to each entry's path. 
+ * to each entry's path.
  * File patterns are case-sensitive and they can contain '**', '*' or '?' wildcards (see 
  * {@link IClasspathEntry#getExclusionPatterns()} for the full description
  * of their syntax and semantics).
+ * Note that file patterns must not include the file extension. 
+ * <code>com/xyz/tests/MyClass</code> is a valid file pattern, whereas 
+ * <code>com/xyz/tests/MyClass.class</code> is not valid.
  * </p>
  * <p>
  * For example, if one of the entry path is <code>/Project/someLib.jar</code>, 
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 3f5be18..e714fac 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
@@ -139,9 +139,7 @@
  * included in the result.
  * <p>
  * Note: This API element is only needed for dealing with Java code that uses
- * new language features of J2SE 1.5. It is included in anticipation of J2SE
- * 1.5 support, which is planned for the next release of Eclipse after 3.0, and
- * may change slightly before reaching its final form.
+ * new language features of J2SE 5.0.
  * </p>
  *
  * @param name the name of the import declaration to add as defined by JLS2 7.5. (For example: <code>"java.io.File"</code> or
@@ -514,10 +512,6 @@
  * 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>
- * <b>NOTE:</b>In Eclipse 3.0, there is no reconciler support for
- * level AST.JLS3. This support is planned for the follow-on release of
- * Eclipse which includes support for J2SE 1.5.
- * </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
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 422c51a..c73c501 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
@@ -115,7 +115,7 @@
 	 * 	- internal to the workbench: "/Project/src"
 	 *  - external to the workbench: "c:/jdk/classes.zip/java/lang"
 	 * @param path the given absolute path
-	 * @exception JavaModelException if this element does not exist or if an
+	 * @exception JavaModelException if this project does not exist or if an
 	 *		exception occurs while accessing its corresponding resource
 	 * @return the first existing package fragment on this project's classpath
 	 * whose path matches the given (absolute) path, or <code>null</code> if none
@@ -131,7 +131,7 @@
 	 *	- internal to the workbench: "/Compiler/src"
 	 *	- external to the workbench: "c:/jdk/classes.zip"
 	 * @param path the given absolute path
-	 * @exception JavaModelException if this element does not exist or if an
+	 * @exception JavaModelException if this project does not exist or if an
 	 *		exception occurs while accessing its corresponding resource
 	 * @return the existing package fragment root on this project's classpath
 	 * whose path matches the given (absolute) path, or <code>null</code> if
@@ -172,7 +172,7 @@
 	 * unit or found by the <code>SearchEngine</code>.
 	 * 
 	 * @param fullyQualifiedName the given fully qualified name
-	 * @exception JavaModelException if this element does not exist or if an
+	 * @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
@@ -197,7 +197,7 @@
 	 * 
 	 * @param fullyQualifiedName the given fully qualified name
 	 * @param owner the owner of the returned type's compilation unit
-	 * @exception JavaModelException if this element does not exist or if an
+	 * @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
@@ -222,7 +222,7 @@
 	 * 
 	 * @param packageName the given package name
 	 * @param typeQualifiedName the given type qualified name
-	 * @exception JavaModelException if this element does not exist or if an
+	 * @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 package name and type qualified name
@@ -251,7 +251,7 @@
 	 * @param packageName the given package name
 	 * @param typeQualifiedName the given type qualified name
 	 * @param owner the owner of the returned type's compilation unit
-	 * @exception JavaModelException if this element does not exist or if an
+	 * @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 package name and type qualified name
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 8040eeb..92c3bd4 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
@@ -175,7 +175,7 @@
  * This is a handle-only method. The type parameter may or may not exist.
  * 
  * @param name the given simple name
- * @return the type parameter declared in this methid with the given name
+ * @return the type parameter declared in this method with the given name
  * @since 3.1
  */
 ITypeParameter getTypeParameter(String name);
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 993f2cc..95d562e 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
@@ -300,7 +300,7 @@
 	 * <p>
 	 * Optionally, the new type can be positioned before the specified
 	 * sibling. If no sibling is specified, the type will be appended
-	 * to this type.
+	 * to this type.</p>
 	 *
 	 * <p>It is possible that a type with the same name already exists in this type.
 	 * The value of the <code>force</code> parameter effects the resolution of
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 9e0e675..9ef3ef0 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
@@ -19,12 +19,11 @@
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Status;
 import org.eclipse.jdt.core.compiler.*;
-import org.eclipse.jdt.core.compiler.InvalidInputException;
+import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
 import org.eclipse.jdt.internal.compiler.parser.Scanner;
 import org.eclipse.jdt.internal.compiler.parser.TerminalTokens;
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
 import org.eclipse.jdt.internal.core.*;
-import org.eclipse.jdt.internal.core.JavaModelStatus;
 import org.eclipse.jdt.internal.core.util.Messages;
 
 /**
@@ -37,6 +36,7 @@
 public final class JavaConventions {
 
 	private final static char DOT= '.';
+	private static final String PACKAGE_INFO = new String(TypeConstants.PACKAGE_INFO_NAME);
 	private final static Scanner SCANNER = new Scanner();
 
 	private JavaConventions() {
@@ -140,7 +140,7 @@
 		// JSR-175 metadata strongly recommends "package-info.java" as the
 		// file in which to store package annotations and
 		// the package-level spec (replaces package.html)
-		if (!identifier.equals("package-info")) { //$NON-NLS-1$
+		if (!identifier.equals(PACKAGE_INFO)) {
 			IStatus status = validateIdentifier(identifier);
 			if (!status.isOK()) {
 				return status;
@@ -183,11 +183,16 @@
 			return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.convention_classFile_notClassFileName, null); 
 		}
 		identifier = name.substring(0, index);
-		IStatus status = validateIdentifier(identifier);
-		if (!status.isOK()) {
-			return status;
+		// JSR-175 metadata strongly recommends "package-info.java" as the
+		// file in which to store package annotations and
+		// the package-level spec (replaces package.html)
+		if (!identifier.equals(PACKAGE_INFO)) {
+			IStatus status = validateIdentifier(identifier);
+			if (!status.isOK()) {
+				return status;
+			}
 		}
-		status = ResourcesPlugin.getWorkspace().validateName(name, IResource.FILE);
+		IStatus status = ResourcesPlugin.getWorkspace().validateName(name, IResource.FILE);
 		if (!status.isOK()) {
 			return status;
 		}
@@ -305,7 +310,7 @@
 			}
 			return JavaModelStatus.VERIFIED_OK;
 		} else {
-			return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.bind(Messages.convention_type_invalidName, (new String[] {name})), null); 
+			return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.bind(Messages.convention_type_invalidName, name), null); 
 		}
 	}
 
@@ -372,7 +377,7 @@
 			typeName = typeName.trim(); // grammar allows spaces
 			char[] scannedID = scannedIdentifier(typeName);
 			if (scannedID == null) {
-				return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.bind(Messages.convention_illegalIdentifier, (new String[] {typeName})), null); 
+				return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.bind(Messages.convention_illegalIdentifier, typeName), null); 
 			}
 			IStatus status = workspace.validateName(new String(scannedID), IResource.FOLDER);
 			if (!status.isOK()) {
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 4f1abbb..ca7ccd5 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
@@ -64,15 +64,19 @@
 import org.eclipse.core.runtime.*;
 import org.eclipse.core.runtime.jobs.ISchedulingRule;
 import org.eclipse.core.runtime.jobs.Job;
-import org.eclipse.core.runtime.preferences.IEclipsePreferences;
-import org.eclipse.core.runtime.preferences.IPreferencesService;
+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.util.SuffixConstants;
 import org.eclipse.jdt.internal.core.*;
+import org.eclipse.jdt.internal.core.builder.JavaBuilder;
+import org.eclipse.jdt.internal.core.builder.State;
 import org.eclipse.jdt.internal.core.util.MementoTokenizer;
 import org.eclipse.jdt.internal.core.util.Messages;
 import org.eclipse.jdt.internal.core.util.Util;
 import org.osgi.framework.BundleContext;
-import org.osgi.service.prefs.BackingStoreException;
 
 /**
  * The plug-in runtime class for the Java model plug-in containing the core
@@ -463,13 +467,13 @@
 	/**
 	 * Possible  configurable option ID.
 	 * @see #getDefaultOptions()
-	 * @since 3.0
+	 * @since 3.1
 	 */
 	public static final String COMPILER_PB_INVALID_JAVADOC_TAGS__DEPRECATED_REF = PLUGIN_ID + ".compiler.problem.invalidJavadocTagsDeprecatedRef"; //$NON-NLS-1$
 	/**
 	 * Possible  configurable option ID.
 	 * @see #getDefaultOptions()
-	 * @since 3.0
+	 * @since 3.1
 	 */
 	public static final String COMPILER_PB_INVALID_JAVADOC_TAGS__NOT_VISIBLE_REF = PLUGIN_ID + ".compiler.problem.invalidJavadocTagsNotVisibleRef"; //$NON-NLS-1$
 	/**
@@ -589,6 +593,18 @@
 	/**
 	 * Possible  configurable option ID.
 	 * @see #getDefaultOptions()
+	 * @since 3.1
+	 */
+	public static final String COMPILER_PB_SUPPRESS_WARNINGS = PLUGIN_ID + ".compiler.problem.suppressWarnings"; //$NON-NLS-1$
+	/**
+	 * Possible  configurable option ID.
+	 * @see #getDefaultOptions()
+	 * @since 3.1
+	 */
+	public static final String COMPILER_PB_UNHANDLED_WARNING_TOKEN = PLUGIN_ID + ".compiler.problem.unhandledWarningToken"; //$NON-NLS-1$
+	/**
+	 * Possible  configurable option ID.
+	 * @see #getDefaultOptions()
 	 */
 	public static final String CORE_JAVA_BUILD_ORDER = PLUGIN_ID + ".computeJavaBuildOrder"; //$NON-NLS-1$
 	/**
@@ -816,13 +832,13 @@
 	 * @see #getDefaultOptions()
 	 * @since 3.1
 	 */
-	public static final String CODEASSIST_FORBIDDEN_REFERENCE_CHECK = PLUGIN_ID + ".codeComplete.restrictionsCheck"; //$NON-NLS-1$
+	public static final String CODEASSIST_FORBIDDEN_REFERENCE_CHECK= PLUGIN_ID + ".codeComplete.forbiddenReferenceCheck"; //$NON-NLS-1$
 	/**
 	 * Possible  configurable option ID.
 	 * @see #getDefaultOptions()
 	 * @since 3.1
 	 */
-	public static final String CODEASSIST_DISCOURAGED_REFERENCE_CHECK = PLUGIN_ID + ".codeComplete.discouragedReferenceCheck"; //$NON-NLS-1$
+	public static final String CODEASSIST_DISCOURAGED_REFERENCE_CHECK= PLUGIN_ID + ".codeComplete.discouragedReferenceCheck"; //$NON-NLS-1$
 	
 	// *************** Possible values for configurable options. ********************
 	
@@ -990,11 +1006,12 @@
 	 * @since 3.0
 	 */
 	public static final String PRIVATE = "private"; //$NON-NLS-1$
-
-	/*
-	 * Cache for options.
+	/**
+	 * Possible  configurable option value.
+	 * @see #getDefaultOptions()
+	 * @since 3.1
 	 */
-	static Hashtable optionsCache;
+	public static final String NEVER = "never"; //$NON-NLS-1$
 
 	/**
 	 * Creates the Java core plug-in.
@@ -1325,8 +1342,19 @@
 	 * none was found.
 	 * @since 2.1
 	 */
-	public static ClasspathContainerInitializer getClasspathContainerInitializer(String containerID){
-		
+	public static ClasspathContainerInitializer getClasspathContainerInitializer(String containerID) {
+		HashMap containerInitializersCache = JavaModelManager.getJavaModelManager().containerInitializersCache;
+		ClasspathContainerInitializer initializer = (ClasspathContainerInitializer) containerInitializersCache.get(containerID);
+		if (initializer == null) {
+			initializer = computeClasspathContainerInitializer(containerID);
+			if (initializer == null)
+				return null;
+			containerInitializersCache.put(containerID, initializer);
+		}
+		return initializer;
+	}
+
+	private static ClasspathContainerInitializer computeClasspathContainerInitializer(String containerID) {
 		Plugin jdtCorePlugin = JavaCore.getPlugin();
 		if (jdtCorePlugin == null) return null;
 
@@ -1854,7 +1882,7 @@
 	 *
 	 * COMPILER / Reporting Unchecked Type Operation
 	 *    When enabled, the compiler will issue an error or a warning whenever an operation involves generic types, and potentially
-	 *    invalidates type safety since involving raw types (e.g. invoking #foo(X<String>) with arguments  (X)).
+	 *    invalidates type safety since involving raw types (e.g. invoking #foo(X&lt;String&gt;) with arguments  (X)).
 	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation"
 	 *     - possible values:   { "error", "warning", "ignore" }
 	 *     - default:           "warning"
@@ -1988,7 +2016,7 @@
 	 *    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:           "enabled"
+	 *     - default:           "disabled"
 	 * 
 	 * COMPILER / Reporting Missing Javadoc Comments
 	 *    This is the generic control for the severity of missing Javadoc comment problems.
@@ -2010,7 +2038,7 @@
 	 *    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:           "enabled"
+	 *     - default:           "disabled"
 	 * 
 	 * COMPILER / Maximum number of problems reported per compilation unit
 	 *    Specify the maximum number of problems reported on each compilation unit.
@@ -2018,7 +2046,7 @@
 	 *     - 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 / Define the Automatic Task Tags
+	 * 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.
@@ -2027,11 +2055,12 @@
 	 *    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 
 	 *     - default:           "TODO,FIXME,XXX"
 	 * 
-	 * COMPILER / Define the Automatic Task Priorities
+	 * 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.
 	 *    If the default is specified, the priority of each task marker is "NORMAL".
@@ -2039,7 +2068,7 @@
 	 *     - possible values:   { "&lt;priority&gt;[,&lt;priority&gt;]*" } where &lt;priority&gt; is one of "HIGH", "NORMAL" or "LOW"
 	 *     - default:           "NORMAL,HIGH,NORMAL"
 	 * 
-	 * COMPILER / Determine whether task tags are case-sensitive
+	 * 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"
 	 *     - possible values:   { "enabled", "disabled" }
@@ -2059,6 +2088,20 @@
 	 *     - possible values:   { "error", "warning", "ignore" }
 	 *     - default:           "warning"
 	 *
+	 * COMPILER / Determining Effect of @SuppressWarnings
+	 *    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" }
+	 *     - default:           "enabled"
+	 *
+	 * COMPILER / Reporting Unhandled Warning Token for @SuppressWarnings
+	 *    When enabled, the compiler will issue an error or a warning when encountering a token
+	 *    it cannot handle inside a @SuppressWarnings annotation.
+	 *     - option id:         "org.eclipse.jdt.core.compiler.problem.unhandledWarningToken"
+	 *     - possible values:   { "error", "warning", "ignore" }
+	 *     - default:           "warning"
+	 *
 	 * 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"
@@ -2272,19 +2315,18 @@
 	 *     - 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 
 	 *     - default:           ""
-	 *     
+	 * 
 	 *  CODEASSIST / Activate Forbidden Reference Sensitive Completion
 	 *    When active, completion doesn't show that have forbidden reference.
-	 *     - option id:         "org.eclipse.jdt.core.codeComplete.restrictionsCheck"
+	 *     - option id:         "org.eclipse.jdt.core.codeComplete.forbiddenReferenceCheck"
 	 *     - possible values:   { "enabled", "disabled" }
-	 *     - default:           "disabled"
+	 *     - default:           "enabled"
 	 * 
 	 *  CODEASSIST / Activate Discouraged Reference Sensitive Completion
 	 *    When active, completion doesn't show that have discouraged reference.
 	 *     - option id:         "org.eclipse.jdt.core.codeComplete.discouragedReferenceCheck"
 	 *     - possible values:   { "enabled", "disabled" }
 	 *     - default:           "disabled"
-	 * 
 	 * </pre>
 	 * 
 	 * @return a mutable table containing the default settings of all known options
@@ -2292,28 +2334,7 @@
 	 * @see #setOptions(Hashtable)
 	 */
  	public static Hashtable getDefaultOptions(){
-	
-		Hashtable defaultOptions = new Hashtable(10);
-
-		// see JavaCorePreferenceInitializer#initializeDefaultPluginPreferences() for changing default settings
-		JavaModelManager manager = JavaModelManager.getJavaModelManager();
-		IEclipsePreferences defaultPreferences = manager.getDefaultPreferences();
-		HashSet optionNames = manager.optionNames;
-		
-		// initialize preferences to their default
-		Iterator iterator = optionNames.iterator();
-		while (iterator.hasNext()) {
-		    String propertyName = (String) iterator.next();
-		    String value = defaultPreferences.get(propertyName, null);
-		    if (value != null) defaultOptions.put(propertyName, value);
-		}
-		// get encoding through resource plugin
-		defaultOptions.put(CORE_ENCODING, getEncoding());
-		// backward compatibility
-		defaultOptions.put(COMPILER_PB_INVALID_IMPORT, ERROR);		
-		defaultOptions.put(COMPILER_PB_UNREACHABLE_CODE, ERROR);
-		
-		return defaultOptions;
+ 		return JavaModelManager.getJavaModelManager().getDefaultOptions();
 	}
 
 	/**
@@ -2361,23 +2382,7 @@
 	 * @since 2.0
 	 */
 	public static String getOption(String optionName) {
-		
-		if (CORE_ENCODING.equals(optionName)){
-			return getEncoding();
-		}
-		// backward compatibility
-		if (COMPILER_PB_INVALID_IMPORT.equals(optionName)
-				|| COMPILER_PB_UNREACHABLE_CODE.equals(optionName)) {
-			return ERROR;
-		}
-		String propertyName = optionName;
-		JavaModelManager manager = JavaModelManager.getJavaModelManager();
-		if (manager.optionNames.contains(propertyName)){
-			IPreferencesService service = Platform.getPreferencesService();
-			String value =  service.get(optionName, null, manager.preferencesLookup);
-			return value==null ? null : value.trim();
-		}
-		return null;
+		return JavaModelManager.getJavaModelManager().getOption(optionName);
 	}
 	
 	/**
@@ -2393,41 +2398,9 @@
 	 * @see JavaCorePreferenceInitializer for changing default settings
 	 */
 	public static Hashtable getOptions() {
-
-		// return cached options if already computed
-		if (optionsCache != null) return new Hashtable(optionsCache);
-
-		// init
-		Hashtable options = new Hashtable(10);
-		JavaModelManager manager = JavaModelManager.getJavaModelManager();
-		HashSet optionNames = manager.optionNames;
-		IPreferencesService service = Platform.getPreferencesService();
-
-		// set options using preferences service lookup
-		Iterator iterator = optionNames.iterator();
-		while (iterator.hasNext()) {
-		    String propertyName = (String) iterator.next();
-		    String propertyValue = service.get(propertyName, null, manager.preferencesLookup);
-		    if (propertyValue != null) {
-			    options.put(propertyName, propertyValue);
-		    }
-		}
-
-		// get encoding through resource plugin
-		options.put(CORE_ENCODING, getEncoding()); 
-
-		// backward compatibility
-		options.put(COMPILER_PB_INVALID_IMPORT, ERROR);
-		options.put(COMPILER_PB_UNREACHABLE_CODE, ERROR);
-
-		// store built map in cache
-		optionsCache = new Hashtable(options);
-
-		// return built map
-		return options;
+		return JavaModelManager.getJavaModelManager().getOptions();
 	}
 
-
 	/**
 	 * Returns the single instance of the Java core plug-in runtime class.
 	 * 
@@ -2514,8 +2487,8 @@
 		}
 		// outside the workspace
 		if (target instanceof File) {
-			File externalFile = (File) target;
-			if (externalFile.isFile()) {
+			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)) { 
 					// external binary archive
@@ -2618,6 +2591,139 @@
 	}
 	
 	/**
+	 * 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 
+	 * 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 
+	 * 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, 
+	 * 		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
+				}
+				
+				// 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
+				}
+				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
+									}
+								}
+							}
+						}
+					};
+					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)
+				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
+				}
+				
+				return Status.OK_STATUS;
+			}
+			public boolean belongsTo(Object family) {
+				return PLUGIN_ID.equals(family);
+			}
+		};
+		job.setPriority(Job.SHORT);
+		job.schedule(2000);	 // wait for the startup activity to calm down
+		
+	}
+	
+	/**
 	 * Returns whether the given marker references the given Java element.
 	 * Used for markers, which denote a Java element rather than a resource.
 	 *
@@ -2812,7 +2918,8 @@
 	 * </p>
 	 * <p>
 	 * The <code>extraAttributes</code> list contains name/value pairs that must be persisted with
-	 * this entry. If no extra attributes are provided, an empty array must be passed in.
+	 * this entry. If no extra attributes are provided, an empty array must be passed in.<br>
+	 * Note that this list should not contain any duplicate name.
 	 * </p>
 	 * <p>
 	 * The <code>isExported</code> flag indicates whether this entry is contributed to dependent
@@ -2992,7 +3099,8 @@
 	 * </p>
 	 * <p>
 	 * The <code>extraAttributes</code> list contains name/value pairs that must be persisted with
-	 * this entry. If no extra attributes are provided, an empty array must be passed in.
+	 * this entry. If no extra attributes are provided, an empty array must be passed in.<br>
+	 * Note that this list should not contain any duplicate name.
 	 * </p>
 	 * <p>
 	 * The <code>isExported</code> flag indicates whether this entry is contributed to dependent
@@ -3116,7 +3224,8 @@
 	 * </p>
 	 * <p>
 	 * The <code>extraAttributes</code> list contains name/value pairs that must be persisted with
-	 * this entry. If no extra attributes are provided, an empty array must be passed in.
+	 * this entry. If no extra attributes are provided, an empty array must be passed in.<br>
+	 * Note that this list should not contain any duplicate name.
 	 * </p>
 	 * <p>
 	 * The <code>isExported</code> flag indicates whether this entry is contributed to dependent
@@ -3325,7 +3434,8 @@
 	 * </p>
 	 * <p>
 	 * The <code>extraAttributes</code> list contains name/value pairs that must be persisted with
-	 * this entry. If no extra attributes are provided, an empty array must be passed in.
+	 * this entry. If no extra attributes are provided, an empty array must be passed in.<br>
+	 * Note that this list should not contain any duplicate name.
 	 * </p>
 	 *
 	 * @param path the absolute workspace-relative path of a source folder
@@ -3449,7 +3559,8 @@
 	 * </p>
 	 * <p>
 	 * The <code>extraAttributes</code> list contains name/value pairs that must be persisted with
-	 * this entry. If no extra attributes are provided, an empty array must be passed in.
+	 * this entry. If no extra attributes are provided, an empty array must be passed in.<br>
+	 * Note that this list should not contain any duplicate name.
 	 * </p>
 	 * <p>
 	 * The <code>isExported</code> flag indicates whether this entry is contributed to dependent
@@ -3973,38 +4084,7 @@
 	 * @see JavaCorePreferenceInitializer for changing default settings
 	 */
 	public static void setOptions(Hashtable newOptions) {
-		
-		try {
-			JavaModelManager manager = JavaModelManager.getJavaModelManager();
-			IEclipsePreferences defaultPreferences = manager.getDefaultPreferences();
-			IEclipsePreferences instancePreferences = manager.getInstancePreferences();
-
-			if (newOptions == null){
-				instancePreferences.clear();
-			} else {
-				Enumeration keys = newOptions.keys();
-				while (keys.hasMoreElements()){
-					String key = (String)keys.nextElement();
-					if (!JavaModelManager.getJavaModelManager().optionNames.contains(key)) continue; // unrecognized option
-					if (key.equals(CORE_ENCODING)) continue; // skipped, contributed by resource prefs
-					String value = (String)newOptions.get(key);
-					String defaultValue = defaultPreferences.get(key, null);
-					if (defaultValue != null && defaultValue.equals(value)) {
-						instancePreferences.remove(key);
-					} else {
-						instancePreferences.put(key, value);
-					}
-				}
-			}
-
-			// persist options
-			instancePreferences.flush();
-			
-			// update cache
-			optionsCache = newOptions==null ? null : new Hashtable(newOptions);
-		} catch (BackingStoreException e) {
-			// ignore
-		}
+		JavaModelManager.getJavaModelManager().setOptions(newOptions);
 	}
 
 	/* (non-Javadoc)
@@ -4016,11 +4096,6 @@
 	 */
 	public void stop(BundleContext context) throws Exception {
 		try {
-			savePluginPreferences();
-			IWorkspace workspace = ResourcesPlugin.getWorkspace();
-			workspace.removeResourceChangeListener(JavaModelManager.getJavaModelManager().deltaState);
-			workspace.removeSaveParticipant(this);
-	
 			JavaModelManager.getJavaModelManager().shutdown();
 		} finally {
 			// ensure we call super.stop as the last thing
@@ -4028,15 +4103,6 @@
 		}
 	}
 
-	/**
-	 * Initiate the background indexing process.
-	 * This should be deferred after the plugin activation.
-	 */
-	private void startIndexing() {
-
-		JavaModelManager.getJavaModelManager().getIndexManager().reset();
-	}
-
 	/* (non-Javadoc)
 	 * Startup the JavaCore plug-in.
 	 * <p>
@@ -4048,71 +4114,6 @@
 	 */
 	public void start(BundleContext context) throws Exception {
 		super.start(context);
-		
-		final JavaModelManager manager = JavaModelManager.getJavaModelManager();
-		try {
-			manager.configurePluginDebugOptions();
-
-			// request state folder creation (workaround 19885)
-			JavaCore.getPlugin().getStateLocation();
-
-			// Initialize eclipse preferences
-			manager.initializePreferences();
-
-			// Listen to preference changes
-			Preferences.IPropertyChangeListener propertyListener = new Preferences.IPropertyChangeListener() {
-				public void propertyChange(Preferences.PropertyChangeEvent event) {
-					JavaCore.optionsCache = null;
-				}
-			};
-			JavaCore.getPlugin().getPluginPreferences().addPropertyChangeListener(propertyListener);
-
-			// retrieve variable values
-			manager.loadVariablesAndContainers();
-
-			final IWorkspace workspace = ResourcesPlugin.getWorkspace();
-			workspace.addResourceChangeListener(
-				manager.deltaState,
-				IResourceChangeEvent.PRE_BUILD
-					| IResourceChangeEvent.POST_BUILD
-					| IResourceChangeEvent.POST_CHANGE
-					| IResourceChangeEvent.PRE_DELETE
-					| IResourceChangeEvent.PRE_CLOSE);
-
-			startIndexing();
-			
-			// process deltas since last activated in indexer thread so that indexes are up-to-date.
-			// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=38658
-			Job processSavedState = new Job(Messages.savedState_jobName) { 
-				protected IStatus run(IProgressMonitor monitor) {
-					try {
-						// add save participant and process delta atomically
-						// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=59937
-						workspace.run(
-							new IWorkspaceRunnable() {
-								public void run(IProgressMonitor progress) throws CoreException {
-									ISavedState savedState = workspace.addSaveParticipant(JavaCore.this, manager);
-									if (savedState != null) {
-										// the event type coming from the saved state is always POST_AUTO_BUILD
-										// force it to be POST_CHANGE so that the delta processor can handle it
-										manager.deltaState.getDeltaProcessor().overridenEventType = IResourceChangeEvent.POST_CHANGE;
-										savedState.processResourceChangeEvents(manager.deltaState);
-									}
-								}
-							},
-							monitor);
-					} catch (CoreException e) {
-						return e.getStatus();
-					}
-					return Status.OK_STATUS;
-				}
-			};
-			processSavedState.setSystem(true);
-			processSavedState.setPriority(Job.SHORT); // process asap
-			processSavedState.schedule();
-		} catch (RuntimeException e) {
-			manager.shutdown();
-			throw e;
-		}
+		JavaModelManager.getJavaModelManager().startup();
 	}
 }
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 b8c6ea9..b2fac6f 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
@@ -1005,8 +1005,8 @@
  * @param typeSignature the type signature string
  * @return the kind of type signature; one of the kind constants:
  * {@link #ARRAY_TYPE_SIGNATURE}, {@link #CLASS_TYPE_SIGNATURE},
- * {@link #BASE_TYPE_SIGNATURE}, {@link #TYPE_VARIABLE_SIGNATURE}
- * or {@link #WILDCARD_TYPE_SIGNATURE}
+ * {@link #BASE_TYPE_SIGNATURE}, or {@link #TYPE_VARIABLE_SIGNATURE},
+ * or (since 3.1) {@link #WILDCARD_TYPE_SIGNATURE} or {@link #CAPTURE_TYPE_SIGNATURE}
  * @exception IllegalArgumentException if this is not a type signature
  * @since 3.0
  */
@@ -1016,6 +1016,24 @@
 		throw new IllegalArgumentException();
 	}
 	char c = typeSignature[0];
+	if (c == C_GENERIC_START) {
+		int count = 1;
+		for (int i = 1, length = typeSignature.length; i < length; i++) {
+			switch (typeSignature[i]) {
+				case 	C_GENERIC_START:
+					count++;
+					break;
+				case C_GENERIC_END:
+					count--;
+					break;
+			}
+			if (count == 0) {
+				if (i+1 < length)
+					c = typeSignature[i+1]; 
+				break;
+			}
+		}
+	}
 	switch (c) {
 		case C_ARRAY :
 			return ARRAY_TYPE_SIGNATURE;
@@ -1051,7 +1069,8 @@
  * @param typeSignature the type signature string
  * @return the kind of type signature; one of the kind constants:
  * {@link #ARRAY_TYPE_SIGNATURE}, {@link #CLASS_TYPE_SIGNATURE},
- * {@link #BASE_TYPE_SIGNATURE}, or {@link #TYPE_VARIABLE_SIGNATURE}
+ * {@link #BASE_TYPE_SIGNATURE}, or {@link #TYPE_VARIABLE_SIGNATURE},
+ * or (since 3.1) {@link #WILDCARD_TYPE_SIGNATURE} or {@link #CAPTURE_TYPE_SIGNATURE}
  * @exception IllegalArgumentException if this is not a type signature
  * @since 3.0
  */
@@ -1061,6 +1080,24 @@
 		throw new IllegalArgumentException();
 	}
 	char c = typeSignature.charAt(0);
+	if (c == C_GENERIC_START) {
+		int count = 1;
+		for (int i = 1, length = typeSignature.length(); i < length; i++) {
+			switch (typeSignature.charAt(i)) {
+				case 	C_GENERIC_START:
+					count++;
+					break;
+				case C_GENERIC_END:
+					count--;
+					break;
+			}
+			if (count == 0) {
+				if (i+1 < length)
+					c = typeSignature.charAt(i+1); 
+				break;
+			}
+		}
+	}
 	switch (c) {
 		case C_ARRAY :
 			return ARRAY_TYPE_SIGNATURE;
@@ -1084,7 +1121,7 @@
 		case C_EXTENDS :
 			return WILDCARD_TYPE_SIGNATURE;
 		case C_CAPTURE :
-			return CAPTURE_TYPE_SIGNATURE;			
+			return CAPTURE_TYPE_SIGNATURE;
 		default :
 			throw new IllegalArgumentException();
 	}
@@ -1166,6 +1203,8 @@
  * @return the list of thrown exception type signatures
  * @exception IllegalArgumentException if the signature is syntactically
  *   incorrect
+ *
+ * @since 3.1
  */
 public static String[] getThrownExceptionTypes(String methodSignature) throws IllegalArgumentException {
 	char[][] parameterTypes = getThrownExceptionTypes(methodSignature.toCharArray());
@@ -1180,6 +1219,8 @@
  * @return the list of thrown exception type signatures
  * @exception IllegalArgumentException if the signature is syntactically
  *   incorrect
+ *
+ * @since 3.1
  */
 public static char[][] getThrownExceptionTypes(char[] methodSignature) throws IllegalArgumentException {
 	// skip type parameters
@@ -1365,15 +1406,43 @@
 				return result;
 			}
 			i = CharOperation.indexOf(C_COLON, methodOrTypeSignature, i);
-			if (i < 0 || i >= length) throw new IllegalArgumentException();
+			if (i < 0 || i >= length) 
+				throw new IllegalArgumentException();
 			// iterate over bounds
 			nextBound: while (methodOrTypeSignature[i] == ':') {
 				i++; // skip colon
-				if (methodOrTypeSignature[i] == ':') {
-					continue nextBound; // empty bound
+				switch (methodOrTypeSignature[i]) {
+					case ':':
+						// no class bound
+						break; 
+					case C_GENERIC_END:
+						break;
+					case C_RESOLVED:
+						try {
+							i = Util.scanClassTypeSignature(methodOrTypeSignature, i);
+							i++; // position at start of next param if any
+						} catch (IllegalArgumentException e) {
+							// not a class type signature -> it is a new type parameter
+						}
+						break;
+					case C_ARRAY:
+						try {
+							i = Util.scanArrayTypeSignature(methodOrTypeSignature, i);
+							i++; // position at start of next param if any
+						} catch (IllegalArgumentException e) {
+							// not an array type signature -> it is a new type parameter
+						}
+						break;
+					case C_TYPE_VARIABLE:
+						try {
+							i = Util.scanTypeVariableSignature(methodOrTypeSignature, i);
+							i++; // position at start of next param if any
+						} catch (IllegalArgumentException e) {
+							// not a type variable signature -> it is a new type parameter
+						}							
+						break;
+					// default: another type parameter is starting
 				}
-				i = Util.scanTypeSignature(methodOrTypeSignature, i);
-				i++; // position at start of next param if any
 			}
 			paramList.add(CharOperation.subarray(methodOrTypeSignature, paramStart, i));
 			paramStart = i; // next param start from here
@@ -1980,74 +2049,77 @@
 	return CharOperation.toStrings(getSimpleNames(name.toCharArray()));
 }
 
-	
 /**
- * Returns a method signature with any capture information removed. 
- * Returns the method signature itself if no capture information is
+ * Removes any capture information from the given type or method signature
+ * and returns the resulting signature.
+ * Returns the type or method signature itself if no capture information is
  * present.
  * <p>
  * For example (using equivalent string-based method):
  * <pre>
  * <code>
- * removeCaptureFromMethod("LTest<!+Ljava.lang.Throwable;>;")
+ * removeCapture("LTest<!+Ljava.lang.Throwable;>;")
  * will return: "LTest<+Ljava.lang.Throwable;>;"
  * </code>
  * </pre>
  * </p>
  *
- * @param captureSignature the signature which may have been captured
- * @return new signature without capture information or siganture itself
- * 	if no specific capture information was there
- * @exception NullPointerException if <code>captureSignature</code> is null
+ * @param methodOrTypeSignature the signature which may have been captured
+ * @return a new signature without capture information or the signature itself
+ * 	if no specific capture information is present
+ * @exception NullPointerException if <code>methodOrTypeSignature</code> is null
+ *
  * @since 3.1
- * TODO (frederic) Create remove(char[], char) method on CharOperation and call it from here
  */
-public static char[] removeCaptureFromMethod(char[] captureSignature) {
+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 = captureSignature.length; i < length; i++) {
-		char c = captureSignature[i];
+	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(captureSignature, 0, result, 0, i);
+				System.arraycopy(methodOrTypeSignature, 0, result, 0, i);
 				count = i;
 			}
 		} else if (result != null) {
 			result[count++] = c;
 		}
 	}
-	if (result == null) return captureSignature;
+	if (result == null) return methodOrTypeSignature;
 	System.arraycopy(result, 0, result = new char[count], 0, count);
 	return result;
 }
 	
 /**
- * Returns a method signature with any capture information removed. 
- * Returns the method signature itself if no capture information is
+ * Removes any capture information from the given type or method signature
+ * and returns the resulting signature.
+ * Returns the type or method signature itself if no capture information is
  * present.
  * <p>
  * For example:
  * <pre>
  * <code>
- * removeCaptureFromMethod("LTest<!+Ljava.lang.Throwable;>;")
+ * removeCapture("LTest<!+Ljava.lang.Throwable;>;")
  * will return: "LTest<+Ljava.lang.Throwable;>;"
  * </code>
  * </pre>
  * </p>
  *
- * @param captureSignature the signature which may have been captured
- * @return new signature without capture information or siganture itself
- * 	if no specific capture information was there
- * @exception NullPointerException if <code>captureSignature</code> is null
+ * @param methodOrTypeSignature the signature which may have been captured
+ * @return a new signature without capture information or the signature itself
+ * 	if no specific capture information is present
+ * @exception NullPointerException if <code>methodOrTypeSignature</code> is null
+ *
  * @since 3.1
  */
-public static String removeCaptureFromMethod(String captureSignature) {
-		char[] array = captureSignature.toCharArray();
-		char[] result = removeCaptureFromMethod(array);
-		if (array == result) return captureSignature;
-		return new String(result);
+public static String removeCapture(String methodOrTypeSignature) {
+	char[] array = methodOrTypeSignature.toCharArray();
+	char[] result = removeCapture(array);
+	if (array == result) return methodOrTypeSignature;
+	return new String(result);
 }
 
 /**
@@ -2362,15 +2434,32 @@
  * @see Util#scanArrayTypeSignature(char[], int)
  */
 private static int appendArrayTypeSignature(char[] string, int start, boolean fullyQualifyTypeNames, StringBuffer buffer, boolean isVarArgs) {
+	int length = string.length;
 	// need a minimum 2 char
-	if (start >= string.length - 1) {
+	if (start >= length - 1) {
 		throw new IllegalArgumentException();
 	}
 	char c = string[start];
 	if (c != C_ARRAY) { //$NON-NLS-1$
 		throw new IllegalArgumentException();
 	}
-	int e = appendTypeSignature(string, start + 1, fullyQualifyTypeNames, buffer);
+	
+	int index = start;
+	c = string[++index];
+	while(c == C_ARRAY) {
+		// need a minimum 2 char
+		if (index >= length - 1) {
+			throw new IllegalArgumentException();
+		}
+		c = string[++index];
+	}
+	
+	int e = appendTypeSignature(string, index, fullyQualifyTypeNames, buffer);
+	
+	for(int i = 1, dims = index - start; i < dims; i++) {
+		buffer.append('[').append(']');
+	}
+	
 	if (isVarArgs) {
 		buffer.append('.').append('.').append('.');
 	} else {
@@ -2674,6 +2763,8 @@
  * variable argument, <code>false</code> otherwise
  * @see #toCharArray(char[], char[], char[][], boolean, boolean)
  * @return the string representation of the method signature
+ *
+ * @since 3.1
  */
 public static String toString(String methodSignature, String methodName, String[] parameterNames, boolean fullyQualifyTypeNames, boolean includeReturnType, boolean isVarArgs) {
 	char[][] params;
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 899f8ac..0416797 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
@@ -375,7 +375,8 @@
 	 * the Unicode 4.0 is supporte, otherwise Unicode 3.0 is supported.
   	 * @return a scanner
 	 * @see org.eclipse.jdt.core.compiler.IScanner
-     * @since 3.0
+	 *
+     * @since 3.1
 	 */
 	public static IScanner createScanner(boolean tokenizeComments, boolean tokenizeWhiteSpace, boolean recordLineSeparator, String sourceLevel, String complianceLevel) {
 		PublicScanner scanner = null;
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 3d1f839..fe44004 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
@@ -202,7 +202,7 @@
 	 *	  <li>The position specified is less than -1 or is greater than the snippet's
 	 *	    length (INDEX_OUT_OF_BOUNDS)</li>
 	 *  </ul>
-	 * @since 3.0
+	 * @since 3.1
 	 */
 	public void codeComplete(
 		String codeSnippet,
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 0840191..c0737f6 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
@@ -10,7 +10,6 @@
  *******************************************************************************/
 package org.eclipse.jdt.core.jdom;
 
-import org.eclipse.jdt.internal.compiler.util.Util;
 import org.eclipse.jdt.internal.core.jdom.*;
 
 /**
@@ -24,11 +23,13 @@
  * org.eclipse.jdt.core.dom package.
  */
 public class DOMFactory implements IDOMFactory {
+	String lineSeparator;
 /**
  * Creates a new DOM factory.
  */
 public DOMFactory() {
 	// constructor is explicitly API
+	this.lineSeparator = org.eclipse.jdt.internal.core.util.Util.getLineSeparator(null, null/*take the workspace line separator as no project is available*/);
 }
 /* (non-Javadoc)
  * Method declared on IDOMFactory.
@@ -58,7 +59,7 @@
  * Method declared on IDOMFactory.
  */
 public IDOMField createField() {
-	return createField("Object aField;"+ Util.LINE_SEPARATOR); //$NON-NLS-1$
+	return createField("Object aField;"+ this.lineSeparator); //$NON-NLS-1$
 }
 /* (non-Javadoc)
  * Method declared on IDOMFactory.
@@ -88,7 +89,7 @@
  * Method declared on IDOMFactory.
  */
 public IDOMInitializer createInitializer() {
-	return createInitializer("static {}"+ Util.LINE_SEPARATOR); //$NON-NLS-1$
+	return createInitializer("static {}"+ this.lineSeparator); //$NON-NLS-1$
 }
 /* (non-Javadoc)
  * Method declared on IDOMFactory.
@@ -103,7 +104,7 @@
  * Method declared on IDOMFactory.
  */
 public IDOMMethod createMethod() {
-	return createMethod("public void newMethod() {"+ Util.LINE_SEPARATOR+"}"+ Util.LINE_SEPARATOR); //$NON-NLS-2$ //$NON-NLS-1$
+	return createMethod("public void newMethod() {"+ this.lineSeparator+"}"+ this.lineSeparator); //$NON-NLS-2$ //$NON-NLS-1$
 }
 /* (non-Javadoc)
  * Method declared on IDOMFactory.
@@ -133,19 +134,19 @@
  * Method declared on IDOMFactory.
  */
 public IDOMType createType() {
-	return createType("public class AClass {"+ Util.LINE_SEPARATOR +"}"+ Util.LINE_SEPARATOR); //$NON-NLS-2$ //$NON-NLS-1$
+	return createType("public class AClass {"+ this.lineSeparator +"}"+ this.lineSeparator); //$NON-NLS-2$ //$NON-NLS-1$
 }
 /* (non-Javadoc)
  * Method declared on IDOMFactory.
  */
 public IDOMType createClass() {
-	return createType("public class AClass {"+ Util.LINE_SEPARATOR +"}"+ Util.LINE_SEPARATOR); //$NON-NLS-2$ //$NON-NLS-1$
+	return createType("public class AClass {"+ this.lineSeparator +"}"+ this.lineSeparator); //$NON-NLS-2$ //$NON-NLS-1$
 }
 /* (non-Javadoc)
  * Method declared on IDOMFactory.
  */
 public IDOMType createInterface() {
-	return createType("public interface AnInterface {"+ Util.LINE_SEPARATOR +"}"+ Util.LINE_SEPARATOR); //$NON-NLS-2$ //$NON-NLS-1$
+	return createType("public interface AnInterface {"+ this.lineSeparator +"}"+ this.lineSeparator); //$NON-NLS-2$ //$NON-NLS-1$
 }
 /* (non-Javadoc)
  * Method declared on IDOMFactory.
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 015b526..913009a 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
@@ -50,12 +50,7 @@
 /**
  * Sets the modifier flags for this import. The flags can be examined using class
  * <code>Flags</code>. Only the static flag is meaningful for import declarations.
- * <p>
- * Note: Static imports are an experimental language feature 
- * under discussion in JSR-201 and under consideration for inclusion
- * in the 1.5 release of J2SE. The support here is therefore tentative
- * and subject to change.
- * </p>
+ *
  * @param flags the modifier flags for this import
  * @see org.eclipse.jdt.core.Flags
  * @since 3.0
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 bbbfc65..2bba98d 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
@@ -16,6 +16,7 @@
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.jdt.core.ICompilationUnit;
 import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.dom.AST;
 import org.eclipse.jdt.internal.core.SortElementsOperation;
 
 /**
@@ -65,7 +66,8 @@
 	public static final String RELATIVE_ORDER = "relativeOrder"; //$NON-NLS-1$
 
 	/**
-	 * Reorders the declarations in the given compilation unit. The caller is
+	 * Reorders the declarations in the given compilation unit according to
+     * JLS2 rules. The caller is
 	 * responsible for arranging in advance that the given compilation unit is
 	 * a working copy, and for saving the changes afterwards.
 	 * <p>
@@ -87,7 +89,7 @@
 	 * </p>
 	 * <p>
 	 * The <code>compare</code> method of the given comparator is passed pairs
-	 * of AST body declarations (subclasses of <code>BodyDeclaration</code>) 
+	 * of JLS2 AST 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
@@ -143,7 +145,8 @@
 	 * corresponding source positions in the permuted source code string
 	 * (but not necessarily any longer in non-decreasing order).
 	 * @param comparator the comparator capable of ordering 
-	 *   <code>BodyDeclaration</code>s
+	 *   <code>BodyDeclaration</code>s; this comparator is passed AST nodes
+     *   from a JLS2 AST
 	 * @param options bitwise-or of option flags; <code>0</code> for default
 	 * behavior (reserved for future growth)
 	 * @param monitor the progress monitor to notify, or <code>null</code> if
@@ -160,17 +163,162 @@
 	 * or if the given comparator is null.
 	 * @see org.eclipse.jdt.core.dom.BodyDeclaration
 	 * @see #RELATIVE_ORDER
+     * @deprecated Clients should port their code to use the new JLS3 AST API and call
+     *    {@link #sort(int, ICompilationUnit, int[], Comparator, int, IProgressMonitor)
+     *    CompilationUnitSorter.sort(AST.JLS3, compilationUnit, positions, comparator, options, monitor)}
+     *    instead of using this method.
 	 */
 	public static void sort(ICompilationUnit compilationUnit,
 	        int[] positions,
 	        Comparator comparator,
 	        int options,
 	        IProgressMonitor monitor) throws JavaModelException {
-		if (compilationUnit == null || comparator == null) {
-			throw new IllegalArgumentException();
-		}
-		ICompilationUnit[] compilationUnits = new ICompilationUnit[] { compilationUnit };
-		SortElementsOperation operation = new SortElementsOperation(compilationUnits, positions, comparator);
-		operation.runOperation(monitor);
+		sort(AST.JLS2, compilationUnit, positions, comparator, options, monitor);
 	}
+    
+    /**
+     * Reorders the declarations in the given compilation unit according to
+     * the specified AST level. The caller is responsible for arranging in
+     * advance that the given compilation unit is a working copy, and for
+     * saving the changes 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 optional <code>positions</code> array contains a non-decreasing 
+     * ordered list of character-based source positions within the compilation
+     * unit's source code string. Upon return from this method, the positions in
+     * the array reflect the corresponding new locations in the modified source
+     * code string. Note that this operation modifies the given array in place.
+     * </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 nodes are from an
+     * AST of the specified level 
+     * ({@link org.eclipse.jdt.core.dom.ASTParser#newParser(int)}. Clients
+     * will generally specify AST.JLS3 since that will cover all constructs found
+     * in Java 1.0, 1.1, 1.2, 1.3, 1.4, and 1.5 source code.
+     * 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 afforts
+     * 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>
+     * Clients should not rely on the AST nodes being properly parented or on
+     * having source range information. (Future releases may provide options
+     * for requesting additional information like source positions, full ASTs,
+     * non-recursive sorting, etc.)
+     * </p>
+     *
+     * @param level the AST level; one of the AST LEVEL constants
+     * @param compilationUnit the given compilation unit, which must be a 
+     * working copy
+     * @param positions an array of source positions to map, or 
+     * <code>null</code> if none. If supplied, the positions must 
+     * character-based source positions within the original source code for
+     * the given compilation unit, arranged in non-decreasing order.
+     * The array is updated in place when this method returns to reflect the
+     * corresponding source positions in the permuted source code string
+     * (but not necessarily any longer in non-decreasing order).
+     * @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 monitor the progress monitor to notify, or <code>null</code> if
+     * none
+     * @exception JavaModelException if the compilation unit could not be
+     * sorted. Reasons include:
+     * <ul>
+     * <li> The given compilation unit does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+     * <li> The given compilation unit is not a working copy (INVALID_ELEMENT_TYPES)</li>
+     * <li> A <code>CoreException</code> occurred while accessing the underlying
+     * resource
+     * </ul>
+     * @exception IllegalArgumentException if the given compilation unit is null
+     * or if the given comparator is null, or if <code>level</code> is not one of
+     * the AST JLS level constants.
+     * @see org.eclipse.jdt.core.dom.BodyDeclaration
+     * @see #RELATIVE_ORDER
+     * @since 3.1
+     */
+    public static void sort(int level, ICompilationUnit compilationUnit,
+            int[] positions,
+            Comparator comparator,
+            int options,
+            IProgressMonitor monitor) throws JavaModelException {
+        if (compilationUnit == null || comparator == null) {
+            throw new IllegalArgumentException();
+        }
+        switch (level) {
+        case AST.JLS2 :
+        case AST.JLS3 :
+            break;
+        default :
+            throw new IllegalArgumentException();
+        }
+        ICompilationUnit[] compilationUnits = new ICompilationUnit[] { compilationUnit };
+        SortElementsOperation operation = new SortElementsOperation(level, compilationUnits, positions, comparator);
+        operation.runOperation(monitor);
+    }
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IAnnotationComponentValue.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IAnnotationComponentValue.java
index 69d85d0..61fc861 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IAnnotationComponentValue.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IAnnotationComponentValue.java
@@ -16,7 +16,7 @@
  * 
  * This interface may be implemented by clients. 
  *  
- * @since 3.0
+ * @since 3.1
  */
 public interface IAnnotationComponentValue {
 	
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 b0e42e9..a7a3cce 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
@@ -57,11 +57,7 @@
 	super(new ProblemReporter(
 		DefaultErrorHandlingPolicies.exitAfterAllProblems(), 
 		options, 
-		problemFactory) {
-		public void record(IProblem problem, CompilationResult unitResult) {
-			requestor.acceptProblem(problem);
-		}
-	},
+		problemFactory),
 	false);
 	this.requestor = requestor;
 	intArrayStack = new int[30][];
@@ -1114,6 +1110,10 @@
 	}
 	return false;
 }
+protected void parse() {
+	this.diet = true;
+	super.parse();
+}
 /*
  * Investigate one entire unit.
  */
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 256ce09..79b2023 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
@@ -329,6 +329,20 @@
 		requestor.acceptFieldReference(fr.token, fr.sourceStart);
 	}
 }
+protected void consumeMemberValuePair() {
+	super.consumeMemberValuePair();
+	MemberValuePair memberValuepair = (MemberValuePair) this.astStack[this.astPtr];
+	if (reportReferenceInfo) {
+		requestor.acceptMethodReference(memberValuepair.name, 0, memberValuepair.sourceStart);
+	}
+}
+protected void consumeMarkerAnnotation() {
+	super.consumeMarkerAnnotation();
+	Annotation annotation = (Annotation)expressionStack[expressionPtr];
+	if (reportReferenceInfo) { // accept annotation type reference
+		this.requestor.acceptTypeReference(annotation.type.getTypeName(), annotation.sourceStart, annotation.sourceEnd);
+	}
+}
 protected void consumeMethodHeaderName(boolean isAnnotationMethod) {
 	long selectorSourcePositions = this.identifierPositionStack[this.identifierPtr];
 	int selectorSourceEnd = (int) selectorSourcePositions;
@@ -435,6 +449,20 @@
 			(int)(messageSend.nameSourcePosition >>> 32));
 	}
 }
+protected void consumeNormalAnnotation() {
+	super.consumeNormalAnnotation();
+	Annotation annotation = (Annotation)expressionStack[expressionPtr];
+	if (reportReferenceInfo) { // accept annotation type reference
+		this.requestor.acceptTypeReference(annotation.type.getTypeName(), annotation.sourceStart, annotation.sourceEnd);
+	}
+}
+protected void consumeSingleMemberAnnotation() {
+	super.consumeSingleMemberAnnotation();
+	SingleMemberAnnotation member = (SingleMemberAnnotation) expressionStack[expressionPtr];
+	if (reportReferenceInfo) {
+		requestor.acceptMethodReference(TypeConstants.VALUE, 0, member.sourceStart);
+	}
+}
 protected void consumeSingleStaticImportDeclarationName() {
 	// SingleTypeImportDeclarationName ::= 'import' 'static' Name
 	super.consumeSingleStaticImportDeclarationName();
@@ -1104,6 +1132,8 @@
 }
 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
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 42fe9e2..1c5015b 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
@@ -34,35 +34,14 @@
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.CompilationResult;
 import org.eclipse.jdt.internal.compiler.ast.*;
-import org.eclipse.jdt.internal.compiler.ast.ASTNode;
-import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
-import org.eclipse.jdt.internal.compiler.ast.Argument;
-import org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference;
-import org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference;
-import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
-import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
-import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
-import org.eclipse.jdt.internal.compiler.ast.ImportReference;
-import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
-import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference;
-import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference;
-import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
-import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
-import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.TypeParameter;
-import org.eclipse.jdt.internal.compiler.ast.TypeReference;
-import org.eclipse.jdt.internal.compiler.ast.Wildcard;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
 import org.eclipse.jdt.internal.compiler.env.*;
-import org.eclipse.jdt.internal.compiler.env.ISourceImport;
-import org.eclipse.jdt.internal.compiler.env.ISourceType;
 
 import org.eclipse.jdt.internal.compiler.lookup.CompilerModifiers;
 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.JavaElement;
-import org.eclipse.jdt.internal.core.SourceFieldElementInfo;
-import org.eclipse.jdt.internal.core.SourceTypeElementInfo;
 
 public class SourceTypeConverter implements CompilerModifiers {
 	
@@ -82,12 +61,14 @@
 	private ICompilationUnit cu;
 	private char[] source;
 	private HashMap annotationPositions;
+	private boolean has1_5Compliance;
 	
 	int namePos;
 	
 	private SourceTypeConverter(int flags, ProblemReporter problemReporter) {
 		this.flags = flags;
 		this.problemReporter = problemReporter;
+		this.has1_5Compliance = problemReporter.options.complianceLevel >= ClassFileConstants.JDK1_5;
 	}
 
 	/*
@@ -128,7 +109,7 @@
 		this.cu = (ICompilationUnit) cuHandle;
 		this.annotationPositions = ((CompilationUnitElementInfo) ((JavaElement) this.cu).getElementInfo()).annotationPositions;
 
-		if (this.annotationPositions != null && this.annotationPositions.size() > 10) { // experimental value
+		if (this.has1_5Compliance && this.annotationPositions != null && this.annotationPositions.size() > 10) { // experimental value
 			// if more than 10 annotations, diet parse as this is faster
 			return new Parser(this.problemReporter, true).dietParse(this.cu, compilationResult);
 		}
@@ -158,12 +139,17 @@
 		}
 		/* convert type(s) */
 		int typeCount = sourceTypes.length;
-		this.unit.types = new TypeDeclaration[typeCount];
+		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];
-			this.unit.types[i] =
-				convert((SourceType) typeInfo.getHandle(), compilationResult);
+			types[i] = convert((SourceType) typeInfo.getHandle(), compilationResult);
 		}
+		this.unit.types = types;
 		return this.unit;
 	}
 	
@@ -232,8 +218,11 @@
 			field.type = createTypeReference(fieldInfo.getTypeName(), start, end);
 		}
 
-		/* convert annotations */
-		field.annotations = convertAnnotations(fieldHandle);
+		// convert 1.5 specific constructs only if compliance is 1.5 or above
+		if (this.has1_5Compliance) {
+			/* convert annotations */
+			field.annotations = convertAnnotations(fieldHandle);
+		}
 
 		/* conversion of field constant */
 		if ((this.flags & FIELD_INITIALIZATION) != 0) {
@@ -283,16 +272,19 @@
 		int start = methodInfo.getNameSourceStart();
 		int end = methodInfo.getNameSourceEnd();
 
-		/* convert type parameters */
-		char[][] typeParameterNames = methodInfo.getTypeParameterNames();
+		// convert 1.5 specific constructs only if compliance is 1.5 or above
 		TypeParameter[] typeParams = null;
-		if (typeParameterNames != null) {
-			int parameterCount = typeParameterNames.length;
-			if (parameterCount > 0) { // method's type parameters must be null if no type parameter
-				char[][][] typeParameterBounds = methodInfo.getTypeParameterBounds();
-				typeParams = new TypeParameter[parameterCount];
-				for (int i = 0; i < parameterCount; i++) {
-					typeParams[i] = createTypeParameter(typeParameterNames[i], typeParameterBounds[i], start, end);
+		if (this.has1_5Compliance) {
+			/* convert type parameters */
+			char[][] typeParameterNames = methodInfo.getTypeParameterNames();
+			if (typeParameterNames != null) {
+				int parameterCount = typeParameterNames.length;
+				if (parameterCount > 0) { // method's type parameters must be null if no type parameter
+					char[][][] typeParameterBounds = methodInfo.getTypeParameterBounds();
+					typeParams = new TypeParameter[parameterCount];
+					for (int i = 0; i < parameterCount; i++) {
+						typeParams[i] = createTypeParameter(typeParameterNames[i], typeParameterBounds[i], start, end);
+					}
 				}
 			}
 		}
@@ -340,8 +332,11 @@
 		method.declarationSourceStart = methodInfo.getDeclarationSourceStart();
 		method.declarationSourceEnd = methodInfo.getDeclarationSourceEnd();
 
-		/* convert annotations */
-		method.annotations = convertAnnotations(methodHandle);
+		// convert 1.5 specific constructs only if compliance is 1.5 or above
+		if (this.has1_5Compliance) {
+			/* convert annotations */
+			method.annotations = convertAnnotations(methodHandle);
+		}
 
 		/* convert arguments */
 		String[] argumentTypeSignatures = methodHandle.getParameterTypes();
@@ -431,19 +426,23 @@
 		type.declarationSourceEnd = typeInfo.getDeclarationSourceEnd();
 		type.bodyEnd = type.declarationSourceEnd;
 		
-		/* convert annotations */
-		type.annotations = convertAnnotations(typeHandle);
-
-		/* convert type parameters */
-		char[][] typeParameterNames = typeInfo.getTypeParameterNames();
-		if (typeParameterNames.length > 0) {
-			int parameterCount = typeParameterNames.length;
-			char[][][] typeParameterBounds = typeInfo.getTypeParameterBounds();
-			type.typeParameters = new TypeParameter[parameterCount];
-			for (int i = 0; i < parameterCount; i++) {
-				type.typeParameters[i] = createTypeParameter(typeParameterNames[i], typeParameterBounds[i], start, end);
+		// convert 1.5 specific constructs only if compliance is 1.5 or above
+		if (this.has1_5Compliance) {
+			/* convert annotations */
+			type.annotations = convertAnnotations(typeHandle);
+	
+			/* convert type parameters */
+			char[][] typeParameterNames = typeInfo.getTypeParameterNames();
+			if (typeParameterNames.length > 0) {
+				int parameterCount = typeParameterNames.length;
+				char[][][] typeParameterBounds = typeInfo.getTypeParameterBounds();
+				type.typeParameters = new TypeParameter[parameterCount];
+				for (int i = 0; i < parameterCount; i++) {
+					type.typeParameters[i] = createTypeParameter(typeParameterNames[i], typeParameterBounds[i], start, end);
+				}
 			}
 		}
+		
 		/* set superclass and superinterfaces */
 		if (typeInfo.getSuperclassName() != null) {
 			type.superclass = createTypeReference(typeInfo.getSuperclassName(), start, end);
@@ -555,13 +554,26 @@
 		if (positions == null) return null;
 		int length = positions.length;
 		Annotation[] annotations = new Annotation[length];
+		int recordedAnnotations = 0;
 		for (int i = 0; i < length; i++) {
 			long position = positions[i];
 			int start = (int) (position >>> 32);
 			int end = (int) position;
 			char[] annotationSource = CharOperation.subarray(cuSource, start, end+1);
 			Expression expression = parseMemberValue(annotationSource);
-			annotations[i] = (Annotation) expression;
+			/*
+			 * 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) {
+			// resize to remove null annotations
+			System.arraycopy(annotations, 0, (annotations = new Annotation[recordedAnnotations]), 0, recordedAnnotations);
 		}
 		return annotations;
 	}
@@ -688,6 +700,9 @@
 					identCount ++;
 					break;
 				case '<' :
+					// 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);
 					nameFragmentEnd = this.namePos-1;
 					char[][] identifiers = CharOperation.splitOn('.', typeName, nameFragmentStart, this.namePos);
@@ -699,6 +714,7 @@
 					nameFragmentStart = -1;
 					nameFragmentEnd = -1;
 					// next increment will skip '>'
+					break;
 			}
 			this.namePos++;
 		}
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 a196c93..6e5066c 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
@@ -60,7 +60,7 @@
 	return JavaElement.JEM_FIELD;
 }
 public String getKey(boolean forceOpen) throws JavaModelException {
-	return getKey(this, org.eclipse.jdt.internal.compiler.lookup.Binding.USE_ACCESS_FLAGS_IN_BINDING_KEY/*with access flags*/, forceOpen);
+	return getKey(this, forceOpen);
 }
 /*
  * @see IField
@@ -88,7 +88,7 @@
 /*
  * @private Debugging purposes
  */
-protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
+protected void toStringInfo(int tab, StringBuffer buffer, Object info, boolean showResolvedInfo) {
 	buffer.append(this.tabString(tab));
 	if (info == null) {
 		toStringName(buffer);
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 915b214..1cedf39 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
@@ -155,7 +155,7 @@
 	return JavaElement.JEM_METHOD;
 }
 public String getKey(boolean forceOpen) throws JavaModelException {
-	return getKey(this, org.eclipse.jdt.internal.compiler.lookup.Binding.USE_ACCESS_FLAGS_IN_BINDING_KEY/*with access flags*/, forceOpen);
+	return getKey(this, forceOpen);
 }
 /*
  * @see IMethod
@@ -331,7 +331,7 @@
 }/*
  * @private Debugging purposes
  */
-protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
+protected void toStringInfo(int tab, StringBuffer buffer, Object info, boolean showResolvedInfo) {
 	buffer.append(tabString(tab));
 	if (info == null) {
 		toStringName(buffer);
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 416f29f..8a49849 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
@@ -395,7 +395,7 @@
 	return NO_INITIALIZERS;
 }
 public String getKey(boolean forceOpen) throws JavaModelException {
-	return getKey(this, org.eclipse.jdt.internal.compiler.lookup.Binding.USE_ACCESS_FLAGS_IN_BINDING_KEY/*with access flags*/, forceOpen);
+	return getKey(this, forceOpen);
 }
 /*
  * @see IType#getMethod(String name, String[] parameterTypeSignatures)
@@ -904,7 +904,7 @@
 /*
  * @private Debugging purposes
  */
-protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
+protected void toStringInfo(int tab, StringBuffer buffer, Object info, boolean showResolvedInfo) {
 	buffer.append(this.tabString(tab));
 	if (info == null) {
 		toStringName(buffer);
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 2110dde..f62da56 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
@@ -50,8 +50,8 @@
 		return super.findType(compoundTypeName);
 	}
 
-	public void findTypes(char[] prefix, ISearchRequestor storage) {
+	public void findTypes(char[] prefix, boolean findMembers, ISearchRequestor storage) {
 		checkCanceled();
-		super.findTypes(prefix, storage);
+		super.findTypes(prefix, findMembers, storage);
 	}
 }
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 5f38317..66183fc 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
@@ -179,7 +179,7 @@
 	/*
 	 * The extra attributes
 	 */
-	private IClasspathAttribute[] extraAttributes;
+	IClasspathAttribute[] extraAttributes;
 
 	/**
 	 * Creates a class path entry of the specified kind with the given path.
@@ -246,10 +246,14 @@
 		if (referringEntry.isExported() || referringEntry.getAccessRuleSet() != null ) {
 			boolean combine = this.entryKind == CPE_SOURCE || referringEntry.combineAccessRules();
 			return new ClasspathEntry(
-								this.getContentKind(), this.getEntryKind(), this.getPath(),
+								getContentKind(), 
+								getEntryKind(), 
+								getPath(),
 								this.inclusionPatterns, 
 								this.exclusionPatterns, 
-								this.getSourceAttachmentPath(), this.getSourceAttachmentRootPath(), this.getOutputLocation(), 
+								getSourceAttachmentPath(), 
+								getSourceAttachmentRootPath(), 
+								getOutputLocation(), 
 								referringEntry.isExported() || this.isExported, // duplicate container entry for tagging it as exported
 								combine(referringEntry.getAccessRules(), getAccessRules(), combine),
 								this.combineAccessRules,
@@ -261,7 +265,7 @@
 
 	private IAccessRule[] combine(IAccessRule[] referringRules, IAccessRule[] rules, boolean combine) {
 		if (!combine) return rules;
-		if (rules == null) return referringRules;
+		if (rules == null || rules.length == 0) return referringRules;
 		
 		// concat access rules
 		int referringRulesLength = referringRules.length;
@@ -274,7 +278,7 @@
 		return result;
 	}
 
-	private static IClasspathAttribute[] decodeExtraAttributes(Element element) {
+	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);
@@ -299,7 +303,7 @@
 		return result;
 	}
 	
-	private static IAccessRule[] decodeAccessRules(Element element) {
+	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);
@@ -435,8 +439,8 @@
 			parameters.put(TAG_OUTPUT, String.valueOf(outputLocation));
 		}
 
-		boolean hasExtraAttributes = this.extraAttributes != NO_EXTRA_ATTRIBUTES;
-		boolean hasRestrictions = getAccessRuleSet() != null;
+		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*/);
 		
 		if (hasExtraAttributes)
@@ -449,7 +453,7 @@
 			writer.endTag(TAG_CLASSPATHENTRY, indent);
 	}
 	
-	private void encodeExtraAttributes(XMLWriter writer, boolean indent, boolean newLine) {
+	void encodeExtraAttributes(XMLWriter writer, boolean indent, boolean newLine) {
 		writer.startTag(TAG_ATTRIBUTES, indent);
 		for (int i = 0; i < this.extraAttributes.length; i++) {
 			IClasspathAttribute attribute = this.extraAttributes[i];
@@ -461,7 +465,7 @@
 		writer.endTag(TAG_ATTRIBUTES, indent);
 	}
 	
-	private void encodeAccessRules(XMLWriter writer, boolean indent, boolean newLine) {
+	void encodeAccessRules(XMLWriter writer, boolean indent, boolean newLine) {
 
 		writer.startTag(TAG_ACCESS_RULES, indent);
 		AccessRule[] rules = getAccessRuleSet().getAccessRules();
@@ -614,7 +618,7 @@
 						null, // source attachment root
 						null, // custom output location
 						false,
-						null,
+						null, // no access rules
 						false, // no accessible files to combine
 						NO_EXTRA_ATTRIBUTES);
 			default :
@@ -1224,7 +1228,7 @@
 			if (entryPath.equals(projectPath)){
 				// complain if self-referring project entry
 				if (kind == IClasspathEntry.CPE_PROJECT){
-					return new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, Messages.bind(Messages.classpath_cannotReferToItself, new String[] {entryPath.makeRelative().toString()}));
+					return new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, Messages.bind(Messages.classpath_cannotReferToItself, entryPath.makeRelative().toString()));
 				}
 				// tolerate nesting output in src if src==prj
 				continue;
@@ -1360,6 +1364,18 @@
 						if (container == null){
 							return new JavaModelStatus(IJavaModelStatusConstants.CP_CONTAINER_PATH_UNBOUND, project, path);
 						} else if (container == JavaModelManager.CONTAINER_INITIALIZATION_IN_PROGRESS) {
+							// Validate extra attributes
+							IClasspathAttribute[] extraAttributes = entry.getExtraAttributes();
+							if (extraAttributes != null) {
+								int length = extraAttributes.length;
+								HashSet set = new HashSet(length);
+								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})); 
+									}
+								}
+							}
 							// don't create a marker if initialization is in progress (case of cp initialization batching)
 							return JavaModelStatus.VERIFIED_OK;
 						}
@@ -1446,8 +1462,8 @@
 								}
 						}
 					} else if (target instanceof File){
-					    File file = (File) target;
-					    if (!file.isFile()) {
+						File file = JavaModel.getFile(target);
+					    if (file == null) {
 							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}))); 
@@ -1517,6 +1533,20 @@
 				}
 				break;
 		}
+
+		// Validate extra attributes
+		IClasspathAttribute[] extraAttributes = entry.getExtraAttributes();
+		if (extraAttributes != null) {
+			int length = extraAttributes.length;
+			HashSet set = new HashSet(length);
+			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 JavaModelStatus.VERIFIED_OK;		
 	}
 }
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 e320905..1345700 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
@@ -388,7 +388,8 @@
 		String source = ""; //$NON-NLS-1$
 		if (!pkg.isDefaultPackage()) {
 			//not the default package...add the package declaration
-			source = "package " + pkg.getElementName() + ";"  + org.eclipse.jdt.internal.compiler.util.Util.LINE_SEPARATOR + org.eclipse.jdt.internal.compiler.util.Util.LINE_SEPARATOR; //$NON-NLS-1$ //$NON-NLS-2$
+			String lineSeparator = Util.getLineSeparator(null/*no existing source*/, getJavaProject());
+			source = "package " + pkg.getElementName() + ";"  + lineSeparator + lineSeparator; //$NON-NLS-1$ //$NON-NLS-2$
 		}
 		CreateCompilationUnitOperation op = new CreateCompilationUnitOperation(pkg, this.name, source, force);
 		op.runOperation(monitor);
@@ -578,7 +579,7 @@
 public char[] getContents() {
 	try {
 		IBuffer buffer = this.getBuffer();
-		return buffer == null ? null : buffer.getCharacters();
+		return buffer == null ? CharOperation.NO_CHAR : buffer.getCharacters();
 	} catch (JavaModelException e) {
 		return CharOperation.NO_CHAR;
 	}
@@ -1124,9 +1125,9 @@
 	}
 }
 /**
- * @private Debugging purposes
+ * Debugging purposes
  */
-protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
+protected void toStringInfo(int tab, StringBuffer buffer, Object info, boolean showResolvedInfo) {
 	if (!isPrimary()) {
 		buffer.append(this.tabString(tab));
 		buffer.append("[Working copy] "); //$NON-NLS-1$
@@ -1140,7 +1141,7 @@
 				buffer.append(" (not open)"); //$NON-NLS-1$
 			}
 		} else {
-			super.toStringInfo(tab, buffer, info);
+			super.toStringInfo(tab, buffer, info, showResolvedInfo);
 		}
 	}
 }
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 54fce6e..c93e061 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
@@ -23,7 +23,6 @@
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
-import org.eclipse.jdt.internal.compiler.util.Util;
 import org.eclipse.jdt.internal.core.util.Messages;
 
 /**
@@ -103,14 +102,22 @@
 					String extension = path.getFileExtension();
 					return new RenameResourceElementsOperation(new IJavaElement[] {dest}, new IJavaElement[] {dest.getParent()}, new String[]{getNewNameFor(element) + '.' + extension}, this.force); //$NON-NLS-1$
 				} else {
-					return new CreateTypeOperation(dest, getSourceFor(element) + Util.LINE_SEPARATOR, this.force);
+					String source = getSourceFor(element);
+					String lineSeparator = org.eclipse.jdt.internal.core.util.Util.getLineSeparator(source, element.getJavaProject());
+					return new CreateTypeOperation(dest, source + lineSeparator, this.force);
 				}
 			case IJavaElement.METHOD :
-				return new CreateMethodOperation((IType) dest, getSourceFor(element) + Util.LINE_SEPARATOR, this.force);
+				String source = getSourceFor(element);
+				String lineSeparator = org.eclipse.jdt.internal.core.util.Util.getLineSeparator(source, element.getJavaProject());
+				return new CreateMethodOperation((IType) dest, source + lineSeparator, this.force);
 			case IJavaElement.FIELD :
-				return new CreateFieldOperation((IType) dest, getSourceFor(element) + Util.LINE_SEPARATOR, this.force);
+				source = getSourceFor(element);
+				lineSeparator = org.eclipse.jdt.internal.core.util.Util.getLineSeparator(source, element.getJavaProject());
+				return new CreateFieldOperation((IType) dest, source + lineSeparator, this.force);
 			case IJavaElement.INITIALIZER :
-				return new CreateInitializerOperation((IType) dest, getSourceFor(element) + Util.LINE_SEPARATOR);
+				source = getSourceFor(element);
+				lineSeparator = org.eclipse.jdt.internal.core.util.Util.getLineSeparator(source, element.getJavaProject());
+				return new CreateInitializerOperation((IType) dest, source + lineSeparator);
 			default :
 				return null;
 		}
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 386bf5c..cc3c386 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
@@ -299,7 +299,7 @@
 			if (!this.force) {
 				throw new JavaModelException(new JavaModelStatus(
 					IJavaModelStatusConstants.NAME_COLLISION, 
-					Messages.bind(Messages.status_nameCollision, (new String[] {destFile.getFullPath().toString()})))); 
+					Messages.bind(Messages.status_nameCollision, destFile.getFullPath().toString()))); 
 			}
 			// update new resource content
 			// in case we do a saveas on the same resource we have to simply update the contents
@@ -439,7 +439,7 @@
 								} else {
 									throw new JavaModelException(new JavaModelStatus(
 										IJavaModelStatusConstants.NAME_COLLISION, 
-										Messages.bind(Messages.status_nameCollision, (new String[] {destinationResource.getFullPath().toString()})))); 
+										Messages.bind(Messages.status_nameCollision, destinationResource.getFullPath().toString()))); 
 								}
 							}
 						}
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 bf939b6..f05a7d7 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
@@ -105,7 +105,7 @@
 			} else {
 				throw new JavaModelException(new JavaModelStatus(
 					IJavaModelStatusConstants.NAME_COLLISION, 
-					Messages.bind(Messages.status_nameCollision, (new String[] {compilationUnitFile.getFullPath().toString()})))); 
+					Messages.bind(Messages.status_nameCollision, compilationUnitFile.getFullPath().toString()))); 
 			}
 		} else {
 			try {
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 d75cb9f..b47da45 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
@@ -11,6 +11,7 @@
 package org.eclipse.jdt.internal.core;
 
 import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IField;
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.IJavaModelStatus;
 import org.eclipse.jdt.core.IJavaModelStatusConstants;
@@ -71,11 +72,19 @@
 protected void initializeDefaultPosition() {
 	IType parentElement = getType();
 	try {
-		IJavaElement[] elements = parentElement.getFields();
-		if (elements != null && elements.length > 0) {
-			createAfter(elements[elements.length - 1]);
+		IField[] fields = parentElement.getFields();
+		if (fields != null && fields.length > 0) {
+			final IField lastField = fields[fields.length - 1];
+			if (parentElement.isEnum()) {
+				IField field = lastField;
+				if (!field.isEnumConstant()) {
+					createAfter(lastField);
+				}
+			} else {
+				createAfter(lastField);
+			}
 		} else {
-			elements = parentElement.getChildren();
+			IJavaElement[] elements = parentElement.getChildren();
 			if (elements != null && elements.length > 0) {
 				createBefore(elements[0]);
 			}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateMethodOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateMethodOperation.java
index c0bfdf1..880565b 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateMethodOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CreateMethodOperation.java
@@ -19,6 +19,7 @@
 import org.eclipse.jdt.core.IJavaModelStatusConstants;
 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.core.dom.MethodDeclaration;
 import org.eclipse.jdt.core.dom.SimpleName;
@@ -55,14 +56,19 @@
 protected String[] convertASTMethodTypesToSignatures() {
 	if (this.parameterTypes == null) {
 		if (this.createdNode != null) {
-			List parameters = ((MethodDeclaration) this.createdNode).parameters();
+			MethodDeclaration methodDeclaration = (MethodDeclaration) this.createdNode;
+			List parameters = methodDeclaration.parameters();
 			int size = parameters.size();
 			this.parameterTypes = new String[size];
 			Iterator iterator = parameters.iterator();
 			// convert the AST types to signatures
 			for (int i = 0; i < size; i++) {
 				SingleVariableDeclaration parameter = (SingleVariableDeclaration) iterator.next();
-				this.parameterTypes[i] = Util.getSignature(parameter.getType());
+				String typeSig = Util.getSignature(parameter.getType());
+				int extraDimensions = parameter.getExtraDimensions();
+				if (methodDeclaration.isVarargs() && i == size-1)
+					extraDimensions++;
+				this.parameterTypes[i] = Signature.createArraySignature(typeSig, extraDimensions);
 			}
 		}
 	}
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 797263b..bdf6a41 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
@@ -30,7 +30,6 @@
 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.compiler.util.Util;
 import org.eclipse.jdt.internal.core.dom.rewrite.Indents;
 import org.eclipse.jface.text.IDocument;
 import org.eclipse.jface.text.TextUtilities;
@@ -151,9 +150,11 @@
 protected String generateSyntaxIncorrectAST() {
 	//create some dummy source to generate an ast node
 	StringBuffer buff = new StringBuffer();
-	buff.append(Util.LINE_SEPARATOR + " public class A {" + Util.LINE_SEPARATOR); //$NON-NLS-1$
+	IType type = getType();
+	String lineSeparator = org.eclipse.jdt.internal.core.util.Util.getLineSeparator(this.source, type == null ? null : type.getJavaProject());
+	buff.append(lineSeparator + " public class A {" + lineSeparator); //$NON-NLS-1$
 	buff.append(this.source);
-	buff.append(Util.LINE_SEPARATOR).append('}');
+	buff.append(lineSeparator).append('}');
 	ASTParser parser = ASTParser.newParser(AST.JLS3);
 	parser.setSource(buff.toString().toCharArray());
 	CompilationUnit compilationUnit = (CompilationUnit) parser.createAST(null);
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 678ade5..607b963 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
@@ -10,23 +10,19 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
 import java.util.*;
-import java.util.ArrayList;
-import java.util.Hashtable;
-import java.util.Map;
 
 import org.eclipse.core.resources.*;
-import org.eclipse.core.resources.IResourceChangeEvent;
-import org.eclipse.core.resources.IResourceChangeListener;
-import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.*;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IPath;
-import org.eclipse.core.runtime.QualifiedName;
 import org.eclipse.jdt.core.*;
-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;
 
 /**
@@ -70,6 +66,9 @@
 	
 	/* A table from IPath (a source attachment path from a classpath entry) to IPath (a root path) */
 	public HashMap sourceAttachments = new HashMap();
+	
+	/* A table from IJavaProject to IJavaProject[] (the list of direct dependent of the key) */
+	public HashMap projectDependencies = new HashMap();
 
 	/* Whether the roots tables should be recomputed */
 	public boolean rootsAreStale = true;
@@ -77,7 +76,7 @@
 	/* Threads that are currently running initializeRoots() */
 	private Set initializingThreads = Collections.synchronizedSet(new HashSet());	
 	
-	public Hashtable externalTimeStamps = new Hashtable();
+	public Hashtable externalTimeStamps;
 	
 	public HashMap projectUpdates = new HashMap();
 
@@ -232,6 +231,7 @@
 		HashMap newRoots = null;
 		HashMap newOtherRoots = null;
 		HashMap newSourceAttachments = null;
+		HashMap newProjectDependencies = null;
 		if (this.rootsAreStale) {
 			Thread currentThread = Thread.currentThread();
 			boolean addedCurrentThread = false;			
@@ -248,6 +248,7 @@
 				newRoots = new HashMap();
 				newOtherRoots = new HashMap();
 				newSourceAttachments = new HashMap();
+				newProjectDependencies = new HashMap();
 		
 				IJavaModel model = JavaModelManager.getJavaModelManager().getJavaModel();
 				IJavaProject[] projects;
@@ -268,7 +269,19 @@
 					}
 					for (int j= 0, classpathLength = classpath.length; j < classpathLength; j++) {
 						IClasspathEntry entry = classpath[j];
-						if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) continue;
+						if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) {
+							IJavaProject key = model.getJavaProject(entry.getPath().segment(0)); // TODO (jerome) reuse handle
+							IJavaProject[] dependents = (IJavaProject[]) newProjectDependencies.get(key);
+							if (dependents == null) {
+								dependents = new IJavaProject[] {project};
+							} else {
+								int dependentsLength = dependents.length;
+								System.arraycopy(dependents, 0, dependents = new IJavaProject[dependentsLength+1], 0, dependentsLength);
+								dependents[dependentsLength] = project;
+							}
+							newProjectDependencies.put(key, dependents);
+							continue;
+						}
 						
 						// root path
 						IPath path = entry.getPath();
@@ -317,6 +330,7 @@
 				this.roots = newRoots;
 				this.otherRoots = newOtherRoots;
 				this.sourceAttachments = newSourceAttachments;
+				this.projectDependencies = newProjectDependencies;
 				this.rootsAreStale = false;
 			}
 		}
@@ -424,6 +438,68 @@
 		}
 
 	}
+	
+	public Hashtable getExternalLibTimeStamps() {
+		if (this.externalTimeStamps == null) {
+			Hashtable timeStamps = new Hashtable();
+			File timestampsFile = getTimeStampsFile();
+			DataInputStream in = null;
+			try {
+				in = new DataInputStream(new BufferedInputStream(new FileInputStream(timestampsFile)));
+				int size = in.readInt();
+				while (size-- > 0) {
+					String key = in.readUTF();
+					long timestamp = in.readLong();
+					timeStamps.put(Path.fromPortableString(key), new Long(timestamp));
+				}
+			} catch (IOException e) {
+				if (timestampsFile.exists())
+					Util.log(e, "Unable to read external time stamps"); //$NON-NLS-1$
+			} finally {
+				if (in != null) {
+					try {
+						in.close();
+					} catch (IOException e) {
+						// nothing we can do: ignore
+					}
+				}
+			}
+			this.externalTimeStamps = timeStamps;
+		}
+		return this.externalTimeStamps;
+	}
+	
+	private File getTimeStampsFile() {
+		return JavaCore.getPlugin().getStateLocation().append("externalLibsTimeStamps").toFile(); //$NON-NLS-1$
+	}
+	
+	public void saveExternalLibTimeStamps() throws CoreException {
+		if (this.externalTimeStamps == null) return;
+		File timestamps = getTimeStampsFile();
+		DataOutputStream out = null;
+		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();
+				out.writeUTF(key.toPortableString());
+				Long timestamp = (Long) this.externalTimeStamps.get(key);
+				out.writeLong(timestamp.longValue());
+			}
+		} catch (IOException e) {
+			IStatus status = new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, IStatus.ERROR, "Problems while saving timestamps", e); //$NON-NLS-1$
+			throw new CoreException(status);
+		} finally {
+			if (out != null) {
+				try {
+					out.close();
+				} catch (IOException e) {
+					// nothing we can do: ignore
+				}
+			}
+		}
+	}
 
 	/*
 	 * Update the roots that are affected by the addition or the removal of the given container resource.
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 38cbb77..3b0356c 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
@@ -12,10 +12,6 @@
 
 import java.io.File;
 import java.util.*;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
 
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IFolder;
@@ -26,26 +22,15 @@
 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.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.ElementChangedEvent;
-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.IJavaProject;
-import org.eclipse.jdt.core.IPackageFragment;
-import org.eclipse.jdt.core.IPackageFragmentRoot;
-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.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.JavaWorkspaceScope;
 import org.eclipse.jdt.internal.core.search.indexing.IndexManager;
 import org.eclipse.jdt.internal.core.util.Util;
 
@@ -198,7 +183,7 @@
 	/*
 	 * The Java model manager
 	 */
-	private JavaModelManager manager;
+	JavaModelManager manager;
 	
 	/*
 	 * The <code>JavaElementDelta</code> corresponding to the <code>IResourceDelta</code> being translated.
@@ -263,31 +248,16 @@
 	 * Adds the dependents of the given project to the list of the projects
 	 * to update.
 	 */
-	private void addDependentProjects(IPath projectPath, HashSet result) {
-		IJavaProject[] projects = null;
-		try {
-			projects = this.manager.getJavaModel().getJavaProjects();
-		} catch (JavaModelException e) {
-			// java model doesn't exist
-			return;
+	private void addDependentProjects(IJavaProject project, HashMap projectDependencies, HashSet result) {
+		IJavaProject[] dependents = (IJavaProject[]) projectDependencies.get(project);
+		if (dependents == null) return;
+		for (int i = 0, length = dependents.length; i < length; i++) {
+			IJavaProject dependent = dependents[i];
+			if (result.contains(dependent))
+				continue; // no need to go further as the project is already known
+			result.add(dependent);
+			addDependentProjects(dependent, projectDependencies, result);
 		}
-		for (int i = 0, length = projects.length; i < length; i++) {
-			IJavaProject project = projects[i];
-			IClasspathEntry[] classpath = null;
-			try {
-				classpath = ((JavaProject)project).getExpandedClasspath(true);
-			} catch (JavaModelException e) {
-				// project doesn't exist: continue with next project
-				continue;
-			}
-			for (int j = 0, length2 = classpath.length; j < length2; j++) {
-				IClasspathEntry entry = classpath[j];
-					if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT
-							&& entry.getPath().equals(projectPath)) {
-						result.add(project);
-					}
-				}
-			}
 	}
 	/*
 	 * Adds the given element to the list of elements used as a scope for external jars refresh.
@@ -317,7 +287,7 @@
 	 */
 	private void addToRootsToRefreshWithDependents(IJavaProject javaProject) {
 		this.rootsToRefresh.add(javaProject);
-		this.addDependentProjects(javaProject.getPath(), this.rootsToRefresh);
+		this.addDependentProjects(javaProject, this.state.projectDependencies, this.rootsToRefresh);
 	}
 	/*
 	 * Check all external archive (referenced by given roots, projects or model) status and issue a corresponding root delta.
@@ -334,21 +304,39 @@
 				// force classpath marker refresh of affected projects
 				JavaModel.flushExternalFileCache();
 				IJavaElementDelta[] projectDeltas = this.currentDelta.getAffectedChildren();
-				for (int i = 0, length = projectDeltas.length; i < length; i++) {
+				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*/);
-					
-					try {
-						// touch the project to force it to be recompiled
-						javaProject.getProject().touch(monitor);
-					} catch (CoreException e) {
-						throw new JavaModelException(e);
+					projectsToTouch[i] = javaProject.getProject();
+				}
+				
+				// touch the projects to force them to be recompiled while taking the workspace lock 
+				// so that there is no concurrency with the Java builder
+				// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=96575
+				IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
+					public void run(IProgressMonitor progressMonitor) throws CoreException {
+						for (int i = 0; i < length; i++) {
+							IProject project = projectsToTouch[i];
+							
+							// touch to force a build of this project
+							if (JavaBuilder.DEBUG)
+								System.out.println("Touching project " + project.getName() + " due to external jar file change"); //$NON-NLS-1$ //$NON-NLS-2$
+							project.touch(progressMonitor);
+						}
 					}
-				}		
+				};
+				try {
+					ResourcesPlugin.getWorkspace().run(runnable, monitor);
+				} catch (CoreException e) {
+					throw new JavaModelException(e);
+				}
+				
 				if (this.currentDelta != null) { // if delta has not been fired while creating markers
 					this.fire(this.currentDelta, DEFAULT_CHANGE_EVENT);
 				}
@@ -799,7 +787,7 @@
 						Object targetLibrary = JavaModel.getTarget(wksRoot, entryPath, true);
 		
 						if (targetLibrary == null){ // missing JAR
-							if (this.state.externalTimeStamps.remove(entryPath) != null){
+							if (this.state.getExternalLibTimeStamps().remove(entryPath) != null){
 								externalArchivesStatus.put(entryPath, EXTERNAL_JAR_REMOVED);
 								// the jar was physically removed: remove the index
 								this.manager.indexManager.removeIndex(entryPath);
@@ -810,19 +798,19 @@
 							File externalFile = (File)targetLibrary;
 							
 							// check timestamp to figure if JAR has changed in some way
-							Long oldTimestamp =(Long) this.state.externalTimeStamps.get(entryPath);
+							Long oldTimestamp =(Long) this.state.getExternalLibTimeStamps().get(entryPath);
 							long newTimeStamp = getTimeStamp(externalFile);
 							if (oldTimestamp != null){
 		
 								if (newTimeStamp == 0){ // file doesn't exist
 									externalArchivesStatus.put(entryPath, EXTERNAL_JAR_REMOVED);
-									this.state.externalTimeStamps.remove(entryPath);
+									this.state.getExternalLibTimeStamps().remove(entryPath);
 									// remove the index
 									this.manager.indexManager.removeIndex(entryPath);
 		
 								} else if (oldTimestamp.longValue() != newTimeStamp){
 									externalArchivesStatus.put(entryPath, EXTERNAL_JAR_CHANGED);
-									this.state.externalTimeStamps.put(entryPath, new Long(newTimeStamp));
+									this.state.getExternalLibTimeStamps().put(entryPath, new Long(newTimeStamp));
 									// first remove the index so that it is forced to be re-indexed
 									this.manager.indexManager.removeIndex(entryPath);
 									// then index the jar
@@ -835,7 +823,7 @@
 									externalArchivesStatus.put(entryPath, EXTERNAL_JAR_UNCHANGED);
 								} else {
 									externalArchivesStatus.put(entryPath, EXTERNAL_JAR_ADDED);
-									this.state.externalTimeStamps.put(entryPath, new Long(newTimeStamp));
+									this.state.getExternalLibTimeStamps().put(entryPath, new Long(newTimeStamp));
 									// index the new jar
 									this.manager.indexManager.indexLibrary(entryPath, project.getProject());
 								}
@@ -859,8 +847,6 @@
 							if (VERBOSE){
 								System.out.println("- External JAR CHANGED, affecting root: "+root.getElementName()); //$NON-NLS-1$
 							}
-							// reset the corresponding project built state, since the builder would miss this change
-							this.manager.setLastBuiltState(project.getProject(), null /*no state*/);
 							contentChanged(root);
 							hasDelta = true;
 						} else if (status == EXTERNAL_JAR_REMOVED) {
@@ -1193,6 +1179,17 @@
 	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];
+		}
+	}
 	/*
 	 * Finds the root info this path is included in.
 	 * Returns null if not found.
@@ -1230,6 +1227,9 @@
 				AbstractSearchScope scope = (AbstractSearchScope)scopes.next();
 				scope.processDelta(deltaToNotify);
 			}
+			JavaWorkspaceScope workspaceScope = this.manager.workspaceScope;
+			if (workspaceScope != null)
+				workspaceScope.processDelta(deltaToNotify);
 		}
 			
 		// Notification
@@ -1705,11 +1705,12 @@
 	 */
 	private void resetProjectCaches() {
 		Iterator iterator = this.projectCachesToReset.iterator();
+		HashMap projectDepencies = this.state.projectDependencies;
 		HashSet affectedDependents = new HashSet();
 		while (iterator.hasNext()) {
 			JavaProject project = (JavaProject)iterator.next();
 			project.resetCaches();
-			addDependentProjects(project.getPath(), affectedDependents);
+			addDependentProjects(project, projectDepencies, affectedDependents);
 		}
 		// reset caches of dependent projects
 		iterator = affectedDependents.iterator();
@@ -2195,7 +2196,12 @@
 	
 				if (deltaRes.getType() == IResource.PROJECT){			
 					// reset the corresponding project built state, since cannot reuse if added back
+					if (JavaBuilder.DEBUG)
+						System.out.println("Clearing last state for removed project : " + deltaRes); //$NON-NLS-1$
 					this.manager.setLastBuiltState((IProject)deltaRes, null /*no state*/);
+					
+					// clean up previous session containers (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=89850)
+					this.manager.previousSessionContainers.remove(element);
 				}
 				return elementType == IJavaElement.PACKAGE_FRAGMENT;
 			case IResourceDelta.CHANGED :
@@ -2258,6 +2264,8 @@
 								this.manager.indexManager.discardJobs(element.getElementName());
 								this.manager.indexManager.removeIndexFamily(res.getFullPath());
 								// reset the corresponding project built state, since cannot reuse if added back
+								if (JavaBuilder.DEBUG)
+									System.out.println("Clearing last state for project loosing Java nature: " + res); //$NON-NLS-1$
 								this.manager.setLastBuiltState(res, null /*no state*/);
 							}
 							return false; // when a project's nature is added/removed don't process children
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ImportContainer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ImportContainer.java
index 82efebf..47a90aa 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ImportContainer.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ImportContainer.java
@@ -110,7 +110,7 @@
 /**
  *  Debugging purposes
  */
-protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
+protected void toStringInfo(int tab, StringBuffer buffer, Object info, boolean showResolvedInfo) {
 	buffer.append(this.tabString(tab));
 	buffer.append("<import container>"); //$NON-NLS-1$
 	if (info == null) {
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 3d33bce..5b86608 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
@@ -101,7 +101,7 @@
 /**
  * @private Debugging purposes
  */
-protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
+protected void toStringInfo(int tab, StringBuffer buffer, Object info, boolean showResolvedInfo) {
 	buffer.append(this.tabString(tab));
 	buffer.append("import "); //$NON-NLS-1$
 	toStringName(buffer);
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Initializer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Initializer.java
index de25ee6..ee1953a 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Initializer.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Initializer.java
@@ -92,7 +92,7 @@
 /**
  * @private Debugging purposes
  */
-protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
+protected void toStringInfo(int tab, StringBuffer buffer, Object info, boolean showResolvedInfo) {
 	buffer.append(this.tabString(tab));
 	if (info == null) {
 		buffer.append("<initializer #"); //$NON-NLS-1$
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 a13b85a..32f0765 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
@@ -83,7 +83,7 @@
 		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.DISABLED); //$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$
 		
 		// Store default values to default preferences
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceModifyListener.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceModifyListener.java
new file mode 100644
index 0000000..3e0b2aa
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceModifyListener.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * 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;
+
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.core.runtime.preferences.PreferenceModifyListener;
+import org.eclipse.jdt.core.*;
+import org.osgi.service.prefs.BackingStoreException;
+import org.osgi.service.prefs.Preferences;
+
+public class JavaCorePreferenceModifyListener extends PreferenceModifyListener {
+	
+	static int PREFIX_LENGTH = JavaModelManager.CP_CONTAINER_PREFERENCES_PREFIX.length();
+	JavaModel javaModel = JavaModelManager.getJavaModelManager().getJavaModel();
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.core.runtime.preferences.PreferenceModifyListener#preApply(org.eclipse.core.runtime.preferences.IEclipsePreferences)
+	 */
+	public IEclipsePreferences preApply(IEclipsePreferences node) {
+		Preferences instance = node.node(InstanceScope.SCOPE);
+		cleanJavaCore(instance.node(JavaCore.PLUGIN_ID));
+		return super.preApply(node);
+	}
+	
+	/**
+	 * Clean imported preferences from obsolete keys.
+	 *
+	 * @param preferences JavaCore preferences.
+	 */
+	void cleanJavaCore(Preferences preferences) {
+		try {
+			String[] keys = preferences.keys();
+			for (int k = 0, kl= keys.length; k<kl; k++) {
+				String key = keys[k];
+				if (key.startsWith(JavaModelManager.CP_CONTAINER_PREFERENCES_PREFIX) && !isJavaProjectAccessible(key)) {
+					preferences.remove(key);
+				}
+			}
+		} catch (BackingStoreException e) {
+			// do nothing
+		}
+	}
+
+	/**
+	 * Returns whether a java project referenced in property key
+	 * is still longer accessible or not.
+	 * 
+	 * @param propertyName
+	 * @return true if a project is referenced in given key and this project
+	 * 	is still accessible, false otherwise.
+	 */
+	boolean isJavaProjectAccessible(String propertyName) {
+		int index = propertyName.indexOf('|', PREFIX_LENGTH);
+		if (index > 0) {
+			final String projectName = propertyName.substring(PREFIX_LENGTH, index).trim();
+			JavaProject project = (JavaProject) javaModel.getJavaProject(projectName);
+			if (project.getProject().isAccessible()) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+}
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 5a5a4f8..06fad7f 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
@@ -527,7 +527,7 @@
 	 */
 	public String toDebugString() {
 		StringBuffer buffer = new StringBuffer();
-		this.toStringInfo(0, buffer, NO_INFO);
+		this.toStringInfo(0, buffer, NO_INFO, true/*show resolved info*/);
 		return buffer.toString();
 	}
 	/**
@@ -552,8 +552,14 @@
 	 *  Debugging purposes
 	 */
 	public String toStringWithAncestors() {
+		return toStringWithAncestors(true/*show resolved info*/);
+	}
+		/**
+	 *  Debugging purposes
+	 */
+	public String toStringWithAncestors(boolean showResolvedInfo) {
 		StringBuffer buffer = new StringBuffer();
-		this.toStringInfo(0, buffer, NO_INFO);
+		this.toStringInfo(0, buffer, NO_INFO, showResolvedInfo);
 		this.toStringAncestors(buffer);
 		return buffer.toString();
 	}
@@ -564,7 +570,7 @@
 		JavaElement parentElement = (JavaElement)this.getParent();
 		if (parentElement != null && parentElement.getParent() != null) {
 			buffer.append(" [in "); //$NON-NLS-1$
-			parentElement.toStringInfo(0, buffer, NO_INFO);
+			parentElement.toStringInfo(0, buffer, NO_INFO, false/*don't show resolved info*/);
 			parentElement.toStringAncestors(buffer);
 			buffer.append("]"); //$NON-NLS-1$
 		}
@@ -585,13 +591,14 @@
 	 */
 	public Object toStringInfo(int tab, StringBuffer buffer) {
 		Object info = JavaModelManager.getJavaModelManager().peekAtInfo(this);
-		this.toStringInfo(tab, buffer, info);
+		this.toStringInfo(tab, buffer, info, true/*show resolved info*/);
 		return info;
 	}
 	/**
 	 *  Debugging purposes
+	 * @param showResolvedInfo TODO
 	 */
-	protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
+	protected void toStringInfo(int tab, StringBuffer buffer, Object info, boolean showResolvedInfo) {
 		buffer.append(this.tabString(tab));
 		toStringName(buffer);
 		if (info == null) {
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 b3855da..cbebfbe 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
@@ -49,7 +49,14 @@
 	 * Note this cache is kept for the whole session.
 	 */ 
 	public static HashSet existingExternalFiles = new HashSet();
-		
+
+	/**
+	 * A set of external files ({@link #existingExternalFiles}) which have
+	 * been confirmed as file (ie. which returns true to {@link java.io.File#isFile()}.
+	 * Note this cache is kept for the whole session.
+	 */ 
+	public static HashSet existingExternalConfirmedFiles = new HashSet();
+
 /**
  * Constructs a new Java Model on the given workspace.
  * Note that only one instance of JavaModel handle should ever be created.
@@ -160,6 +167,7 @@
  */
 public static void flushExternalFileCache() {
 	existingExternalFiles = new HashSet();
+	existingExternalConfirmedFiles = new HashSet();
 }
 
 /*
@@ -317,7 +325,7 @@
 /**
  * @private Debugging purposes
  */
-protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
+protected void toStringInfo(int tab, StringBuffer buffer, Object info, boolean showResolvedInfo) {
 	buffer.append(this.tabString(tab));
 	buffer.append("Java Model"); //$NON-NLS-1$
 	if (info == null) {
@@ -367,4 +375,29 @@
 	}
 	return null;	
 }
+
+/**
+ * Helper method - returns whether an object is afile (ie. which returns true to {@link java.io.File#isFile()}.
+ */
+public static boolean isFile(Object target) {
+	return getFile(target) != null;
+}
+
+/**
+ * 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) {
+	if (existingExternalConfirmedFiles.contains(target))
+		return (File) target;
+	if (target instanceof File) {
+		File f = (File) target;
+		if (f.isFile()) {
+			existingExternalConfirmedFiles.add(f);
+			return f;
+		}
+	}
+	
+	return null;
+}
 }
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 0e9c077..c1758f4 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
@@ -20,8 +20,10 @@
 
 import org.eclipse.core.resources.*;
 import org.eclipse.core.runtime.*;
+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.InstanceScope;
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.compiler.CharOperation;
@@ -35,6 +37,7 @@
 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.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.Messages;
@@ -75,6 +78,7 @@
 	public HashMap previousSessionContainers = new HashMap(5);
 	private ThreadLocal containerInitializationInProgress = new ThreadLocal();
 	public boolean batchContainerInitializations = false;
+	public HashMap containerInitializersCache = new HashMap(5);
 	
 	/*
 	 * A HashSet that contains the IJavaProject whose classpath is being resolved.
@@ -82,6 +86,11 @@
 	private ThreadLocal classpathsBeingResolved = new ThreadLocal();
 	
 	/*
+	 * The unique workspace scope
+	 */
+	public JavaWorkspaceScope workspaceScope;
+	
+	/*
 	 * Pools of symbols used in the Java model.
 	 * Used as a replacement for String#intern() that could prevent garbage collection of strings on some VMs.
 	 */
@@ -91,6 +100,8 @@
 	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$
+	
+	private final static int VARIABLES_AND_CONTAINERS_FILE_VERSION = 1;
 
 	/**
 	 * Name of the extension point for contributing classpath variable initializers
@@ -139,6 +150,7 @@
 	private static final String RESOLUTION_DEBUG = JavaCore.PLUGIN_ID + "/debug/resolution" ; //$NON-NLS-1$
 	private static final String SELECTION_DEBUG = JavaCore.PLUGIN_ID + "/debug/selection" ; //$NON-NLS-1$
 	private static final String SEARCH_DEBUG = JavaCore.PLUGIN_ID + "/debug/search" ; //$NON-NLS-1$
+	private static final String SOURCE_MAPPER_DEBUG_VERBOSE = JavaCore.PLUGIN_ID + "/debug/sourcemapper" ; //$NON-NLS-1$
 
 	public static final String COMPLETION_PERF = JavaCore.PLUGIN_ID + "/perf/completion" ; //$NON-NLS-1$
 	public static final String SELECTION_PERF = JavaCore.PLUGIN_ID + "/perf/selection" ; //$NON-NLS-1$
@@ -153,7 +165,9 @@
 	public final static ICompilationUnit[] NO_WORKING_COPY = new ICompilationUnit[0];
 	
 	// Preferences
-	public HashSet optionNames = new HashSet(20);
+	HashSet optionNames = new HashSet(20);
+	Hashtable optionsCache;
+
 	public final IEclipsePreferences[] preferencesLookup = new IEclipsePreferences[2];
 	static final int PREF_INSTANCE = 0;
 	static final int PREF_DEFAULT = 1;
@@ -237,18 +251,14 @@
 	public synchronized void containerPut(IJavaProject project, IPath containerPath, IClasspathContainer container){
 
 		// set/unset the initialization in progress
-		HashSet projectInitializations = containerInitializationInProgress(project);
 		if (container == CONTAINER_INITIALIZATION_IN_PROGRESS) {
+			HashSet projectInitializations = containerInitializationInProgress(project);
 			projectInitializations.add(containerPath);
 			
 			// do not write out intermediate initialization value
 			return;
 		} else {
-			projectInitializations.remove(containerPath);
-			if (projectInitializations.size() == 0) {
-				Map initializations = (Map)this.containerInitializationInProgress.get();
-				initializations.remove(project);
-			}
+			containerRemoveInitializationInProgress(project, containerPath);
 
 			Map projectContainers = (Map)this.containers.get(project);
 			if (projectContainers == null){
@@ -358,6 +368,15 @@
 		return true;
 	}
 	
+	private void containerRemoveInitializationInProgress(IJavaProject project, IPath containerPath) {
+		HashSet projectInitializations = containerInitializationInProgress(project);
+		projectInitializations.remove(containerPath);
+		if (projectInitializations.size() == 0) {
+			Map initializations = (Map)this.containerInitializationInProgress.get();
+			initializations.remove(project);
+		}
+	}
+	
 	private synchronized void containersReset(String[] containerIDs) {
 		for (int i = 0; i < containerIDs.length; i++) {
 			String containerID = containerIDs[i];
@@ -464,10 +483,29 @@
 		if (folder == null) {
 			return null;
 		}
+		IJavaElement element;
 		if (project == null) {
 			project = JavaCore.create(folder.getProject());
+			element = determineIfOnClasspath(folder, project);
+			if (element == null) {
+				// walk all projects and find one that have the given folder on its classpath
+				IJavaProject[] projects;
+				try {
+					projects = JavaModelManager.getJavaModelManager().getJavaModel().getJavaProjects();
+				} catch (JavaModelException e) {
+					return null;
+				}
+				for (int i = 0, length = projects.length; i < length; i++) {
+					project = projects[i];
+					element = determineIfOnClasspath(folder, project);
+					if (element != null)
+						break;
+				}
+			}
+		} else {
+			element = determineIfOnClasspath(folder, project);
 		}
-		IJavaElement element = determineIfOnClasspath(folder, project);
+		
 		if (conflictsWithOutputLocation(folder.getFullPath(), (JavaProject)project)
 		 	|| (folder.getName().indexOf('.') >= 0 
 		 		&& !(element instanceof IPackageFragmentRoot))) {
@@ -608,7 +646,7 @@
 	/**
 	 * The singleton manager
 	 */
-	private final static JavaModelManager MANAGER= new JavaModelManager();
+	private static JavaModelManager MANAGER= new JavaModelManager();
 
 	/**
 	 * Infos cache.
@@ -669,6 +707,26 @@
 			this.project = project;
 		}
 		
+		public void rememberExternalLibTimestamps() {
+			IClasspathEntry[] classpath = this.resolvedClasspath;
+			if (classpath == null) return;
+			IWorkspaceRoot wRoot = ResourcesPlugin.getWorkspace().getRoot();
+			Map externalTimeStamps = JavaModelManager.getJavaModelManager().deltaState.getExternalLibTimeStamps();
+			for (int i = 0, length = classpath.length; i < length; i++) {
+				IClasspathEntry entry = classpath[i];
+				if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
+					IPath path = entry.getPath();
+					if (externalTimeStamps.get(path) == null) {
+						Object target = JavaModel.getTarget(wRoot, path, true);
+						if (target instanceof java.io.File) {
+							long timestamp = DeltaProcessor.getTimeStamp((java.io.File)target);
+							externalTimeStamps.put(path, new Long(timestamp));							
+						}
+					}
+				}
+			}
+		}
+		
 		// updating raw classpath need to flush obsoleted cached information about resolved entries
 		public synchronized void updateClasspathInformation(IClasspathEntry[] newRawClasspath) {
 
@@ -792,6 +850,14 @@
 	}
 
 	/**
+	 * @deprecated
+	 */
+	private void addDeprecatedOptions(Hashtable options) {
+		options.put(JavaCore.COMPILER_PB_INVALID_IMPORT, JavaCore.ERROR);		
+		options.put(JavaCore.COMPILER_PB_UNREACHABLE_CODE, JavaCore.ERROR);
+	}
+
+	/**
 	 * Starts caching ZipFiles.
 	 * Ignores if there are already clients.
 	 */
@@ -863,6 +929,9 @@
 
 			option = Platform.getDebugOption(ZIP_ACCESS_DEBUG);
 			if(option != null) JavaModelManager.ZIP_ACCESS_VERBOSE = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
+			
+			option = Platform.getDebugOption(SOURCE_MAPPER_DEBUG_VERBOSE);
+			if(option != null) SourceMapper.VERBOSE = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
 		}
 		
 		// configure performance options
@@ -1009,6 +1078,28 @@
 		return preferencesLookup[PREF_INSTANCE];
 	}
  
+	public Hashtable getDefaultOptions(){
+	
+		Hashtable defaultOptions = new Hashtable(10);
+
+		// see JavaCorePreferenceInitializer#initializeDefaultPluginPreferences() for changing default settings
+		IEclipsePreferences defaultPreferences = getDefaultPreferences();
+		
+		// initialize preferences to their default
+		Iterator iterator = this.optionNames.iterator();
+		while (iterator.hasNext()) {
+		    String propertyName = (String) iterator.next();
+		    String value = defaultPreferences.get(propertyName, null);
+		    if (value != null) defaultOptions.put(propertyName, value);
+		}
+		// get encoding through resource plugin
+		defaultOptions.put(JavaCore.CORE_ENCODING, JavaCore.getEncoding());
+		// backward compatibility
+		addDeprecatedOptions(defaultOptions);
+		
+		return defaultOptions;
+	}
+	
 	/**
 	 * Get default eclipse preference for JavaCore plugin.
 	 */
@@ -1037,7 +1128,11 @@
 	 * For use by image builder and evaluation support only
 	 */
 	public Object getLastBuiltState(IProject project, IProgressMonitor monitor) {
-		if (!JavaProject.hasJavaNature(project)) return null; // should never be requested on non-Java projects
+		if (!JavaProject.hasJavaNature(project)) {
+			if (JavaBuilder.DEBUG)
+				System.out.println(project + " is not a Java project"); //$NON-NLS-1$
+			return null; // should never be requested on non-Java projects
+		}
 		PerProjectInfo info = getPerProjectInfo(project, true/*create if missing*/);
 		if (!info.triedRead) {
 			info.triedRead = true;
@@ -1052,6 +1147,56 @@
 		return info.savedState;
 	}
 
+	public String getOption(String optionName) {
+		
+		if (JavaCore.CORE_ENCODING.equals(optionName)){
+			return JavaCore.getEncoding();
+		}
+		// backward compatibility
+		if (isDeprecatedOption(optionName)) {
+			return JavaCore.ERROR;
+		}
+		String propertyName = optionName;
+		if (this.optionNames.contains(propertyName)){
+			IPreferencesService service = Platform.getPreferencesService();
+			String value =  service.get(optionName, null, this.preferencesLookup);
+			return value==null ? null : value.trim();
+		}
+		return null;
+	}
+	
+	public Hashtable getOptions() {
+
+		// return cached options if already computed
+		if (this.optionsCache != null) return new Hashtable(this.optionsCache);
+
+		// init
+		Hashtable options = new Hashtable(10);
+		IPreferencesService service = Platform.getPreferencesService();
+
+		// set options using preferences service lookup
+		Iterator iterator = optionNames.iterator();
+		while (iterator.hasNext()) {
+		    String propertyName = (String) iterator.next();
+		    String propertyValue = service.get(propertyName, null, this.preferencesLookup);
+		    if (propertyValue != null) {
+			    options.put(propertyName, propertyValue);
+		    }
+		}
+
+		// get encoding through resource plugin
+		options.put(JavaCore.CORE_ENCODING, JavaCore.getEncoding()); 
+
+		// backward compatibility
+		addDeprecatedOptions(options);
+
+		// store built map in cache
+		this.optionsCache = new Hashtable(options);
+
+		// return built map
+		return options;
+	}
+	
 	/*
 	 * Returns the per-project info for the given project. If specified, create the info if the info doesn't exist.
 	 */
@@ -1173,6 +1318,10 @@
 		}
 		return result;
 	}
+	
+	private File getVariableAndContainersFile() {
+		return JavaCore.getPlugin().getStateLocation().append("variablesAndContainers.dat").toFile(); //$NON-NLS-1$
+	}
 
 	/**
  	 * Returns the name of the variables for which an CP variable initializer is registered through an extension point
@@ -1248,11 +1397,18 @@
 			int primaryLength = primaryWCs == null ? 0 : primaryWCs.length;
 			int size = workingCopyToInfos.size(); // note size is > 0 otherwise pathToPerWorkingCopyInfos would be null
 			ICompilationUnit[] result = new ICompilationUnit[primaryLength + size];
+			int index = 0;
 			if (primaryWCs != null) {
-				System.arraycopy(primaryWCs, 0, result, 0, primaryLength);
+				for (int i = 0; i < primaryLength; i++) {
+					ICompilationUnit primaryWorkingCopy = primaryWCs[i];
+					ICompilationUnit workingCopy = new CompilationUnit((PackageFragment) primaryWorkingCopy.getParent(), primaryWorkingCopy.getElementName(), owner);
+					if (!workingCopyToInfos.containsKey(workingCopy))
+						result[index++] = primaryWorkingCopy;
+				}
+				if (index != primaryLength)
+					System.arraycopy(result, 0, result = new ICompilationUnit[index+size], 0, index);
 			}
 			Iterator iterator = workingCopyToInfos.values().iterator();
-			int index = primaryLength;
 			while(iterator.hasNext()) {
 				result[index++] = ((JavaModelManager.PerWorkingCopyInfo)iterator.next()).getWorkingCopy();
 			}
@@ -1260,6 +1416,13 @@
 		}		
 	}
 	
+	public JavaWorkspaceScope getWorkspaceScope() {
+		if (this.workspaceScope == null) {
+			this.workspaceScope = new JavaWorkspaceScope();
+		}
+		return this.workspaceScope;
+	}
+	
 	/**
 	 * Returns the open ZipFile at the given location. If the ZipFile
 	 * does not yet exist, it is created, opened, and added to the cache
@@ -1345,6 +1508,9 @@
 					paths.add(path);
 				}
 			}
+			/* TODO (frederic) put back when JDT/UI dummy project will be thrown away...
+			 * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=97524
+			 *
 			if (javaProject.equals(javaProjectToInit)) {
 				if (paths == null) {
 					paths = new HashSet();
@@ -1352,7 +1518,16 @@
 				}
 				paths.add(containerToInit);
 			}
+			*/
 		}
+		// TODO (frederic) remove following block when JDT/UI dummy project will be thrown away...
+		HashSet containerPaths = (HashSet) allContainerPaths.get(javaProjectToInit);
+		if (containerPaths == null) {
+			containerPaths = new HashSet();
+			allContainerPaths.put(javaProjectToInit, containerPaths);
+		}
+		containerPaths.add(containerToInit);
+		// end block
 		
 		// mark all containers as being initialized
 		this.containerInitializationInProgress.set(allContainerPaths);
@@ -1440,7 +1615,9 @@
 					stats.endRun();
 				}
 				if (!ok) {
-					containerPut(project, containerPath, null); // flush cache
+					// 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(
@@ -1562,6 +1739,14 @@
 	    return getClasspathBeingResolved().contains(project);
 	}
 	
+	/**
+	 * @deprecated
+	 */
+	private boolean isDeprecatedOption(String optionName) {
+		return JavaCore.COMPILER_PB_INVALID_IMPORT.equals(optionName)
+				|| JavaCore.COMPILER_PB_UNREACHABLE_CODE.equals(optionName);
+	}
+	
 	public void setClasspathBeingResolved(IJavaProject project, boolean classpathIsResolved) {
 	    if (classpathIsResolved) {
 	        getClasspathBeingResolved().add(project);
@@ -1571,7 +1756,6 @@
 	}
 
 	public void loadVariablesAndContainers() throws CoreException {
-
 		// backward compatibility, consider persistent property	
 		QualifiedName qName = new QualifiedName(JavaCore.PLUGIN_ID, "variables"); //$NON-NLS-1$
 		String xmlString = ResourcesPlugin.getWorkspace().getRoot().getPersistentProperty(qName);
@@ -1616,14 +1800,12 @@
 			if (xmlString != null){
 				ResourcesPlugin.getWorkspace().getRoot().setPersistentProperty(qName, null); // flush old one
 			}
-			
 		}
-		
-		// load variables and containers from preferences into cache
-		IEclipsePreferences preferences = getInstancePreferences();
 
-		// only get variable from preferences not set to their default
+		// backward compatibility, load variables and containers from preferences into cache
+		IEclipsePreferences preferences = getInstancePreferences();
 		try {
+			// only get variable from preferences not set to their default
 			String[] propertyNames = preferences.keys();
 			int variablePrefixLength = CP_VARIABLE_PREFERENCES_PREFIX.length();
 			for (int i = 0; i < propertyNames.length; i++){
@@ -1632,20 +1814,82 @@
 					String varName = propertyName.substring(variablePrefixLength);
 					String propertyValue = preferences.get(propertyName, null);
 					if (propertyValue != null) {
-						IPath varPath = new Path(propertyValue.trim());
+						String pathString = propertyValue.trim();
+						
+						if (CP_ENTRY_IGNORE.equals(pathString)) {
+							// cleanup old preferences
+							preferences.remove(propertyName); 
+							continue;
+						}
+						
+						// add variable to table
+						IPath varPath = new Path(pathString);
 						this.variables.put(varName, varPath); 
 						this.previousSessionVariables.put(varName, varPath);
 					}
-				}
-				if (propertyName.startsWith(CP_CONTAINER_PREFERENCES_PREFIX)){
+				} else if (propertyName.startsWith(CP_CONTAINER_PREFERENCES_PREFIX)){
 					String propertyValue = preferences.get(propertyName, null);
-					if (propertyValue != null)
+					if (propertyValue != null) {
+						// cleanup old preferences
+						preferences.remove(propertyName); 
+						
+						// recreate container
 						recreatePersistedContainer(propertyName, propertyValue, true/*add to container values*/);
+					}
 				}
 			}
 		} 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*/);
+					}
+				}
+			}
+		} 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
+				}
+			}
+		}
+
 		// override persisted values for variables which have a registered initializer
 		String[] registeredVariables = getRegisteredVariableNames();
 		for (int i = 0; i < registeredVariables.length; i++) {
@@ -1733,6 +1977,11 @@
 				e.printStackTrace();
 				throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, Platform.PLUGIN_ERROR, "Error reading last build state for project "+ project.getName(), e)); //$NON-NLS-1$
 			}
+		} else if (JavaBuilder.DEBUG) {
+			if (file == null)
+				System.out.println("Project does not exist: " + project); //$NON-NLS-1$
+			else
+				System.out.println("Build state file " + file.getPath() + " does not exist"); //$NON-NLS-1$ //$NON-NLS-2$
 		}
 		return null;
 	}
@@ -1742,44 +1991,47 @@
 		int index = propertyName.indexOf('|', containerPrefixLength);
 		if (containerString != null) containerString = containerString.trim();
 		if (index > 0) {
-			final String projectName = propertyName.substring(containerPrefixLength, index).trim();
-			JavaProject project = (JavaProject)getJavaModelManager().getJavaModel().getJavaProject(projectName);
-			if (!project.getProject().isAccessible()) return; // avoid leaking deleted project's persisted container
-			final IPath containerPath = new Path(propertyName.substring(index+1).trim());
-			
-			if (containerString == null || containerString.equals(CP_ENTRY_IGNORE)) {
-				getJavaModelManager().containerPut(project, containerPath, null);
-			} else {
-				final IClasspathEntry[] containerEntries = project.decodeClasspath(containerString, false, false);
-				if (containerEntries != null && containerEntries != JavaProject.INVALID_CLASSPATH) {
-					IClasspathContainer container = new IClasspathContainer() {
-						public IClasspathEntry[] getClasspathEntries() {
-							return containerEntries;
-						}
-						public String getDescription() {
-							return "Persisted container ["+containerPath+" for project ["+ projectName+"]"; //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
-						}
-						public int getKind() {
-							return 0; 
-						}
-						public IPath getPath() {
-							return containerPath;
-						}
-						public String toString() {
-							return getDescription();
-						}
+			String projectName = propertyName.substring(containerPrefixLength, index).trim();
+			IJavaProject project = getJavaModelManager().getJavaModel().getJavaProject(projectName);
+			IPath containerPath = new Path(propertyName.substring(index+1).trim());
+			recreatePersistedContainer(project, containerPath, containerString, addToContainerValues);
+		}
+	}
+	
+	private static void recreatePersistedContainer(final IJavaProject project, final IPath containerPath, String containerString, boolean addToContainerValues) {
+		if (!project.getProject().isAccessible()) return; // avoid leaking deleted project's persisted container	
+		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) {
+				IClasspathContainer container = new IClasspathContainer() {
+					public IClasspathEntry[] getClasspathEntries() {
+						return containerEntries;
+					}
+					public String getDescription() {
+						return "Persisted container ["+containerPath+" for project ["+ project.getElementName()+"]"; //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
+					}
+					public int getKind() {
+						return 0; 
+					}
+					public IPath getPath() {
+						return containerPath;
+					}
+					public String toString() {
+						return getDescription();
+					}
 
-					};
-					if (addToContainerValues) {
-						getJavaModelManager().containerPut(project, containerPath, container);
-					}
-					Map projectContainers = (Map)getJavaModelManager().previousSessionContainers.get(project);
-					if (projectContainers == null){
-						projectContainers = new HashMap(1);
-						getJavaModelManager().previousSessionContainers.put(project, projectContainers);
-					}
-					projectContainers.put(containerPath, container);
+				};
+				if (addToContainerValues) {
+					getJavaModelManager().containerPut(project, containerPath, container);
 				}
+				Map projectContainers = (Map)getJavaModelManager().previousSessionContainers.get(project);
+				if (projectContainers == null){
+					projectContainers = new HashMap(1);
+					getJavaModelManager().previousSessionContainers.put(project, projectContainers);
+				}
+				projectContainers.put(containerPath, container);
 			}
 		}
 	}
@@ -1884,6 +2136,11 @@
 		}
 	}
 	
+	public static final void doNotUse() {
+		// used by tests to simulate a startup
+		MANAGER = new JavaModelManager();
+	}
+	
 	/*
 	 * Resets the temporary cache for newly created elements to null.
 	 */
@@ -1954,46 +2211,94 @@
 			System.out.println(Messages.bind(Messages.build_saveStateComplete, String.valueOf(t))); 
 		}
 	}
-
+	
+	private void saveVariablesAndContainers() 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());
+			}
+			
+			// 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);
+		} finally {
+			if (out != null) {
+				try {
+					out.close();
+				} catch (IOException e) {
+					// nothing we can do: ignore
+				}
+			}
+		}
+	}
+	
 	/**
 	 * @see ISaveParticipant
 	 */
 	public void saving(ISaveContext context) throws CoreException {
 		
-	    // save container values on snapshot/full save
-		IJavaProject[] projects = getJavaModel().getJavaProjects();
-		IEclipsePreferences preferences = getInstancePreferences();
-		for (int i = 0, length = projects.length; i < length; i++) {
-		    IJavaProject project = projects[i];
-			// clone while iterating (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=59638)
-			Map projectContainers = containerClone(project);
-			if (projectContainers == null) continue;
-			for (Iterator keys = projectContainers.keySet().iterator(); keys.hasNext();) {
-			    IPath containerPath = (IPath) keys.next();
-			    IClasspathContainer container = (IClasspathContainer) projectContainers.get(containerPath);
-				String containerKey = CP_CONTAINER_PREFERENCES_PREFIX+project.getElementName() +"|"+containerPath;//$NON-NLS-1$
-				String containerString = CP_ENTRY_IGNORE;
-				try {
-					if (container != null) {
-						IClasspathEntry[] entries = container.getClasspathEntries();
-						containerString = ((JavaProject)project).encodeClasspath(
-								entries, 
-								null, 
-								false);
-					}
-				} catch(JavaModelException e){
-					// could not encode entry: leave it as CP_ENTRY_IGNORE
-					Util.log(e, "Could not persist container " + containerPath + " for project " + project.getElementName()); //$NON-NLS-1$ //$NON-NLS-2$
-				}
-				preferences.put(containerKey, containerString);
-			}
-		}
-		try {
-			preferences.flush();
-		} catch (BackingStoreException e) {
-			IStatus status = new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, IStatus.ERROR, "Problems while saving context", e); //$NON-NLS-1$
-			throw new CoreException(status);
-		}
+	    // save variable and container values on snapshot/full save
+		saveVariablesAndContainers();
 		
 		if (context.getKind() == ISaveContext.FULL_SAVE) {
 			// will need delta since this save (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=38658)
@@ -2002,7 +2307,10 @@
 			// clean up indexes on workspace full save
 			// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=52347)
 			IndexManager manager = this.indexManager;
-			if (manager != null) {
+			if (manager != null 
+					// don't force initialization of workspace scope as we could be shutting down
+					// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=93941)
+					&& this.workspaceScope != null) { 
 				manager.cleanUpIndexes();
 			}
 		}
@@ -2012,18 +2320,27 @@
 			if (!JavaProject.hasJavaNature(savedProject)) return; // ignore
 			PerProjectInfo info = getPerProjectInfo(savedProject, true /* create info */);
 			saveState(info, context);
+			info.rememberExternalLibTimestamps();
 			return;
 		}
-
+	
 		ArrayList vStats= null; // lazy initialized
-		for (Iterator iter =  this.perProjectInfos.values().iterator(); iter.hasNext();) {
-			try {
-				PerProjectInfo info = (PerProjectInfo) iter.next();
-				saveState(info, context);
-			} catch (CoreException e) {
-				if (vStats == null)
-					vStats= new ArrayList();
-				vStats.add(e.getStatus());
+		ArrayList values = null;
+		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());
+				}
 			}
 		}
 		if (vStats != null) {
@@ -2031,6 +2348,9 @@
 			vStats.toArray(stats);
 			throw new CoreException(new MultiStatus(JavaCore.PLUGIN_ID, IStatus.ERROR, stats, Messages.build_cannotSaveStates, null)); 
 		}
+		
+		// save external libs timestamps
+		this.deltaState.saveExternalLibTimeStamps();
 	}
 
 	/**
@@ -2108,11 +2428,134 @@
 			}
 		}
 	}
+	
+	public void setOptions(Hashtable newOptions) {
+		
+		try {
+			IEclipsePreferences defaultPreferences = getDefaultPreferences();
+			IEclipsePreferences instancePreferences = getInstancePreferences();
+
+			if (newOptions == null){
+				instancePreferences.clear();
+			} else {
+				Enumeration keys = newOptions.keys();
+				while (keys.hasMoreElements()){
+					String key = (String)keys.nextElement();
+					if (!this.optionNames.contains(key)) continue; // unrecognized option
+					if (key.equals(JavaCore.CORE_ENCODING)) continue; // skipped, contributed by resource prefs
+					String value = (String)newOptions.get(key);
+					String defaultValue = defaultPreferences.get(key, null);
+					if (defaultValue != null && defaultValue.equals(value)) {
+						instancePreferences.remove(key);
+					} else {
+						instancePreferences.put(key, value);
+					}
+				}
+			}
+
+			// persist options
+			instancePreferences.flush();
+			
+			// update cache
+			this.optionsCache = newOptions==null ? null : new Hashtable(newOptions);
+		} catch (BackingStoreException e) {
+			// ignore
+		}
+	}
+		
+	public void startup() throws CoreException {
+		try {
+			configurePluginDebugOptions();
+
+			// request state folder creation (workaround 19885)
+			JavaCore.getPlugin().getStateLocation();
+
+			// Initialize eclipse preferences
+			initializePreferences();
+
+			// Listen to preference changes
+			Preferences.IPropertyChangeListener propertyListener = new Preferences.IPropertyChangeListener() {
+				public void propertyChange(Preferences.PropertyChangeEvent event) {
+					JavaModelManager.this.optionsCache = null;
+				}
+			};
+			JavaCore.getPlugin().getPluginPreferences().addPropertyChangeListener(propertyListener);
+
+			// retrieve variable values
+			loadVariablesAndContainers();
+
+			final IWorkspace workspace = ResourcesPlugin.getWorkspace();
+			workspace.addResourceChangeListener(
+				this.deltaState,
+				IResourceChangeEvent.PRE_BUILD
+					| IResourceChangeEvent.POST_BUILD
+					| IResourceChangeEvent.POST_CHANGE
+					| IResourceChangeEvent.PRE_DELETE
+					| IResourceChangeEvent.PRE_CLOSE);
+
+			startIndexing();
+			
+			// process deltas since last activated in indexer thread so that indexes are up-to-date.
+			// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=38658
+			Job processSavedState = new Job(Messages.savedState_jobName) { 
+				protected IStatus run(IProgressMonitor monitor) {
+					try {
+						// add save participant and process delta atomically
+						// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=59937
+						workspace.run(
+							new IWorkspaceRunnable() {
+								public void run(IProgressMonitor progress) throws CoreException {
+									ISavedState savedState = workspace.addSaveParticipant(JavaCore.getJavaCore(), JavaModelManager.this);
+									if (savedState != null) {
+										// the event type coming from the saved state is always POST_AUTO_BUILD
+										// force it to be POST_CHANGE so that the delta processor can handle it
+										JavaModelManager.this.deltaState.getDeltaProcessor().overridenEventType = IResourceChangeEvent.POST_CHANGE;
+										savedState.processResourceChangeEvents(JavaModelManager.this.deltaState);
+									}
+								}
+							},
+							monitor);
+					} catch (CoreException e) {
+						return e.getStatus();
+					}
+					return Status.OK_STATUS;
+				}
+			};
+			processSavedState.setSystem(true);
+			processSavedState.setPriority(Job.SHORT); // process asap
+			processSavedState.schedule();
+		} catch (RuntimeException e) {
+			shutdown();
+			throw e;
+		}
+	}
+
+	/**
+	 * Initiate the background indexing process.
+	 * This should be deferred after the plugin activation.
+	 */
+	private void startIndexing() {
+		getIndexManager().reset();
+	}
 
 	public void shutdown () {
+		JavaCore javaCore = JavaCore.getJavaCore();
+		javaCore.savePluginPreferences();
+		IWorkspace workspace = ResourcesPlugin.getWorkspace();
+		workspace.removeResourceChangeListener(this.deltaState);
+		workspace.removeSaveParticipant(javaCore);
+	
 		if (this.indexManager != null){ // no more indexing
 			this.indexManager.shutdown();
 		}
+		
+		// wait for the initialization job to finish
+		try {
+			Platform.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
 	}
 		
@@ -2327,10 +2770,12 @@
 			// discard obsoleted information about previous session
 			this.previousSessionVariables.remove(variableName);
 		}
-
+	
 		String variableKey = CP_VARIABLE_PREFERENCES_PREFIX+variableName;
-		String variableString = variablePath == null ? CP_ENTRY_IGNORE : variablePath.toString();
-		getInstancePreferences().put(variableKey, variableString);
+		if (variablePath == null)
+			getInstancePreferences().remove(variableKey);
+		else
+			getInstancePreferences().put(variableKey, variablePath.toString());
 		try {
 			getInstancePreferences().flush();
 		} catch (BackingStoreException e) {
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 989536d..a5ea949 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
@@ -11,15 +11,6 @@
 package org.eclipse.jdt.internal.core;
 
 import java.io.*;
-import java.io.BufferedInputStream;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStreamWriter;
-import java.io.StringReader;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -337,8 +328,6 @@
 			throw newNotPresentException();
 		}
 		
-		IWorkspace workspace = ResourcesPlugin.getWorkspace();
-		IWorkspaceRoot wRoot = workspace.getRoot();
 		// cannot refresh cp markers on opening (emulate cp check on startup) since can create deadlocks (see bug 37274)
 		IClasspathEntry[] resolvedClasspath = getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
 
@@ -346,23 +335,11 @@
 		info.setChildren(computePackageFragmentRoots(resolvedClasspath, false, null /*no reverse map*/));	
 		
 		// remember the timestamps of external libraries the first time they are looked up
-		for (int i = 0, length = resolvedClasspath.length; i < length; i++) {
-			IClasspathEntry entry = resolvedClasspath[i];
-			if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
-				IPath path = entry.getPath();
-				Object target = JavaModel.getTarget(wRoot, path, true);
-				if (target instanceof java.io.File) {
-					Map externalTimeStamps = JavaModelManager.getJavaModelManager().deltaState.externalTimeStamps;
-					if (externalTimeStamps.get(path) == null) {
-						long timestamp = DeltaProcessor.getTimeStamp((java.io.File)target);
-						externalTimeStamps.put(path, new Long(timestamp));							
-					}
-				}
-			}
-		}			
+		getPerProjectInfo().rememberExternalLibTimestamps();			
 
 		return true;
 	}
+
 	protected void closing(Object info) {
 		
 		// forget source attachment recommendations
@@ -550,7 +527,7 @@
 						root = getPackageFragmentRoot((IResource) target);
 					} else {
 						// external target - only JARs allowed
-						if (((java.io.File)target).isFile() && (org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(entryPath.lastSegment()))) {
+						if (JavaModel.isFile(target) && (org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(entryPath.lastSegment()))) {
 							root = new JarPackageFragmentRoot(entryPath, this);
 						}
 					}
@@ -863,7 +840,7 @@
 			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()})))); 
+							Messages.bind(Messages.classpath_xmlFormatError, new String[] {this.getElementName(), e.getMessage()}))); 
 			}
 			if (logProblems) {
 				Util.log(e, 
@@ -876,7 +853,7 @@
 			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()})))); 
+						Messages.bind(Messages.classpath_illegalEntryInClasspathFile, new String[] {this.getElementName(), e.getMessage()}))); 
 			}
 			if (logProblems) {
 				Util.log(e, 
@@ -928,7 +905,7 @@
 		try {
 			ByteArrayOutputStream s = new ByteArrayOutputStream();
 			OutputStreamWriter writer = new OutputStreamWriter(s, "UTF8"); //$NON-NLS-1$
-			XMLWriter xmlWriter = new XMLWriter(writer);
+			XMLWriter xmlWriter = new XMLWriter(writer, this);
 			
 			xmlWriter.startTag(ClasspathEntry.TAG_CLASSPATH, indent);
 			for (int i = 0; i < classpath.length; ++i) {
@@ -1603,7 +1580,7 @@
 			Iterator propertyNames = projectOptions.keySet().iterator();
 			while (propertyNames.hasNext()) {
 				String propertyName = (String) propertyNames.next();
-				String propertyValue = (String) perProjectInfo.options.get(propertyName);
+				String propertyValue = (String) projectOptions.get(propertyName);
 				if (propertyValue != null && optionNames.contains(propertyName)){
 					options.put(propertyName, propertyValue.trim());
 				}
@@ -2135,6 +2112,26 @@
 				// fallback to default
 				property = new String(bytes);
 			}
+		} 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
+			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);
+				}
+			}
 		}
 		return property;
 	}
@@ -2242,41 +2239,102 @@
 	 * @see IJavaProject
 	 */
 	public boolean isOnClasspath(IJavaElement element) {
-		IPath path = element.getPath();
-		IClasspathEntry[] classpath;
+		IClasspathEntry[] rawClasspath;
 		try {
-			classpath = getResolvedClasspath(true/*ignoreUnresolvedEntry*/, false/*don't generateMarkerOnError*/, false/*don't returnResolutionInProgress*/);
+			rawClasspath = getRawClasspath();
 		} catch(JavaModelException e){
 			return false; // not a Java project
 		}
+		int elementType = element.getElementType();
+		boolean isPackageFragmentRoot = false;
 		boolean isFolderPath = false;
-		switch (element.getElementType()) {
-			case IJavaElement.PACKAGE_FRAGMENT_ROOT:
-				// package fragment roots must match exactly entry pathes (no exclusion there)
-				for (int i = 0; i < classpath.length; i++) {
-					IClasspathEntry entry = classpath[i];
-					IPath entryPath = entry.getPath();
-					if (entryPath.equals(path)) {
-						return true;
-					}
-				}
+		boolean isSource = false;
+		switch (elementType) {
+			case IJavaElement.JAVA_MODEL:
 				return false;
-				
+			case IJavaElement.JAVA_PROJECT:
+				break;
+			case IJavaElement.PACKAGE_FRAGMENT_ROOT:
+				isPackageFragmentRoot = true;
+				break;
 			case IJavaElement.PACKAGE_FRAGMENT:
-				if (!((IPackageFragmentRoot)element.getParent()).isArchive()) {
-					// ensure that folders are only excluded if all of their children are excluded
-					isFolderPath = true;
-				}
+				isFolderPath = !((IPackageFragmentRoot)element.getParent()).isArchive();
+				break;
+			case IJavaElement.COMPILATION_UNIT:
+				isSource = true;
+				break;
+			default:
+				isSource = element.getAncestor(IJavaElement.COMPILATION_UNIT) != null;
 				break;
 		}
-		for (int i = 0; i < classpath.length; i++) {
-			IClasspathEntry entry = classpath[i];
-			IPath entryPath = entry.getPath();
-			if (entryPath.isPrefixOf(path) 
-					&& !Util.isExcluded(path, ((ClasspathEntry)entry).fullInclusionPatternChars(), ((ClasspathEntry)entry).fullExclusionPatternChars(), isFolderPath)) {
-				return true;
+		IPath elementPath = element.getPath();
+		
+		// first look at unresolved entries
+		int length = rawClasspath.length;
+		for (int i = 0; i < length; i++) {
+			IClasspathEntry entry = rawClasspath[i];
+			switch (entry.getEntryKind()) {
+				case IClasspathEntry.CPE_LIBRARY:
+				case IClasspathEntry.CPE_PROJECT:
+				case IClasspathEntry.CPE_SOURCE:
+					if (isOnClasspathEntry(elementPath, isFolderPath, isPackageFragmentRoot, entry))
+						return true;
+					break;
 			}
 		}
+		
+		// no need to go further for compilation units and elements inside a compilation unit
+		// it can only be in a source folder, thus on the raw classpath
+		if (isSource)
+			return false;
+		
+		// then look at resolved entries
+		for (int i = 0; i < length; i++) {
+			IClasspathEntry rawEntry = rawClasspath[i];
+			switch (rawEntry.getEntryKind()) {
+				case IClasspathEntry.CPE_CONTAINER:
+					IClasspathContainer container;
+					try {
+						container = JavaCore.getClasspathContainer(rawEntry.getPath(), this);
+					} catch (JavaModelException e) {
+						break;
+					}
+					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++){
+						IClasspathEntry resolvedEntry = containerEntries[j];
+						if (isOnClasspathEntry(elementPath, isFolderPath, isPackageFragmentRoot, resolvedEntry))
+							return true;
+					}					
+					break;
+				case IClasspathEntry.CPE_VARIABLE:
+					IClasspathEntry resolvedEntry = JavaCore.getResolvedClasspathEntry(rawEntry);
+					if (resolvedEntry == null) 
+						break;
+					if (isOnClasspathEntry(elementPath, isFolderPath, isPackageFragmentRoot, resolvedEntry))
+						return true;
+					break;
+			}
+		}
+		
+		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;
 	}
 
@@ -2349,8 +2407,9 @@
 	 * @see IJavaProject#newEvaluationContext()
 	 */
 	public IEvaluationContext newEvaluationContext() {
-
-		return new EvaluationContextWrapper(new EvaluationContext(), this);
+		EvaluationContext context = new EvaluationContext();
+		context.setLineSeparator(Util.getLineSeparator(null/*no existing source*/, this));
+		return new EvaluationContextWrapper(context, this);
 	}
 
 	/*
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 b7cd37e..c70d140 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
@@ -180,7 +180,7 @@
         return true;
     }
 	
-	protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
+	protected void toStringInfo(int tab, StringBuffer buffer, Object info, boolean showResolvedInfo) {
 		buffer.append(this.tabString(tab));
 		if (info != NO_INFO) {
 			buffer.append(Signature.toString(this.getTypeSignature()));
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 504a766..da25a32 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
@@ -124,11 +124,13 @@
 	public long timeSpentInSeekTypesInBinaryPackage = 0;
 
 	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$
+			start = System.currentTimeMillis();
 		}
 		this.packageFragmentRoots = packageFragmentRoots;
 		try {
@@ -138,7 +140,6 @@
 		}
 		if (workingCopies != null) {
 			this.unitsToLookInside = new HashMap();
-			HashSet visited = new HashSet();
 			for (int i = 0, length = workingCopies.length; i < length; i++) {
 				ICompilationUnit workingCopy = workingCopies[i];
 				PackageFragment pkg = (PackageFragment) workingCopy.getParent();
@@ -171,26 +172,37 @@
 				
 				// add root of package fragment to cache
 				IPackageFragmentRoot root = (IPackageFragmentRoot) pkg.getParent();
-				if (visited.contains(root)) continue;
 				String[] pkgName = pkg.names;
 				Object existing = this.packageFragments.get(pkgName);
 				if (existing == null) {
 					this.packageFragments.put(pkgName, root);
 				} else {
 					if (existing instanceof PackageFragmentRoot) {
-						this.packageFragments.put(pkgName, new IPackageFragmentRoot[] {(PackageFragmentRoot) existing, root});
+						if (!existing.equals(root))
+							this.packageFragments.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;
-						this.packageFragments.put(pkgName, roots);
+						boolean containsRoot = false;
+						for (int j = 0; j < rootLength; j++) {
+							if (roots[j].equals(root)) {
+								containsRoot = true;
+								break;
+							}
+						}
+						if (containsRoot) {
+							System.arraycopy(roots, 0, roots = new IPackageFragmentRoot[rootLength+1], 0, rootLength);
+							roots[rootLength] = root;
+							this.packageFragments.put(pkgName, roots);
+						}
 					}
 				}
-				visited.add(root);
 			}
 		}
 		this.rootToResolvedEntries = rootToResolvedEntries;
+        if (VERBOSE) {
+            System.out.println(Thread.currentThread() + " -> spent: " + (start - System.currentTimeMillis()) + "ms");  //$NON-NLS-1$ //$NON-NLS-2$
+        }
 	}
 
 	/**
@@ -757,6 +769,7 @@
 					seekTypesInBinaryPackage(matchName, pkg, partialMatch, acceptFlags, requestor);
 					break;
 				case IPackageFragmentRoot.K_SOURCE :
+					matchName= matchName.replace('$', '.');
 					seekTypesInSourcePackage(matchName, pkg, partialMatch, acceptFlags, requestor);
 					break;
 				default :
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 f7a44dd..1de6701 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
@@ -11,7 +11,6 @@
 package org.eclipse.jdt.internal.core;
 
 import org.eclipse.jdt.core.BindingKey;
-import org.eclipse.jdt.core.Flags;
 import org.eclipse.jdt.core.ICompilationUnit;
 import org.eclipse.jdt.core.IField;
 import org.eclipse.jdt.core.IJavaElement;
@@ -64,34 +63,25 @@
 		return this.name;
 	}
 	
-	protected String getKey(IField field, boolean withAccessFlags, boolean forceOpen) throws JavaModelException {
+	protected String getKey(IField field, boolean forceOpen) throws JavaModelException {
 		StringBuffer key = new StringBuffer();
 		
 		// declaring class 
-		String declaringKey = getKey((IType) field.getParent(), false/*without access flags*/, forceOpen);
+		String declaringKey = getKey((IType) field.getParent(), forceOpen);
 		key.append(declaringKey);
 		
 		// field name
 		key.append('.');
 		key.append(field.getElementName());
-		
-		// flags
-		if (withAccessFlags) {
-			key.append('^');
-			if (forceOpen) 
-				key.append(field.getFlags());
-			else
-				key.append(Flags.AccDefault);
-		}
 
 		return key.toString();
 	}
 	
-	protected String getKey(IMethod method, boolean withAccessFlags, boolean forceOpen) throws JavaModelException {
+	protected String getKey(IMethod method, boolean forceOpen) throws JavaModelException {
 		StringBuffer key = new StringBuffer();
 		
 		// declaring class 
-		String declaringKey = getKey((IType) method.getParent(), false/*without access flags*/, forceOpen);
+		String declaringKey = getKey((IType) method.getParent(), forceOpen);
 		key.append(declaringKey);
 		
 		// selector
@@ -112,19 +102,10 @@
 		else
 			key.append('V');
 		
-		// flags
-		if (withAccessFlags) {
-			key.append('^');
-			if (forceOpen)
-				key.append(method.getFlags());
-			else
-				key.append(Flags.AccDefault); // cannot get the flags without opening the element		
-		}
-		
 		return key.toString();
 	}
 	
-	protected String getKey(IType type, boolean withAccessFlags, boolean forceOpen) throws JavaModelException {
+	protected String getKey(IType type, boolean forceOpen) throws JavaModelException {
 		StringBuffer key = new StringBuffer();
 		key.append('L');
 		String packageName = type.getPackageFragment().getElementName();
@@ -147,13 +128,6 @@
 		}
 		key.append(typeQualifiedName);
 		key.append(';');
-		if (withAccessFlags) {
-			key.append('^');
-			if (forceOpen)
-				key.append(type.getFlags());
-			else
-				key.append(Flags.AccDefault);
-		}
 		return key.toString();
 	}
 
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageDeclaration.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageDeclaration.java
index 1172955..4d31c65 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageDeclaration.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageDeclaration.java
@@ -55,7 +55,7 @@
 /**
  * @private Debugging purposes
  */
-protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
+protected void toStringInfo(int tab, StringBuffer buffer, Object info, boolean showResolvedInfo) {
 	buffer.append(this.tabString(tab));
 	buffer.append("package "); //$NON-NLS-1$
 	toStringName(buffer);
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 62ad20b..f2065fa 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
@@ -415,7 +415,7 @@
 /**
  * Debugging purposes
  */
-protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
+protected void toStringInfo(int tab, StringBuffer buffer, Object info, boolean showResolvedInfo) {
 	buffer.append(this.tabString(tab));
 	if (this.names.length == 0) {
 		buffer.append("<default>"); //$NON-NLS-1$
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 e9dda69..0896050 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
@@ -374,8 +374,8 @@
 						return entry;
 					}
 				} else if (target instanceof java.io.File){
-					java.io.File file = (java.io.File) target;
-					if (file.isFile()) {
+					java.io.File file = JavaModel.getFile(target);
+					if (file != null) {
 						if (org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(file.getName())){
 							return entry;
 						}
@@ -820,12 +820,12 @@
 /**
  * @private Debugging purposes
  */
-protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
+protected void toStringInfo(int tab, StringBuffer buffer, Object info, boolean showResolvedInfo) {
 	buffer.append(this.tabString(tab));
 	IPath path = getPath();
 	if (getJavaProject().getElementName().equals(path.segment(0))) {
 	    if (path.segmentCount() == 1) {
-	buffer.append("<project root>"); //$NON-NLS-1$
+			buffer.append("<project root>"); //$NON-NLS-1$
 	    } else {
 			buffer.append(path.removeFirstSegments(1).makeRelative());
 	    }
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 fb01686..3e24250 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
@@ -43,10 +43,12 @@
 	/**
 	 * @private Debugging purposes
 	 */
-	protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
-		super.toStringInfo(tab, buffer, info);
-		buffer.append(" {key="); //$NON-NLS-1$
-		buffer.append(this.uniqueKey);
-		buffer.append("}"); //$NON-NLS-1$
+	protected void toStringInfo(int tab, StringBuffer buffer, Object info, boolean showResolvedInfo) {
+		super.toStringInfo(tab, buffer, info, showResolvedInfo);
+		if (showResolvedInfo) {
+			buffer.append(" {key="); //$NON-NLS-1$
+			buffer.append(this.uniqueKey);
+			buffer.append("}"); //$NON-NLS-1$
+		}
 	}
 }
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 3014dc9..5c68ee4 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
@@ -40,10 +40,12 @@
 	/**
 	 * @private Debugging purposes
 	 */
-	protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
-		super.toStringInfo(tab, buffer, info);
-		buffer.append(" {key="); //$NON-NLS-1$
-		buffer.append(this.uniqueKey);
-		buffer.append("}"); //$NON-NLS-1$
+	protected void toStringInfo(int tab, StringBuffer buffer, Object info, boolean showResolvedInfo) {
+		super.toStringInfo(tab, buffer, info, showResolvedInfo);
+		if (showResolvedInfo) {
+			buffer.append(" {key="); //$NON-NLS-1$
+			buffer.append(this.uniqueKey);
+			buffer.append("}"); //$NON-NLS-1$
+		}
 	}
 }
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 7f31640..90b3553 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
@@ -49,10 +49,12 @@
 	/**
 	 * @private Debugging purposes
 	 */
-	protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
-		super.toStringInfo(tab, buffer, info);
-		buffer.append(" {key="); //$NON-NLS-1$
-		buffer.append(this.uniqueKey);
-		buffer.append("}"); //$NON-NLS-1$
+	protected void toStringInfo(int tab, StringBuffer buffer, Object info, boolean showResolvedInfo) {
+		super.toStringInfo(tab, buffer, info, showResolvedInfo);
+		if (showResolvedInfo) {
+			buffer.append(" {key="); //$NON-NLS-1$
+			buffer.append(this.uniqueKey);
+			buffer.append("}"); //$NON-NLS-1$
+		}
 	}
 }
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 0c027fd..ec7e24d 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
@@ -43,10 +43,12 @@
 	/**
 	 * @private Debugging purposes
 	 */
-	protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
-		super.toStringInfo(tab, buffer, info);
-		buffer.append(" {key="); //$NON-NLS-1$
-		buffer.append(this.uniqueKey);
-		buffer.append("}"); //$NON-NLS-1$
+	protected void toStringInfo(int tab, StringBuffer buffer, Object info, boolean showResolvedInfo) {
+		super.toStringInfo(tab, buffer, info, showResolvedInfo);
+		if (showResolvedInfo) {
+			buffer.append(" {key="); //$NON-NLS-1$
+			buffer.append(this.uniqueKey);
+			buffer.append("}"); //$NON-NLS-1$
+		}
 	}
 }
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 c9d8e45..3ba8dba 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
@@ -41,10 +41,12 @@
 	/**
 	 * @private Debugging purposes
 	 */
-	protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
-		super.toStringInfo(tab, buffer, info);
-		buffer.append(" {key="); //$NON-NLS-1$
-		buffer.append(this.uniqueKey);
-		buffer.append("}"); //$NON-NLS-1$
+	protected void toStringInfo(int tab, StringBuffer buffer, Object info, boolean showResolvedInfo) {
+		super.toStringInfo(tab, buffer, info, showResolvedInfo);
+		if (showResolvedInfo) {
+			buffer.append(" {key="); //$NON-NLS-1$
+			buffer.append(this.uniqueKey);
+			buffer.append("}"); //$NON-NLS-1$
+		}
 	}
 }
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 9d2f0a3..b61905c 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
@@ -49,10 +49,12 @@
 	/**
 	 * @private Debugging purposes
 	 */
-	protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
-		super.toStringInfo(tab, buffer, info);
-		buffer.append(" {key="); //$NON-NLS-1$
-		buffer.append(this.uniqueKey);
-		buffer.append("}"); //$NON-NLS-1$
+	protected void toStringInfo(int tab, StringBuffer buffer, Object info, boolean showResolvedInfo) {
+		super.toStringInfo(tab, buffer, info, showResolvedInfo);
+		if (showResolvedInfo) {
+			buffer.append(" {key="); //$NON-NLS-1$
+			buffer.append(this.uniqueKey);
+			buffer.append("}"); //$NON-NLS-1$
+		}
 	}
 }
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 6dab364..4da06fa 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
@@ -101,7 +101,7 @@
 					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.getParent().getElementName().toCharArray();
+						char[] classFileChars = type.getElementName().toCharArray();
 						accessRestriction = accessRuleSet.getViolatedRestriction(CharOperation.concatWith(packageChars, classFileChars, '/'));
 					}
 				}
@@ -205,7 +205,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 ISearchRequestor storage) {
+	public void findTypes(char[] prefix, final boolean findMembers, final ISearchRequestor storage) {
 
 		/*
 			if (true){
@@ -271,9 +271,9 @@
 				public void acceptType(int modifiers, char[] packageName, char[] simpleTypeName, char[][] enclosingTypeNames, String path, AccessRestriction access) {
 					if (excludePath != null && excludePath.equals(path))
 						return;
-					if (enclosingTypeNames != null && enclosingTypeNames.length > 0)
+					if (!findMembers && enclosingTypeNames != null && enclosingTypeNames.length > 0)
 						return; // accept only top level types
-					storage.acceptType(packageName, simpleTypeName, modifiers, access);
+					storage.acceptType(packageName, simpleTypeName, enclosingTypeNames, modifiers, access);
 				}
 			};
 			try {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SearchableEnvironmentRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SearchableEnvironmentRequestor.java
index 0346a12..5800cce 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SearchableEnvironmentRequestor.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SearchableEnvironmentRequestor.java
@@ -107,12 +107,12 @@
 				if (accessRuleSet != null) {
 					// TODO (philippe) improve char[] <-> String conversions to avoid performing them on the fly
 					char[][] packageChars = CharOperation.splitOn('.', packageName);
-					char[] fileChars = type.getParent().getElementName().toCharArray();
-					accessRestriction = accessRuleSet.getViolatedRestriction(CharOperation.concatWith(packageChars, fileChars, '/'));
+					char[] fileWithoutExtension = type.getElementName().toCharArray();
+					accessRestriction = accessRuleSet.getViolatedRestriction(CharOperation.concatWith(packageChars, fileWithoutExtension, '/'));
 				}
 			}
 		}
-		this.requestor.acceptType(packageName, type.getElementName().toCharArray(), type.getFlags(), accessRestriction);
+		this.requestor.acceptType(packageName, type.getElementName().toCharArray(), null, type.getFlags(), accessRestriction);
 	} catch (JavaModelException jme) {
 		// ignore
 	}
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 153d2e2..53e7c13 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
@@ -13,6 +13,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.Iterator;
 import java.util.List;
 
 import org.eclipse.jdt.core.IBuffer;
@@ -26,12 +27,16 @@
 import org.eclipse.jdt.core.dom.ASTNode;
 import org.eclipse.jdt.core.dom.ASTParser;
 import org.eclipse.jdt.core.dom.ASTVisitor;
+import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
 import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration;
 import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
+import org.eclipse.jdt.core.dom.BodyDeclaration;
+import org.eclipse.jdt.core.dom.EnumConstantDeclaration;
 import org.eclipse.jdt.core.dom.EnumDeclaration;
 import org.eclipse.jdt.core.dom.TypeDeclaration;
 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
 import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
+import org.eclipse.jdt.core.util.CompilationUnitSorter;
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.core.util.Messages;
 import org.eclipse.jface.text.BadLocationException;
@@ -49,17 +54,21 @@
 	
 	Comparator comparator;
 	int[] positions;
+    int apiLevel;
 	
 	/**
 	 * Constructor for SortElementsOperation.
+     * 
+     * @param level the AST API level; one of the AST LEVEL constants
 	 * @param elements
 	 * @param positions
 	 * @param comparator
 	 */
-	public SortElementsOperation(IJavaElement[] elements, int[] positions, Comparator comparator) {
+	public SortElementsOperation(int level, IJavaElement[] elements, int[] positions, Comparator comparator) {
 		super(elements);
 		this.comparator = comparator;
-		this.positions = positions;
+        this.positions = positions;
+        this.apiLevel = level;
 	}
 
 	/**
@@ -100,12 +109,62 @@
 	 */
 	private String processElement(ICompilationUnit unit, char[] source) {
 		CompilerOptions options = new CompilerOptions(unit.getJavaProject().getOptions(true));
-		ASTParser parser = ASTParser.newParser(AST.JLS3);
+		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;
@@ -190,7 +249,7 @@
 					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();
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 33af54e..dc936e7 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
@@ -98,7 +98,7 @@
  */
 public String getKey() {
 	try {
-		return getKey(this, org.eclipse.jdt.internal.compiler.lookup.Binding.USE_ACCESS_FLAGS_IN_BINDING_KEY/*with access flags*/, false/*don't open*/);
+		return getKey(this, false/*don't open*/);
 	} catch (JavaModelException e) {
 		// happen only if force open is true
 		return null;
@@ -147,7 +147,7 @@
 /**
  * @private Debugging purposes
  */
-protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
+protected void toStringInfo(int tab, StringBuffer buffer, Object info, boolean showResolvedInfo) {
 	buffer.append(this.tabString(tab));
 	if (info == null) {
 		toStringName(buffer);
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 23bf465..23fdcae 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
@@ -13,11 +13,15 @@
 import java.io.File;
 import java.io.FilenameFilter;
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.Set;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
@@ -36,6 +40,7 @@
 import org.eclipse.jdt.core.IPackageFragmentRoot;
 import org.eclipse.jdt.core.ISourceRange;
 import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.ITypeParameter;
 import org.eclipse.jdt.core.JavaConventions;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.Signature;
@@ -78,7 +83,7 @@
 	 * the zip (empty specifies the default root). <code>null</code> is
 	 * not a valid root path.
 	 */
-	protected HashSet rootPaths;
+	protected ArrayList rootPaths;
 
 	/**
 	 * The binary type source is being mapped for
@@ -94,7 +99,7 @@
 	 * the zip (empty specifies the default root). <code>null</code> is
 	 * not a valid root path.
 	 */
-	protected String rootPath;
+	protected String rootPath = ""; //$NON-NLS-1$
 
 	/**
 	 * Used for efficiency
@@ -199,7 +204,7 @@
 			// use no encoding
 		}
 		if (rootPath != null) {
-			this.rootPaths = new HashSet();
+			this.rootPaths = new ArrayList();
 			this.rootPaths.add(rootPath);
 		}
 		this.sourcePath = sourcePath;
@@ -306,9 +311,7 @@
 	}
 	
 	private void computeAllRootPaths(IPackageFragmentRoot root) {
-		if (this.rootPaths == null) {
-			this.rootPaths = new HashSet();
-		}
+		final HashSet tempRoots = new HashSet();
 		long time = 0;
 		if (VERBOSE) {
 			System.out.println("compute all root paths for " + root.getElementName()); //$NON-NLS-1$
@@ -330,9 +333,11 @@
 						int index = entryName.indexOf('/');
 						if (index != -1 && Util.isClassFileName(entryName)) {
 							String firstLevelPackageName = entryName.substring(0, index);
-							IStatus status = JavaConventions.validatePackageName(firstLevelPackageName);
-							if (status.isOK() || status.getSeverity() == IStatus.WARNING) {
-								firstLevelPackageNames.add(firstLevelPackageName);
+							if (!firstLevelPackageNames.contains(firstLevelPackageName)) {
+								IStatus status = JavaConventions.validatePackageName(firstLevelPackageName);
+								if (status.isOK() || status.getSeverity() == IStatus.WARNING) {
+									firstLevelPackageNames.add(firstLevelPackageName);
+								}
 							}
 						} else if (Util.isClassFileName(entryName)) {
 							containsADefaultPackage = true;
@@ -393,15 +398,15 @@
 						if (segmentCount > 1) {
 							loop: for (int i = 0, max = path.segmentCount() - 1; i < max; i++) {
 								if (firstLevelPackageNames.contains(path.segment(i))) {
-									this.rootPaths.add(path.uptoSegment(i).toString());
+									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)
 								}
 								if (i == max - 1 && containsADefaultPackage) {
-									this.rootPaths.add(path.uptoSegment(max).toString());
+									tempRoots.add(path.uptoSegment(max));
 								}
 							}
 						} else if (containsADefaultPackage) {
-							this.rootPaths.add(""); //$NON-NLS-1$
+							tempRoots.add(new Path("")); //$NON-NLS-1$
 						}
 					}
 				}
@@ -414,23 +419,54 @@
 			Object target = JavaModel.getTarget(ResourcesPlugin.getWorkspace().getRoot(), this.sourcePath, true);
 			if (target instanceof IResource) {
 				if (target instanceof IContainer) {
-					computeRootPath((IContainer)target, firstLevelPackageNames, containsADefaultPackage);
+					computeRootPath((IContainer)target, firstLevelPackageNames, containsADefaultPackage, tempRoots);
 				}
 			} else if (target instanceof File) {
 				File file = (File)target;
 				if (file.isDirectory()) {
-					computeRootPath(file, firstLevelPackageNames, containsADefaultPackage);
+					computeRootPath(file, firstLevelPackageNames, containsADefaultPackage, tempRoots);
 				}
 			}
 		}
-		if (VERBOSE) {
-			System.out.println("Found " + this.rootPaths.size() + " root paths");	//$NON-NLS-1$ //$NON-NLS-2$
-			System.out.println("Spent " + (System.currentTimeMillis() - time) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
+		int size = tempRoots.size();
+		if (this.rootPaths != null) {
+			for (Iterator iterator = this.rootPaths.iterator(); iterator.hasNext(); ) {
+				tempRoots.add(new Path((String) iterator.next()));
+			}
+			this.rootPaths.clear();
+		} else {
+			this.rootPaths = new ArrayList(size);
+		}
+		size = tempRoots.size();
+		if (size > 0) {
+			ArrayList sortedRoots = new ArrayList(tempRoots);
+			if (size > 1) {
+				Collections.sort(sortedRoots, new Comparator() {
+					public int compare(Object o1, Object o2) {
+						IPath path1 = (IPath) o1;
+						IPath path2 = (IPath) o2;
+						return path1.segmentCount() - path2.segmentCount();
+					}
+				});
+			}
+			for (Iterator iter = sortedRoots.iterator(); iter.hasNext();) {
+				IPath path = (IPath) iter.next();
+				this.rootPaths.add(path.toString());
+			}
 		}
 		this.areRootPathsComputed = true;
+		if (VERBOSE) {
+			System.out.println("Spent " + (System.currentTimeMillis() - time) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
+			System.out.println("Found " + size + " root paths");	//$NON-NLS-1$ //$NON-NLS-2$
+			int i = 0;
+			for (Iterator iterator = this.rootPaths.iterator(); iterator.hasNext();) {
+				System.out.println("root[" + i + "]=" + ((String) iterator.next()));//$NON-NLS-1$ //$NON-NLS-2$
+				i++;
+			}
+		}
 	}
 	
-	private void computeRootPath(File directory, HashSet firstLevelPackageNames, boolean hasDefaultPackage) {
+	private void computeRootPath(File directory, HashSet firstLevelPackageNames, boolean hasDefaultPackage, Set set) {
 		File[] files = directory.listFiles();
 		boolean hasSubDirectories = false;
 		loop: for (int i = 0, max = files.length; i < max; i++) {
@@ -440,23 +476,23 @@
 				if (firstLevelPackageNames.contains(file.getName())) {
 					IPath fullPath = new Path(file.getParentFile().getPath());
 					IPath rootPathEntry = fullPath.removeFirstSegments(this.sourcePath.segmentCount()).setDevice(null);
-					this.rootPaths.add(rootPathEntry.toString());
+					set.add(rootPathEntry);
 					break loop;
 				} else {
-					computeRootPath(file, firstLevelPackageNames, hasDefaultPackage);
+					computeRootPath(file, firstLevelPackageNames, hasDefaultPackage, set);
 				}
 			} else if (i == max - 1 && !hasSubDirectories && hasDefaultPackage) {
 				File parentDir = file.getParentFile();
 				if (parentDir.list(FILENAME_FILTER).length != 0) {
 					IPath fullPath = new Path(parentDir.getPath());
 					IPath rootPathEntry = fullPath.removeFirstSegments(this.sourcePath.segmentCount()).setDevice(null);
-					this.rootPaths.add(rootPathEntry.toString());
+					set.add(rootPathEntry);
 				}
 			}
 		}
 	}	
 
-	private void computeRootPath(IContainer container, HashSet firstLevelPackageNames, boolean hasDefaultPackage) {
+	private void computeRootPath(IContainer container, HashSet firstLevelPackageNames, boolean hasDefaultPackage, Set set) {
 		try {
 			IResource[] resources = container.members();
 			boolean hasSubDirectories = false;
@@ -467,10 +503,10 @@
 					if (firstLevelPackageNames.contains(resource.getName())) {
 						IPath fullPath = container.getFullPath();
 						IPath rootPathEntry = fullPath.removeFirstSegments(this.sourcePath.segmentCount()).setDevice(null);
-						this.rootPaths.add(rootPathEntry.toString());
+						set.add(rootPathEntry);
 						break loop;
 					} else {
-						computeRootPath((IFolder) resource, firstLevelPackageNames, hasDefaultPackage);
+						computeRootPath((IFolder) resource, firstLevelPackageNames, hasDefaultPackage, set);
 					}
 				}
 				if (i == max - 1 && !hasSubDirectories && hasDefaultPackage) {
@@ -485,7 +521,7 @@
 					if (hasJavaSourceFile) {
 						IPath fullPath = container.getFullPath();
 						IPath rootPathEntry = fullPath.removeFirstSegments(this.sourcePath.segmentCount()).setDevice(null);
-						this.rootPaths.add(rootPathEntry.toString());
+						set.add(rootPathEntry);
 					}
 				}
 			}
@@ -563,8 +599,24 @@
 		this.typeNameRanges[typeDepth] =
 			new SourceRange(typeInfo.nameSourceStart, typeInfo.nameSourceEnd - typeInfo.nameSourceStart + 1);
 		this.typeDeclarationStarts[typeDepth] = typeInfo.declarationStart;
+
+		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));
+				setSourceRange(
+					typeParameter,
+					new SourceRange(
+						typeParameterInfo.declarationStart,
+						typeParameterInfo.declarationEnd - typeParameterInfo.declarationStart + 1),
+					new SourceRange(
+						typeParameterInfo.nameSourceStart,
+						typeParameterInfo.nameSourceEnd - typeParameterInfo.nameSourceStart + 1));
+			}
+		}
 	}
-	
+
 	/**
 	 * @see ISourceElementRequestor
 	 */
@@ -613,7 +665,28 @@
 				new SourceRange(methodInfo.nameSourceStart, methodInfo.nameSourceEnd - methodInfo.nameSourceStart + 1);
 			fMemberDeclarationStart[typeDepth] = methodInfo.declarationStart;
 			fMethodParameterTypes[typeDepth] = methodInfo.parameterTypes;
-			fMethodParameterNames[typeDepth] =methodInfo. parameterNames;
+			fMethodParameterNames[typeDepth] = methodInfo. parameterNames;
+			
+			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));
+					setSourceRange(
+						typeParameter,
+						new SourceRange(
+							typeParameterInfo.declarationStart,
+							typeParameterInfo.declarationEnd - typeParameterInfo.declarationStart + 1),
+						new SourceRange(
+							typeParameterInfo.nameSourceStart,
+							typeParameterInfo.nameSourceEnd - typeParameterInfo.nameSourceStart + 1));
+				}
+			}	
 		}
 	}
 	
@@ -740,15 +813,14 @@
 	
 		char[] source = null;
 		
-		if (!areRootPathsComputed) {
-			computeAllRootPaths((IPackageFragmentRoot) type.getPackageFragment().getParent());
-		}
-		
 		if (this.rootPath != null) {
 			source = getSourceForRootPath(this.rootPath, name);
 		}
 
 		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
@@ -843,14 +915,31 @@
 	 * {-1, -1} if no source range is known for the name of the element.
 	 */
 	public SourceRange getNameRange(IJavaElement element) {
-		if (element.getElementType() == IJavaElement.METHOD
-			&& ((IMember) element).isBinary()) {
-			IJavaElement[] el = getUnqualifiedMethodHandle((IMethod) element, false);
-			if(el[1] != null && fSourceRanges.get(el[0]) == null) {
-				element = getUnqualifiedMethodHandle((IMethod) element, true)[0];
-			} else {
-				element = el[0];
-			}
+		switch(element.getElementType()) {
+			case IJavaElement.METHOD :
+				if (((IMember) element).isBinary()) {
+					IJavaElement[] el = getUnqualifiedMethodHandle((IMethod) element, false);
+					if(el[1] != null && fSourceRanges.get(el[0]) == null) {
+						element = getUnqualifiedMethodHandle((IMethod) element, true)[0];
+					} else {
+						element = el[0];
+					}
+				}
+				break;
+			case IJavaElement.TYPE_PARAMETER :
+				IJavaElement parent = element.getParent();
+				if (parent.getElementType() == IJavaElement.METHOD) {
+					IMethod method = (IMethod) parent;
+					if (method.isBinary()) {
+						IJavaElement[] el = getUnqualifiedMethodHandle(method, false);
+						if(el[1] != null && fSourceRanges.get(el[0]) == null) {
+							method = (IMethod) getUnqualifiedMethodHandle(method, true)[0];
+						} else {
+							method = (IMethod) el[0];
+						}
+						element = method.getTypeParameter(element.getElementName());
+					}
+				}
 		}
 		SourceRange[] ranges = (SourceRange[]) fSourceRanges.get(element);
 		if (ranges == null) {
@@ -886,14 +975,31 @@
 	 * {-1, -1} if no source range is known for the element.
 	 */
 	public SourceRange getSourceRange(IJavaElement element) {
-		if (element.getElementType() == IJavaElement.METHOD
-			&& ((IMember) element).isBinary()) {
-			IJavaElement[] el = getUnqualifiedMethodHandle((IMethod) element, false);
-			if(el[1] != null && fSourceRanges.get(el[0]) == null) {
-				element = getUnqualifiedMethodHandle((IMethod) element, true)[0];
-			} else {
-				element = el[0];
-			}
+		switch(element.getElementType()) {
+			case IJavaElement.METHOD :
+				if (((IMember) element).isBinary()) {
+					IJavaElement[] el = getUnqualifiedMethodHandle((IMethod) element, false);
+					if(el[1] != null && fSourceRanges.get(el[0]) == null) {
+						element = getUnqualifiedMethodHandle((IMethod) element, true)[0];
+					} else {
+						element = el[0];
+					}
+				}
+				break;
+			case IJavaElement.TYPE_PARAMETER :
+				IJavaElement parent = element.getParent();
+				if (parent.getElementType() == IJavaElement.METHOD) {
+					IMethod method = (IMethod) parent;
+					if (method.isBinary()) {
+						IJavaElement[] el = getUnqualifiedMethodHandle(method, false);
+						if(el[1] != null && fSourceRanges.get(el[0]) == null) {
+							method = (IMethod) getUnqualifiedMethodHandle(method, true)[0];
+						} else {
+							method = (IMethod) el[0];
+						}
+						element = method.getTypeParameter(element.getElementName());
+					}
+				}
 		}
 		SourceRange[] ranges = (SourceRange[]) fSourceRanges.get(element);
 		if (ranges == null) {
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 2730f34..e337487 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
@@ -96,7 +96,7 @@
  */
 public String getKey() {
 	try {
-		return getKey(this, org.eclipse.jdt.internal.compiler.lookup.Binding.USE_ACCESS_FLAGS_IN_BINDING_KEY/*with access flags*/, false/*don't open*/);
+		return getKey(this, false/*don't open*/);
 	} catch (JavaModelException e) {
 		// happen only if force open is true
 		return null;
@@ -250,7 +250,7 @@
 /**
  * @private Debugging purposes
  */
-protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
+protected void toStringInfo(int tab, StringBuffer buffer, Object info, boolean showResolvedInfo) {
 	buffer.append(tabString(tab));
 	if (info == null) {
 		toStringName(buffer);
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 4f72a4d..ff40087 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
@@ -336,7 +336,7 @@
  */
 public String getKey() {
 	try {
-		return getKey(this, org.eclipse.jdt.internal.compiler.lookup.Binding.USE_ACCESS_FLAGS_IN_BINDING_KEY/*with access flags*/, false/*don't open*/);
+		return getKey(this, false/*don't open*/);
 	} catch (JavaModelException e) {
 		// happen only if force open is true
 		return null;
@@ -832,7 +832,7 @@
 /**
  * @private Debugging purposes
  */
-protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
+protected void toStringInfo(int tab, StringBuffer buffer, Object info, boolean showResolvedInfo) {
 	buffer.append(tabString(tab));
 	if (info == null) {
 		String elementName = getElementName();
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 a1b861e..a3361a6 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
@@ -58,6 +58,26 @@
 		return new SourceRange(info.nameStart, info.nameEnd - info.nameStart + 1);
 	}
 
+	/*
+	 * @see ISourceReference
+	 */
+	public ISourceRange getSourceRange() 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.getSourceRange(this);
+			}
+		}
+		return super.getSourceRange();
+	}
+
+	public IClassFile getClassFile() {
+		return ((JavaElement)getParent()).getClassFile();
+	}
+
 	protected void toStringName(StringBuffer buffer) {
 		buffer.append('<');
 		buffer.append(getElementName());
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 481781c..14c3a78 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
@@ -21,6 +21,8 @@
 import javax.xml.parsers.ParserConfigurationException;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.Path;
+import org.eclipse.jdt.core.IAccessRule;
+import org.eclipse.jdt.core.IClasspathAttribute;
 import org.eclipse.jdt.core.IClasspathEntry;
 import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.internal.core.util.Messages;
@@ -61,7 +63,7 @@
 	public boolean isSystemLibrary() {
 		return this.isSystemLibrary;
 	}
-	
+
 	/* (non-Javadoc)
 	 * @see java.lang.Object#equals(java.lang.Object)
 	 */
@@ -97,7 +99,7 @@
 	/* package */  String serialize() throws IOException {
 		ByteArrayOutputStream s = new ByteArrayOutputStream();
 		OutputStreamWriter writer = new OutputStreamWriter(s, "UTF8"); //$NON-NLS-1$
-		XMLWriter xmlWriter = new XMLWriter(writer);
+		XMLWriter xmlWriter = new XMLWriter(writer, null/*use the workspace line delimiter*/);
 		
 		HashMap library = new HashMap();
 		library.put(TAG_VERSION, String.valueOf(CURRENT_VERSION));
@@ -105,17 +107,35 @@
 		xmlWriter.printTag(TAG_USERLIBRARY, library, true, true, false);
 		
 		for (int i = 0; i < this.entries.length; ++i) {
-			IClasspathEntry curr= this.entries[i];
-			
+			ClasspathEntry cpEntry = (ClasspathEntry) this.entries[i];
+		
 			HashMap archive = new HashMap();
-			archive.put(TAG_PATH, curr.getPath().toString());
-			IPath sourceAttach= curr.getSourceAttachmentPath();
+			archive.put(TAG_PATH, cpEntry.getPath().toString());
+			IPath sourceAttach= cpEntry.getSourceAttachmentPath();
 			if (sourceAttach != null)
 				archive.put(TAG_SOURCEATTACHMENT, sourceAttach);
-			IPath sourceAttachRoot= curr.getSourceAttachmentRootPath();
+			IPath sourceAttachRoot= cpEntry.getSourceAttachmentRootPath();
 			if (sourceAttachRoot != null)
 				archive.put(TAG_SOURCEATTACHMENTROOT, sourceAttachRoot);				
-			xmlWriter.printTag(TAG_ARCHIVE, archive, true, true, true);
+
+			boolean hasExtraAttributes = cpEntry.extraAttributes != null && cpEntry.extraAttributes.length != 0;
+			boolean hasRestrictions = cpEntry.getAccessRuleSet() != null; // access rule set is null if no access rules
+			xmlWriter.printTag(TAG_ARCHIVE, archive, true, true, !(hasExtraAttributes || hasRestrictions));
+
+			// write extra attributes if necessary
+			if (hasExtraAttributes) {
+				cpEntry.encodeExtraAttributes(xmlWriter, true, true);
+			}
+
+			// write extra attributes and restriction if necessary
+			if (hasRestrictions) {
+				cpEntry.encodeAccessRules(xmlWriter, true, true);
+			}
+
+			// write archive end tag if necessary
+			if (hasExtraAttributes || hasRestrictions) {
+				xmlWriter.endTag(TAG_ARCHIVE, true);
+			}
 		}	
 		xmlWriter.endTag(TAG_USERLIBRARY, true);
 		writer.flush();
@@ -157,7 +177,10 @@
 					String path = element.getAttribute(TAG_PATH);
 					IPath sourceAttach= element.hasAttribute(TAG_SOURCEATTACHMENT) ? new Path(element.getAttribute(TAG_SOURCEATTACHMENT)) : null;
 					IPath sourceAttachRoot= element.hasAttribute(TAG_SOURCEATTACHMENTROOT) ? new Path(element.getAttribute(TAG_SOURCEATTACHMENTROOT)) : null;
-					res.add(JavaCore.newLibraryEntry(new Path(path), sourceAttach, sourceAttachRoot));
+					IClasspathAttribute[] extraAttributes = ClasspathEntry.decodeExtraAttributes(element);
+					IAccessRule[] accessRules = ClasspathEntry.decodeAccessRules(element);
+					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/XMLWriter.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/XMLWriter.java
index 7294367..7fad140 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
@@ -14,6 +14,9 @@
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashMap;
+
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.internal.core.util.Util;
 /**
  * @since 3.0
  */
@@ -54,10 +57,13 @@
 		return null;
 	}
 	private int tab;
-	public XMLWriter(Writer writer) {
+	private String lineSeparator;
+	public XMLWriter(Writer writer, IJavaProject project) {
 		super(writer);
 		this.tab= 0;
-		println(XML_VERSION);
+		this.lineSeparator = Util.getLineSeparator((String) null, project);
+		print(XML_VERSION);
+		print(this.lineSeparator);
 	}
 	public void endTag(String name, boolean insertTab) {
 		this.tab --;
@@ -89,10 +95,9 @@
 		if (insertTab) {
 			printTabulation();
 		}
+		print(sb.toString());
 		if (insertNewLine) {
-			println(sb.toString());
-		} else {
-			print(sb.toString());
+			print(this.lineSeparator);
 		}
 		if (parameters != null && !closeTag)
 			this.tab++;
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 99202df..b253f44 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
@@ -59,6 +59,14 @@
 					IMarker.CHAR_END, 
 					IMarker.LINE_NUMBER, 
 					IJavaModelMarker.ARGUMENTS};
+public final static String[] JAVA_TASK_MARKER_ATTRIBUTE_NAMES = {
+	IMarker.MESSAGE, 
+	IMarker.PRIORITY, 
+	IJavaModelMarker.ID, 
+	IMarker.CHAR_START, 
+	IMarker.CHAR_END, 
+	IMarker.LINE_NUMBER, 
+	IJavaModelMarker.ARGUMENTS};
 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);
@@ -313,8 +321,12 @@
 		option = (String) projectOptions.get(JavaCore.COMPILER_PB_MISSING_JAVADOC_TAGS);
 		if (option == null || option.equals(JavaCore.IGNORE)) {
 			option = (String) projectOptions.get(JavaCore.COMPILER_PB_MISSING_JAVADOC_COMMENTS);
-			if (option == null || option.equals(JavaCore.IGNORE))
-				projectOptions.put(JavaCore.COMPILER_DOC_COMMENT_SUPPORT, JavaCore.DISABLED);
+			if (option == null || option.equals(JavaCore.IGNORE)) {
+				option = (String) projectOptions.get(JavaCore.COMPILER_PB_UNUSED_IMPORT);
+				if (option == null || option.equals(JavaCore.IGNORE)) { // Unused import need also to look inside javadoc comment
+					projectOptions.put(JavaCore.COMPILER_DOC_COMMENT_SUPPORT, JavaCore.DISABLED);
+				}
+			}
 		}
 	}
 	
@@ -430,11 +442,11 @@
 			else if (JavaCore.COMPILER_TASK_PRIORITY_LOW.equals(compilerPriority))
 				priority = P_LOW;
 			marker.setAttributes(
-				JAVA_PROBLEM_MARKER_ATTRIBUTE_NAMES,
+				JAVA_TASK_MARKER_ATTRIBUTE_NAMES,
 				new Object[] { 
 					task.getMessage(),
 					priority,
-					org.eclipse.jdt.internal.compiler.util.Util.toBoolean(false),
+					new Integer(task.getID()),
 					new Integer(task.getSourceStart()),
 					new Integer(task.getSourceEnd() + 1),
 					new Integer(task.getSourceLineNumber()),
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 b623720..046b1fb 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
@@ -219,7 +219,7 @@
 								createProblemFor(
 									resource,
 									null,
-									Messages.bind(Messages.build_duplicateResource, (new String[] {id})), 
+									Messages.bind(Messages.build_duplicateResource, id), 
 									javaBuilder.javaProject.getOption(JavaCore.CORE_JAVA_BUILD_DUPLICATE_RESOURCE, true));
 								return false;
 							}
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 56ce053..24d54a9 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
@@ -17,6 +17,7 @@
 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;
 
 public class ClasspathDirectory extends ClasspathLocation {
 
@@ -98,7 +99,8 @@
 		if (reader != null) {
 			if (this.accessRuleSet == null)
 				return new NameEnvironmentAnswer(reader, null);
-			return new NameEnvironmentAnswer(reader, this.accessRuleSet.getViolatedRestriction(qualifiedBinaryFileName.toCharArray()));
+			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
@@ -112,7 +114,8 @@
 						if (reader != null) {
 							if (this.accessRuleSet == null)
 								return new NameEnvironmentAnswer(reader, null);
-							return new NameEnvironmentAnswer(reader, this.accessRuleSet.getViolatedRestriction(qualifiedBinaryFileName.toCharArray()));
+							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
 					}
@@ -149,4 +152,10 @@
 		return start;
 	return start + " with " + this.accessRuleSet; //$NON-NLS-1$
 }
+
+public String debugPathString() {
+	return this.binaryLocation;
+}
+
+
 }
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 ba3817b..45bcc8c 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
@@ -18,6 +18,7 @@
 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.SimpleSet;
 
 import java.io.*;
@@ -42,21 +43,20 @@
 
 /**
  * Calculate and cache the package list available in the zipFile.
- * @param zipFile The zip file to use
+ * @param jar The ClasspathJar to use
  * @return A SimpleSet with the all the package names in the zipFile.
  */
-static SimpleSet findPackageSet(ZipFile zipFile) {
-	String zipFileName = zipFile.getName();
-	File zipFileObject = new File(zipFileName);
-	long lastModified = zipFileObject.lastModified();
-	long fileSize = zipFileObject.length();
+static SimpleSet findPackageSet(ClasspathJar jar) {
+	String zipFileName = jar.zipFilename;
+	long lastModified = jar.lastModified();
+	long fileSize = new File(zipFileName).length();
 	PackageCacheEntry cacheEntry = (PackageCacheEntry) PackageCache.get(zipFileName);
 	if (cacheEntry != null && cacheEntry.lastModified == lastModified && cacheEntry.fileSize == fileSize)
 		return cacheEntry.packageSet;
 
 	SimpleSet packageSet = new SimpleSet(41);
 	packageSet.add(""); //$NON-NLS-1$
-	nextEntry : for (Enumeration e = zipFile.entries(); e.hasMoreElements(); ) {
+	nextEntry : for (Enumeration e = jar.zipFile.entries(); e.hasMoreElements(); ) {
 		String fileName = ((ZipEntry) e.nextElement()).getName();
 
 		// add the package name & all of its parent packages
@@ -79,17 +79,11 @@
 String zipFilename; // keep for equals
 IFile resource;
 ZipFile zipFile;
+long lastModified;
 boolean closeZipFileAtEnd;
 SimpleSet knownPackageNames;
 AccessRuleSet accessRuleSet;
 
-ClasspathJar(String zipFilename, AccessRuleSet accessRuleSet) {
-	this.zipFilename = zipFilename;
-	this.zipFile = null;
-	this.knownPackageNames = null;
-	this.accessRuleSet = accessRuleSet;
-}
-
 ClasspathJar(IFile resource, AccessRuleSet accessRuleSet) {
 	this.resource = resource;
 	IPath location = resource.getLocation();
@@ -99,6 +93,14 @@
 	this.accessRuleSet = accessRuleSet;
 }
 
+ClasspathJar(String zipFilename, long lastModified, AccessRuleSet accessRuleSet) {
+	this.zipFilename = zipFilename;
+	this.lastModified = lastModified;
+	this.zipFile = null;
+	this.knownPackageNames = null;
+	this.accessRuleSet = accessRuleSet;
+}
+
 public ClasspathJar(ZipFile zipFile, AccessRuleSet accessRuleSet) {
 	this.zipFilename = zipFile.getName();
 	this.zipFile = zipFile;
@@ -126,8 +128,8 @@
 	if (this.accessRuleSet != jar.accessRuleSet)
 		if (this.accessRuleSet == null || !this.accessRuleSet.equals(jar.accessRuleSet))
 			return false;
-	return this.zipFilename.equals(((ClasspathJar) o).zipFilename);
-} 
+	return this.zipFilename.equals(jar.zipFilename) && this.lastModified() == jar.lastModified();
+}
 
 public NameEnvironmentAnswer findClass(String binaryFileName, String qualifiedPackageName, String qualifiedBinaryFileName) {
 	if (!isPackage(qualifiedPackageName)) return null; // most common case
@@ -137,7 +139,8 @@
 		if (reader != null) {
 			if (this.accessRuleSet == null)
 				return new NameEnvironmentAnswer(reader, null);
-			return new NameEnvironmentAnswer(reader, this.accessRuleSet.getViolatedRestriction(qualifiedBinaryFileName.toCharArray()));
+			String fileNameWithoutExtension = qualifiedBinaryFileName.substring(0, qualifiedBinaryFileName.length() - SuffixConstants.SUFFIX_CLASS.length);
+			return new NameEnvironmentAnswer(reader, this.accessRuleSet.getViolatedRestriction(fileNameWithoutExtension.toCharArray()));
 		}
 	} catch (Exception e) { // treat as if class file is missing
 	}
@@ -161,17 +164,30 @@
 			this.zipFile = new ZipFile(zipFilename);
 			this.closeZipFileAtEnd = true;
 		}
-		this.knownPackageNames = findPackageSet(this.zipFile);
+		this.knownPackageNames = findPackageSet(this);
 	} catch(Exception e) {
 		this.knownPackageNames = new SimpleSet(); // assume for this build the zipFile is empty
 	}
 	return this.knownPackageNames.includes(qualifiedPackageName);
 }
 
+public long lastModified() {
+	if (this.lastModified == 0)
+		this.lastModified = new File(this.zipFilename).lastModified();
+	return this.lastModified;
+}
+
 public String toString() {
 	String start = "Classpath jar file " + this.zipFilename; //$NON-NLS-1$
 	if (this.accessRuleSet == null)
 		return start;
 	return start + " with " + this.accessRuleSet; //$NON-NLS-1$
 }
+
+public String debugPathString() {
+	if (this.lastModified == 0)
+		return this.zipFilename;
+	return this.zipFilename + '(' + (new Date(this.lastModified)) + " : " + this.lastModified + ')'; //$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 6db53e7..d7cb036 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
@@ -26,8 +26,12 @@
 	return new ClasspathDirectory(binaryFolder, isOutputFolder, accessRuleSet);
 }
 
-static ClasspathLocation forLibrary(String libraryPathname, AccessRuleSet accessRestriction) {
-	return new ClasspathJar(libraryPathname, accessRestriction);
+static ClasspathLocation forLibrary(String libraryPathname, long lastModified, AccessRuleSet accessRuleSet) {
+	return new ClasspathJar(libraryPathname, lastModified, accessRuleSet);
+}
+
+static ClasspathLocation forLibrary(String libraryPathname, AccessRuleSet accessRuleSet) {
+	return forLibrary(libraryPathname, 0, accessRuleSet);
 }
 
 static ClasspathLocation forLibrary(IFile library, AccessRuleSet accessRuleSet) {
@@ -50,4 +54,7 @@
 public void reset() {
 	// reset any internal caches before another compile loop starts
 }
+
+public abstract String debugPathString();
+
 }
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 96c32e8..da7935d 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
@@ -177,7 +177,7 @@
 	} 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, (new String[] {e.missingClassFile}))); 
+			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);
@@ -408,8 +408,10 @@
 			}
 		} catch (CoreException ignore) { // skip it
 		}
-		if (DEBUG)
-			System.out.println(newSourceLocations[n] + " != " + oldSourceLocations[o]); //$NON-NLS-1$
+		if (DEBUG) {
+			System.out.println("New location: " + newSourceLocations[n] + "\n!= old location: " + oldSourceLocations[o]); //$NON-NLS-1$ //$NON-NLS-2$
+			printLocations(newSourceLocations, oldSourceLocations);
+		}
 		return true;
 	}
 	while (n < newLength) {
@@ -420,13 +422,17 @@
 			}
 		} catch (CoreException ignore) { // skip it
 		}
-		if (DEBUG)
+		if (DEBUG) {
 			System.out.println("Added non-empty source folder"); //$NON-NLS-1$
+			printLocations(newSourceLocations, oldSourceLocations);
+		}
 		return true;
 	}
 	if (o < oldLength) {
-		if (DEBUG)
+		if (DEBUG) {
 			System.out.println("Removed source folder"); //$NON-NLS-1$
+			printLocations(newSourceLocations, oldSourceLocations);
+		}
 		return true;
 	}
 
@@ -436,18 +442,16 @@
 	oldLength = oldBinaryLocations.length;
 	for (n = o = 0; n < newLength && o < oldLength; n++, o++) {
 		if (newBinaryLocations[n].equals(oldBinaryLocations[o])) continue;
-		if (DEBUG)
-			System.out.println(newBinaryLocations[n] + " != " + oldBinaryLocations[o]); //$NON-NLS-1$
+		if (DEBUG) {
+			System.out.println("New location: " + newBinaryLocations[n] + "\n!= old location: " + oldBinaryLocations[o]); //$NON-NLS-1$ //$NON-NLS-2$
+			printLocations(newBinaryLocations, oldBinaryLocations);
+		}
 		return true;
 	}
 	if (n < newLength || o < oldLength) {
 		if (DEBUG) {
 			System.out.println("Number of binary folders/jar files has changed:"); //$NON-NLS-1$
-			for (int i = 0; i < newLength; i++)
-				System.out.println(newBinaryLocations[i]);
-			System.out.println("was:"); //$NON-NLS-1$
-			for (int i = 0; i < oldLength; i++)
-				System.out.println(oldBinaryLocations[i]);
+			printLocations(newBinaryLocations, oldBinaryLocations);
 		}
 		return true;
 	}
@@ -547,6 +551,9 @@
 		return false;
 	}
 
+	if (JavaCore.WARNING.equals(javaProject.getOption(JavaCore.CORE_INCOMPLETE_CLASSPATH, true)))
+		return true;
+
 	// 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);
@@ -598,6 +605,15 @@
 	}
 }
 
+private void printLocations(ClasspathLocation[] newLocations, ClasspathLocation[] oldLocations) {
+	System.out.println("New locations:"); //$NON-NLS-1$
+	for (int i = 0, length = newLocations.length; i < length; i++)
+		System.out.println("    " + newLocations[i].debugPathString()); //$NON-NLS-1$
+	System.out.println("Old locations:"); //$NON-NLS-1$
+	for (int i = 0, length = oldLocations.length; i < length; i++)
+		System.out.println("    " + oldLocations[i].debugPathString()); //$NON-NLS-1$
+}
+
 private void recordNewState(State state) {
 	Object[] keyTable = binaryLocationsPerProject.keyTable;
 	for (int i = 0, l = keyTable.length; i < l; i++) {
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 fccb5fe..f3230c9 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
@@ -43,7 +43,7 @@
 private StringSet structurallyChangedTypes;
 public static int MaxStructurallyChangedTypes = 100; // keep track of ? structurally changed types, otherwise consider all to be changed
 
-static final byte VERSION = 0x0011; // added discouraged access rules
+public static final byte VERSION = 0x0013; // added timestamps to external jars
 
 static final byte SOURCE_FOLDER = 1;
 static final byte BINARY_FOLDER = 2;
@@ -197,10 +197,10 @@
 
 static State read(IProject project, DataInputStream in) throws IOException {
 	if (JavaBuilder.DEBUG)
-		System.out.println("About to read state..."); //$NON-NLS-1$
+		System.out.println("About to read state " + project.getName()); //$NON-NLS-1$
 	if (VERSION != in.readByte()) {
 		if (JavaBuilder.DEBUG)
-			System.out.println("Found non-compatible state version... answered null"); //$NON-NLS-1$
+			System.out.println("Found non-compatible state version... answered null for " + project.getName()); //$NON-NLS-1$
 		return null;
 	}
 
@@ -244,7 +244,7 @@
 				newState.binaryLocations[i] = ClasspathLocation.forBinaryFolder(outputFolder, in.readBoolean(), readRestriction(in));
 				break;
 			case EXTERNAL_JAR :
-				newState.binaryLocations[i] = ClasspathLocation.forLibrary(in.readUTF(), readRestriction(in));
+				newState.binaryLocations[i] = ClasspathLocation.forLibrary(in.readUTF(), in.readLong(), readRestriction(in));
 				break;
 			case INTERNAL_JAR :
 				newState.binaryLocations[i] = ClasspathLocation.forLibrary(root.getFile(new Path(in.readUTF())), readRestriction(in));
@@ -426,6 +426,7 @@
 			if (jar.resource == null) {
 				out.writeByte(EXTERNAL_JAR);
 				out.writeUTF(jar.zipFilename);
+				out.writeLong(jar.lastModified());
 			} else {
 				out.writeByte(INTERNAL_JAR);
 				out.writeUTF(jar.resource.getFullPath().toString());
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 1516c51..c960f20 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
@@ -291,7 +291,8 @@
 				typeDelta.superTypes();
 			}
 			if ((newFlags & IJavaElementDelta.F_MODIFIERS) != 0
-					&& this.hierarchy.hasSupertype(type.getElementName())) {
+					&& (this.hierarchy.hasSupertype(type.getElementName())
+						|| type.equals(this.hierarchy.focusType))) {
 				if (typeDelta == null) {
 					typeDelta = new SimpleDelta();
 				}
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 cc6b329..4bb296e 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
@@ -85,8 +85,6 @@
 		buffer.append('<');
 		for (int i = 0, length = this.typeParameterSignatures.length; i < length; i++) {
 			buffer.append(this.typeParameterSignatures[i]);
-			if (i != length-1)
-				buffer.append(',');
 		}
 		buffer.append('>');
 		if (this.superclass == null)
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 53d8c8b..2fed303 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
@@ -12,12 +12,10 @@
 
 import java.util.*;
 
+import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.SubProgressMonitor;
 import org.eclipse.jdt.core.*;
-import org.eclipse.jdt.core.IJavaProject;
-import org.eclipse.jdt.core.IType;
-import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.search.*;
 import org.eclipse.jdt.internal.compiler.env.AccessRuleSet;
@@ -35,7 +33,6 @@
 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
@@ -351,7 +348,9 @@
 protected IBinaryType createInfoFromClassFileInJar(Openable classFile) {
 	String filePath = (((ClassFile)classFile).getType().getFullyQualifiedName('$')).replace('.', '/') + SuffixConstants.SUFFIX_STRING_class;
 	IPackageFragmentRoot root = classFile.getPackageFragmentRoot();
-	String rootPath = root.isExternal() ? root.getPath().toOSString() : root.getPath().toString();
+	IPath path = root.getPath();
+	// take the OS path for external jars, and the forward slash path for internal jars
+	String rootPath = path.getDevice() == null ? path.toString() : path.toOSString();
 	String documentPath = rootPath + IJavaSearchScope.JAR_FILE_ENTRY_SEPARATOR + filePath;
 	IBinaryType binaryType = (IBinaryType)this.binariesFromIndexMatches.get(documentPath);
 	if (binaryType != null) {
@@ -434,14 +433,15 @@
 	IndexQueryRequestor searchRequestor = new IndexQueryRequestor() {
 		public boolean acceptIndexMatch(String documentPath, SearchPattern indexRecord, SearchParticipant participant, AccessRuleSet access) {
 			SuperTypeReferencePattern record = (SuperTypeReferencePattern)indexRecord;
-			pathRequestor.acceptPath(documentPath, record.enclosingTypeName == IIndexConstants.ONE_ZERO);
+			boolean isLocalOrAnonymous = record.enclosingTypeName == IIndexConstants.ONE_ZERO;
+			pathRequestor.acceptPath(documentPath, isLocalOrAnonymous);
 			char[] typeName = record.simpleName;
 			int suffix = documentPath.toLowerCase().indexOf(SUFFIX_STRING_class);
 			if (suffix != -1){ 
 				HierarchyBinaryType binaryType = (HierarchyBinaryType)binariesFromIndexMatches.get(documentPath);
 				if (binaryType == null){
 					char[] enclosingTypeName = record.enclosingTypeName;
-					if (enclosingTypeName == IIndexConstants.ONE_ZERO) { // local or anonymous type
+					if (isLocalOrAnonymous) {
 						int lastSlash = documentPath.lastIndexOf('/');
 						int lastDollar = documentPath.lastIndexOf('$');
 						if (lastDollar == -1) {
@@ -451,7 +451,7 @@
 							typeName = documentPath.substring(lastSlash+1, suffix).toCharArray();
 						} else {
 							enclosingTypeName = documentPath.substring(lastSlash+1, lastDollar).toCharArray();
-							typeName = Util.localTypeName(documentPath, lastDollar, suffix).toCharArray();
+							typeName = documentPath.substring(lastDollar+1, suffix).toCharArray();
 						}
 					}
 					binaryType = new HierarchyBinaryType(record.modifiers, record.pkgName, typeName, enclosingTypeName, record.typeParameterSignatures, record.classOrInterface);
@@ -459,7 +459,8 @@
 				}
 				binaryType.recordSuperType(record.superSimpleName, record.superQualification, record.superClassOrInterface);
 			}
-			if (!foundSuperNames.containsKey(typeName)){
+			if (!isLocalOrAnonymous // local or anonymous types cannot have subtypes outside the cu that define them
+					&& !foundSuperNames.containsKey(typeName)){
 				foundSuperNames.put(typeName, typeName);
 				queue.add(typeName);
 			}
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 2a5f271..8c8609b 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
@@ -880,6 +880,17 @@
 						return true;
 					}
 				}
+				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);
+					IPath hierarchyProject = javaProject().getPath();
+					for (int i = 0; i < classpath.length; i++) {
+						if (classpath[i].getEntryKind() == IClasspathEntry.CPE_PROJECT 
+								&& classpath[i].getPath().equals(hierarchyProject)) {
+							return true;
+						}
+					}
+				}
 				return false;
 			} catch (JavaModelException e) {
 				return false;
@@ -1470,7 +1481,7 @@
 public String toString() {
 	StringBuffer buffer = new StringBuffer();
 	buffer.append("Focus: "); //$NON-NLS-1$
-	buffer.append(this.focusType == null ? "<NONE>" : ((JavaElement)this.focusType).toStringWithAncestors()); //$NON-NLS-1$
+	buffer.append(this.focusType == null ? "<NONE>" : ((JavaElement)this.focusType).toStringWithAncestors(false/*don't show key*/)); //$NON-NLS-1$
 	buffer.append("\n"); //$NON-NLS-1$
 	if (exists()) {
 		if (this.focusType != null) {
@@ -1513,7 +1524,7 @@
 			buffer.append("  "); //$NON-NLS-1$
 		}
 		JavaElement element = (JavaElement)types[i];
-		buffer.append(element.toStringWithAncestors());
+		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/DOMField.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMField.java
index 257993c..eba8825 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
@@ -18,6 +18,7 @@
 import org.eclipse.jdt.core.jdom.*;
 import org.eclipse.jdt.internal.core.util.Messages;
 import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
+import org.eclipse.jdt.internal.core.util.Util;
 /**
  * DOMField provides an implementation of IDOMField.
  *
@@ -381,16 +382,16 @@
 				.append('=')
 				.append(fInitializer)
 				.append(';')
-				.append(org.eclipse.jdt.internal.compiler.util.Util.LINE_SEPARATOR);
+				.append(Util.getLineSeparator(buffer.toString(), null));
 		} else {
 			buffer
 				.append(fDocument, fNameRange[1] + 1, fInitializerRange[0] - fNameRange[1] - 1)
 				.append(getInitializer())
 				.append(';')
-				.append(org.eclipse.jdt.internal.compiler.util.Util.LINE_SEPARATOR);
+				.append(Util.getLineSeparator(buffer.toString(), null));
 		}
 	} else {
-		buffer.append(';').append(org.eclipse.jdt.internal.compiler.util.Util.LINE_SEPARATOR);
+		buffer.append(';').append(Util.getLineSeparator(buffer.toString(), null));
 	}
 	return buffer.getContents();
 }
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 595da2e..1a99239 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
@@ -16,6 +16,7 @@
 import org.eclipse.jdt.core.jdom.*;
 import org.eclipse.jdt.internal.core.util.Messages;
 import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
+import org.eclipse.jdt.internal.core.util.Util;
 
 /**
  * DOMImport provides an implementation of IDOMImport.
@@ -99,7 +100,7 @@
 			.append("import ") //$NON-NLS-1$
 			.append(fName)
 			.append(';')
-			.append(org.eclipse.jdt.internal.compiler.util.Util.LINE_SEPARATOR);
+			.append(Util.getLineSeparator(buffer.toString(), null));
 	} else {
 		buffer.append(fDocument, fSourceRange[0], fNameRange[0] - fSourceRange[0]);
 		//buffer.append(fDocument, fNameRange[0], fNameRange[1] - fNameRange[0] + 1);
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 1bd97cf..cba8276 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
@@ -15,6 +15,7 @@
 import org.eclipse.jdt.core.jdom.*;
 import org.eclipse.jdt.internal.core.util.Messages;
 import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
+import org.eclipse.jdt.internal.core.util.Util;
 /**
  * DOMInitializer provides an implementation of IDOMInitializer.
  *
@@ -107,7 +108,7 @@
 			.append(getBody())
 			.append(fDocument, fBodyRange[1] + 1, fSourceRange[1] - fBodyRange[1]);
 	} else {
-		buffer.append("{}").append(org.eclipse.jdt.internal.compiler.util.Util.LINE_SEPARATOR); //$NON-NLS-1$
+		buffer.append("{}").append(Util.getLineSeparator(buffer.toString(), null)); //$NON-NLS-1$
 	}
 }
 /**
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 92f15c4..c83d0eb 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
@@ -18,6 +18,7 @@
 import org.eclipse.jdt.core.jdom.*;
 import org.eclipse.jdt.internal.core.util.Messages;
 import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
+import org.eclipse.jdt.internal.core.util.Util;
 /**
  * DOMMethod provides an implementation of IDOMMethod.
  *
@@ -599,7 +600,7 @@
 	fBody= body;
 	setHasBody(body != null);
 	if (!hasBody()) {
-		fBody= ";" + org.eclipse.jdt.internal.compiler.util.Util.LINE_SEPARATOR; //$NON-NLS-1$
+		fBody= ";" + Util.getLineSeparator(body, null); //$NON-NLS-1$
 	}
 }
 /**
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 a6ab806..3bc7454 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
@@ -15,6 +15,7 @@
 import org.eclipse.jdt.core.jdom.*;
 import org.eclipse.jdt.internal.core.util.Messages;
 import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
+import org.eclipse.jdt.internal.core.util.Util;
 
 /**
  * DOMPackage provides an implementation of IDOMPackage.
@@ -76,12 +77,13 @@
  */
 protected void appendFragmentedContents(CharArrayBuffer buffer) {
 	if (fNameRange[0] < 0) {
+		String lineSeparator = Util.getLineSeparator(buffer.toString(), null);
 		buffer
 			.append("package ") //$NON-NLS-1$
 			.append(fName)
 			.append(';')
-			.append(org.eclipse.jdt.internal.compiler.util.Util.LINE_SEPARATOR)
-			.append(org.eclipse.jdt.internal.compiler.util.Util.LINE_SEPARATOR);
+			.append(lineSeparator)
+			.append(lineSeparator);
 	} else {
 		buffer
 			.append(fDocument, fSourceRange[0], fNameRange[0] - fSourceRange[0])
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 9140e31..81b4fe7 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
@@ -27,7 +27,8 @@
 		static final int FLAGS = 6;
 		static final int WILDCARD = 7;
 		static final int CAPTURE = 8;
-		static final int END = 9;
+		static final int BASE_TYPE = 9;
+		static final int END = 10;
 		
 		static final int START = -1;
 		
@@ -46,6 +47,12 @@
 			return result;
 		}
 		
+		boolean isAtCaptureStart() {
+			return 
+				this.index < this.source.length
+				&& this.source[this.index] == '!';
+		}
+		
 		boolean isAtFieldOrMethodStart() {
 			return 
 				this.index < this.source.length
@@ -93,6 +100,12 @@
 				&& this.source[this.index] == '~';
 		}
 		
+		boolean isAtWildcardStart() {
+			return 
+				this.index < this.source.length
+				&& "*+-".indexOf(this.source[this.index]) != -1; //$NON-NLS-1$
+		}
+		
 		boolean isAtTypeParameterStart() {
 			return 
 				this.index < this.source.length
@@ -100,27 +113,27 @@
 		}
 	
 		boolean isAtTypeArgumentStart() {
-			return this.index < this.source.length && "LIZVCDBFJS[*+-!".indexOf(this.source[this.index]) != -1; //$NON-NLS-1$
+			return this.index < this.source.length && "LIZVCDBFJS[!".indexOf(this.source[this.index]) != -1; //$NON-NLS-1$
 		}
 		
-		boolean isAtMethodTypeVariableStart() {
-			return 
-				this.index < this.source.length
-				&& this.source[this.index] == ':';
-		}
-
 		boolean isAtFlagsStart() {
 			return 
 				this.index < this.source.length
 				&& this.source[this.index] == '^';
 		}
 		
-		boolean isAtTypeTypeVariableStart() {
+		boolean isAtTypeVariableStart() {
 			return 
 				this.index < this.source.length
 				&& this.source[this.index] == ':';
 		}
 		
+		boolean isAtTypeWithCaptureStart() {
+			return 
+				this.index < this.source.length
+				&& this.source[this.index] == '&';
+		}
+		
 		int nextToken() {
 			int previousTokenEnd = this.index;
 			this.start = this.index;
@@ -139,9 +152,10 @@
 					case 'V':
 					case 'Z':
 						// base type
-						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.index++;
-							this.token = TYPE;
+							this.token = BASE_TYPE;
 							return this.token;
 						}
 						break;
@@ -175,6 +189,7 @@
 									this.token = LOCAL_VAR;
 									break;
 								case TYPE:
+								case BASE_TYPE:
 									if (this.index > this.start && this.source[this.start-1] == '.')
 										this.token = FIELD;
 									break;
@@ -203,10 +218,7 @@
 						this.token = ARRAY;
 						return this.token;
 					case '<':
-						if (this.index == previousTokenEnd) {
-							this.start = this.index+1;
-							previousTokenEnd = this.start;
-						} else if (this.start > 0) {
+						if (this.start > 0) {
 							switch (this.source[this.start-1]) {
 								case '.':
 									if (this.source[this.start-2] == '>')
@@ -216,8 +228,13 @@
 										this.token = METHOD;
 									return this.token;
 								default:
-									this.token = TYPE;
-									return this.token;
+									if (this.index == previousTokenEnd) {
+										this.start = this.index+1;
+										previousTokenEnd = this.start;
+									} else {
+										this.token = TYPE;
+										return this.token;
+									}
 							}
 						} 
 						break;
@@ -225,9 +242,13 @@
 						this.token = METHOD;
 						return this.token;
 					case ')':
-						this.start = ++this.index;
-						this.token = END;
-						return this.token;
+						if (this.token == TYPE) {
+							this.token = FIELD;
+							return this.token;
+						}
+						this.start = this.index+1;
+						previousTokenEnd = this.start;
+						break;
 					case '#':
 						if (this.index == previousTokenEnd) {
 							this.start = this.index+1;
@@ -252,6 +273,9 @@
 								else
 									this.token = END;
 								break;
+							case WILDCARD:
+								this.token = TYPE;
+								break;
 							default:
 								this.token = END;
 								break;
@@ -264,6 +288,7 @@
 						this.token = WILDCARD;
 						return this.token;
 					case '!':
+					case '&':
 						this.index++;
 						this.token = CAPTURE;
 						return this.token;
@@ -301,7 +326,7 @@
 		}
 		
 		void skipParametersStart() {
-			if (this.index < this.source.length && this.source[this.index] == '<')
+			while (this.index < this.source.length && (this.source[this.index] == '<' || this.source[this.index] == '%'))
 				this.index++;
 		}
 		
@@ -343,6 +368,15 @@
 				case FLAGS:
 					buffer.append("MODIFIERS: "); //$NON-NLS-1$
 					break;
+				case WILDCARD:
+					buffer.append("WILDCARD: "); //$NON-NLS-1$
+					break;
+				case CAPTURE:
+					buffer.append("CAPTURE: "); //$NON-NLS-1$
+					break;
+				case BASE_TYPE:
+					buffer.append("BASE TYPE: "); //$NON-NLS-1$
+					break;
 				case END:
 					buffer.append("END: "); //$NON-NLS-1$
 					break;
@@ -387,7 +421,11 @@
 		// default is to do nothing
 	}
 	
-	public void consumeCapture() {
+	public void consumeBaseType(char[] baseTypeSig) {
+		// default is to do nothing
+	}
+
+	public void consumeCapture(int position) {
 		// default is to do nothing
 	}
 	
@@ -395,7 +433,7 @@
 		// default is to do nothing
 	}
 	
-	public void consumeParameterizedMethod() {
+	public void consumeParameterizedGenericMethod() {
 		// default is to do nothing
 	}
 	
@@ -451,6 +489,10 @@
 		// default is to do nothing
 	}
 
+	public void consumeKey() {
+		// default is to do nothing
+	}
+
 	public void consumeTopLevelType() {
 		// default is to do nothing
 	}
@@ -463,10 +505,14 @@
 		// default is to do nothing
 	}
 	
-	public void consumeTypeVariable(char[] typeVariableName) {
+	public void consumeTypeVariable(char[] position, char[] typeVariableName) {
 		// default is to do nothing
 	}
 	
+	public void consumeTypeWithCapture() {
+		// default is to do nothing
+	}
+
 	public void consumeWildCard(int kind) {
 		// default is to do nothing
 	}
@@ -503,8 +549,10 @@
 				return;
 			}
 		}
-		if (!hasTypeName())
+		if (!hasTypeName()) {
+			consumeKey();
 			return;
+		}
 		consumeTopLevelType();
 		parseSecondaryType();
 		parseInnerType();
@@ -520,7 +568,7 @@
 				parseInnerType();
 			} else if (this.scanner.isAtTypeArgumentStart())
 				// parameterized type
-				parseParameterizedType(null/*top level type*/, false/*no raw*/);
+				parseParameterizedType(null/*top level type or member type with raw enclosing type*/, false/*no raw*/);
 			else if (this.scanner.isAtRawTypeEnd())
 				// raw type
 				parseRawType();
@@ -536,14 +584,13 @@
 		if (this.scanner.isAtFieldOrMethodStart()) {
 			switch (this.scanner.nextToken()) {
  				case Scanner.FIELD:
- 					consumeField(this.scanner.getTokenSource());
-					parseFlags();
+ 					parseField();
  					return;
  				case Scanner.METHOD:
  					parseMethod();
  					if (this.scanner.isAtLocalVariableStart()) {
  						parseLocalVariable();
- 					} else if (this.scanner.isAtMethodTypeVariableStart()) {
+ 					} else if (this.scanner.isAtTypeVariableStart()) {
 						parseTypeVariable();
 					}
 			 		break;
@@ -551,12 +598,23 @@
  					malformedKey();
  					return;
 			}
-		} else if (this.scanner.isAtTypeTypeVariableStart()) {
+		} else if (this.scanner.isAtTypeVariableStart()) {
 			parseTypeVariable();
+		} else if (this.scanner.isAtWildcardStart()) {
+			parseWildcard();
+		} else if (this.scanner.isAtTypeWithCaptureStart()) {
+			parseTypeWithCapture();
 		}
+		
+		consumeKey();
 	}
 	
 	private void parseFullyQualifiedName() {
+		if (this.scanner.isAtCaptureStart()) {
+			parseCapture();
+			this.hasTypeName = false;
+			return;
+		}
 		switch(this.scanner.nextToken()) {
 			case Scanner.PACKAGE:
 				this.keyStart = 0;
@@ -567,49 +625,27 @@
 				this.keyStart = this.scanner.start-1;
 				consumeFullyQualifiedName(this.scanner.getTokenSource());
 				break;
+			case Scanner.BASE_TYPE:
+				this.keyStart = this.scanner.start-1;
+				consumeBaseType(this.scanner.getTokenSource());
+				this.hasTypeName = false;
+				break;
 	 		case Scanner.ARRAY:
 	 			this.keyStart = this.scanner.start;
 	 			consumeArrayDimension(this.scanner.getTokenSource());
-				if (this.scanner.nextToken() == Scanner.TYPE)
-	 				consumeFullyQualifiedName(this.scanner.getTokenSource());
-				else {
-					malformedKey();
-					return;
+	 			switch (this.scanner.nextToken()) {
+	 				case Scanner.TYPE:
+		 				consumeFullyQualifiedName(this.scanner.getTokenSource());
+		 				break;
+	 				case Scanner.BASE_TYPE:
+	 					consumeBaseType(this.scanner.getTokenSource());
+	 					this.hasTypeName = false;
+	 					break;
+	 				default:
+						malformedKey();
+						return;
 				}
 				break;
-	 		case Scanner.WILDCARD:
-			 	char[] source = this.scanner.getTokenSource();
-			 	if (source.length == 0) {
-			 		malformedKey();
-			 		return;
-			 	}
-			 	int kind = -1;
-			 	switch (source[0]) {
-				 	case '*':
-				 		kind = Wildcard.UNBOUND;
-				 		break;
-				 	case '+':
-				 		kind = Wildcard.EXTENDS;
-				 		break;
-				 	case '-':
-				 		kind = Wildcard.SUPER;
-				 		break;
-			 	}
-			 	if (kind == -1) {
-			 		malformedKey();
-			 		return;
-			 	}
-			 	consumeWildCard(kind);
-			 	if (kind == Wildcard.UNBOUND) {
-			 		this.hasTypeName = false;
-			 		return;
-			 	}
-			 	parseFullyQualifiedName();
-	 			break;
-	 		case Scanner.CAPTURE:
-	 			consumeCapture();
-	 			parseFullyQualifiedName();
-	 			break;
 			default:
 	 			malformedKey();
 				return;
@@ -617,10 +653,11 @@
 	}
 	
 	private void parseParameterizedMethod() {
+		this.scanner.skipParametersStart();
 		while (!this.scanner.isAtParametersEnd()) {
 			parseTypeArgument();
 		}
-		consumeParameterizedMethod();
+		consumeParameterizedGenericMethod();
 	}
 	
 	private void parseGenericType() {
@@ -681,6 +718,31 @@
 			parseParameterizedMethod();
 	}
 	
+	private void parseCapture() {
+		if (this.scanner.nextToken() != Scanner.CAPTURE) return;
+	 	parseCaptureWildcard();
+		if (this.scanner.nextToken() != Scanner.TYPE) {
+	 		malformedKey();
+			return;
+	 	}
+		char[] positionChars = this.scanner.getTokenSource();
+		int position = Integer.parseInt(new String(positionChars));
+		consumeCapture(position);
+		this.scanner.skipTypeEnd();
+	}
+	
+	private void parseCaptureWildcard() {
+		BindingKeyParser parser = newParser();
+		parser.parse();
+		consumeParser(parser);
+	}
+	
+	private void parseField() {
+		char[] fieldName = this.scanner.getTokenSource();
+		parseReturnType();
+ 		consumeField(fieldName);
+	}
+	
 	private void parseFlags() {
 		if (!this.scanner.isAtFlagsStart() || this.scanner.nextToken() != Scanner.FLAGS) return;
 		consumeModifiers(this.scanner.getTokenSource());
@@ -712,6 +774,12 @@
 		consumeRawType();
 	}
 	
+	private void parseReturnType() {
+		BindingKeyParser parser = newParser();
+		parser.parse();
+		consumeParser(parser);
+	}
+
 	private void parseSecondaryType() {
 		if (!this.scanner.isAtSecondaryTypeStart() || this.scanner.nextToken() != Scanner.TYPE) return;
 		consumeSecondaryType(this.scanner.getTokenSource());
@@ -723,13 +791,65 @@
 		consumeParser(parser);
 	}
 	
+	private void parseTypeWithCapture() {
+		if (this.scanner.nextToken() != Scanner.CAPTURE) return;
+		BindingKeyParser parser = newParser();
+		parser.parse();
+		consumeParser(parser);
+		consumeTypeWithCapture();
+	}
+	
 	private void parseTypeVariable() {
 		if (this.scanner.nextToken() != Scanner.TYPE) {
 			malformedKey();
 			return;
 		}
-		consumeTypeVariable(this.scanner.getTokenSource());
+		char[] typeVariableName = this.scanner.getTokenSource();
+		char[] position;
+		int length = typeVariableName.length;
+		if (length > 0 && Character.isDigit(typeVariableName[0])) {
+			int firstT = CharOperation.indexOf('T', typeVariableName);
+			position = CharOperation.subarray(typeVariableName, 0, firstT);
+			typeVariableName = CharOperation.subarray(typeVariableName, firstT+1, typeVariableName.length);
+		} else {
+			position = CharOperation.NO_CHAR;
+		}
+		consumeTypeVariable(position, typeVariableName);
 		this.scanner.skipTypeEnd();
 	}
 	
+	private void parseWildcard() {
+		if (this.scanner.nextToken() != Scanner.WILDCARD) return;
+	 	char[] source = this.scanner.getTokenSource();
+	 	if (source.length == 0) {
+	 		malformedKey();
+	 		return;
+	 	}
+	 	int kind = -1;
+	 	switch (source[0]) {
+		 	case '*':
+		 		kind = Wildcard.UNBOUND;
+		 		break;
+		 	case '+':
+		 		kind = Wildcard.EXTENDS;
+		 		break;
+		 	case '-':
+		 		kind = Wildcard.SUPER;
+		 		break;
+	 	}
+	 	if (kind == -1) {
+	 		malformedKey();
+	 		return;
+	 	}
+	 	if (kind != Wildcard.UNBOUND)
+	 		parseWildcardBound();
+	 	consumeWildCard(kind);
+	}
+	
+	private void parseWildcardBound() {
+		BindingKeyParser parser = newParser();
+		parser.parse();
+		consumeParser(parser);
+	}
+	
 }
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 d5f21f9..27c74f2 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
@@ -13,10 +13,20 @@
 import java.util.ArrayList;
 
 import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.ASTVisitor;
 import org.eclipse.jdt.internal.compiler.Compiler;
+import org.eclipse.jdt.internal.compiler.ast.ArrayReference;
+import org.eclipse.jdt.internal.compiler.ast.Assignment;
+import org.eclipse.jdt.internal.compiler.ast.CastExpression;
 import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.ConditionalExpression;
+import org.eclipse.jdt.internal.compiler.ast.FieldReference;
+import org.eclipse.jdt.internal.compiler.ast.MessageSend;
+import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference;
+import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
 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;
@@ -29,6 +39,8 @@
 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;
 import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
 import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
@@ -50,14 +62,18 @@
 	TypeBinding typeBinding;
 	TypeDeclaration typeDeclaration;
 	ArrayList types = new ArrayList();
+	int rank = 0;
 	
-	boolean isCapture;
-	int wildcardKind = -1;
+	int wildcardRank;
 	
-	private BindingKeyResolver(BindingKeyParser parser, Compiler compiler, LookupEnvironment environment) {
+	CompilationUnitDeclaration outerMostParsedUnit;
+	
+	private BindingKeyResolver(BindingKeyParser parser, Compiler compiler, LookupEnvironment environment, int wildcardRank, CompilationUnitDeclaration outerMostParsedUnit) {
 		super(parser);
 		this.compiler = compiler;
 		this.environment = environment;
+		this.wildcardRank = wildcardRank;
+		this.outerMostParsedUnit = outerMostParsedUnit;
 	}
 	
 	public BindingKeyResolver(String key) {
@@ -84,8 +100,92 @@
 		this.dimension = brakets.length;
 	}
 	
-	public void consumeCapture() {
-		this.isCapture = true;
+	public void consumeBaseType(char[] baseTypeSig) {
+		this.compoundName = new char[][] {getKey().toCharArray()};
+		TypeBinding baseTypeBinding = getBaseTypeBinding(baseTypeSig);
+		if (baseTypeBinding != null) {
+			this.typeBinding = baseTypeBinding;
+		}
+	}
+	
+	public void consumeCapture(final int position) {
+		CompilationUnitDeclaration outerParsedUnit = this.outerMostParsedUnit == null ? this.parsedUnit : this.outerMostParsedUnit;
+		if (outerParsedUnit == null) return;
+		final Binding wildcardBinding = ((BindingKeyResolver) this.types.get(0)).compilerBinding;
+		class CaptureFinder extends ASTVisitor {
+			CaptureBinding capture;
+			boolean checkType(TypeBinding binding) {
+				if (binding == null)
+					return false;
+				switch (binding.kind()) {
+					case Binding.PARAMETERIZED_TYPE:
+						TypeBinding[] arguments = ((ParameterizedTypeBinding) binding).arguments;
+						if (arguments == null) return false;
+						for (int i = 0, length = arguments.length; i < length; i++) {
+							if (checkType(arguments[i]))
+								return true;
+						}
+						break;
+					case Binding.WILDCARD_TYPE:
+						return checkType(((WildcardBinding) binding).bound);
+					case Binding.ARRAY_TYPE:
+						return checkType(((ArrayBinding) binding).leafComponentType);
+					case Binding.TYPE_PARAMETER:
+						if (binding.isCapture()) {
+							CaptureBinding captureBinding = (CaptureBinding) binding;
+							if (captureBinding.position == position && captureBinding.wildcard == wildcardBinding) {
+								this.capture = captureBinding;
+								return true;
+							}
+						}
+						break;
+				}
+				return false;
+			}
+			public boolean visit(SingleNameReference singleNameReference, BlockScope blockScope) {
+				if (checkType(singleNameReference.resolvedType)) 
+					return false;
+				return super.visit(singleNameReference, blockScope);
+			}
+			public boolean visit(QualifiedNameReference qualifiedNameReference, BlockScope blockScope) {
+				if (checkType(qualifiedNameReference.resolvedType))
+					return false;
+				return super.visit(qualifiedNameReference, blockScope);
+			}
+			public boolean visit(MessageSend messageSend, BlockScope blockScope) {
+				if (checkType(messageSend.resolvedType))
+					return false;
+				return super.visit(messageSend, blockScope);
+			}
+			public boolean visit(FieldReference fieldReference, BlockScope blockScope) {
+				if (checkType(fieldReference.resolvedType))
+					return false;
+				return super.visit(fieldReference, blockScope);
+			}
+			public boolean visit(ConditionalExpression conditionalExpression, BlockScope blockScope) {
+				if (checkType(conditionalExpression.resolvedType))
+					return false;
+				return super.visit(conditionalExpression, blockScope);
+			}
+			public boolean visit(CastExpression castExpression, BlockScope blockScope) {
+				if (checkType(castExpression.resolvedType))
+					return false;
+				return super.visit(castExpression, blockScope);
+			}
+			public boolean visit(Assignment assignment, BlockScope blockScope) {
+				if (checkType(assignment.resolvedType))
+					return false;
+				return super.visit(assignment, blockScope);
+			}
+			public boolean visit(ArrayReference arrayReference, BlockScope blockScope) {
+				if (checkType(arrayReference.resolvedType))
+					return false;
+				return super.visit(arrayReference, blockScope);
+			}
+		}
+		CaptureFinder captureFinder = new CaptureFinder();
+		outerParsedUnit.traverse(captureFinder, outerParsedUnit.scope);
+		this.typeBinding = captureFinder.capture;
 	}
 	
 	public void consumeField(char[] fieldName) {
@@ -93,25 +193,29 @@
 	 	for (int i = 0, length = fields.length; i < length; i++) {
 			FieldBinding field = fields[i];
 			if (CharOperation.equals(fieldName, field.name)) {
+				this.typeBinding = null;
 				this.compilerBinding = field;
 				return;
 			}
 		}
 	}
 
-	public void consumeParameterizedMethod() {
+	public void consumeParameterizedGenericMethod() {
+		if (this.methodBinding == null)
+			return;
 		TypeBinding[] arguments = getTypeBindingArguments();
-		if (arguments.length != this.methodBinding.typeVariables().length) return;
-	 	this.methodBinding = new ParameterizedGenericMethodBinding(this.methodBinding, arguments, this.environment);
+		if (arguments.length != this.methodBinding.typeVariables().length)
+			this.methodBinding = new ParameterizedGenericMethodBinding(this.methodBinding, (RawTypeBinding) null, this.environment);
+		else
+	 		this.methodBinding = new ParameterizedGenericMethodBinding(this.methodBinding, arguments, this.environment);
 		this.compilerBinding = this.methodBinding;
 	}
 	
 	public void consumeLocalType(char[] uniqueKey) {
  		LocalTypeBinding[] localTypeBindings  = this.parsedUnit.localTypes;
  		for (int i = 0; i < this.parsedUnit.localTypeCount; i++)
- 			if (CharOperation.equals(uniqueKey, localTypeBindings[i].computeUniqueKey(false/*without access flags*/))) {
+ 			if (CharOperation.equals(uniqueKey, localTypeBindings[i].computeUniqueKey(false/*not a leaf*/))) {
  				this.typeBinding = localTypeBindings[i];
-				this.compilerBinding = this.typeBinding;
  				return;
  			}
 	}
@@ -123,6 +227,7 @@
 	 	for (int i = 0; i < this.scope.localIndex; i++) {
 			LocalVariableBinding local = this.scope.locals[i];
 			if (CharOperation.equals(varName, local.name)) {
+				this.methodBinding = null;
 				this.compilerBinding = local;
 				return;
 			}
@@ -134,10 +239,11 @@
 	 	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())) {
-				char[] methodSignature = method.original().genericSignature();
+				char[] methodSignature = method.genericSignature();
 				if (methodSignature == null)
 					methodSignature = method.signature();
 				if (CharOperation.equals(signature, methodSignature)) {
+					this.typeBinding = null;
 					this.methodBinding = method;
 					this.compilerBinding = this.methodBinding;
 					return;
@@ -148,7 +254,6 @@
 	
 	public void consumeMemberType(char[] simpleTypeName) {
 		this.typeBinding = getTypeBinding(simpleTypeName);
-		this.compilerBinding = this.typeBinding;
 	}
 
 	public void consumePackage(char[] pkgName) {
@@ -159,7 +264,7 @@
 	public void consumeParameterizedType(char[] simpleTypeName, boolean isRaw) {
 		TypeBinding[] arguments = getTypeBindingArguments();
 		if (simpleTypeName != null) {
-			// parameterized member type
+			// 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);
@@ -167,16 +272,19 @@
 				// raw type
 				this.typeBinding = this.environment.createRawType(this.genericType, (ReferenceBinding) this.typeBinding);
 		} else {
-			// parameterized top level type
+			// parameterized top level type or parameterized member type with raw enclosing type
 			this.genericType = (ReferenceBinding) this.typeBinding;
-			this.typeBinding = this.environment.createParameterizedType(this.genericType, arguments, null);
+			ReferenceBinding enclosing = this.genericType.enclosingType();
+			if (enclosing != null) enclosing = (ReferenceBinding) this.environment.convertToRawType(enclosing);
+			this.typeBinding = this.environment.createParameterizedType(this.genericType, arguments, enclosing);
 		}
-		this.compilerBinding = this.typeBinding;
 	}
 	
 
 	public void consumeParser(BindingKeyParser parser) {
 		this.types.add(parser);
+		if (((BindingKeyResolver) parser).compilerBinding instanceof WildcardBinding)
+			this.rank++;
 	}
 	
 	public void consumeScope(int scopeNumber) {
@@ -190,13 +298,12 @@
 	
 	public void consumeRawType() {
 		if (this.typeBinding == null) return;
-		this.typeBinding = this.environment.createRawType((ReferenceBinding) this.typeBinding, null/*no enclosing type*/);
+		this.typeBinding = this.environment.createRawType((ReferenceBinding) this.typeBinding, this.typeBinding.enclosingType());
 	}
 	public void consumeSecondaryType(char[] simpleTypeName) {
 		if (this.parsedUnit == null) return;
 		this.typeDeclaration = null; // start from the parsed unit
 		this.typeBinding = getTypeBinding(simpleTypeName);
-		this.compilerBinding = this.typeBinding;
 	}
 	
 	public void consumeFullyQualifiedName(char[] fullyQualifiedName) {
@@ -204,47 +311,59 @@
 	}
 	
 	public void consumeTopLevelType() {
-		if (this.compoundName.length == 1 && this.compoundName[0].length == 1) {
-			// case of base type
- 			TypeBinding baseTypeBinding = getBaseTypeBinding(this.compoundName[0]);
- 			if (baseTypeBinding != null) {
-				this.typeBinding = baseTypeBinding;
-				this.compilerBinding = this.typeBinding;
-				return;
- 			}
-		}
 		this.parsedUnit = getCompilationUnitDeclaration();
 		if (this.parsedUnit != null && this.compiler != null) {
 			this.compiler.process(this.parsedUnit, this.compiler.totalUnits+1); // noop if unit has already been resolved
 		}
 		if (this.parsedUnit == null) {
 			this.typeBinding = getBinaryBinding();
-			this.compilerBinding = this.typeBinding;
 		} else {
 			char[] typeName = this.compoundName[this.compoundName.length-1];
 			this.typeBinding = getTypeBinding(typeName);
+		}
+	}
+	
+	public void consumeKey() {
+		if (this.typeBinding != null) {
+			this.typeBinding = getArrayBinding(this.dimension, this.typeBinding);
 			this.compilerBinding = this.typeBinding;
 		}
 	}
 	
-	public void consumeType() {
-		this.typeBinding = getArrayBinding(this.dimension, this.typeBinding);
-		this.compilerBinding = this.typeBinding;
-	}
-	
-	public void consumeTypeVariable(char[] typeVariableName) {
+	public void consumeTypeVariable(char[] position, char[] typeVariableName) {
+		if (position.length > 0) {
+			int pos = Integer.parseInt(new String(position));
+			MethodBinding[] methods = ((ReferenceBinding) this.typeBinding).methods();
+			if (methods != null && pos < methods.length) {
+				this.methodBinding = methods[pos];
+			}
+		}
 	 	TypeVariableBinding[] typeVariableBindings = this.methodBinding != null ? this.methodBinding.typeVariables() : this.typeBinding.typeVariables();
 	 	for (int i = 0, length = typeVariableBindings.length; i < length; i++) {
 			TypeVariableBinding typeVariableBinding = typeVariableBindings[i];
 			if (CharOperation.equals(typeVariableName, typeVariableBinding.sourceName())) {
-				this.compilerBinding = typeVariableBinding;
+				this.typeBinding = typeVariableBinding;
 				return;
 			}
 		}
 	}
 	
+	public void consumeTypeWithCapture() {
+		BindingKeyResolver resolver = (BindingKeyResolver) this.types.get(0);
+		this.typeBinding =(TypeBinding) resolver.compilerBinding;
+	}
+	
 	public void consumeWildCard(int kind) {
-		this.wildcardKind = kind;
+		switch (kind) {
+			case Wildcard.EXTENDS:
+			case Wildcard.SUPER:
+				BindingKeyResolver boundResolver = (BindingKeyResolver) this.types.get(0);
+				this.typeBinding = this.environment.createWildcard((ReferenceBinding) this.typeBinding, this.wildcardRank, (TypeBinding) boundResolver.compilerBinding, null /*no extra bound*/, kind);
+				break;
+			case Wildcard.UNBOUND:
+				this.typeBinding = this.environment.createWildcard((ReferenceBinding) this.typeBinding, rank++, null/*no bound*/, null /*no extra bound*/, kind);
+				break;
+		}
 	}
 	
 	/*
@@ -290,6 +409,7 @@
 	 * Returns null if not found.
 	 */
 	private TypeBinding getBinaryBinding() {
+		if (this.compoundName.length == 0) return null;
 		return this.environment.getType(this.compoundName);
 	}
 	 
@@ -343,25 +463,9 @@
 	private TypeBinding[] getTypeBindingArguments() {
 		int size = this.types.size();
 		TypeBinding[] arguments = new TypeBinding[size];
-		int rank = 0;
 		for (int i = 0; i < size; i++) {
 			BindingKeyResolver resolver = (BindingKeyResolver) this.types.get(i);
-			TypeBinding binding;
-			int kind = resolver.wildcardKind;
-			switch (kind) {
-				case Wildcard.EXTENDS:
-				case Wildcard.SUPER:
-					binding = this.environment.createWildcard((ReferenceBinding) this.typeBinding, rank++, (TypeBinding) resolver.compilerBinding, null /*no extra bound*/, kind);
-					break;
-				case Wildcard.UNBOUND:
-					binding = this.environment.createWildcard((ReferenceBinding) this.typeBinding, rank++, null/*no bound*/, null /*no extra bound*/, kind);
-					break;
-				default:
-					binding = (TypeBinding) resolver.compilerBinding;
-			}
-			if (resolver.isCapture)
-				binding = new CaptureBinding((WildcardBinding) binding);
-			arguments[i] = binding;
+			arguments[i] = (TypeBinding) resolver.compilerBinding;
 		}
 		this.types = new ArrayList();
 		return arguments;
@@ -372,7 +476,7 @@
 	}
 	
 	public BindingKeyParser newParser() {
-		return new BindingKeyResolver(this, this.compiler, this.environment);
+		return new BindingKeyResolver(this, this.compiler, this.environment, this.rank, this.outerMostParsedUnit == null ? this.parsedUnit : this.outerMostParsedUnit);
 	}
 	 
 	public String toString() {
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 94046cc..541adfc 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
@@ -11,7 +11,6 @@
 package org.eclipse.jdt.internal.core.util;
 
 import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
-import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.compiler.parser.Parser;
 import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
@@ -50,8 +49,6 @@
 		boolean checkDeprecated = false;
 		int lastCommentIndex = -1;
 		
-		// 
-		
 		//since jdk1.2 look only in the last java doc comment...
 		nextComment : for (lastCommentIndex = this.scanner.commentPtr; lastCommentIndex >= 0; lastCommentIndex--){
 			//look for @deprecated into the first javadoc comment preceeding the declaration
@@ -113,24 +110,6 @@
 		super.consumeInterfaceHeader();
 	}
 
-	protected void consumeInternalCompilationUnit() {
-		// InternalCompilationUnit ::= PackageDeclaration
-		// InternalCompilationUnit ::= PackageDeclaration ImportDeclarations ReduceImports
-		// InternalCompilationUnit ::= ImportDeclarations ReduceImports
-	}
-	protected void consumeInternalCompilationUnitWithTypes() {
-		// InternalCompilationUnit ::= PackageDeclaration ImportDeclarations ReduceImports TypeDeclarations
-		// InternalCompilationUnit ::= PackageDeclaration TypeDeclarations
-		// InternalCompilationUnit ::= TypeDeclarations
-		// InternalCompilationUnit ::= ImportDeclarations ReduceImports TypeDeclarations
-		// consume type declarations
-		int length;
-		if ((length = this.astLengthStack[this.astLengthPtr--]) != 0) {
-			this.compilationUnit.types = new TypeDeclaration[length];
-			this.astPtr -= length;
-			System.arraycopy(this.astStack, this.astPtr + 1, this.compilationUnit.types, 0, length);
-		}
-	}
 	/**
 	 * Insure that start position is always positive.
 	 * @see org.eclipse.jdt.internal.compiler.parser.Parser#containsComment(int, int)
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 6632b61..e672880 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
@@ -10,6 +10,7 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.util;
 
+import org.eclipse.jdt.core.Signature;
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.util.ClassFileBytesDisassembler;
 import org.eclipse.jdt.core.util.IBytecodeVisitor;
@@ -26,6 +27,7 @@
  */
 public class DefaultBytecodeVisitor implements IBytecodeVisitor {
 	private static final String EMPTY_CLASS_NAME = "\"\""; //$NON-NLS-1$
+	private static final String EMPTY_LOCAL_NAME = ""; //$NON-NLS-1$
 	private static final int T_BOOLEAN = 4;
 	private static final int T_CHAR = 5;
 	private static final int T_FLOAT = 6;
@@ -115,10 +117,10 @@
 	 */
 	public void _aload_1(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_load, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_load, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.ALOAD_1],
 			getLocalVariableName(pc, 1)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -127,10 +129,10 @@
 	 */
 	public void _aload_2(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_load, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_load, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.ALOAD_2],
 			getLocalVariableName(pc, 2)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -139,10 +141,10 @@
 	 */
 	public void _aload_3(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_load, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_load, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.ALOAD_3],
 			getLocalVariableName(pc, 3)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -151,10 +153,10 @@
 	 */
 	public void _aload(int pc, int index) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_load, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_load, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.ALOAD],
-			getLocalVariableName(pc, index)
-		})));
+			getLocalVariableName(pc, index, true)
+		}));
 		writeNewLine();
 	}
 
@@ -164,11 +166,11 @@
 	public void _anewarray(int pc, int index, IConstantPoolEntry constantClass) {
 		dumpPcNumber(pc);
 		buffer
-			.append(Messages.bind(Messages.classformat_anewarray, (new String[] {
+			.append(Messages.bind(Messages.classformat_anewarray, new String[] {
 				OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.ANEWARRAY],
 				Integer.toString(index),
 				returnConstantClassName(constantClass)
-			})));
+			}));
 		writeNewLine();
 	}
 
@@ -195,10 +197,10 @@
 	 */
 	public void _astore_0(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_store, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_store, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.ASTORE_0],
 			getLocalVariableName(pc, 0)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -207,13 +209,17 @@
 	 */
 	public void _astore_1(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_store, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_store, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.ASTORE_1],
 			getLocalVariableName(pc, 1)
-		})));
+		}));
 		writeNewLine();
 	}
 	private String getLocalVariableName(int pc, int index) {
+		return getLocalVariableName(pc, index, false);
+	}
+	
+	private String getLocalVariableName(int pc, int index, boolean showIndex) {
         int nextPC = pc + 1;
         switch(index) {
             case 0 :
@@ -229,11 +235,20 @@
             final ILocalVariableTableEntry entry = this.localVariableTableEntries[i];
             final int startPC = entry.getStartPC();
             if (entry.getIndex() == index && (startPC <= nextPC) && ((startPC + entry.getLength()) > nextPC)) {
-                return new String(entry.getName());
+            	final StringBuffer stringBuffer = new StringBuffer();
+            	if (showIndex) {
+            		stringBuffer.append(' ').append(index);
+            	}
+            	stringBuffer.append(' ').append('[').append(entry.getName()).append(']');
+            	return String.valueOf(stringBuffer);
             }
         }
-		String localVariableName = Messages.bind(Messages.disassembler_localvariablename, (new String[] {Integer.toString(index)})); 
-		return localVariableName;
+    	if (showIndex) {
+        	final StringBuffer stringBuffer = new StringBuffer();
+        	stringBuffer.append(' ').append(index);
+         	return String.valueOf(stringBuffer);
+    	}
+        return EMPTY_LOCAL_NAME;
 	}
 
 	/**
@@ -241,10 +256,10 @@
 	 */
 	public void _astore_2(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_store, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_store, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.ASTORE_2],
 			getLocalVariableName(pc, 2)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -253,10 +268,10 @@
 	 */
 	public void _astore_3(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_store, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_store, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.ASTORE_3],
 			getLocalVariableName(pc, 3)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -265,10 +280,10 @@
 	 */
 	public void _astore(int pc, int index) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_store, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_store, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.ASTORE],
-			getLocalVariableName(pc, index)
-		})));
+			getLocalVariableName(pc, index, true)
+		}));
 		writeNewLine();
 	}
 
@@ -334,11 +349,11 @@
 	public void _checkcast(int pc, int index, IConstantPoolEntry constantClass) {
 		dumpPcNumber(pc);
 		buffer
-			.append(Messages.bind(Messages.classformat_checkcast, (new String[] {
+			.append(Messages.bind(Messages.classformat_checkcast, new String[] {
 				OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.CHECKCAST],
 				Integer.toString(index),
 				returnConstantClassName(constantClass)
-			})));
+			}));
 		writeNewLine();
 	}
 
@@ -446,10 +461,10 @@
 	 */
 	public void _dload_0(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_load, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_load,new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.DLOAD_0],
 			getLocalVariableName(pc, 0)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -458,10 +473,10 @@
 	 */
 	public void _dload_1(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_load, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_load, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.DLOAD_1],
 			getLocalVariableName(pc, 1)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -470,10 +485,10 @@
 	 */
 	public void _dload_2(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_load, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_load, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.DLOAD_2],
 			getLocalVariableName(pc, 2)
-		})));
+		}));
 		writeNewLine();
 	}
 	
@@ -482,10 +497,10 @@
 	 */
 	public void _dload_3(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_load, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_load, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.DLOAD_3],
 			getLocalVariableName(pc, 3)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -494,10 +509,10 @@
 	 */
 	public void _dload(int pc, int index) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_load, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_load, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.DLOAD],
-			getLocalVariableName(pc, index)
-		})));
+			getLocalVariableName(pc, index, true)
+		}));
 		writeNewLine();
 	}
 
@@ -542,10 +557,10 @@
 	 */
 	public void _dstore_0(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_store, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_store, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.DSTORE_0],
 			getLocalVariableName(pc, 0)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -554,10 +569,10 @@
 	 */
 	public void _dstore_1(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_store, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_store, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.DSTORE_1],
 			getLocalVariableName(pc, 1)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -566,10 +581,10 @@
 	 */
 	public void _dstore_2(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_store, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_store, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.DSTORE_2],
 			getLocalVariableName(pc, 2)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -578,10 +593,10 @@
 	 */
 	public void _dstore_3(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_store, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_store, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.DSTORE_3],
 			getLocalVariableName(pc, 3)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -590,10 +605,10 @@
 	 */
 	public void _dstore(int pc, int index) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_store, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_store, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.DSTORE],
-			getLocalVariableName(pc, index)
-		})));
+			getLocalVariableName(pc, index, true)
+		}));
 		writeNewLine();
 	}
 
@@ -773,10 +788,10 @@
 	 */
 	public void _fload_0(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_load, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_load, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.FLOAD_0],
 			getLocalVariableName(pc, 0)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -785,10 +800,10 @@
 	 */
 	public void _fload_1(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_load, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_load, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.FLOAD_1],
 			getLocalVariableName(pc, 1)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -797,10 +812,10 @@
 	 */
 	public void _fload_2(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_load, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_load, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.FLOAD_2],
 			getLocalVariableName(pc, 2)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -809,10 +824,10 @@
 	 */
 	public void _fload_3(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_load, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_load, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.FLOAD_3],
 			getLocalVariableName(pc, 3)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -821,10 +836,10 @@
 	 */
 	public void _fload(int pc, int index) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_load, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_load, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.FLOAD],
-			getLocalVariableName(pc, index)
-		})));
+			getLocalVariableName(pc, index, true)
+		}));
 		writeNewLine();
 	}
 
@@ -869,10 +884,10 @@
 	 */
 	public void _fstore_0(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_store, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_store,new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.FSTORE_0],
 			getLocalVariableName(pc, 0)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -881,10 +896,10 @@
 	 */
 	public void _fstore_1(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_store, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_store, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.FSTORE_1],
 			getLocalVariableName(pc, 1)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -893,10 +908,10 @@
 	 */
 	public void _fstore_2(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_store, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_store, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.FSTORE_2],
 			getLocalVariableName(pc, 2)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -905,10 +920,10 @@
 	 */
 	public void _fstore_3(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_store, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_store, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.FSTORE_3],
 			getLocalVariableName(pc, 3)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -917,10 +932,10 @@
 	 */
 	public void _fstore(int pc, int index) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_store, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_store, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.FSTORE],
-			getLocalVariableName(pc, index)
-		})));
+			getLocalVariableName(pc, index, true)
+		}));
 		writeNewLine();
 	}
 
@@ -938,13 +953,13 @@
 	 */
 	public void _getfield(int pc, int index, IConstantPoolEntry constantFieldref) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_getfield, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_getfield, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.GETFIELD],
 			Integer.toString(index),
 			returnDeclaringClassName(constantFieldref),
 			new String(constantFieldref.getFieldName()),
-			new String(constantFieldref.getFieldDescriptor())
-		})));
+			returnClassName(Signature.toCharArray(constantFieldref.getFieldDescriptor()))
+		}));
 		writeNewLine();
 	}
 
@@ -953,13 +968,13 @@
 	 */
 	public void _getstatic(int pc, int index, IConstantPoolEntry constantFieldref) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_getstatic, (new String[] {
-			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.GETSTATIC],
-			Integer.toString(index),
-			returnDeclaringClassName(constantFieldref),
-			new String(constantFieldref.getFieldName()),
-			new String(constantFieldref.getFieldDescriptor())
-		})));
+		buffer.append(Messages.bind(Messages.classformat_getstatic, new String[] {
+				OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.GETSTATIC],
+				Integer.toString(index),
+				returnDeclaringClassName(constantFieldref),
+				new String(constantFieldref.getFieldName()),
+				returnClassName(Signature.toCharArray(constantFieldref.getFieldDescriptor()))
+			}));
 		writeNewLine();
 	}
 
@@ -1328,12 +1343,12 @@
 	 */
 	public void _iinc(int pc, int index, int _const) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_iinc, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_iinc, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.IINC],
 			Integer.toString(index),
 			Integer.toString(_const),
-			getLocalVariableName(pc, index)
-		})));
+			getLocalVariableName(pc, index, false)
+		}));
 		writeNewLine();
 	}
 
@@ -1342,10 +1357,10 @@
 	 */
 	public void _iload_0(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_load, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_load, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.ILOAD_0],
 			getLocalVariableName(pc, 0)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -1354,10 +1369,10 @@
 	 */
 	public void _iload_1(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_load, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_load, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.ILOAD_1],
 			getLocalVariableName(pc, 1)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -1366,10 +1381,10 @@
 	 */
 	public void _iload_2(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_load, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_load, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.ILOAD_2],
 			getLocalVariableName(pc, 2)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -1378,10 +1393,10 @@
 	 */
 	public void _iload_3(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_load, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_load, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.ILOAD_3],
 			getLocalVariableName(pc, 3)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -1390,10 +1405,10 @@
 	 */
 	public void _iload(int pc, int index) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_load, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_load, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.ILOAD],
-			getLocalVariableName(pc, index)
-		})));
+			getLocalVariableName(pc, index, true)
+		}));
 		writeNewLine();
 	}
 
@@ -1420,11 +1435,11 @@
 	 */
 	public void _instanceof(int pc, int index, IConstantPoolEntry constantClass) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_instanceof, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_instanceof, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.INSTANCEOF],
 			Integer.toString(index),
 			returnConstantClassName(constantClass)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -1438,27 +1453,17 @@
 		IConstantPoolEntry constantInterfaceMethodref) {
 
 		dumpPcNumber(pc);
-		if (isCompact()) {
-			buffer.append(Messages.bind(Messages.classformat_invokeinterface_compact, (new String[] {
-				OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.INVOKEINTERFACE],
-				Integer.toString(index),
-				Integer.toString(nargs),
-				Util.toString(
-					constantInterfaceMethodref.getClassName(),
-					constantInterfaceMethodref.getMethodName(),
-					constantInterfaceMethodref.getMethodDescriptor(),
-					true)
-			})));
-		} else {
-			buffer.append(Messages.bind(Messages.classformat_invokeinterface, (new String[] {
-					OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.INVOKEINTERFACE],
-					Integer.toString(index),
-					Integer.toString(nargs),
-					returnDeclaringClassName(constantInterfaceMethodref),
-					new String(constantInterfaceMethodref.getMethodName()),
-					new String(constantInterfaceMethodref.getMethodDescriptor()),
-			})));
-		}
+		buffer.append(Messages.bind(Messages.classformat_invokeinterface, new String[] {
+			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.INVOKEINTERFACE],
+			Integer.toString(index),
+			Integer.toString(nargs),
+			Util.toString(
+				constantInterfaceMethodref.getClassName(),
+				constantInterfaceMethodref.getMethodName(),
+				constantInterfaceMethodref.getMethodDescriptor(),
+				true,
+				isCompact())
+		}));
 		writeNewLine();
 	}
 
@@ -1467,25 +1472,16 @@
 	 */
 	public void _invokespecial(int pc, int index, IConstantPoolEntry constantMethodref) {
 		dumpPcNumber(pc);
-		if (isCompact()) {
-			buffer.append(Messages.bind(Messages.classformat_invokespecial_compact, (new String[] {
-				OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.INVOKESPECIAL],
-				Integer.toString(index),
-				Util.toString(
-					constantMethodref.getClassName(),
-					constantMethodref.getMethodName(),
-					constantMethodref.getMethodDescriptor(),
-					true)
-			})));
-		} else {
-			buffer.append(Messages.bind(Messages.classformat_invokespecial, (new String[] {
-					OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.INVOKESPECIAL],
-					Integer.toString(index),
-					returnDeclaringClassName(constantMethodref),
-					new String(constantMethodref.getMethodName()),
-					new String(constantMethodref.getMethodDescriptor()),
-			})));
-		}
+		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())
+		}));
 		writeNewLine();
 	}
 
@@ -1494,25 +1490,16 @@
 	 */
 	public void _invokestatic(int pc, int index, IConstantPoolEntry constantMethodref) {
 		dumpPcNumber(pc);
-		if (isCompact()) {
-			buffer.append(Messages.bind(Messages.classformat_invokestatic_compact, (new String[] {
-				OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.INVOKESTATIC],
-				Integer.toString(index),
-				Util.toString(
-					constantMethodref.getClassName(),
-					constantMethodref.getMethodName(),
-					constantMethodref.getMethodDescriptor(),
-					true)
-			})));
-		} else {
-			buffer.append(Messages.bind(Messages.classformat_invokestatic, (new String[] {
-				OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.INVOKESTATIC],
-				Integer.toString(index),
-				returnDeclaringClassName(constantMethodref),
-				new String(constantMethodref.getMethodName()),
-				new String(constantMethodref.getMethodDescriptor()),
-			})));
-		}
+		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())
+		}));
 		writeNewLine();
 	}
 
@@ -1521,25 +1508,16 @@
 	 */
 	public void _invokevirtual(int pc, int index, IConstantPoolEntry constantMethodref) {
 		dumpPcNumber(pc);
-		if (isCompact()) {
-			buffer.append(Messages.bind(Messages.classformat_invokevirtual_compact, (new String[] {
-				OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.INVOKEVIRTUAL],
-				Integer.toString(index),
-				Util.toString(
-					constantMethodref.getClassName(),
-					constantMethodref.getMethodName(),
-					constantMethodref.getMethodDescriptor(),
-					true)
-			})));
-		} else {
-			buffer.append(Messages.bind(Messages.classformat_invokevirtual, (new String[] {
-					OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.INVOKEVIRTUAL],
-					Integer.toString(index),
-					returnDeclaringClassName(constantMethodref),
-					new String(constantMethodref.getMethodName()),
-					new String(constantMethodref.getMethodDescriptor()),
-			})));
-		}
+		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())
+		}));
 		writeNewLine();
 	}
 
@@ -1593,10 +1571,10 @@
 	 */
 	public void _istore_0(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_store, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_store, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.ISTORE_0],
 			getLocalVariableName(pc, 0)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -1605,10 +1583,10 @@
 	 */
 	public void _istore_1(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_store, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_store, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.ISTORE_1],
 			getLocalVariableName(pc, 1)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -1617,10 +1595,10 @@
 	 */
 	public void _istore_2(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_store, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_store, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.ISTORE_2],
 			getLocalVariableName(pc, 2)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -1629,10 +1607,10 @@
 	 */
 	public void _istore_3(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_store, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_store, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.ISTORE_3],
 			getLocalVariableName(pc, 3)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -1641,10 +1619,10 @@
 	 */
 	public void _istore(int pc, int index) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_store, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_store, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.ISTORE],
-			getLocalVariableName(pc, index)
-		})));
+			getLocalVariableName(pc, index, true)
+		}));
 		writeNewLine();
 	}
 
@@ -1794,32 +1772,32 @@
 		dumpPcNumber(pc);
 		switch (constantPoolEntry.getKind()) {
 			case IConstantPoolConstant.CONSTANT_Float :
-				buffer.append(Messages.bind(Messages.classformat_ldc_w_float, (new String[] {
+				buffer.append(Messages.bind(Messages.classformat_ldc_w_float, new String[] {
 					OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.LDC_W],
 					Integer.toString(index),
 					Float.toString(constantPoolEntry.getFloatValue())
-				})));
+				}));
 				break;
 			case IConstantPoolConstant.CONSTANT_Integer :
-				buffer.append(Messages.bind(Messages.classformat_ldc_w_integer, (new String[] {
+				buffer.append(Messages.bind(Messages.classformat_ldc_w_integer, new String[] {
 					OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.LDC_W],
 					Integer.toString(index),
 					Integer.toString(constantPoolEntry.getIntegerValue())
-				})));
+				}));
 				break;
 			case IConstantPoolConstant.CONSTANT_String :
-				buffer.append(Messages.bind(Messages.classformat_ldc_w_string, (new String[] {
+				buffer.append(Messages.bind(Messages.classformat_ldc_w_string, new String[] {
 					OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.LDC_W],
 					Integer.toString(index),
 					constantPoolEntry.getStringValue()
-				})));
+				}));
 				break;
 			case IConstantPoolConstant.CONSTANT_Class :
-				buffer.append(Messages.bind(Messages.classformat_ldc_w_class, (new String[] {
+				buffer.append(Messages.bind(Messages.classformat_ldc_w_class, new String[] {
 					OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.LDC_W],
 					Integer.toString(index),
 					returnConstantClassName(constantPoolEntry)
-				})));
+				}));
 		}
 		writeNewLine();
 	}
@@ -1831,32 +1809,32 @@
 		dumpPcNumber(pc);
 		switch (constantPoolEntry.getKind()) {
 			case IConstantPoolConstant.CONSTANT_Float :
-				buffer.append(Messages.bind(Messages.classformat_ldc_w_float, (new String[] {
+				buffer.append(Messages.bind(Messages.classformat_ldc_w_float, new String[] {
 					OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.LDC],
 					Integer.toString(index),
 					Float.toString(constantPoolEntry.getFloatValue())
-				})));
+				}));
 				break;
 			case IConstantPoolConstant.CONSTANT_Integer :
-				buffer.append(Messages.bind(Messages.classformat_ldc_w_integer, (new String[] {
+				buffer.append(Messages.bind(Messages.classformat_ldc_w_integer, new String[] {
 					OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.LDC],
 					Integer.toString(index),
 					Integer.toString(constantPoolEntry.getIntegerValue())
-				})));
+				}));
 				break;
 			case IConstantPoolConstant.CONSTANT_String :
-				buffer.append(Messages.bind(Messages.classformat_ldc_w_string, (new String[] {
+				buffer.append(Messages.bind(Messages.classformat_ldc_w_string, new String[] {
 					OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.LDC],
 					Integer.toString(index),
 					constantPoolEntry.getStringValue()
-				})));
+				}));
 				break;
 			case IConstantPoolConstant.CONSTANT_Class :
-				buffer.append(Messages.bind(Messages.classformat_ldc_w_class, (new String[] {
+				buffer.append(Messages.bind(Messages.classformat_ldc_w_class, new String[] {
 					OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.LDC],
 					Integer.toString(index),
 					returnConstantClassName(constantPoolEntry)
-				})));
+				}));
 		}
 		writeNewLine();
 	}
@@ -1868,18 +1846,18 @@
 		dumpPcNumber(pc);
 		switch (constantPoolEntry.getKind()) {
 			case IConstantPoolConstant.CONSTANT_Long :
-				buffer.append(Messages.bind(Messages.classformat_ldc2_w_long, (new String[] {
+				buffer.append(Messages.bind(Messages.classformat_ldc2_w_long, new String[] {
 					OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.LDC2_W],
 					Integer.toString(index),
 					Long.toString(constantPoolEntry.getLongValue())
-				})));
+				}));
 				break;
 			case IConstantPoolConstant.CONSTANT_Double :
-				buffer.append(Messages.bind(Messages.classformat_ldc2_w_double, (new String[] {
+				buffer.append(Messages.bind(Messages.classformat_ldc2_w_double, new String[] {
 					OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.LDC2_W],
 					Integer.toString(index),
 					Double.toString(constantPoolEntry.getDoubleValue())
-				})));
+				}));
 		}
 		writeNewLine();
 	}
@@ -1898,10 +1876,10 @@
 	 */
 	public void _lload_0(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_load, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_load, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.LLOAD_0],
 			getLocalVariableName(pc, 0)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -1910,10 +1888,10 @@
 	 */
 	public void _lload_1(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_load, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_load, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.LLOAD_1],
 			getLocalVariableName(pc, 1)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -1922,10 +1900,10 @@
 	 */
 	public void _lload_2(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_load, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_load, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.LLOAD_2],
 			getLocalVariableName(pc, 2)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -1934,10 +1912,10 @@
 	 */
 	public void _lload_3(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_load, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_load, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.LLOAD_3],
 			getLocalVariableName(pc, 3)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -1946,10 +1924,10 @@
 	 */
 	public void _lload(int pc, int index) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_load, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_load, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.LLOAD],
-			getLocalVariableName(pc, index)
-		})));
+			getLocalVariableName(pc, index, true)
+		}));
 		writeNewLine();
 	}
 
@@ -2041,10 +2019,10 @@
 	 */
 	public void _lstore_0(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_store, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_store, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.LSTORE_0],
 			getLocalVariableName(pc, 0)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -2053,10 +2031,10 @@
 	 */
 	public void _lstore_1(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_store, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_store, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.LSTORE_1],
 			getLocalVariableName(pc, 1)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -2065,10 +2043,10 @@
 	 */
 	public void _lstore_2(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_store, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_store, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.LSTORE_2],
 			getLocalVariableName(pc, 2)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -2077,10 +2055,10 @@
 	 */
 	public void _lstore_3(int pc) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_store, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_store, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.LSTORE_3],
 			getLocalVariableName(pc, 3)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -2089,10 +2067,10 @@
 	 */
 	public void _lstore(int pc, int index) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_store, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_store, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.LSTORE],
-			getLocalVariableName(pc, index)
-		})));
+			getLocalVariableName(pc, index, true)
+		}));
 		writeNewLine();
 	}
 
@@ -2150,12 +2128,12 @@
 		int dimensions,
 		IConstantPoolEntry constantClass) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_multianewarray, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_multianewarray, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.MULTIANEWARRAY],
 			Integer.toString(index),
 			returnConstantClassName(constantClass),
 			appendDimensions(dimensions)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -2164,11 +2142,11 @@
 	 */
 	public void _new(int pc, int index, IConstantPoolEntry constantClass) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_new, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_new, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.NEW],
 			Integer.toString(index),
 			returnConstantClassName(constantClass)
-		})));
+		}));
 		writeNewLine();
 	}
 
@@ -2179,52 +2157,52 @@
 		dumpPcNumber(pc);
 		switch(atype) {
 			case T_BOOLEAN :
-				this.buffer.append(Messages.bind(Messages.classformat_newarray_boolean, (new String[] {
+				this.buffer.append(Messages.bind(Messages.classformat_newarray_boolean, new String[] {
 					OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.NEWARRAY],
 					Integer.toString(atype)
-				})));
+				}));
 				break;
 			case T_CHAR :
-				this.buffer.append(Messages.bind(Messages.classformat_newarray_char, (new String[] {
+				this.buffer.append(Messages.bind(Messages.classformat_newarray_char, new String[] {
 					OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.NEWARRAY],
 					Integer.toString(atype)
-				})));
+				}));
 				break;
 			case T_FLOAT :
-				this.buffer.append(Messages.bind(Messages.classformat_newarray_float, (new String[] {
+				this.buffer.append(Messages.bind(Messages.classformat_newarray_float, new String[] {
 					OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.NEWARRAY],
 					Integer.toString(atype)
-				})));
+				}));
 				break;
 			case T_DOUBLE :
-				this.buffer.append(Messages.bind(Messages.classformat_newarray_double, (new String[] {
+				this.buffer.append(Messages.bind(Messages.classformat_newarray_double, new String[] {
 					OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.NEWARRAY],
 					Integer.toString(atype)
-				})));
+				}));
 				break;
 			case T_BYTE :
-				this.buffer.append(Messages.bind(Messages.classformat_newarray_byte, (new String[] {
+				this.buffer.append(Messages.bind(Messages.classformat_newarray_byte, new String[] {
 					OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.NEWARRAY],
 					Integer.toString(atype)
-				})));
+				}));
 				break;
 			case T_SHORT :
-				this.buffer.append(Messages.bind(Messages.classformat_newarray_short, (new String[] {
+				this.buffer.append(Messages.bind(Messages.classformat_newarray_short, new String[] {
 					OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.NEWARRAY],
 					Integer.toString(atype)
-				})));
+				}));
 				break;
 			case T_INT :
-				this.buffer.append(Messages.bind(Messages.classformat_newarray_int, (new String[] {
+				this.buffer.append(Messages.bind(Messages.classformat_newarray_int, new String[] {
 					OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.NEWARRAY],
 					Integer.toString(atype)
-				})));
+				}));
 				break;
 			case T_LONG :
-				this.buffer.append(Messages.bind(Messages.classformat_newarray_long, (new String[] {
+				this.buffer.append(Messages.bind(Messages.classformat_newarray_long, new String[] {
 					OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.NEWARRAY],
 					Integer.toString(atype)
-				})));
+				}));
 		}
 		writeNewLine();
 	}
@@ -2261,13 +2239,13 @@
 	 */
 	public void _putfield(int pc, int index, IConstantPoolEntry constantFieldref) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_putfield, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_putfield, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.PUTFIELD],
 			Integer.toString(index),
 			returnDeclaringClassName(constantFieldref),
 			new String(constantFieldref.getFieldName()),
-			new String(constantFieldref.getFieldDescriptor())
-		})));
+			returnClassName(Signature.toCharArray(constantFieldref.getFieldDescriptor()))
+		}));
 		writeNewLine();
 	}
 
@@ -2276,13 +2254,13 @@
 	 */
 	public void _putstatic(int pc, int index, IConstantPoolEntry constantFieldref) {
 		dumpPcNumber(pc);
-		buffer.append(Messages.bind(Messages.classformat_putstatic, (new String[] {
+		buffer.append(Messages.bind(Messages.classformat_putstatic, new String[] {
 			OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.PUTSTATIC],
 			Integer.toString(index),
 			returnDeclaringClassName(constantFieldref),
 			new String(constantFieldref.getFieldName()),
-			new String(constantFieldref.getFieldDescriptor())
-		})));
+			returnClassName(Signature.toCharArray(constantFieldref.getFieldDescriptor()))
+		}));
 		writeNewLine();
 	}
 
@@ -2464,6 +2442,9 @@
 
 	private String returnConstantClassName(IConstantPoolEntry constantClass) {
 		char[] classInfoName = constantClass.getClassInfoName();
+		return returnClassName(classInfoName);
+	}
+	private String returnClassName(char[] classInfoName) {
 		if (classInfoName.length == 0) {
 			return EMPTY_CLASS_NAME;
 		} else if (isCompact()) {
@@ -2471,22 +2452,14 @@
 			if (lastIndexOfSlash != -1) {
 				return new String(classInfoName, lastIndexOfSlash + 1, classInfoName.length - lastIndexOfSlash - 1);
 			}
-			return new String(classInfoName);
-		} else {
-			return new String(classInfoName);
 		}
+		CharOperation.replace(classInfoName, '/', '.');
+		return new String(classInfoName);
 	}
 
 	private String returnDeclaringClassName(IConstantPoolEntry constantRef) {
-		if (isCompact()) {
-			char[] className = constantRef.getClassName();
-			int lastIndexOfSlash = CharOperation.lastIndexOf('/', className);
-			if (lastIndexOfSlash != -1) {
-				return new String(className, lastIndexOfSlash + 1, className.length - lastIndexOfSlash - 1);
-			}
-			return new String(constantRef.getClassName());
-		}
-		return new String(constantRef.getClassName());
+		final char[] className = constantRef.getClassName();
+		return returnClassName(className);
 	}
 
 	private void writeNewLine() {
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 ddf744c..1be2fa0 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
@@ -39,6 +39,7 @@
  */
 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$
@@ -394,13 +395,13 @@
 				char[] exceptionName = exceptionNames[i];
 				CharOperation.replace(exceptionName, '/', '.');
 				buffer
-					.append(exceptionName)
+					.append(returnClassName(exceptionName, '.', mode))
 					.append(Messages.disassembler_comma)
 					.append(Messages.disassembler_space); 
 			}
 			char[] exceptionName = exceptionNames[length - 1];
 			CharOperation.replace(exceptionName, '/', '.');
-			buffer.append(exceptionName);
+			buffer.append(returnClassName(exceptionName, '.', mode));
 		}
 		if (checkMode(mode, DETAILED)) {
 			if (annotationDefaultAttribute != null) {
@@ -578,7 +579,7 @@
 		if (superclassName != null) {
 			buffer.append(" extends "); //$NON-NLS-1$
 			CharOperation.replace(superclassName, '/', '.');
-			buffer.append(superclassName);
+			buffer.append(returnClassName(superclassName, '.', mode));
 		}
 		char[][] superclassInterfaces = classFileReader.getInterfaceNames();
 		int length = superclassInterfaces.length;
@@ -588,13 +589,13 @@
 				char[] superinterface = superclassInterfaces[i];
 				CharOperation.replace(superinterface, '/', '.');
 				buffer
-					.append(superinterface)
+					.append(returnClassName(superinterface, '.', mode))
 					.append(Messages.disassembler_comma)
 					.append(Messages.disassembler_space); 
 			}
 			char[] superinterface = superclassInterfaces[length - 1];
 			CharOperation.replace(superinterface, '/', '.');
-			buffer.append(superinterface);
+			buffer.append(returnClassName(superinterface, '.', mode));
 		}
 		buffer.append(Messages.bind(Messages.disassembler_opentypedeclaration)); 
 		if (checkMode(mode, SYSTEM)) {
@@ -743,13 +744,15 @@
 				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(localVariableTableEntry.getDescriptor())
+						new String(returnClassName(typeName, '.', mode))
 					}));
 				writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute + 1);
 			}
@@ -757,13 +760,15 @@
 			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(localVariableTableEntry.getDescriptor())
+					new String(returnClassName(typeName, '.', mode))
 				}));
 		} 
 		ILocalVariableTypeTableAttribute localVariableTypeAttribute= getLocalVariableTypeAttribute(codeAttribute);
@@ -779,13 +784,15 @@
 				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(localVariableTypeTableEntry.getSignature())
+						new String(returnClassName(typeName, '.', mode))
 					}));
 				writeNewLine(buffer, lineSeparator, tabNumberForLocalVariableAttribute + 1);
 			}
@@ -793,13 +800,15 @@
 			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(localVariableTypeTableEntry.getSignature())
+					new String(returnClassName(typeName, '.', mode))
 				}));
 		} 
 	}
@@ -831,12 +840,13 @@
 					buffer.append(
 						Messages.bind(Messages.disassembler_constantpool_fieldref,
 							new String[] {
-							Integer.toString(i),
-							Integer.toString(constantPoolEntry.getClassIndex()),
-							Integer.toString(constantPoolEntry.getNameAndTypeIndex()),
-							new String(constantPoolEntry.getClassName()),
-							new String(constantPoolEntry.getFieldName()),
-							new String(constantPoolEntry.getFieldDescriptor())}));
+								Integer.toString(i),
+								Integer.toString(constantPoolEntry.getClassIndex()),
+								Integer.toString(constantPoolEntry.getNameAndTypeIndex()),
+								new String(constantPoolEntry.getClassName()),
+								new String(constantPoolEntry.getFieldName()),
+								new String(constantPoolEntry.getFieldDescriptor())
+							}));
 					break;
 				case IConstantPoolConstant.CONSTANT_Float :
 					buffer.append(
@@ -849,8 +859,8 @@
 					buffer.append(
 						Messages.bind(Messages.disassembler_constantpool_integer,
 							new String[] {
-							Integer.toString(i),
-							Integer.toString(constantPoolEntry.getIntegerValue())}));
+								Integer.toString(i),
+								Integer.toString(constantPoolEntry.getIntegerValue())}));
 					break;
 				case IConstantPoolConstant.CONSTANT_InterfaceMethodref :
 					buffer.append(
@@ -1438,6 +1448,24 @@
 		return (mode & flag) != 0;
 	}
 	
+	private boolean isCompact(int mode) {
+		return (mode & ClassFileBytesDisassembler.COMPACT) != 0;
+	}
+
+	private String returnClassName(char[] classInfoName, char separator, int mode) {
+		if (classInfoName.length == 0) {
+			return EMPTY_CLASS_NAME;
+		} else if (isCompact(mode)) {
+			int lastIndexOfSlash = CharOperation.lastIndexOf(separator, classInfoName);
+			if (lastIndexOfSlash != -1) {
+				return new String(classInfoName, lastIndexOfSlash + 1, classInfoName.length - lastIndexOfSlash - 1);
+			}
+			return new String(classInfoName);
+		} else {
+			return new String(classInfoName);
+		}
+	}
+	
 	private void writeNewLine(StringBuffer buffer, String lineSeparator, int tabNumber) {
 		buffer.append(lineSeparator);
 		dumpTab(tabNumber, buffer);
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/KeyKind.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/KeyKind.java
index a145a5a..d2a788a 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/KeyKind.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/KeyKind.java
@@ -12,20 +12,22 @@
 
 public class KeyKind extends BindingKeyParser {
 
-	public static final int F_TYPE = 0x0001;
-	public static final int F_METHOD = 0x0010;
-	public static final int F_FIELD = 0x0011;
-	public static final int F_TYPE_PARAMETER = 0x0100;
-	public static final int F_LOCAL_VAR = 0x0101;
-	public static final int F_MEMBER = 0x0110;
-	public static final int F_LOCAL = 0x0111;
-	public static final int F_PARAMETERIZED_TYPE = 0x1000;
-	public static final int F_RAW_TYPE = 0x1001;
-	public static final int F_WILDCARD_TYPE = 0x1010;
-	public static final int F_PARAMETERIZED_METHOD = 0x1011;
-	public static final int F_CAPTURE = 0x1111;
+	public static final int F_TYPE = 0x00001;
+	public static final int F_METHOD = 0x00010;
+	public static final int F_FIELD = 0x00011;
+	public static final int F_TYPE_PARAMETER = 0x00100;
+	public static final int F_LOCAL_VAR = 0x00101;
+	public static final int F_MEMBER = 0x00110;
+	public static final int F_LOCAL = 0x00111;
+	public static final int F_PARAMETERIZED_TYPE = 0x01000;
+	public static final int F_RAW_TYPE = 0x01001;
+	public static final int F_WILDCARD_TYPE = 0x01010;
+	public static final int F_PARAMETERIZED_METHOD = 0x01011;
+	public static final int F_CAPTURE = 0x01111;
+	public static final int F_CONSTRUCTOR = 0x10000;
 	
 	public int flags = 0;
+	private KeyKind innerKeyKind;
 	
 	public KeyKind(BindingKeyParser parser) {
 		super(parser);
@@ -34,8 +36,12 @@
 	public KeyKind(String key) {
 		super(key);
 	}
+	
+	public void consumeBaseType(char[] baseTypeSig) {
+		this.flags |= F_TYPE;
+	}
 
-	public void consumeCapture() {
+	public void consumeCapture(int position) {
 		this.flags |= F_CAPTURE;
 	}
 	
@@ -57,15 +63,21 @@
 
 	public void consumeMethod(char[] selector, char[] signature) {
 		this.flags |= F_METHOD;
+		if (selector.length == 0)
+			this.flags |= F_CONSTRUCTOR;
 	}
 
-	public void consumeParameterizedMethod() {
+	public void consumeParameterizedGenericMethod() {
 		this.flags |= F_PARAMETERIZED_METHOD;
 	}
 
 	public void consumeParameterizedType(char[] simpleTypeName, boolean isRaw) {
 		this.flags |= isRaw ? F_RAW_TYPE : F_PARAMETERIZED_TYPE;
 	}
+	
+	public void consumeParser(BindingKeyParser parser) {
+		this.innerKeyKind = (KeyKind) parser;
+	}
 
 	public void consumeRawType() {
 		this.flags |= F_RAW_TYPE;
@@ -78,12 +90,16 @@
 	public void consumeTypeParameter(char[] typeParameterName) {
 		this.flags |= F_TYPE_PARAMETER;
 	}
+	
+	public void consumeTypeWithCapture() {
+		this.flags = this.innerKeyKind.flags;
+	}
 
 	public void consumeWildCard(int kind) {
 		this.flags |= F_WILDCARD_TYPE;
 	}
 
 	public BindingKeyParser newParser() {
-		return new BindingKeyParser(this);
+		return new KeyKind(this);
 	}
 }
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 c269c33..99ff0e2 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
@@ -12,13 +12,14 @@
 
 import java.util.ArrayList;
 
+import org.eclipse.jdt.core.Signature;
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.ast.Wildcard;
+import org.eclipse.jdt.internal.compiler.codegen.ConstantPool;
 
 /*
  * Converts a binding key into a signature 
  */
-// TODO (jerome) handle methods and fields
 public class KeyToSignature extends BindingKeyParser {
 	
 	public static final int SIGNATURE = 0;
@@ -31,9 +32,11 @@
 	private ArrayList typeParameters = new ArrayList();
 	private int mainTypeStart = -1;
 	private int mainTypeEnd;
+	private int typeSigStart = -1;
 	
 	public KeyToSignature(BindingKeyParser parser) {
 		super(parser);
+		this.kind = ((KeyToSignature) parser).kind;
 	}
 	
 	public KeyToSignature(String key, int kind) {
@@ -45,8 +48,14 @@
 		this.signature.append(brakets);
 	}
 	
-	public void consumeCapture() {
-		this.signature.append('!');
+	public void consumeBaseType(char[] baseTypeSig) {
+		this.typeSigStart = this.signature.length();
+		this.signature.append(baseTypeSig);
+	}
+	
+	public void consumeCapture(int position) {
+		// behave as if it was a wildcard
+		this.signature = ((KeyToSignature) this.arguments.get(0)).signature;
 	}
 		
 	public void consumeLocalType(char[] uniqueKey) {
@@ -75,6 +84,92 @@
 		this.signature.append(pkgName);
 	}
 	
+	public void consumeParameterizedGenericMethod() {
+		int typeParametersSize = this.arguments.size();
+		if (typeParametersSize > 0) {
+			int sigLength = this.signature.length();
+			char[] methodSignature = new char[sigLength];
+			this.signature.getChars(0, sigLength, methodSignature, 0);
+			char[][] typeParameterSigs = Signature.getTypeParameters(methodSignature);
+			if (typeParameterSigs.length != typeParametersSize)
+				return;
+			this.signature = new StringBuffer();
+			
+			// type parameters
+			for (int i = 0; i < typeParametersSize; i++)
+				typeParameterSigs[i] = CharOperation.concat(Signature.C_TYPE_VARIABLE,Signature.getTypeVariable(typeParameterSigs[i]), Signature.C_SEMICOLON);
+			int paramStart = CharOperation.indexOf(Signature.C_PARAM_START, methodSignature);
+			char[] typeParametersString = CharOperation.subarray(methodSignature, 0, paramStart);
+			this.signature.append(typeParametersString);
+			
+			// substitute parameters
+			this.signature.append(Signature.C_PARAM_START);
+			char[][] parameters = Signature.getParameterTypes(methodSignature);
+			for (int i = 0, parametersLength = parameters.length; i < parametersLength; i++)
+				substitute(parameters[i], typeParameterSigs, typeParametersSize);
+			this.signature.append(Signature.C_PARAM_END);
+			
+			// substitute return type
+			char[] returnType = Signature.getReturnType(methodSignature);
+			substitute(returnType, typeParameterSigs, typeParametersSize);
+
+			// substitute exceptions
+			char[][] exceptions = Signature.getThrownExceptionTypes(methodSignature);
+			for (int i = 0, exceptionsLength = exceptions.length; i < exceptionsLength; i++) {
+				this.signature.append(Signature.C_EXCEPTION_START);
+				substitute(exceptions[i], typeParameterSigs, typeParametersSize);
+			}
+		
+		}
+	}
+	
+	/*
+	 * Substitutes the type variables referenced in the given parameter (a parameterized type signature) with the corresponding
+	 * type argument.
+	 * Appends the given parameter if it is not a parameterized type signature.
+	 */
+	private void substitute(char[] parameter, char[][] typeParameterSigs, int typeParametersLength) {
+		for (int i = 0; i < typeParametersLength; i++) {
+			if (CharOperation.equals(parameter, typeParameterSigs[i])) {
+				String typeArgument = ((KeyToSignature) this.arguments.get(i)).signature.toString();
+				this.signature.append(typeArgument);
+				return;
+			}
+		}
+		int genericStart = CharOperation.indexOf(Signature.C_GENERIC_START, parameter);
+		if (genericStart > -1) {
+			this.signature.append(CharOperation.subarray(parameter, 0, genericStart));
+			char[][] parameters = Signature.getTypeArguments(parameter);
+			this.signature.append(Signature.C_GENERIC_START);
+			for (int j = 0, paramsLength = parameters.length; j < paramsLength; j++)
+				substitute(parameters[j], typeParameterSigs, typeParametersLength);
+			this.signature.append(Signature.C_GENERIC_END);
+			this.signature.append(Signature.C_SEMICOLON);
+		} else {
+			// handle array, wildcard and capture
+			int index = 0;
+			int length = parameter.length;
+			loop: while (index < length) {
+				char current = parameter[index];
+				switch (current) {
+					case Signature.C_CAPTURE:
+					case Signature.C_EXTENDS:
+					case Signature.C_SUPER:
+					case Signature.C_ARRAY:
+						this.signature.append(current);
+						index++;
+						break;
+					default:
+						break loop;
+				}
+			}
+			if (index > 0) 
+				substitute(CharOperation.subarray(parameter, index, length), typeParameterSigs, typeParametersLength);
+			else
+				this.signature.append(parameter);
+		}
+	}
+	
 	public void consumeParameterizedType(char[] simpleTypeName, boolean isRaw) {
 		if (simpleTypeName != null) {
 			// member type
@@ -85,7 +180,7 @@
 			this.signature.append('<');
 			int length = this.arguments.size();
 			for (int i = 0; i < length; i++) {
-				this.signature.append(this.arguments.get(i));
+				this.signature.append(((KeyToSignature) this.arguments.get(i)).signature);
 			}
 			this.signature.append('>');
 			if (this.kind != TYPE_ARGUMENTS)
@@ -94,10 +189,17 @@
 	}
 	
 	public void consumeParser(BindingKeyParser parser) {
-		this.arguments.add(((KeyToSignature) parser).signature);
+		this.arguments.add(parser);
+	}
+	
+	public void consumeField(char[] fieldName) {
+		if (this.kind == SIGNATURE) {
+			this.signature = ((KeyToSignature) this.arguments.get(0)).signature;
+		}
 	}
 	
 	public void consumeFullyQualifiedName(char[] fullyQualifiedName) {
+		this.typeSigStart = this.signature.length();
 		this.signature.append('L');
 		this.signature.append(CharOperation.replaceOnCopy(fullyQualifiedName, '/', '.'));
 	}
@@ -112,21 +214,26 @@
 	}
 
 	public void consumeType() {
-		int length = this.typeParameters.size();
-		if (length > 0) {
-			this.signature.append('<');
-			for (int i = 0; i < length; i++) {
-				this.signature.append('T');
-				this.signature.append((char[]) this.typeParameters.get(i));
-				this.signature.append(';');
-			}
-			this.signature.append('>');
-			this.typeParameters = new ArrayList();
-		}
 		// remove main type if needed
 		if (this.mainTypeStart != -1) {
 			this.signature.replace(this.mainTypeStart, this.mainTypeEnd, ""); //$NON-NLS-1$
 		}
+		// parameter types
+		int length = this.typeParameters.size();
+		if (length > 0) {
+			StringBuffer typeParametersSig = new StringBuffer();
+			typeParametersSig.append('<');
+			for (int i = 0; i < length; i++) {
+				char[] typeParameterSig = Signature.createTypeParameterSignature(
+						(char[]) this.typeParameters.get(i), 
+						new char[][]{ ConstantPool.ObjectSignature });
+				typeParametersSig.append(typeParameterSig);
+				// TODO (jerome) add type parameter bounds in binding key
+			}
+			typeParametersSig.append('>');
+			this.signature.insert(this.typeSigStart, typeParametersSig);
+			this.typeParameters = new ArrayList();
+		}
 		this.signature.append(';');
 	}
 	
@@ -134,23 +241,33 @@
 		this.typeParameters.add(typeParameterName);
 	}
 	
-	public void consumeTypeVariable(char[] typeVariableName) {
+	public void consumeTypeVariable(char[] position, char[] typeVariableName) {
 		this.signature = new StringBuffer();
 		this.signature.append('T');
 		this.signature.append(typeVariableName);
 		this.signature.append(';');
 	}
 	
+	public void consumeTypeWithCapture() {
+		KeyToSignature keyToSignature = (KeyToSignature) this.arguments.get(0);
+		this.signature = keyToSignature.signature;
+		this.arguments = keyToSignature.arguments;
+	}
+	
 	public void consumeWildCard(int wildCardKind) {
+		// don't put generic type in signature
+		this.signature = new StringBuffer();
 		switch (wildCardKind) {
 			case Wildcard.UNBOUND:
 				this.signature.append('*');
 				break;
 			case Wildcard.EXTENDS:
 				this.signature.append('+');
+				this.signature.append(((KeyToSignature) this.arguments.get(0)).signature);
 				break;
 			case Wildcard.SUPER:
 				this.signature.append('-');
+				this.signature.append(((KeyToSignature) this.arguments.get(0)).signature);
 				break;
 			default:
 				// malformed
@@ -162,7 +279,7 @@
 		int length = this.arguments.size();
 		String[] result = new String[length];
 		for (int i = 0; i < length; i++) {
-			result[i] = ((StringBuffer) this.arguments.get(i)).toString();
+			result[i] = ((KeyToSignature) this.arguments.get(i)).signature.toString();
 		}
 		return result;
 	}
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 3678ae1..6b5bf2e 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
@@ -158,12 +158,14 @@
 	public static String classpath_disabledInclusionExclusionPatterns;
 	public static String classpath_disabledMultipleOutputLocations;
 	public static String classpath_incompatibleLibraryJDKLevel;
+	public static String classpath_duplicateEntryExtraAttribute;
 	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 convention_unit_nullName;
@@ -289,13 +291,9 @@
 	public static String classformat_new;
 	public static String classformat_iinc;
 	public static String classformat_invokespecial;
-	public static String classformat_invokespecial_compact;
 	public static String classformat_invokeinterface;
-	public static String classformat_invokeinterface_compact;
 	public static String classformat_invokestatic;
-	public static String classformat_invokestatic_compact;
 	public static String classformat_invokevirtual;
-	public static String classformat_invokevirtual_compact;
 	public static String classformat_getfield;
 	public static String classformat_getstatic;
 	public static String classformat_putstatic;
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 a0d634e..c99113f 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
@@ -46,7 +46,7 @@
 			this.annotations = new IAnnotation[length];
 			for (int i = 0; i < length; i++) {
 				Annotation annotation = new Annotation(classFileBytes, constantPool, offset + readOffset);
-				this.annotations[i++] = annotation;
+				this.annotations[i] = annotation;
 				this.readOffset += annotation.sizeInBytes();
 			}
 		} else {
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 dbd2607..6d9095f 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
@@ -906,6 +906,9 @@
 					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) {
 					isWhiteSpace = jumpOverUnicodeWhiteSpace();
 					offset = this.currentPosition - offset;
@@ -954,12 +957,7 @@
 					this.withoutUnicodePtr = 0;
 				}
 			}
-			//little trick to get out in the middle of a source compuation
-			if (this.currentPosition > this.eofPosition)
-				return TokenNameEOF;
-
 			// ---------Identify the next token-------------
-
 			switch (this.currentCharacter) {
 				case '@' :
 /*					if (this.sourceLevel >= ClassFileConstants.JDK1_5) {
@@ -2386,11 +2384,6 @@
 	}
 	this.commentPtr = -1; // reset comment stack
 	this.foundTaskCount = 0;
-	
-//	// if resetTo is used with being > than end.
-//	if (begin > this.eofPosition) {
-//		begin = this.eofPosition;
-//	}
 }
 
 public final void scanEscapeCharacter() throws InvalidInputException {
@@ -3357,20 +3350,30 @@
 	this.containsAssertKeyword = false;
 	this.linePtr = -1;	
 }
-
 /*
  * Should be used if a parse (usually a diet parse) has already been performed on the unit, 
  * so as to get the already computed line end positions.
  */
-public final void setSource(CompilationResult compilationResult) {
-	char[] contents = compilationResult.compilationUnit.getContents();
-	setSource(contents);
+public final void setSource(char[] contents, CompilationResult compilationResult) {
+	if (contents == null) {
+		char[] cuContents = compilationResult.compilationUnit.getContents();
+		setSource(cuContents);
+	} else {
+		setSource(contents);
+	}
 	int[] lineSeparatorPositions = compilationResult.lineSeparatorPositions;
 	if (lineSeparatorPositions != null) {
 		this.lineEnds = lineSeparatorPositions;
 		this.linePtr = lineSeparatorPositions.length - 1;
 	}
 }
+/*
+ * Should be used if a parse (usually a diet parse) has already been performed on the unit, 
+ * so as to get the already computed line end positions.
+ */
+public final void setSource(CompilationResult compilationResult) {
+	setSource(null, compilationResult);
+}
 public String toString() {
 	if (this.startPosition == this.source.length)
 		return "EOF\n\n" + new String(this.source); //$NON-NLS-1$
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 e1bb0aa..2bdd34f 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
@@ -16,11 +16,10 @@
 import java.util.zip.ZipFile;
 
 import org.eclipse.core.resources.*;
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IFolder;
-import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.*;
 import org.eclipse.core.runtime.content.IContentType;
+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.dom.ASTNode;
@@ -841,6 +840,41 @@
 	}
 	
 	/**
+	 * Returns the line separator found in the given text.
+	 * If it is null, or not found return the line delimitor for the given project.
+	 * If the project is null, returns the line separator for the workspace.
+	 * If still null, return the system line separator.
+	 */
+	public static String getLineSeparator(String text, IJavaProject project) {
+		String lineSeparator = null;
+		
+		// line delimiter in given text
+		if (text != null) {
+			lineSeparator = findLineSeparator(text.toCharArray());
+			if (lineSeparator != null)
+				return lineSeparator;
+		}
+		
+		// line delimiter in project preference
+		IScopeContext[] scopeContext;
+		if (project != null) {
+			scopeContext= new IScopeContext[] { new ProjectScope(project.getProject()) };
+			lineSeparator= Platform.getPreferencesService().getString(Platform.PI_RUNTIME, Platform.PREF_LINE_SEPARATOR, null, scopeContext);
+			if (lineSeparator != null)
+				return lineSeparator;
+		}
+		
+		// line delimiter in workspace preference
+		scopeContext= new IScopeContext[] { new InstanceScope() };
+		lineSeparator = Platform.getPreferencesService().getString(Platform.PI_RUNTIME, Platform.PREF_LINE_SEPARATOR, null, scopeContext);
+		if (lineSeparator != null)
+			return lineSeparator;
+		
+		// system line delimiter
+		return org.eclipse.jdt.internal.compiler.util.Util.LINE_SEPARATOR;
+	}
+	
+	/**
 	 * Returns the line separator used by the given buffer.
 	 * Uses the given text if none found.
 	 *
@@ -854,7 +888,7 @@
 			lineSeparator = findLineSeparator(text);
 			if (lineSeparator == null) {
 				// default to system line separator
-				return org.eclipse.jdt.internal.compiler.util.Util.LINE_SEPARATOR;
+				return getLineSeparator((String) null, (IJavaProject) null);
 			}
 		}
 		return lineSeparator;
@@ -1017,6 +1051,18 @@
 	}
 	
 	/*
+	 * 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.
+	 * 
+	 * @return the declaring type signature
+	 */
+	public static String getDeclaringTypeSignature(String key) {
+		KeyToSignature keyToSignature = new KeyToSignature(key, KeyToSignature.DECLARING_TYPE);
+		keyToSignature.parse();
+		return keyToSignature.signature.toString();
+	}
+	
+	/*
 	 * Appends to the given buffer the fully qualified name (as it appears in the source) of the given type
 	 */
 	private static void getFullyQualifiedName(Type type, StringBuffer buffer) {
@@ -1931,14 +1977,6 @@
 		}
 		return segs;
 	}
-	
-	/**
-	 * Converts a char[] to String.
-	 */
-	public static String toString(char[] c) {
-		return new String(c);
-	}
-
 	/**
 	 * Converts a char[][] to String, where segments are separated by '.'.
 	 */
@@ -1976,19 +2014,34 @@
 		}
 		return result;
 	}
-	private static void appendArrayTypeSignature(char[] string, int start, StringBuffer buffer) {
+	private static void appendArrayTypeSignature(char[] string, int start, StringBuffer buffer, boolean compact) {
+		int length = string.length;
 		// need a minimum 2 char
-		if (start >= string.length - 1) {
+		if (start >= length - 1) {
 			throw new IllegalArgumentException();
 		}
 		char c = string[start];
 		if (c != Signature.C_ARRAY) { //$NON-NLS-1$
 			throw new IllegalArgumentException();
 		}
-		appendTypeSignature(string, start + 1, buffer);
-		buffer.append('[').append(']');
+		
+		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];
+		}
+		
+		appendTypeSignature(string, index, buffer, compact);
+		
+		for(int i = 0, dims = index - start; i < dims; i++) {
+			buffer.append('[').append(']');
+		}
 	}
-	private static void appendClassTypeSignature(char[] string, int start, StringBuffer buffer) {
+	private static void appendClassTypeSignature(char[] string, int start, StringBuffer buffer, boolean compact) {
 		char c = string[start];
 		if (c != Signature.C_RESOLVED) {
 			return;
@@ -2002,12 +2055,13 @@
 					// all done
 					return;
 				case Signature.C_DOT :
+				case '/' :
 					// erase package prefix
-					buffer.setLength(checkpoint);
-					break;
-				 case '/' :
-					// erase package prefix
-					buffer.setLength(checkpoint);
+					if (compact) {
+						buffer.setLength(checkpoint);
+					} else {
+						buffer.append('.');
+					}
 					break;
 				 case Signature.C_DOLLAR :
 					/**
@@ -2024,14 +2078,14 @@
 			p++;
 		}
 	}
-	static void appendTypeSignature(char[] string, int start, StringBuffer buffer) {
+	static void appendTypeSignature(char[] string, int start, StringBuffer buffer, boolean compact) {
 		char c = string[start];
 		switch (c) {
 			case Signature.C_ARRAY :
-				appendArrayTypeSignature(string, start, buffer);
+				appendArrayTypeSignature(string, start, buffer, compact);
 				break;
 			case Signature.C_RESOLVED :
-				appendClassTypeSignature(string, start, buffer);
+				appendClassTypeSignature(string, start, buffer, compact);
 				break;
 			case Signature.C_TYPE_VARIABLE :
 				int e = Util.scanTypeVariableSignature(string, start);
@@ -2066,8 +2120,8 @@
 				break;
 		}
 	}
-	public static String toString(char[] declaringClass, char[] methodName, char[] methodSignature, boolean includeReturnType) {
-		boolean isConstructor = CharOperation.equals(methodName, INIT);
+	public static String toString(char[] declaringClass, char[] methodName, char[] methodSignature, boolean includeReturnType, boolean compact) {
+		final boolean isConstructor = CharOperation.equals(methodName, INIT);
 		int firstParen = CharOperation.indexOf(Signature.C_PARAM_START, methodSignature);
 		if (firstParen == -1) {
 			return ""; //$NON-NLS-1$
@@ -2075,25 +2129,28 @@
 		
 		StringBuffer buffer = new StringBuffer(methodSignature.length + 10);
 		
-		if (!isConstructor) {
-			// return type
-			if (includeReturnType) {
-				char[] rts = Signature.getReturnType(methodSignature);
-				appendTypeSignature(rts, 0 , buffer);
-				buffer.append(' ');
+		// decode declaring class name
+		// it can be either an array signature or a type signature
+		if (declaringClass.length > 0) {
+			char[] declaringClassSignature = null;
+			if (declaringClass[0] == Signature.C_ARRAY) {
+				CharOperation.replace(declaringClass, '/', '.');
+				declaringClassSignature = Signature.toCharArray(declaringClass);
+			} else {
+				CharOperation.replace(declaringClass, '/', '.');
+				declaringClassSignature = declaringClass;
+			}
+			int lastIndexOfSlash = CharOperation.lastIndexOf('.', declaringClassSignature);
+			if (compact && lastIndexOfSlash != -1) {
+				buffer.append(declaringClassSignature, lastIndexOfSlash + 1, declaringClassSignature.length - lastIndexOfSlash - 1);
+			} else {
+				buffer.append(declaringClassSignature);
 			}
 		}
-		
+
 		// selector
-		int lastIndexOfSlash = CharOperation.lastIndexOf('/', declaringClass);
-		if (lastIndexOfSlash != -1) {
-			buffer.append(declaringClass, lastIndexOfSlash + 1, declaringClass.length - lastIndexOfSlash - 1);
-		} else {
-			buffer.append(declaringClass);
-		}
 		if (!isConstructor) {
 			buffer.append('.');
-	
 			if (methodName != null) {
 				buffer.append(methodName);
 			}
@@ -2103,17 +2160,23 @@
 		buffer.append('(');
 		char[][] pts = Signature.getParameterTypes(methodSignature);
 		for (int i = 0, max = pts.length; i < max; i++) {
-			if (i == max - 1) {
-				appendTypeSignature(pts[i], 0 , buffer);
-			} else {
-				appendTypeSignature(pts[i], 0 , buffer);
-			}
+			appendTypeSignature(pts[i], 0 , buffer, compact);
 			if (i != pts.length - 1) {
 				buffer.append(',');
 				buffer.append(' ');
 			}
 		}
 		buffer.append(')');
+		
+		if (!isConstructor) {
+			buffer.append(" : "); //$NON-NLS-1$
+			// return type
+			if (includeReturnType) {
+				char[] rts = Signature.getReturnType(methodSignature);
+				appendTypeSignature(rts, 0 , buffer, compact);
+				buffer.append(' ');
+			}
+		}
 		return String.valueOf(buffer);
 	}
 	/*
@@ -2352,15 +2415,25 @@
 	 * @exception IllegalArgumentException if this is not an array type signature
 	 */
 	public static int scanArrayTypeSignature(char[] string, int start) {
+		int length = string.length;
 		// need a minimum 2 char
-		if (start >= string.length - 1) {
+		if (start >= length - 1) {
 			throw new IllegalArgumentException();
 		}
 		char c = string[start];
 		if (c != Signature.C_ARRAY) { //$NON-NLS-1$
 			throw new IllegalArgumentException();
 		}
-		return scanTypeSignature(string, start + 1);
+		
+		c = string[++start];
+		while(c == Signature.C_ARRAY) {
+			// need a minimum 2 char
+			if (start >= length - 1) {
+				throw new IllegalArgumentException();
+			}
+			c = string[++start];
+		}
+		return scanTypeSignature(string, start);
 	}
 	
 	/**
@@ -2545,6 +2618,8 @@
 				return scanTypeVariableSignature(string, start);
 			case Signature.C_ARRAY :
 				return scanArrayTypeSignature(string, start);
+			case Signature.C_STAR:
+				return start;
 			default:
 				throw new IllegalArgumentException();
 		}
@@ -2677,7 +2752,7 @@
 	 */
 	public final static char[][] splitTypeLevelsSignature(String typeSignature) {
 		// In case of IJavaElement signature, replace '$' by '.'
-		char[] source = Signature.removeCaptureFromMethod(typeSignature.toCharArray());
+		char[] source = Signature.removeCapture(typeSignature.toCharArray());
 		CharOperation.replace(source, '$', '.');
 
 		// Init counters and arrays
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 ea0d966..b271672 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
@@ -164,6 +164,7 @@
 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}
 
 ### miscellaneous
 file_notFound = File not found: ''{0}''
@@ -172,6 +173,7 @@
 path_mustBeAbsolute = Path must be absolute
 cache_invalidLoadFactor = Incorrect load factor
 savedState_jobName = Processing Java changes since last activation
+javamodel_initialization = Initializing Java tooling
 
 ### access restrictions
 restrictedAccess_project = The type {0} is not accessible due to restriction on required project {1}
@@ -314,19 +316,15 @@
 classformat_ldc2_w_double = {0} <Double {2}> [{1}]
 classformat_multianewarray = {0} {2}{3} [{1}]
 classformat_new = {0} {2} [{1}]
-classformat_iinc = {0} {1} {2} [{3}]
-classformat_invokespecial = {0} {2}.{3}{4} [{1}]
-classformat_invokespecial_compact ={0} {2} [{1}]
-classformat_invokeinterface ={0} {3}.{4}{5} [{1}] [nargs: {2}]
-classformat_invokeinterface_compact ={0} {3} [{1}] [nargs: {2}]
-classformat_invokestatic ={0} {2}.{3}{4} [{1}]
-classformat_invokestatic_compact ={0} {2} [{1}]
-classformat_invokevirtual ={0} {2}.{3}{4} [{1}]
-classformat_invokevirtual_compact ={0} {2} [{1}]
-classformat_getfield ={0} {2}.{3} {4} [{1}]
-classformat_getstatic ={0} {2}.{3} {4} [{1}]
-classformat_putstatic ={0} {2}.{3} {4} [{1}]
-classformat_putfield ={0} {2}.{3} {4} [{1}]
+classformat_iinc = {0} {1} {2}{3}
+classformat_invokespecial ={0} {2} [{1}]
+classformat_invokeinterface ={0} {3} [{1}] [nargs: {2}]
+classformat_invokestatic ={0} {2} [{1}]
+classformat_invokevirtual ={0} {2} [{1}]
+classformat_getfield ={0} {2}.{3} : {4} [{1}]
+classformat_getstatic ={0} {2}.{3} : {4} [{1}]
+classformat_putstatic ={0} {2}.{3} : {4} [{1}]
+classformat_putfield ={0} {2}.{3} : {4} [{1}]
 classformat_newarray_boolean = {0} boolean [{1}]
 classformat_newarray_char = {0} char [{1}]
 classformat_newarray_float = {0} float [{1}]
@@ -335,8 +333,8 @@
 classformat_newarray_short = {0} short [{1}]
 classformat_newarray_int = {0} int [{1}]
 classformat_newarray_long = {0} long [{1}]
-classformat_store = {0} [{1}]
-classformat_load = {0} [{1}]
+classformat_store = {0}{1}
+classformat_load = {0}{1}
 classfileformat_anyexceptionhandler=any
 classfileformat_exceptiontableentry = [pc: {0}, pc: {1}] -> {2} when : {3}
 classfileformat_linenumbertableentry = [pc: {0}, line: {1}]
diff --git a/org.eclipse.jdt.core/plugin.properties b/org.eclipse.jdt.core/plugin.properties
index f1c9b2e..c165a9d 100644
--- a/org.eclipse.jdt.core/plugin.properties
+++ b/org.eclipse.jdt.core/plugin.properties
@@ -21,5 +21,6 @@
 javaTaskName=Java Task
 javaPropertiesName=Java Properties File
 javaSourceName=Java Source File
+javaClassName=Java Class File
 jarManifestName=JAR Manifest File
 extraJavaLikeFileExtensions=Extra Java-like File Extensions
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/plugin.xml b/org.eclipse.jdt.core/plugin.xml
index 89024aa..346f9ec 100644
--- a/org.eclipse.jdt.core/plugin.xml
+++ b/org.eclipse.jdt.core/plugin.xml
@@ -3,24 +3,12 @@
 <!-- =================================================================================== -->
 <!-- JDT/CORE Plug-in Manifest                                                           -->
 <!-- =================================================================================== -->
-<plugin
-    name = "%pluginName"
-    id = "org.eclipse.jdt.core"
-    version = "3.1.0"
-    provider-name = "%providerName"
-    class="org.eclipse.jdt.core.JavaCore">
+<plugin>
 
 <!-- =================================================================================== -->
 <!-- Prerequisite Plug-ins                                                               -->
 <!-- =================================================================================== -->
 
-<requires>
-    <import plugin="org.eclipse.core.resources"/>
-    <import plugin="org.eclipse.core.runtime"/>    
-    <import plugin="org.eclipse.text"/>
-    <import plugin="org.apache.ant" optional="true"/>
-    <import plugin="org.eclipse.team.core" optional="true"/>
-</requires>
 
 <!-- =================================================================================== -->
 <!-- Runtime Libraries                                                                   -->
@@ -187,6 +175,15 @@
 		base-type="org.eclipse.core.runtime.text"
 		priority="high"				
 		file-extensions="java"/>
+	<!-- declares a content type for Java class files -->
+    <content-type id="javaClass" name="%javaClassName" 
+        priority="high"				
+        file-extensions="class">        
+        <describer
+            class="org.eclipse.core.runtime.content.BinarySignatureDescriber">
+            <parameter name="signature" value="CA, FE, BA, BE"/>
+        </describer>
+    </content-type>        
 	<!-- declares a content type for JAR manifest files -->
     <content-type id="JARManifest" name="%jarManifestName" 
         base-type="org.eclipse.core.runtime.text"
@@ -202,5 +199,9 @@
       point="org.eclipse.core.runtime.preferences">
    <initializer class="org.eclipse.jdt.internal.core.JavaCorePreferenceInitializer"/>
 </extension>
+<extension
+      point="org.eclipse.core.runtime.preferences">
+   <modifier class="org.eclipse.jdt.internal.core.JavaCorePreferenceModifyListener"/>
+</extension>
 
 </plugin>
diff --git a/org.eclipse.jdt.core/schema/classpathContainerInitializer.exsd b/org.eclipse.jdt.core/schema/classpathContainerInitializer.exsd
index 07085b2..c296a2f 100644
--- a/org.eclipse.jdt.core/schema/classpathContainerInitializer.exsd
+++ b/org.eclipse.jdt.core/schema/classpathContainerInitializer.exsd
@@ -58,6 +58,9 @@
                   the class that implements this container initializer.

          This class must implement a public subclass of &lt;code&gt;org.eclipse.jdt.core.ClasspathContainerInitializer&lt;/code&gt; with a public 0-argument constructor.

                </documentation>

+               <appInfo>

+                  <meta.attribute kind="java" basedOn="org.eclipse.jdt.core.ClasspathContainerInitializer"/>

+               </appInfo>

             </annotation>

          </attribute>

       </complexType>

diff --git a/org.eclipse.jdt.core/schema/classpathVariableInitializer.exsd b/org.eclipse.jdt.core/schema/classpathVariableInitializer.exsd
index ca78aa8..c5d33a5 100644
--- a/org.eclipse.jdt.core/schema/classpathVariableInitializer.exsd
+++ b/org.eclipse.jdt.core/schema/classpathVariableInitializer.exsd
@@ -58,6 +58,9 @@
                   the class that implements this variable initializer.

          This class must implement a public subclass of &lt;code&gt;org.eclipse.jdt.core.ClasspathVariableInitializer&lt;/code&gt; with a public 0-argument constructor.

                </documentation>

+               <appInfo>

+                  <meta.attribute kind="java" basedOn="org.eclipse.jdt.core.ClasspathVariableInitializer"/>

+               </appInfo>

             </annotation>

          </attribute>

       </complexType>

diff --git a/org.eclipse.jdt.core/scripts/export-batch-jdtcom.xml b/org.eclipse.jdt.core/scripts/export-batch-jdtcom.xml
index 742ef03..19ad32d 100644
--- a/org.eclipse.jdt.core/scripts/export-batch-jdtcom.xml
+++ b/org.eclipse.jdt.core/scripts/export-batch-jdtcom.xml
@@ -22,13 +22,6 @@
 	        </fileset>
 	        <fileset dir="bin" includes="org/eclipse/jdt/internal/compiler/**,org/eclipse/jdt/core/compiler/**"/>
 		</zip>
-<!--		<jar 
-			jarfile="${dest}/jdtcom.jar"
-			basedir="bin"
-			includes="org/eclipse/jdt/internal/compiler/**,org/eclipse/jdt/core/compiler/**"
-			manifest="META-INF/MANIFEST.MF"
-			index="true"/> -->
-		
 		<echo message="UPDATE jdtcomsrc.zip" />
 		<zip zipfile="${dest}/jdtcomsrc.zip">
 		    <zipfileset dir="batch" />
diff --git a/org.eclipse.jdt.core/scripts/export-ejavac.xml b/org.eclipse.jdt.core/scripts/export-ejavac.xml
index 594271c..09ef024 100644
--- a/org.eclipse.jdt.core/scripts/export-ejavac.xml
+++ b/org.eclipse.jdt.core/scripts/export-ejavac.xml
@@ -2,11 +2,11 @@
 <project name="export-executable" default="build" basedir="..">
 
 	<property name="version" value="310" />
-	<property name="gcc-path" value="d:/gcj/thisiscool-gcc/gcc-4.0" />
+	<property name="gcc-path" value="D:\java_tools\thisiscool-gcc\gcc-4.0.old" />
 	<property name="binaryname" value="ejavac${version}" />
 	<property name="dest" value="../../bingcj/" />
 	<property name="work" value="${dest}tmp/" />
-	<property name="source" value="d:/eclipse/workspaces/dev3.1/plugins/org.eclipse.jdt.core" />
+	<property name="source" value="D:/eclipse/workspaces/head/org.eclipse.jdt.core" />
 	<property name="gcj_script_name" value="export-executable.xml"/>
 
     <target name="build">
diff --git a/org.eclipse.jdt.core/scripts/exportplugin.xml b/org.eclipse.jdt.core/scripts/exportplugin.xml
index 0433f0e..41ec08a 100644
--- a/org.eclipse.jdt.core/scripts/exportplugin.xml
+++ b/org.eclipse.jdt.core/scripts/exportplugin.xml
@@ -1,7 +1,13 @@
 <?xml version="1.0" encoding="UTF-8"?>
 
 <!-- build script to create a plugin from ${plugin} -->
-<project name="${plugin}" default="export plug-in [_3.1.0]" basedir="..">
+<project name="${plugin}" default="export plug-in [_3.1.1]" basedir="..">
+
+<target name="export plug-in [_3.1.1]">
+	<antcall target="zz_internal_export">
+		<param name="jdt_core_version" value="3.1.1"/>
+	</antcall>
+</target>
 
 <target name="export plug-in [_3.1.0]">
 	<antcall target="zz_internal_export">
@@ -82,8 +88,8 @@
 	</zip>
 
 	<delete file="${plugin-dir}/jdtCompilerAdapter.jar"/>
-	<echo message="UPDATE jdtcoresrc.zip" />
-	<zip zipfile="${plugin-dir}/jdtcoresrc.zip">
+	<echo message="UPDATE src.zip" />
+	<zip zipfile="${plugin-dir}/src.zip">
         <fileset file="component.xml"/>	
 	    <fileset dir="batch" />
 	    <fileset dir="codeassist" />
diff --git a/org.eclipse.jdt.core/scripts/ikvm_script.xml b/org.eclipse.jdt.core/scripts/ikvm_script.xml
new file mode 100644
index 0000000..7324c60
--- /dev/null
+++ b/org.eclipse.jdt.core/scripts/ikvm_script.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0"?>
+<project name="ecj" default="all" basedir="..">
+	<!-- target name="checkout">
+     <exec program="cvs" commandline="-z3 -d:pserver:anonymous@dev.eclipse.org:/home/eclipse co org.eclipse.jdt.core" />
+   </target>
+   <target name="allsources">
+     <exec program="cmd" commandline="/c dir /s/b org.eclipse.jdt.core\batch\*.java > allsources.lst" />
+     <exec program="cmd" commandline="/c dir /s/b org.eclipse.jdt.core\compiler\*.java >> allsources.lst" />
+   </target>
+   <target name="classes">
+     <exec program="../bin/ikvmstub.exe" commandline="IKVM.GNU.Classpath" useruntimeengine="true" />
+     <exec program="jikes" commandline="-nowarn -classpath IKVM.GNU.Classpath.jar;org.eclipse.jdt.core/compiler;org.eclipse.jdt.core/batch @allsources.lst" />
+     <delete file="IKVM.GNU.Classpath.jar" />
+   </target -->
+	<property name="ikvm_home" value="D:\java_tools\ikvm" />
+	<property name="dest" value="../../bingcj" />
+	<property name="work" value="${dest}/tmp" />
+	<property name="build.compiler" value="org.eclipse.jdt.core.JDTCompilerAdapter"/>
+	<property name="source" value="D:/eclipse/workspaces/head/org.eclipse.jdt.core" />
+
+    <target name="clean">
+		<echo message="target: ${dest}" />
+		<delete dir="${dest}" failonerror="no"/>
+		<mkdir dir="${dest}" />
+	</target>	
+
+	<target name="retrieve_class_files">
+		<copy todir="${work}">
+		    <fileset dir="${source}/batch/" includes='**/*.java' />
+		</copy>
+		<copy todir="${work}">
+		    <fileset dir="${source}/compiler/" includes='**/*.java' />
+		</copy>
+
+		<echo message="copy resource files"/>
+		<copy todir="${dest}">
+		    <fileset dir="${source}/compiler/" includes='**/*.rsc' />
+		</copy>
+
+		<echo message="copy properties files from compiler"/>
+		<copy todir="${dest}">
+		    <fileset dir="${source}/compiler/" includes='**/*.properties' />
+		    <fileset dir="${source}/batch/" includes='**/*.properties' />
+		</copy>
+
+		<javac srcdir="${work}" destdir="${dest}" nowarn="off" deprecation="off" source="1.4" debug="off" verbose="on">
+			<classpath>
+				<path location="${work}"/>
+			</classpath>
+		</javac>
+
+		<delete dir="${work}" failonerror="no"/>
+	</target>
+
+	<target name="ecj">
+		<exec dir="${dest}" executable="${ikvm_home}/bin/ikvmc.exe" output="${dest}/log.txt">
+			<arg line="-out:ecj.exe -main:org.eclipse.jdt.internal.compiler.batch.Main -recurse:./*.class -recurse:./*.properties -recurse:./*.rsc"/>
+		</exec>
+		<copy file="${ikvm_home}/bin/IKVM.Runtime.dll" todir="${dest}" />
+		<copy file="${ikvm_home}/bin/IKVM.GNU.Classpath.dll" todir="${dest}" />
+	</target>
+
+	<target name="all" depends="clean, retrieve_class_files, ecj">
+	</target>
+</project>
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchEngine.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchEngine.java
index 2d8e8a5..22ed1ec 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchEngine.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchEngine.java
@@ -19,12 +19,12 @@
 import org.eclipse.jdt.internal.core.search.matching.*;
 
 /**
- * A <code>SearchEngine</code> searches for Java elements following a search pattern.
+ * A {@link SearchEngine} searches for Java elements following a search pattern.
  * The search can be limited to a search scope.
  * <p>
  * Various search patterns can be created using the factory methods 
- * <code>createSearchPattern(String, int, int, boolean)</code>, <code>createSearchPattern(IJavaElement, int)</code>,
- * <code>createOrSearchPattern(ISearchPattern, ISearchPattern)</code>.
+ * {@link SearchPattern#createPattern(String, int, int, int)}, {@link SearchPattern#createPattern(IJavaElement, int)},
+ * {@link SearchPattern#createOrPattern(SearchPattern, SearchPattern)}.
  * </p>
  * <p>For example, one can search for references to a method in the hierarchy of a type, 
  * or one can search for the declarations of types starting with "Abstract" in a project.
@@ -324,26 +324,26 @@
 	 * @param stringPattern the given pattern
 	 * @param searchFor determines the nature of the searched elements
 	 *	<ul>
-	 * 	<li><code>IJavaSearchConstants.CLASS</code>: only look for classes</li>
-	 *		<li><code>IJavaSearchConstants.INTERFACE</code>: only look for interfaces</li>
-	 * 	<li><code>IJavaSearchConstants.TYPE</code>: look for both classes and interfaces</li>
-	 *		<li><code>IJavaSearchConstants.FIELD</code>: look for fields</li>
-	 *		<li><code>IJavaSearchConstants.METHOD</code>: look for methods</li>
-	 *		<li><code>IJavaSearchConstants.CONSTRUCTOR</code>: look for constructors</li>
-	 *		<li><code>IJavaSearchConstants.PACKAGE</code>: look for packages</li>
+	 * 	<li>{@link IJavaSearchConstants#CLASS}: only look for classes</li>
+	 *		<li>{@link IJavaSearchConstants#INTERFACE}: only look for interfaces</li>
+	 * 	<li>{@link IJavaSearchConstants#TYPE}: look for both classes and interfaces</li>
+	 *		<li>{@link IJavaSearchConstants#FIELD}: look for fields</li>
+	 *		<li>{@link IJavaSearchConstants#METHOD}: look for methods</li>
+	 *		<li>{@link IJavaSearchConstants#CONSTRUCTOR}: look for constructors</li>
+	 *		<li>{@link IJavaSearchConstants#PACKAGE}: look for packages</li>
 	 *	</ul>
 	 * @param limitTo determines the nature of the expected matches
 	 *	<ul>
-	 * 		<li><code>IJavaSearchConstants.DECLARATIONS</code>: will search declarations matching with the corresponding
+	 * 		<li>{@link IJavaSearchConstants#DECLARATIONS}: will search declarations matching with the corresponding
 	 * 			element. In case the element is a method, declarations of matching methods in subtypes will also
 	 *  		be found, allowing to find declarations of abstract methods, etc.</li>
 	 *
-	 *		 <li><code>IJavaSearchConstants.REFERENCES</code>: will search references to the given element.</li>
+	 *		 <li>{@link IJavaSearchConstants#REFERENCES}: will search references to the given element.</li>
 	 *
-	 *		 <li><code>IJavaSearchConstants.ALL_OCCURRENCES</code>: will search for either declarations or references as specified
+	 *		 <li>{@link IJavaSearchConstants#ALL_OCCURRENCES}: will search for either declarations or references as specified
 	 *  		above.</li>
 	 *
-	 *		 <li><code>IJavaSearchConstants.IMPLEMENTORS</code>: for interface, will find all types which implements a given interface.</li>
+	 *		 <li>{@link IJavaSearchConstants#IMPLEMENTORS}: for interface, will find all types which implements a given interface.</li>
 	 *	</ul>
 	 *
 	 * @param isCaseSensitive indicates whether the search is case sensitive or not.
@@ -365,16 +365,16 @@
 	 * @param element the Java element the search pattern is based on
 	 * @param limitTo determines the nature of the expected matches
 	 * 	<ul>
-	 * 		<li><code>IJavaSearchConstants.DECLARATIONS</code>: will search declarations matching with the corresponding
+	 * 		<li>{@link IJavaSearchConstants#DECLARATIONS}: will search declarations matching with the corresponding
 	 * 			element. In case the element is a method, declarations of matching methods in subtypes will also
 	 *  		be found, allowing to find declarations of abstract methods, etc.</li>
 	 *
-	 *		 <li><code>IJavaSearchConstants.REFERENCES</code>: will search references to the given element.</li>
+	 *		 <li>{@link IJavaSearchConstants#REFERENCES}: will search references to the given element.</li>
 	 *
-	 *		 <li><code>IJavaSearchConstants.ALL_OCCURRENCES</code>: will search for either declarations or references as specified
+	 *		 <li>{@link IJavaSearchConstants#ALL_OCCURRENCES}: will search for either declarations or references as specified
 	 *  		above.</li>
 	 *
-	 *		 <li><code>IJavaSearchConstants.IMPLEMENTORS</code>: for interface, will find all types which implements a given interface.</li>
+	 *		 <li>{@link IJavaSearchConstants#IMPLEMENTORS}: for interface, will find all types which implements a given interface.</li>
 	 *	</ul>
 	 * @return a search pattern for a Java element or <code>null</code> if the given element is ill-formed
 	 * @deprecated Use {@link SearchPattern#createPattern(IJavaElement, int)} instead.
@@ -413,16 +413,16 @@
 	 * @param workspace the workspace
 	 * @param patternString the pattern to be searched for
 	 * @param searchFor a hint what kind of Java element the string pattern represents.
-	 *  Look into <code>IJavaSearchConstants</code> for valid values
+	 *  Look into {@link IJavaSearchConstants} for valid values
 	 * @param limitTo one of the following values:
 	 *	<ul>
-	 *	  <li><code>IJavaSearchConstants.DECLARATIONS</code>: search 
+	 *	  <li>{@link IJavaSearchConstants#DECLARATIONS}: search 
 	 *		  for declarations only </li>
-	 *	  <li><code>IJavaSearchConstants.REFERENCES</code>: search 
+	 *	  <li>{@link IJavaSearchConstants#REFERENCES}: search 
 	 *		  for all references </li>
-	 *	  <li><code>IJavaSearchConstants.ALL_OCCURENCES</code>: search 
+	 *	  <li>{@link IJavaSearchConstants#ALL_OCCURRENCES}: search 
 	 *		  for both declarations and all references </li>
-	 *	  <li><code>IJavaSearchConstants.IMPLEMENTORS</code>: search for
+	 *	  <li>{@link IJavaSearchConstants#IMPLEMENTORS}: search for
 	 *		  all implementors of an interface; the value is only valid if
 	 *		  the Java element represents an interface</li>
 	 * 	</ul>
@@ -459,13 +459,13 @@
 	 * @param element the Java element to be searched for
 	 * @param limitTo one of the following values:
 	 *	<ul>
-	 *	  <li><code>IJavaSearchConstants.DECLARATIONS</code>: search 
+	 *	  <li>{@link IJavaSearchConstants#DECLARATIONS}: search 
 	 *		  for declarations only </li>
-	 *	  <li><code>IJavaSearchConstants.REFERENCES</code>: search 
+	 *	  <li>{@link IJavaSearchConstants#REFERENCES}: search 
 	 *		  for all references </li>
-	 *	  <li><code>IJavaSearchConstants.ALL_OCCURENCES</code>: search 
+	 *	  <li>{@link IJavaSearchConstants#ALL_OCCURRENCES}: search 
 	 *		  for both declarations and all references </li>
-	 *	  <li><code>IJavaSearchConstants.IMPLEMENTORS</code>: search for
+	 *	  <li>{@link IJavaSearchConstants#IMPLEMENTORS}: search for
 	 *		  all implementors of an interface; the value is only valid if
 	 *		  the Java element represents an interface</li>
 	 * 	</ul>
@@ -544,29 +544,33 @@
 	 *					for this type, or a wild-carded string for this type.
 	 * @param matchRule one of
 	 * <ul>
-	 *		<li><code>SearchPattern.R_EXACT_MATCH</code> if the package name and type name are the full names
+	 *		<li>{@link SearchPattern#R_EXACT_MATCH} if the package name and type name are the full names
 	 *			of the searched types.</li>
-	 *		<li><code>SearchPattern.R_PREFIX_MATCH</code> if the package name and type name are prefixes of the names
+	 *		<li>{@link SearchPattern#R_PREFIX_MATCH} if the package name and type name are prefixes of the names
 	 *			of the searched types.</li>
-	 *		<li><code>SearchPattern.R_PATTERN_MATCH</code> if the package name and type name contain wild-cards.</li>
+	 *		<li>{@link SearchPattern#R_PATTERN_MATCH} if the package name and type name contain wild-cards.</li>
 	 * </ul>
-	 * combined with <code>SearchPattern.R_CASE_SENSITIVE</code>,
-	 *   e.g. <code>R_EXACT_MATCH | R_CASE_SENSITIVE</code> if an exact and case sensitive match is requested, 
-	 *   or <code>R_PREFIX_MATCH</code> if a prefix non case sensitive match is requested.
-	 * @param searchFor one of
-	 * <ul>
-	 * 		<li><code>IJavaSearchConstants.CLASS</code> if searching for classes only</li>
-	 * 		<li><code>IJavaSearchConstants.INTERFACE</code> if searching for interfaces only</li>
-	 * 		<li><code>IJavaSearchConstants.TYPE</code> if searching for both classes and interfaces</li>
-	 * </ul>
+	 * combined with {@link SearchPattern#R_CASE_SENSITIVE},
+	 *   e.g. {@link SearchPattern#R_EXACT_MATCH} | {@link SearchPattern#R_CASE_SENSITIVE} if an exact and case sensitive match is requested, 
+	 *   or {@link SearchPattern#R_PREFIX_MATCH} if a prefix non case sensitive match is requested.
+	 * @param searchFor determines the nature of the searched elements
+	 *	<ul>
+	 * 	<li>{@link IJavaSearchConstants#CLASS}: only look for classes</li>
+	 *		<li>{@link IJavaSearchConstants#INTERFACE}: only look for interfaces</li>
+	 * 	<li>{@link IJavaSearchConstants#ENUM}: only look for enumeration</li>
+	 *		<li>{@link IJavaSearchConstants#ANNOTATION_TYPE}: only look for annotation type</li>
+	 * 	<li>{@link IJavaSearchConstants#CLASS_AND_ENUM}: only look for classes and enumerations</li>
+	 *		<li>{@link IJavaSearchConstants#CLASS_AND_INTERFACE}: only look for classes and interfaces</li>
+	 * 	<li>{@link IJavaSearchConstants#TYPE}: look for all types (ie. classes, interfaces, enum and annotation types)</li>
+	 *	</ul>
 	 * @param scope the scope to search in
 	 * @param nameRequestor the requestor that collects the results of the search
 	 * @param waitingPolicy one of
 	 * <ul>
-	 *		<li><code>IJavaSearchConstants.FORCE_IMMEDIATE_SEARCH</code> if the search should start immediately</li>
-	 *		<li><code>IJavaSearchConstants.CANCEL_IF_NOT_READY_TO_SEARCH</code> if the search should be cancelled if the
+	 *		<li>{@link IJavaSearchConstants#FORCE_IMMEDIATE_SEARCH} if the search should start immediately</li>
+	 *		<li>{@link IJavaSearchConstants#CANCEL_IF_NOT_READY_TO_SEARCH} if the search should be cancelled if the
 	 *			underlying indexer has not finished indexing the workspace</li>
-	 *		<li><code>IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH</code> if the search should wait for the
+	 *		<li>{@link IJavaSearchConstants#WAIT_UNTIL_READY_TO_SEARCH} if the search should wait for the
 	 *			underlying indexer to finish indexing the workspace</li>
 	 * </ul>
 	 * @param progressMonitor the progress monitor to report progress to, or <code>null</code> if no progress
@@ -575,7 +579,7 @@
 	 *	<ul>
 	 *		<li>the classpath is incorrectly set</li>
 	 *	</ul>
-	 * @since 3.0
+	 * @since 3.1
 	 */
 	public void searchAllTypeNames(
 		final char[] packageName, 
@@ -601,10 +605,10 @@
 	 * @param nameRequestor the requestor that collects the results of the search
 	 * @param waitingPolicy one of
 	 * <ul>
-	 *		<li><code>IJavaSearchConstants.FORCE_IMMEDIATE_SEARCH</code> if the search should start immediately</li>
-	 *		<li><code>IJavaSearchConstants.CANCEL_IF_NOT_READY_TO_SEARCH</code> if the search should be cancelled if the
+	 *		<li>{@link IJavaSearchConstants#FORCE_IMMEDIATE_SEARCH} if the search should start immediately</li>
+	 *		<li>{@link IJavaSearchConstants#CANCEL_IF_NOT_READY_TO_SEARCH} if the search should be cancelled if the
 	 *			underlying indexer has not finished indexing the workspace</li>
-	 *		<li><code>IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH</code> if the search should wait for the
+	 *		<li>{@link IJavaSearchConstants#WAIT_UNTIL_READY_TO_SEARCH} if the search should wait for the
 	 *			underlying indexer to finish indexing the workspace</li>
 	 * </ul>
 	 * @param progressMonitor the progress monitor to report progress to, or <code>null</code> if no progress
@@ -647,29 +651,29 @@
 	 *					for this type, or a wild-carded string for this type.
 	 * @param matchRule one of
 	 * <ul>
-	 *		<li><code>SearchPattern.R_EXACT_MATCH</code> if the package name and type name are the full names
+	 *		<li>{@link SearchPattern#R_EXACT_MATCH} if the package name and type name are the full names
 	 *			of the searched types.</li>
-	 *		<li><code>SearchPattern.R_PREFIX_MATCH</code> if the package name and type name are prefixes of the names
+	 *		<li>{@link SearchPattern#R_PREFIX_MATCH} if the package name and type name are prefixes of the names
 	 *			of the searched types.</li>
-	 *		<li><code>SearchPattern.R_PATTERN_MATCH</code> if the package name and type name contain wild-cards.</li>
+	 *		<li>{@link SearchPattern#R_PATTERN_MATCH} if the package name and type name contain wild-cards.</li>
 	 * </ul>
-	 * combined with <code>SearchPattern.R_CASE_SENSITIVE</code>,
-	 *   e.g. <code>R_EXACT_MATCH | R_CASE_SENSITIVE</code> if an exact and case sensitive match is requested, 
-	 *   or <code>R_PREFIX_MATCH</code> if a prefix non case sensitive match is requested.
+	 * combined with {@link SearchPattern#R_CASE_SENSITIVE},
+	 *   e.g. {@link SearchPattern#R_EXACT_MATCH} | {@link SearchPattern#R_CASE_SENSITIVE} if an exact and case sensitive match is requested, 
+	 *   or {@link SearchPattern#R_PREFIX_MATCH} if a prefix non case sensitive match is requested.
 	 * @param searchFor one of
 	 * <ul>
-	 * 		<li><code>IJavaSearchConstants.CLASS</code> if searching for classes only</li>
-	 * 		<li><code>IJavaSearchConstants.INTERFACE</code> if searching for interfaces only</li>
-	 * 		<li><code>IJavaSearchConstants.TYPE</code> if searching for both classes and interfaces</li>
+	 * 		<li>{@link IJavaSearchConstants#CLASS} if searching for classes only</li>
+	 * 		<li>{@link IJavaSearchConstants#INTERFACE} if searching for interfaces only</li>
+	 * 		<li>{@link IJavaSearchConstants#TYPE} if searching for both classes and interfaces</li>
 	 * </ul>
 	 * @param scope the scope to search in
 	 * @param nameRequestor the requestor that collects the results of the search
 	 * @param waitingPolicy one of
 	 * <ul>
-	 *		<li><code>IJavaSearchConstants.FORCE_IMMEDIATE_SEARCH</code> if the search should start immediately</li>
-	 *		<li><code>IJavaSearchConstants.CANCEL_IF_NOT_READY_TO_SEARCH</code> if the search should be cancelled if the
+	 *		<li>{@link IJavaSearchConstants#FORCE_IMMEDIATE_SEARCH} if the search should start immediately</li>
+	 *		<li>{@link IJavaSearchConstants#CANCEL_IF_NOT_READY_TO_SEARCH} if the search should be cancelled if the
 	 *			underlying indexer has not finished indexing the workspace</li>
-	 *		<li><code>IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH</code> if the search should wait for the
+	 *		<li>{@link IJavaSearchConstants#WAIT_UNTIL_READY_TO_SEARCH} if the search should wait for the
 	 *			underlying indexer to finish indexing the workspace</li>
 	 * </ul>
 	 * @param progressMonitor the progress monitor to report progress to, or <code>null</code> if no progress
@@ -707,27 +711,27 @@
 	 *					for this type, or a wild-carded string for this type.
 	 * @param matchMode one of
 	 * <ul>
-	 *		<li><code>IJavaSearchConstants.EXACT_MATCH</code> if the package name and type name are the full names
+	 *		<li>{@link IJavaSearchConstants#EXACT_MATCH} if the package name and type name are the full names
 	 *			of the searched types.</li>
-	 *		<li><code>IJavaSearchConstants.PREFIX_MATCH</code> if the package name and type name are prefixes of the names
+	 *		<li>{@link IJavaSearchConstants#PREFIX_MATCH} if the package name and type name are prefixes of the names
 	 *			of the searched types.</li>
-	 *		<li><code>IJavaSearchConstants.PATTERN_MATCH</code> if the package name and type name contain wild-cards.</li>
+	 *		<li>{@link IJavaSearchConstants#PATTERN_MATCH} if the package name and type name contain wild-cards.</li>
 	 * </ul>
 	 * @param isCaseSensitive whether the search should be case sensitive
 	 * @param searchFor one of
 	 * <ul>
-	 * 		<li><code>IJavaSearchConstants.CLASS</code> if searching for classes only</li>
-	 * 		<li><code>IJavaSearchConstants.INTERFACE</code> if searching for interfaces only</li>
-	 * 		<li><code>IJavaSearchConstants.TYPE</code> if searching for both classes and interfaces</li>
+	 * 		<li>{@link IJavaSearchConstants#CLASS} if searching for classes only</li>
+	 * 		<li>{@link IJavaSearchConstants#INTERFACE} if searching for interfaces only</li>
+	 * 		<li>{@link IJavaSearchConstants#TYPE} if searching for both classes and interfaces</li>
 	 * </ul>
 	 * @param scope the scope to search in
 	 * @param nameRequestor the requestor that collects the results of the search
 	 * @param waitingPolicy one of
 	 * <ul>
-	 *		<li><code>IJavaSearchConstants.FORCE_IMMEDIATE_SEARCH</code> if the search should start immediately</li>
-	 *		<li><code>IJavaSearchConstants.CANCEL_IF_NOT_READY_TO_SEARCH</code> if the search should be cancelled if the
+	 *		<li>{@link IJavaSearchConstants#FORCE_IMMEDIATE_SEARCH} if the search should start immediately</li>
+	 *		<li>{@link IJavaSearchConstants#CANCEL_IF_NOT_READY_TO_SEARCH} if the search should be cancelled if the
 	 *			underlying indexer has not finished indexing the workspace</li>
-	 *		<li><code>IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH</code> if the search should wait for the
+	 *		<li>{@link IJavaSearchConstants#WAIT_UNTIL_READY_TO_SEARCH} if the search should wait for the
 	 *			underlying indexer to finish indexing the workspace</li>
 	 * </ul>
 	 * @param progressMonitor the progress monitor to report progress to, or <code>null</code> if no progress
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchMatch.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchMatch.java
index c4129c9..17efa21 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchMatch.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchMatch.java
@@ -63,6 +63,7 @@
 	
 	// store other necessary information
 	private boolean raw = false;
+	private boolean implicit = false;
 
 	/**
 	 * Creates a new search match.
@@ -201,6 +202,20 @@
 	}
 
 	/**
+	 * Returns whether the associated element is implicit or not.
+	 * 
+	 * Note that this piece of information is currently only implemented
+	 * for implicit member pair value in annotation.
+	 * 
+	 * @return <code>true</code> if this match is associated to an implicit
+	 * element and <code>false</code> otherwise
+	 * @since 3.1
+	 */
+	public final boolean isImplicit() {
+		return this.implicit;
+	}
+
+	/**
 	 * Returns whether the associated element is a raw type/method or not.
 	 * 
 	 * @return <code>true</code> if this match is associated to a raw
@@ -254,6 +269,19 @@
 	}
 
 	/**
+	 * Sets whether the associated element is implicit or not.
+	 * Typically, this is the case when match is on an implicit constructor
+	 * or an implicit member pair value in annotation.
+	 * 
+	 * @param implicit <code>true</code> if this match is associated to an implicit
+	 * element and <code>false</code> otherwise
+	 * @since 3.1
+	 */
+	public final void setImplicit(boolean implicit) {
+		this.implicit = implicit;
+	}
+
+	/**
 	 * Sets the length of this search match.
 	 * 
 	 * @param length the length of the match, or -1 if unknown
@@ -290,7 +318,7 @@
 	}
 
 	/**
-	 * Returns the rule used while creating the match.
+	 * Set the rule used while reporting the match.
 	 * 
 	 * @param rule one of {@link SearchPattern#R_FULL_MATCH}, {@link SearchPattern#R_EQUIVALENT_MATCH}
 	 * 	or {@link SearchPattern#R_ERASURE_MATCH}
@@ -301,7 +329,7 @@
 	}
 
 	/**
-	 * Returns whether the associated element is a raw type/method or not.
+	 * Set whether the associated element is a raw type/method or not.
 	 * 
 	 * @param raw <code>true</code> if this search match is associated to a raw
 	 * type or method and <code>false</code> otherwise
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchParticipant.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchParticipant.java
index ee39ea4..a61f4fa 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchParticipant.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchParticipant.java
@@ -14,6 +14,7 @@
 import org.eclipse.core.resources.IWorkspaceRoot;
 import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.*;
+import org.eclipse.jdt.internal.core.JavaModel;
 import org.eclipse.jdt.internal.core.JavaModelManager;
 import org.eclipse.jdt.internal.core.search.indexing.IndexManager;
 
@@ -173,8 +174,13 @@
 	public final void scheduleDocumentIndexing(SearchDocument document, IPath indexLocation) {
 		IPath documentPath = new Path(document.getPath());
 		IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
-		IResource resource = root.findMember(documentPath);
-		IPath containerPath = resource == null ? documentPath : resource.getProject().getFullPath();
+		Object file = JavaModel.getTarget(root, documentPath, true);
+		IPath containerPath = documentPath;
+		if (file instanceof IResource) {
+			containerPath = ((IResource)file).getProject().getFullPath();
+		} else if (file == null) {
+			containerPath = documentPath.removeLastSegments(documentPath.segmentCount()-1);
+		}
 		IndexManager manager = JavaModelManager.getJavaModelManager().getIndexManager();
 		String osIndexLocation = indexLocation.toOSString();
 		// TODO (jerome) should not have to create index manually, should expose API that recreates index instead
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchPattern.java
index 84f57f6..ac39929 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchPattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchPattern.java
@@ -339,7 +339,7 @@
 	 *			<li>&lt;Exception&gt;Sample(Exception)</li>
 	 *		</ul>
 	 * Type arguments have the same pattern that for type patterns
-	 * @see #createTypePattern(String,int,int)
+	 * @see #createTypePattern(String,int,int,char)
 	 */
 	private static SearchPattern createMethodOrConstructorPattern(String patternString, int limitTo, int matchRule, boolean isConstructor) {
 		
@@ -767,7 +767,11 @@
 	 *	<ul>
 	 * 	<li>{@link IJavaSearchConstants#CLASS}: only look for classes</li>
 	 *		<li>{@link IJavaSearchConstants#INTERFACE}: only look for interfaces</li>
-	 * 	<li>{@link IJavaSearchConstants#TYPE}: look for both classes and interfaces</li>
+	 * 	<li>{@link IJavaSearchConstants#ENUM}: only look for enumeration</li>
+	 *		<li>{@link IJavaSearchConstants#ANNOTATION_TYPE}: only look for annotation type</li>
+	 * 	<li>{@link IJavaSearchConstants#CLASS_AND_ENUM}: only look for classes and enumerations</li>
+	 *		<li>{@link IJavaSearchConstants#CLASS_AND_INTERFACE}: only look for classes and interfaces</li>
+	 * 	<li>{@link IJavaSearchConstants#TYPE}: look for all types (ie. classes, interfaces, enum and annotation types)</li>
 	 *		<li>{@link IJavaSearchConstants#FIELD}: look for fields</li>
 	 *		<li>{@link IJavaSearchConstants#METHOD}: look for methods</li>
 	 *		<li>{@link IJavaSearchConstants#CONSTRUCTOR}: look for constructors</li>
@@ -808,8 +812,20 @@
 		limitTo &= ~(IJavaSearchConstants.IGNORE_DECLARING_TYPE+IJavaSearchConstants.IGNORE_RETURN_TYPE);
 	
 		switch (searchFor) {
+			case IJavaSearchConstants.CLASS:
+				return createTypePattern(stringPattern, limitTo, matchRule, IIndexConstants.CLASS_SUFFIX);
+			case IJavaSearchConstants.CLASS_AND_INTERFACE:
+				return createTypePattern(stringPattern, limitTo, matchRule, IIndexConstants.CLASS_AND_INTERFACE_SUFFIX);
+			case IJavaSearchConstants.CLASS_AND_ENUM:
+				return createTypePattern(stringPattern, limitTo, matchRule, IIndexConstants.CLASS_AND_ENUM_SUFFIX);
+			case IJavaSearchConstants.INTERFACE:
+				return createTypePattern(stringPattern, limitTo, matchRule, IIndexConstants.INTERFACE_SUFFIX);
+			case IJavaSearchConstants.ENUM:
+				return createTypePattern(stringPattern, limitTo, matchRule, IIndexConstants.ENUM_SUFFIX);
+			case IJavaSearchConstants.ANNOTATION_TYPE:
+				return createTypePattern(stringPattern, limitTo, matchRule, IIndexConstants.ANNOTATION_TYPE_SUFFIX);
 			case IJavaSearchConstants.TYPE:
-				return createTypePattern(stringPattern, limitTo, matchRule);
+				return createTypePattern(stringPattern, limitTo, matchRule, IIndexConstants.TYPE_SUFFIX);
 			case IJavaSearchConstants.METHOD:
 				return createMethodOrConstructorPattern(stringPattern, limitTo, matchRule, false/*not a constructor*/);
 			case IJavaSearchConstants.CONSTRUCTOR:
@@ -1265,16 +1281,16 @@
 	 * Type pattern are formed by [qualification '.']type [typeArguments].
 	 * e.g. java.lang.Object
 	 *		Runnable
-	 *		List<String>
+	 *		List&lt;String&gt;
 	 *
 	 * @since 3.1
 	 *		Type arguments can be specified to search references to parameterized types.
-	 * 	and look as follow: '<' { [ '?' {'extends'|'super'} ] type ( ',' [ '?' {'extends'|'super'} ] type )* | '?' } '>'
+	 * 	and look as follow: '&lt;' { [ '?' {'extends'|'super'} ] type ( ',' [ '?' {'extends'|'super'} ] type )* | '?' } '&gt;'
 	 * 	Please note that:
-	 * 		- '*' is not valid inside type arguments definition <>
-	 * 		- '?' is treated as a wildcard when it is inside <> (ie. it must be put on first position of the type argument)
+	 * 		- '*' is not valid inside type arguments definition &lt;&gt;
+	 * 		- '?' is treated as a wildcard when it is inside &lt;&gt; (ie. it must be put on first position of the type argument)
 	 */
-	private static SearchPattern createTypePattern(String patternString, int limitTo, int matchRule) {
+	private static SearchPattern createTypePattern(String patternString, int limitTo, int matchRule, char indexSuffix) {
 		
 		Scanner scanner = new Scanner(false /*comment*/, true /*whitespace*/, false /*nls*/, ClassFileConstants.JDK1_3/*sourceLevel*/, null /*taskTags*/, null/*taskPriorities*/, true/*taskCaseSensitive*/); 
 		scanner.setSource(patternString.toCharArray());
@@ -1356,14 +1372,14 @@
 		}
 		switch (limitTo) {
 			case IJavaSearchConstants.DECLARATIONS : // cannot search for explicit member types
-				return new QualifiedTypeDeclarationPattern(qualificationChars, typeChars, IIndexConstants.TYPE_SUFFIX, matchRule);
+				return new QualifiedTypeDeclarationPattern(qualificationChars, typeChars, indexSuffix, matchRule);
 			case IJavaSearchConstants.REFERENCES :
 				return new TypeReferencePattern(qualificationChars, typeChars, typeSignature, matchRule);
 			case IJavaSearchConstants.IMPLEMENTORS : 
 				return new SuperTypeReferencePattern(qualificationChars, typeChars, true, matchRule);
 			case IJavaSearchConstants.ALL_OCCURRENCES :
 				return new OrPattern(
-					new QualifiedTypeDeclarationPattern(qualificationChars, typeChars, IIndexConstants.TYPE_SUFFIX, matchRule),// cannot search for explicit member types
+					new QualifiedTypeDeclarationPattern(qualificationChars, typeChars, indexSuffix, matchRule),// cannot search for explicit member types
 					new TypeReferencePattern(qualificationChars, typeChars, matchRule));
 		}
 		return null;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/DiskIndex.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/DiskIndex.java
index 23cbcd7..51ab864 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/DiskIndex.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/DiskIndex.java
@@ -35,7 +35,7 @@
 private HashtableOfObject categoryTables; // category name -> HashtableOfObject(words -> int[] of document #'s) or offset if not read yet
 private char[] cachedCategoryName;
 
-public static final String SIGNATURE= "INDEX VERSION 1.100"; //$NON-NLS-1$
+public static final String SIGNATURE= "INDEX VERSION 1.106"; //$NON-NLS-1$
 public static boolean DEBUG = false;
 
 private static final int RE_INDEXED = -1;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/Index.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/Index.java
index 118f2c5..816ecb1 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/Index.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/Index.java
@@ -79,8 +79,13 @@
 	this.memoryIndex.addIndexEntry(category, key, containerRelativePath);
 }
 public String containerRelativePath(String documentPath) {
-	int jarSeparator = documentPath.indexOf(IJavaSearchScope.JAR_FILE_ENTRY_SEPARATOR);
-	return documentPath.substring((jarSeparator == -1 ? this.containerPath.length() : jarSeparator) + 1);
+	int index = documentPath.indexOf(IJavaSearchScope.JAR_FILE_ENTRY_SEPARATOR);
+	if (index == -1) {
+		index = this.containerPath.length();
+		if (documentPath.length() <= index)
+			throw new IllegalArgumentException("Document path " + documentPath + " must be relative to " + this.containerPath); //$NON-NLS-1$ //$NON-NLS-2$
+	}
+	return documentPath.substring(index + 1);
 }
 public File getIndexFile() {
 	if (this.diskIndex == null) return null;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/BasicSearchEngine.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/BasicSearchEngine.java
index 9d39284..f800536 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/BasicSearchEngine.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/BasicSearchEngine.java
@@ -131,19 +131,19 @@
 	public static IJavaSearchScope createJavaSearchScope(IJavaElement[] elements, int includeMask) {
 		JavaSearchScope scope = new JavaSearchScope();
 		HashSet visitedProjects = new HashSet(2);
-		try {
-			for (int i = 0, length = elements.length; i < length; i++) {
-				IJavaElement element = elements[i];
-				if (element != null) {
+		for (int i = 0, length = elements.length; i < length; i++) {
+			IJavaElement element = elements[i];
+			if (element != null) {
+				try {
 					if (element instanceof JavaProject) {
 						scope.add((JavaProject)element, includeMask, visitedProjects);
 					} else {
 						scope.add(element);
 					}
+				} catch (JavaModelException e) {
+					// ignore
 				}
 			}
-		} catch (JavaModelException e) {
-			// ignore
 		}
 		return scope;
 	}
@@ -154,7 +154,7 @@
 	 * @return a new workspace scope
 	 */
 	public static IJavaSearchScope createWorkspaceScope() {
-		return JavaWorkspaceScope.createScope();
+		return JavaModelManager.getJavaModelManager().getWorkspaceScope();
 	}
 	
 	/**
@@ -186,7 +186,7 @@
 				SubProgressMonitor subMonitor= monitor==null ? null : new SubProgressMonitor(monitor, 1000);
 				if (subMonitor != null) subMonitor.beginTask("", 1000); //$NON-NLS-1$
 				try {
-					if (subMonitor != null) subMonitor.subTask(Messages.bind(Messages.engine_searching_indexing, (new String[] {participant.getDescription()}))); 
+					if (subMonitor != null) subMonitor.subTask(Messages.bind(Messages.engine_searching_indexing, new String[] {participant.getDescription()})); 
 					participant.beginSearching();
 					requestor.enterParticipant(participant);
 					PathCollector pathCollector = new PathCollector();
@@ -197,7 +197,7 @@
 					if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
 	
 					// locate index matches if any (note that all search matches could have been issued during index querying)
-					if (subMonitor != null) subMonitor.subTask(Messages.bind(Messages.engine_searching_matching, (new String[] {participant.getDescription()}))); 
+					if (subMonitor != null) subMonitor.subTask(Messages.bind(Messages.engine_searching_matching, new String[] {participant.getDescription()})); 
 					String[] indexMatchPaths = pathCollector.getPaths();
 					pathCollector = null; // release
 					int indexMatchLength = indexMatchPaths == null ? 0 : indexMatchPaths.length;
@@ -338,11 +338,35 @@
 		return getWorkingCopies();
 	}
 
+	boolean match(char patternTypeSuffix, int modifiers) {
+		switch(patternTypeSuffix) {
+			case IIndexConstants.CLASS_SUFFIX :
+				return (modifiers & (Flags.AccAnnotation | Flags.AccInterface | Flags.AccEnum)) == 0;
+			case IIndexConstants.CLASS_AND_INTERFACE_SUFFIX:
+				return (modifiers & (Flags.AccAnnotation | Flags.AccEnum)) == 0;
+			case IIndexConstants.CLASS_AND_ENUM_SUFFIX:
+				return (modifiers & (Flags.AccAnnotation | Flags.AccInterface)) == 0;
+			case IIndexConstants.INTERFACE_SUFFIX :
+				return (modifiers & Flags.AccInterface) != 0;
+			case IIndexConstants.ENUM_SUFFIX :
+				return (modifiers & Flags.AccEnum) != 0;
+			case IIndexConstants.ANNOTATION_TYPE_SUFFIX :
+				return (modifiers & Flags.AccAnnotation) != 0;
+		}
+		return true;
+	}
+
 	boolean match(char patternTypeSuffix, char[] patternPkg, char[] patternTypeName, int matchRule, int typeKind, char[] pkg, char[] typeName) {
 		switch(patternTypeSuffix) {
 			case IIndexConstants.CLASS_SUFFIX :
 				if (typeKind != IGenericType.CLASS_DECL) return false;
 				break;
+			case IIndexConstants.CLASS_AND_INTERFACE_SUFFIX:
+				if (typeKind != IGenericType.CLASS_DECL && typeKind != IGenericType.INTERFACE_DECL) return false;
+				break;
+			case IIndexConstants.CLASS_AND_ENUM_SUFFIX:
+				if (typeKind != IGenericType.CLASS_DECL && typeKind != IGenericType.ENUM_DECL) return false;
+				break;
 			case IIndexConstants.INTERFACE_SUFFIX :
 				if (typeKind != IGenericType.INTERFACE_DECL) return false;
 				break;
@@ -361,6 +385,9 @@
 		
 		if (patternTypeName != null) {
 			int matchMode = matchRule - (isCaseSensitive ? SearchPattern.R_CASE_SENSITIVE : 0);
+			if (!isCaseSensitive) {
+				patternTypeName = CharOperation.toLowerCase(patternTypeName);
+			}
 			switch(matchMode) {
 				case SearchPattern.R_EXACT_MATCH :
 					return CharOperation.equals(patternTypeName, typeName, isCaseSensitive);
@@ -391,6 +418,9 @@
 	 *@since 3.0
 	 */
 	public void search(SearchPattern pattern, SearchParticipant[] participants, IJavaSearchScope scope, SearchRequestor requestor, IProgressMonitor monitor) throws CoreException {
+		if (VERBOSE) {
+			System.out.println("BasicSearchEngine.search(SearchPattern, SearchParticipant[], IJavaSearchScope, SearchRequestor, IProgressMonitor)"); //$NON-NLS-1$
+		}
 		findMatches(pattern, participants, scope, requestor, monitor);
 	}
 
@@ -415,12 +445,16 @@
 	 * combined with <code>SearchPattern.R_CASE_SENSITIVE</code>,
 	 *   e.g. <code>R_EXACT_MATCH | R_CASE_SENSITIVE</code> if an exact and case sensitive match is requested, 
 	 *   or <code>R_PREFIX_MATCH</code> if a prefix non case sensitive match is requested.
-	 * @param searchFor one of
-	 * <ul>
-	 * 		<li><code>IJavaSearchConstants.CLASS</code> if searching for classes only</li>
-	 * 		<li><code>IJavaSearchConstants.INTERFACE</code> if searching for interfaces only</li>
-	 * 		<li><code>IJavaSearchConstants.TYPE</code> if searching for both classes and interfaces</li>
-	 * </ul>
+	 * @param searchFor determines the nature of the searched elements
+	 *	<ul>
+	 * 	<li>{@link IJavaSearchConstants#CLASS}: only look for classes</li>
+	 *		<li>{@link IJavaSearchConstants#INTERFACE}: only look for interfaces</li>
+	 * 	<li>{@link IJavaSearchConstants#ENUM}: only look for enumeration</li>
+	 *		<li>{@link IJavaSearchConstants#ANNOTATION_TYPE}: only look for annotation type</li>
+	 * 	<li>{@link IJavaSearchConstants#CLASS_AND_ENUM}: only look for classes and enumerations</li>
+	 *		<li>{@link IJavaSearchConstants#CLASS_AND_INTERFACE}: only look for classes and interfaces</li>
+	 * 	<li>{@link IJavaSearchConstants#TYPE}: look for all types (ie. classes, interfaces, enum and annotation types)</li>
+	 *	</ul>
 	 * @param scope the scope to search in
 	 * @param nameRequestor the requestor that collects the results of the search
 	 * @param waitingPolicy one of
@@ -449,6 +483,15 @@
 		int waitingPolicy,
 		IProgressMonitor progressMonitor)  throws JavaModelException {
 
+		if (VERBOSE) {
+			System.out.println("BasicSearchEngine.searchAllTypeNames(char[], char[], int, int, IJavaSearchScope, IRestrictedAccessTypeRequestor, int, IProgressMonitor)"); //$NON-NLS-1$
+			System.out.println("	- package name: "+(packageName==null?"null":new String(packageName))); //$NON-NLS-1$ //$NON-NLS-2$
+			System.out.println("	- type name: "+(typeName==null?"null":new String(typeName))); //$NON-NLS-1$ //$NON-NLS-2$
+			System.out.println("	- match rule: "+matchRule); //$NON-NLS-1$
+			System.out.println("	- search for: "+searchFor); //$NON-NLS-1$
+			System.out.println("	- scope: "+scope); //$NON-NLS-1$
+		}
+
 		IndexManager indexManager = JavaModelManager.getJavaModelManager().getIndexManager();
 			
 		final char typeSuffix;
@@ -456,6 +499,12 @@
 			case IJavaSearchConstants.CLASS :
 				typeSuffix = IIndexConstants.CLASS_SUFFIX;
 				break;
+			case IJavaSearchConstants.CLASS_AND_INTERFACE :
+				typeSuffix = IIndexConstants.CLASS_AND_INTERFACE_SUFFIX;
+				break;
+			case IJavaSearchConstants.CLASS_AND_ENUM :
+				typeSuffix = IIndexConstants.CLASS_AND_ENUM_SUFFIX;
+				break;
 			case IJavaSearchConstants.INTERFACE :
 				typeSuffix = IIndexConstants.INTERFACE_SUFFIX;
 				break;
@@ -493,16 +542,10 @@
 						&& !workingCopyPaths.contains(documentPath)) { // filter out working copies
 					if (access != null) {
 						// Compute document relative path
-						int pos = documentPath.lastIndexOf('.');
-						char[] extension = null;
-						if (pos >= 0 && pos > documentPath.lastIndexOf('/')) {
-							extension = documentPath.substring(pos).toCharArray();
-						}
-						int pkgLength = record.pkg==null ? 0 : record.pkg.length+1;
+						int pkgLength = (record.pkg==null || record.pkg.length==0) ? 0 : record.pkg.length+1;
 						int nameLength = record.simpleName==null ? 0 : record.simpleName.length;
-						int extLength = extension==null ? 0 : extension.length;
-						char[] path = new char[pkgLength+nameLength+extLength];
-						pos = 0;
+						char[] path = new char[pkgLength+nameLength];
+						int pos = 0;
 						if (pkgLength > 0) {
 							System.arraycopy(record.pkg, 0, path, pos, pkgLength-1);
 							CharOperation.replace(path, '.', '/');
@@ -512,16 +555,15 @@
 						if (nameLength > 0) {
 							System.arraycopy(record.simpleName, 0, path, pos, nameLength);
 							pos += nameLength;
-							if (extLength > 0) {
-								System.arraycopy(extension, 0, path, pos, extLength);
-							}
 						}
 						// Update access restriction if path is not empty
 						if (pos > 0) {
 							accessRestriction = access.getViolatedRestriction(path);
 						}
 					}
-					nameRequestor.acceptType(record.modifiers, record.pkg, record.simpleName, record.enclosingTypeNames, documentPath, accessRestriction);
+					if (match(record.typeSuffix, record.modifiers)) {
+						nameRequestor.acceptType(record.modifiers, record.pkg, record.simpleName, record.enclosingTypeNames, documentPath, accessRestriction);
+					}
 				}
 				return true;
 			}
@@ -671,6 +713,14 @@
 		int waitingPolicy,
 		IProgressMonitor progressMonitor)  throws JavaModelException {
 
+		if (VERBOSE) {
+			System.out.println("BasicSearchEngine.searchAllTypeNames(char[][], char[][], int, int, IJavaSearchScope, IRestrictedAccessTypeRequestor, int, IProgressMonitor)"); //$NON-NLS-1$
+			System.out.println("	- package name: "+(qualifications==null?"null":new String(CharOperation.concatWith(qualifications, ',')))); //$NON-NLS-1$ //$NON-NLS-2$
+			System.out.println("	- type name: "+(typeNames==null?"null":new String(CharOperation.concatWith(typeNames, ',')))); //$NON-NLS-1$ //$NON-NLS-2$
+			System.out.println("	- match rule: "+matchRule); //$NON-NLS-1$
+			System.out.println("	- search for: "+searchFor); //$NON-NLS-1$
+			System.out.println("	- scope: "+scope); //$NON-NLS-1$
+		}
 		IndexManager indexManager = JavaModelManager.getJavaModelManager().getIndexManager();
 
 		final char typeSuffix;
@@ -678,6 +728,12 @@
 			case IJavaSearchConstants.CLASS :
 				typeSuffix = IIndexConstants.CLASS_SUFFIX;
 				break;
+			case IJavaSearchConstants.CLASS_AND_INTERFACE :
+				typeSuffix = IIndexConstants.CLASS_AND_INTERFACE_SUFFIX;
+				break;
+			case IJavaSearchConstants.CLASS_AND_ENUM :
+				typeSuffix = IIndexConstants.CLASS_AND_ENUM_SUFFIX;
+				break;
 			case IJavaSearchConstants.INTERFACE :
 				typeSuffix = IIndexConstants.INTERFACE_SUFFIX;
 				break;
@@ -709,15 +765,10 @@
 					AccessRestriction accessRestriction = null;
 					if (access != null) {
 						// Compute document relative path
-						int pos = documentPath.lastIndexOf('.');
-						char[] extension = null;
-						if (pos >= 0 && pos > documentPath.lastIndexOf('/'))
-							extension = documentPath.substring(pos).toCharArray();
-						int qualificationLength = record.qualification == null ? 0 : record.qualification.length + 1;
+						int qualificationLength = (record.qualification == null || record.qualification.length == 0) ? 0 : record.qualification.length + 1;
 						int nameLength = record.simpleName == null ? 0 : record.simpleName.length;
-						int extLength = extension == null ? 0 : extension.length;
-						char[] path = new char[qualificationLength + nameLength + extLength];
-						pos = 0;
+						char[] path = new char[qualificationLength + nameLength];
+						int pos = 0;
 						if (qualificationLength > 0) {
 							System.arraycopy(record.qualification, 0, path, pos, qualificationLength - 1);
 							CharOperation.replace(path, '.', '/');
@@ -727,8 +778,6 @@
 						if (nameLength > 0) {
 							System.arraycopy(record.simpleName, 0, path, pos, nameLength);
 							pos += nameLength;
-							if (extLength > 0)
-								System.arraycopy(extension, 0, path, pos, extLength);
 						}
 						// Update access restriction if path is not empty
 						if (pos > 0) {
@@ -861,13 +910,16 @@
 	}
 	
 	public void searchDeclarations(IJavaElement enclosingElement, SearchRequestor requestor, SearchPattern pattern, IProgressMonitor monitor) throws JavaModelException {
+		if (VERBOSE) {
+			System.out.println("	- java element: "+enclosingElement); //$NON-NLS-1$
+		}
 		IJavaSearchScope scope = createJavaSearchScope(new IJavaElement[] {enclosingElement});
 		IResource resource = this.getResource(enclosingElement);
 		try {
 			if (resource instanceof IFile) {
 				try {
 					requestor.beginReporting();
-					if (BasicSearchEngine.VERBOSE) {
+					if (VERBOSE) {
 						System.out.println("Searching for " + pattern + " in " + resource.getFullPath()); //$NON-NLS-1$//$NON-NLS-2$
 					}
 					SearchParticipant participant = getDefaultSearchParticipant();
@@ -938,6 +990,9 @@
 	 * @since 3.0
 	 */	
 	public void searchDeclarationsOfAccessedFields(IJavaElement enclosingElement, SearchRequestor requestor, IProgressMonitor monitor) throws JavaModelException {
+		if (VERBOSE) {
+			System.out.println("BasicSearchEngine.searchDeclarationsOfAccessedFields(IJavaElement, SearchRequestor, SearchPattern, IProgressMonitor)"); //$NON-NLS-1$
+		}
 		SearchPattern pattern = new DeclarationOfAccessedFieldsPattern(enclosingElement);
 		searchDeclarations(enclosingElement, requestor, pattern, monitor);
 	}
@@ -980,6 +1035,9 @@
 	 * @since 3.0
 	 */	
 	public void searchDeclarationsOfReferencedTypes(IJavaElement enclosingElement, SearchRequestor requestor, IProgressMonitor monitor) throws JavaModelException {
+		if (VERBOSE) {
+			System.out.println("BasicSearchEngine.searchDeclarationsOfReferencedTypes(IJavaElement, SearchRequestor, SearchPattern, IProgressMonitor)"); //$NON-NLS-1$
+		}
 		SearchPattern pattern = new DeclarationOfReferencedTypesPattern(enclosingElement);
 		searchDeclarations(enclosingElement, requestor, pattern, monitor);
 	}
@@ -1025,6 +1083,9 @@
 	 * @since 3.0
 	 */	
 	public void searchDeclarationsOfSentMessages(IJavaElement enclosingElement, SearchRequestor requestor, IProgressMonitor monitor) throws JavaModelException {
+		if (VERBOSE) {
+			System.out.println("BasicSearchEngine.searchDeclarationsOfSentMessages(IJavaElement, SearchRequestor, SearchPattern, IProgressMonitor)"); //$NON-NLS-1$
+		}
 		SearchPattern pattern = new DeclarationOfReferencedMethodsPattern(enclosingElement);
 		searchDeclarations(enclosingElement, requestor, pattern, monitor);
 	}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchScope.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchScope.java
index b9f378e..07fa0fd 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchScope.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchScope.java
@@ -110,13 +110,8 @@
 	JavaModelManager.PerProjectInfo perProjectInfo = javaProject.getPerProjectInfo();
 	for (int i = 0, length = entries.length; i < length; i++) {
 		IClasspathEntry entry = entries[i];
-		IClasspathEntry rawEntry = null;
-		if (perProjectInfo != null && perProjectInfo.resolvedPathToRawEntries != null) {
-			rawEntry = (IClasspathEntry) perProjectInfo.resolvedPathToRawEntries.get(entry.getPath());
-		}
-		if (rawEntry == null) continue;
 		AccessRuleSet access = null;
-		ClasspathEntry cpEntry = (ClasspathEntry) rawEntry;
+		ClasspathEntry cpEntry = (ClasspathEntry) entry;
 		if (referringEntry != null) {
 			// Add only exported entries.
 			// Source folder are implicitly exported.
@@ -127,13 +122,19 @@
 		access = cpEntry.getAccessRuleSet();
 		switch (entry.getEntryKind()) {
 			case IClasspathEntry.CPE_LIBRARY:
+				IClasspathEntry rawEntry = null;
+				if (perProjectInfo != null && perProjectInfo.resolvedPathToRawEntries != null) {
+					rawEntry = (IClasspathEntry) perProjectInfo.resolvedPathToRawEntries.get(entry.getPath());
+				}
+				if (rawEntry == null) break;
 				switch (rawEntry.getEntryKind()) {
 					case IClasspathEntry.CPE_LIBRARY:
 					case IClasspathEntry.CPE_VARIABLE:
 						if ((includeMask & APPLICATION_LIBRARIES) != 0) {
 							IPath path = entry.getPath();
 							if (pathToAdd == null || pathToAdd.equals(path)) {
-								add("", path.toString(), true, access); //$NON-NLS-1$
+								String pathToString = path.getDevice() == null ? path.toString() : path.toOSString();
+								add("", pathToString, true, access); //$NON-NLS-1$
 								addEnclosingProjectOrJar(path);
 							}
 						}
@@ -145,7 +146,8 @@
 								|| (includeMask & SYSTEM_LIBRARIES) != 0) {
 							IPath path = entry.getPath();
 							if (pathToAdd == null || pathToAdd.equals(path)) {
-								add("", path.toString(), true, access); //$NON-NLS-1$
+								String pathToString = path.getDevice() == null ? path.toString() : path.toOSString();
+								add("", pathToString, true, access); //$NON-NLS-1$
 								addEnclosingProjectOrJar(path);
 							}
 						}
@@ -178,6 +180,7 @@
  */
 public void add(IJavaElement element) throws JavaModelException {
 	IPath containerPath = null;
+	String containerPathToString = null;
 	int includeMask = SOURCES | APPLICATION_LIBRARIES | SYSTEM_LIBRARIES;
 	switch (element.getElementType()) {
 		case IJavaElement.JAVA_MODEL:
@@ -190,20 +193,29 @@
 			IPackageFragmentRoot root = (IPackageFragmentRoot)element;
 			IPath rootPath = root.getPath();
 			containerPath = root.getKind() == IPackageFragmentRoot.K_SOURCE ? root.getParent().getPath() : rootPath;
-			add("", containerPath.toString(), true, null); //$NON-NLS-1$
+			containerPathToString = containerPath.getDevice() == null ? containerPath.toString() : containerPath.toOSString();
+			IResource rootResource = root.getResource();
+			if (rootResource != null && rootResource.isAccessible()) {
+				String relativePath = Util.relativePath(rootResource.getFullPath(), containerPath.segmentCount());
+				add(relativePath, containerPathToString, true, null);
+			} else {
+				add("", containerPathToString, true, null); //$NON-NLS-1$
+			}
 			break;
 		case IJavaElement.PACKAGE_FRAGMENT:
 			root = (IPackageFragmentRoot)element.getParent();
 			if (root.isArchive()) {
 				String relativePath = Util.concatWith(((PackageFragment) element).names, '/');
 				containerPath = root.getPath();
-				add(relativePath, containerPath.toString(), false, null);
+				containerPathToString = containerPath.getDevice() == null ? containerPath.toString() : containerPath.toOSString();
+				add(relativePath, containerPathToString, false, null);
 			} else {
 				IResource resource = element.getResource();
 				if (resource != null && resource.isAccessible()) {
 					containerPath = root.getKind() == IPackageFragmentRoot.K_SOURCE ? root.getParent().getPath() : root.getPath();
+					containerPathToString = containerPath.getDevice() == null ? containerPath.toString() : containerPath.toOSString();
 					String relativePath = Util.relativePath(resource.getFullPath(), containerPath.segmentCount());
-					add(relativePath, containerPath.toString(), false, null);
+					add(relativePath, containerPathToString, false, null);
 				}
 			}
 			break;
@@ -224,7 +236,8 @@
 				containerPath = root.getPath();
 				relativePath = getPath(element, true/*relative path*/).toString();
 			}
-			add(relativePath, containerPath.toString(), true, null);
+			containerPathToString = containerPath.getDevice() == null ? containerPath.toString() : containerPath.toOSString();
+			add(relativePath, containerPathToString, true, null);
 	}
 	
 	if (containerPath != null)
@@ -301,9 +314,22 @@
 
 private boolean encloses(String scopePath, String path, int index) {
 	if (this.pathWithSubFolders[index]) {
-		if (path.startsWith(scopePath)) {
+		// TODO (frederic) apply similar change also if not looking at subfolders
+		int pathLength = path.length();
+		int scopeLength = scopePath.length();
+		if (pathLength < scopeLength) {
+			return false;
+		}
+		if (scopeLength == 0) {
 			return true;
 		}
+		if (pathLength == scopeLength) {
+			return path.equals(scopePath);
+		}
+		if (path.startsWith(scopePath)) {
+			if (scopePath.charAt(scopeLength-1) == '/') scopeLength--;
+			return path.charAt(scopeLength) == '/';
+		}
 	} else {
 		// if not looking at subfolders, this scope encloses the given path 
 		// if this path is a direct child of the scope's ressource
@@ -336,8 +362,9 @@
 	IPackageFragmentRoot root = (IPackageFragmentRoot) element.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
 	if (root != null && root.isArchive()) {
 		IPath rootPath = root.getPath();
+		String rootPathToString = rootPath.getDevice() == null ? rootPath.toString() : rootPath.toOSString();
 		IPath relativePath = getPath(element, true/*relative path*/);
-		return indexOf(relativePath.toString(), rootPath.toString()) >= 0;
+		return indexOf(relativePath.toString(), rootPathToString) >= 0;
 	}
 	return this.indexOf(getPath(element, false/*full path*/).toString(), null) >= 0;
 }
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaWorkspaceScope.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaWorkspaceScope.java
index 0b90852..ea4b7da 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaWorkspaceScope.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaWorkspaceScope.java
@@ -30,18 +30,6 @@
 
 protected boolean needsInitialize;
 
-private static JavaWorkspaceScope TheWorkspaceScope = null;
-	
-public static JavaWorkspaceScope createScope() {
-	if (TheWorkspaceScope == null)
-		TheWorkspaceScope = new JavaWorkspaceScope();
-
-	return TheWorkspaceScope;
-}
-
-private JavaWorkspaceScope() {
-	JavaModelManager.getJavaModelManager().rememberScope(this);
-}
 public boolean encloses(IJavaElement element) {
 	/*
 	if (this.needsInitialize) {
@@ -119,10 +107,16 @@
 					this.needsInitialize = true;
 					break;
 				case IJavaElementDelta.CHANGED:
-					children = delta.getAffectedChildren();
-					for (int i = 0, length = children.length; i < length; i++) {
-						IJavaElementDelta child = children[i];
-						this.processDelta(child);
+					int flags = delta.getFlags();
+					if ((flags & IJavaElementDelta.F_CLOSED) != 0
+							|| (flags & IJavaElementDelta.F_OPENED) != 0) {
+						this.needsInitialize = true;
+					} else {
+						children = delta.getAffectedChildren();
+						for (int i = 0, length = children.length; i < length; i++) {
+							IJavaElementDelta child = children[i];
+							this.processDelta(child);
+						}
 					}
 					break;
 			}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AbstractIndexer.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AbstractIndexer.java
index 1957109..ec22707 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AbstractIndexer.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AbstractIndexer.java
@@ -80,6 +80,9 @@
 		char[] simpleTypeName = CharOperation.lastSegment(typeName,'.');
 		addTypeReference(simpleTypeName);
 		addIndexEntry(CONSTRUCTOR_REF, ConstructorPattern.createIndexKey(simpleTypeName, argCount));
+		char[] innermostTypeName = CharOperation.lastSegment(simpleTypeName,'$');
+		if (innermostTypeName != simpleTypeName)
+			addIndexEntry(CONSTRUCTOR_REF, ConstructorPattern.createIndexKey(innermostTypeName, argCount));
 	}
 	public void addEnumDeclaration(int modifiers, char[] packageName, char[] name, char[][] enclosingTypeNames, char[][] superinterfaces) {
 		addIndexEntry(TYPE_DECL, TypeDeclarationPattern.createIndexKey(modifiers, name, packageName, enclosingTypeNames));
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IIndexConstants.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IIndexConstants.java
index eba9567..b4ee43a 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IIndexConstants.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IIndexConstants.java
@@ -10,6 +10,8 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.search.indexing;
 
+import org.eclipse.jdt.core.search.IJavaSearchConstants;
+
 public interface IIndexConstants {
 
 	/* index encoding */
@@ -31,6 +33,8 @@
 	char ENUM_SUFFIX = 'E';
 	char ANNOTATION_TYPE_SUFFIX = 'A';
 	char TYPE_SUFFIX = 0;
+	char CLASS_AND_ENUM_SUFFIX = IJavaSearchConstants.CLASS_AND_ENUM;
+	char CLASS_AND_INTERFACE_SUFFIX = IJavaSearchConstants.CLASS_AND_INTERFACE;
 	char SEPARATOR= '/';
 
 	char[] ONE_STAR = new char[] {'*'};
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java
index fb4c740..31ace01 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java
@@ -189,18 +189,19 @@
 		}
 
 		// index isn't cached, consider reusing an existing index file
+		String containerPathString = containerPath.getDevice() == null ? containerPath.toString() : containerPath.toOSString();
 		if (reuseExistingFile) {
 			File indexFile = new File(indexLocation);
 			if (indexFile.exists()) { // check before creating index so as to avoid creating a new empty index if file is missing
 				try {
-					index = new Index(indexLocation, containerPath.toString(), true /*reuse index file*/); //$NON-NLS-1$
+					index = new Index(indexLocation, containerPathString, true /*reuse index file*/); //$NON-NLS-1$
 					indexes.put(indexLocation, index);
 					return index;
 				} catch (IOException e) {
 					// failed to read the existing file or its no longer compatible
 					if (currentIndexState != REBUILDING_STATE) { // rebuild index if existing file is corrupt, unless the index is already being rebuilt
 						if (VERBOSE)
-							Util.verbose("-> cannot reuse existing index: "+indexLocation+" path: "+containerPath.toOSString()); //$NON-NLS-1$ //$NON-NLS-2$
+							Util.verbose("-> cannot reuse existing index: "+indexLocation+" path: "+containerPathString); //$NON-NLS-1$ //$NON-NLS-2$
 						rebuildIndex(indexLocation, containerPath);
 						return null;
 					} 
@@ -216,13 +217,13 @@
 		if (createIfMissing) {
 			try {
 				if (VERBOSE)
-					Util.verbose("-> create empty index: "+indexLocation+" path: "+containerPath.toOSString()); //$NON-NLS-1$ //$NON-NLS-2$
-				index = new Index(indexLocation, containerPath.toString(), false /*do not reuse index file*/); //$NON-NLS-1$
+					Util.verbose("-> create empty index: "+indexLocation+" path: "+containerPathString); //$NON-NLS-1$ //$NON-NLS-2$
+				index = new Index(indexLocation, containerPathString, false /*do not reuse index file*/); //$NON-NLS-1$
 				indexes.put(indexLocation, index);
 				return index;
 			} catch (IOException e) {
 				if (VERBOSE)
-					Util.verbose("-> unable to create empty index: "+indexLocation+" path: "+containerPath.toOSString()); //$NON-NLS-1$ //$NON-NLS-2$
+					Util.verbose("-> unable to create empty index: "+indexLocation+" path: "+containerPathString); //$NON-NLS-1$ //$NON-NLS-2$
 				// The file could not be created. Possible reason: the project has been deleted.
 				return null;
 			}
@@ -423,6 +424,7 @@
  */
 public synchronized Index recreateIndex(IPath containerPath) {
 	// only called to over write an existing cached index...
+	String containerPathString = containerPath.getDevice() == null ? containerPath.toString() : containerPath.toOSString();
 	try {
 		// Path is already canonical
 		String indexLocation = computeIndexLocation(containerPath);
@@ -431,15 +433,15 @@
 		ReadWriteMonitor monitor = index == null ? null : index.monitor;
 
 		if (VERBOSE)
-			Util.verbose("-> recreating index: "+indexLocation+" for path: "+containerPath.toOSString()); //$NON-NLS-1$ //$NON-NLS-2$
-		index = new Index(indexLocation, containerPath.toString(), false /*reuse index file*/); //$NON-NLS-1$
+			Util.verbose("-> recreating index: "+indexLocation+" for path: "+containerPathString); //$NON-NLS-1$ //$NON-NLS-2$
+		index = new Index(indexLocation, containerPathString, false /*reuse index file*/); //$NON-NLS-1$
 		this.indexes.put(indexLocation, index);
 		index.monitor = monitor;
 		return index;
 	} catch (IOException e) {
 		// The file could not be created. Possible reason: the project has been deleted.
 		if (VERBOSE) {
-			Util.verbose("-> failed to recreate index for path: "+containerPath.toOSString()); //$NON-NLS-1$ //$NON-NLS-2$
+			Util.verbose("-> failed to recreate index for path: "+containerPathString); //$NON-NLS-1$ //$NON-NLS-2$
 			e.printStackTrace();
 		}
 		return null;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/SourceIndexerRequestor.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/SourceIndexerRequestor.java
index f386716..8feb299 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/SourceIndexerRequestor.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/SourceIndexerRequestor.java
@@ -36,6 +36,9 @@
  * @see ISourceElementRequestor#acceptConstructorReference(char[], int, int)
  */
 public void acceptConstructorReference(char[] typeName, int argCount, int sourcePosition) {
+	if (CharOperation.indexOf(Signature.C_GENERIC_START, typeName) > 0) {
+		typeName = Signature.toCharArray(Signature.getTypeErasure(Signature.createTypeSignature(typeName, false)).toCharArray());
+	}
 	this.indexer.addConstructorReference(typeName, argCount);
 	int lastDot = CharOperation.lastIndexOf('.', typeName);
 	if (lastDot != -1) {
@@ -142,15 +145,15 @@
 private void enterClass(TypeInfo typeInfo) {
 
 	// eliminate possible qualifications, given they need to be fully resolved again
-	if (typeInfo.superclass != null){
-		typeInfo.superclass = CharOperation.lastSegment(typeInfo.superclass, '.');
+	if (typeInfo.superclass != null) {
+		typeInfo.superclass = getSimpleName(typeInfo.superclass);
 		
 		// add implicit constructor reference to default constructor
 		this.indexer.addConstructorReference(typeInfo.superclass, 0);
 	}
 	if (typeInfo.superinterfaces != null){
-		for (int i = 0, length = typeInfo.superinterfaces.length; i < length; i++){
-			typeInfo.superinterfaces[i] = CharOperation.lastSegment(typeInfo.superinterfaces[i], '.');
+		for (int i = 0, length = typeInfo.superinterfaces.length; i < length; i++) {
+			typeInfo.superinterfaces[i] = getSimpleName(typeInfo.superinterfaces[i]);
 		}
 	}
 	char[][] typeNames;
@@ -188,7 +191,7 @@
 	// eliminate possible qualifications, given they need to be fully resolved again
 	if (typeInfo.superinterfaces != null){
 		for (int i = 0, length = typeInfo.superinterfaces.length; i < length; i++){
-			typeInfo.superinterfaces[i] = CharOperation.lastSegment(typeInfo.superinterfaces[i], '.');
+			typeInfo.superinterfaces[i] = getSimpleName(typeInfo.superinterfaces[i]);
 		}
 	}	
 	char[][] typeNames;
@@ -217,7 +220,7 @@
 	// eliminate possible qualifications, given they need to be fully resolved again
 	if (typeInfo.superinterfaces != null){
 		for (int i = 0, length = typeInfo.superinterfaces.length; i < length; i++){
-			typeInfo.superinterfaces[i] = CharOperation.lastSegment(typeInfo.superinterfaces[i], '.');
+			typeInfo.superinterfaces[i] = getSimpleName(typeInfo.superinterfaces[i]);
 		}
 	}	
 	char[][] typeNames;
@@ -302,6 +305,38 @@
 public void exitType(int declarationEnd) {
 	popTypeName();
 }
+/*
+ * Returns the unqualified name without parameters from the given type name.
+ */
+private char[] getSimpleName(char[] typeName) {
+	int lastDot = -1, lastGenericStart = -1;
+	int depthCount = 0;
+	int length = typeName.length;
+	lastDotLookup: for (int i = length -1; i >= 0; i--) {
+		switch (typeName[i]) {
+			case '.':
+				if (depthCount == 0) {
+					lastDot = i;
+					break lastDotLookup;
+				}
+				break;
+			case '<':
+				depthCount--;
+				if (depthCount == 0) lastGenericStart = i;
+				break;
+			case '>':
+				depthCount++;
+				break;
+		}
+	}
+	if (lastGenericStart < 0) {
+		if (lastDot < 0) {
+			return typeName;
+		}
+		return  CharOperation.subarray(typeName, lastDot + 1, length);
+	}
+	return  CharOperation.subarray(typeName, lastDot + 1, lastGenericStart);
+}
 public void popTypeName() {
 	if (depth > 0) {
 		enclosingTypeNames[--depth] = null;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ClassFileMatchLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ClassFileMatchLocator.java
index ea70f40..64703bd 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ClassFileMatchLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ClassFileMatchLocator.java
@@ -246,15 +246,20 @@
 		if (!checkTypeName(pattern.simpleName, patternString, fullyQualifiedTypeName, pattern.isCaseSensitive())) return false;
 	}
 
+	int kind  = type.getKind();
 	switch (pattern.typeSuffix) {
 		case CLASS_SUFFIX:
-			return type.getKind() == IGenericType.CLASS_DECL;
+			return kind == IGenericType.CLASS_DECL;
 		case INTERFACE_SUFFIX:
-			return type.getKind() == IGenericType.INTERFACE_DECL;
+			return kind == IGenericType.INTERFACE_DECL;
 		case ENUM_SUFFIX:
-			return type.getKind() == IGenericType.ENUM_DECL;
+			return kind == IGenericType.ENUM_DECL;
 		case ANNOTATION_TYPE_SUFFIX:
-			return type.getKind() == IGenericType.ANNOTATION_TYPE_DECL;
+			return kind == IGenericType.ANNOTATION_TYPE_DECL;
+		case CLASS_AND_INTERFACE_SUFFIX:
+			return kind == IGenericType.CLASS_DECL || kind == IGenericType.INTERFACE_DECL;
+		case CLASS_AND_ENUM_SUFFIX:
+			return kind == IGenericType.CLASS_DECL || kind == IGenericType.ENUM_DECL;
 		case TYPE_SUFFIX: // nothing
 	}
 	return true;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ClasspathSourceDirectory.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ClasspathSourceDirectory.java
index 040cceb..d6a9f10 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ClasspathSourceDirectory.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ClasspathSourceDirectory.java
@@ -140,4 +140,9 @@
 public String toString() {
 	return "Source classpath directory " + sourceFolder.getFullPath().toString(); //$NON-NLS-1$
 }
+
+public String debugPathString() {
+	return this.sourceLocation;
+}
+
 }
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorLocator.java
index 731521d..de41665 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorLocator.java
@@ -343,8 +343,14 @@
 		ExplicitConstructorCall constructorCall = constructor.constructorCall;
 		if (constructorCall != null && constructorCall.accessMode == ExplicitConstructorCall.ImplicitSuper) {
 			// eliminate explicit super call as it will be treated with matchLevel(ExplicitConstructorCall, boolean)
-			referencesLevel = resolveLevel(constructorCall.binding);
-			if (referencesLevel == ACCURATE_MATCH) return ACCURATE_MATCH; // cannot get better
+			int callCount = (constructorCall.arguments == null) ? 0 : constructorCall.arguments.length;
+			int patternCount = (this.pattern.parameterSimpleNames == null) ? 0 : this.pattern.parameterSimpleNames.length;
+			if (patternCount != callCount) {
+				referencesLevel = IMPOSSIBLE_MATCH;
+			} else {
+				referencesLevel = resolveLevel(constructorCall.binding);
+				if (referencesLevel == ACCURATE_MATCH) return ACCURATE_MATCH; // cannot get better
+			}
 		}
 	}
 	if (!checkDeclarations) return referencesLevel;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorPattern.java
index 1e6c055..ac3eb02 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorPattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorPattern.java
@@ -121,9 +121,9 @@
 
 	// Get unique key for parameterized constructors
 	String genericDeclaringTypeSignature = null;
-	BindingKey key;
-	if (method.isResolved() && (key = new BindingKey(method.getKey())).isParameterizedType()) {
-		genericDeclaringTypeSignature = key.getDeclaringTypeSignature();
+	String key;
+	if (method.isResolved() && new BindingKey(key = method.getKey()).isParameterizedType()) {
+		genericDeclaringTypeSignature = Util.getDeclaringTypeSignature(key);
 	} else {
 		constructorParameters = true;
 	}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/FieldLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/FieldLocator.java
index 6c5e12d..5904f2c 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/FieldLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/FieldLocator.java
@@ -342,11 +342,15 @@
  */
 protected int resolveLevelForType(TypeBinding typeBinding) {
 	FieldPattern fieldPattern = (FieldPattern) this.pattern;
+	TypeBinding fieldTypeBinding = typeBinding;
+	if (fieldTypeBinding != null && fieldTypeBinding.isParameterizedType()) {
+		fieldTypeBinding = typeBinding.erasure();
+	}
 	return resolveLevelForType(
 			fieldPattern.typeSimpleName,
 			fieldPattern.typeQualification,
 			fieldPattern.getTypeArguments(),
 			0,
-			typeBinding);
+			fieldTypeBinding);
 }
 }
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchPattern.java
index b5edcd7..c1bf7b7 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchPattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchPattern.java
@@ -242,7 +242,7 @@
 	void storeTypeSignaturesAndArguments(IType type) {
 		BindingKey key;
 		if (type.isResolved() && (key = new BindingKey(type.getKey())).isParameterizedType()) {
-			String signature = key.toSignature();
+			String signature = key.internalToSignature();
 			this.typeSignatures = Util.splitTypeLevelsSignature(signature);
 			setTypeArguments(Util.getAllTypeArguments(this.typeSignatures));
 		} else {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java
index 219672c..ca99465 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java
@@ -13,6 +13,7 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.zip.ZipFile;
@@ -38,6 +39,7 @@
 import org.eclipse.jdt.internal.compiler.CompilationResult;
 import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
 import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
 import org.eclipse.jdt.internal.compiler.env.*;
@@ -65,6 +67,7 @@
 import org.eclipse.jdt.internal.core.PackageFragmentRoot;
 import org.eclipse.jdt.internal.core.SearchableEnvironment;
 import org.eclipse.jdt.internal.core.SourceMapper;
+import org.eclipse.jdt.internal.core.SourceMethod;
 import org.eclipse.jdt.internal.core.SourceTypeElementInfo;
 import org.eclipse.jdt.internal.core.index.Index;
 import org.eclipse.jdt.internal.core.search.*;
@@ -118,6 +121,9 @@
 CompilationUnitScope unitScope;
 SimpleLookupTable bindings;
 
+// Cache for method handles
+HashSet methodHandles;
+
 /**
  * An ast visitor that visits local type declarations.
  */
@@ -146,21 +152,11 @@
 				occurrenceCount = occurrenceCount + 1;
 			}
 			occurrencesCounts.put(simpleName, occurrenceCount);
-			if (typeDeclaration.allocation == null || typeDeclaration.allocation.enumConstant == null) {
-				if ((typeDeclaration.bits & ASTNode.IsAnonymousTypeMASK) != 0) {				
-					reportMatching(typeDeclaration, this.enclosingElement, -1, nodeSet, occurrenceCount);
-				} else {
-					Integer level = (Integer) nodeSet.matchingNodes.removeKey(typeDeclaration);
-					reportMatching(typeDeclaration, this.enclosingElement, level != null ? level.intValue() : -1, nodeSet, occurrenceCount);
-				}
+			if ((typeDeclaration.bits & ASTNode.IsAnonymousTypeMASK) != 0) {				
+				reportMatching(typeDeclaration, this.enclosingElement, -1, nodeSet, occurrenceCount);
 			} else {
 				Integer level = (Integer) nodeSet.matchingNodes.removeKey(typeDeclaration);
-				if (level != null) {
-					FieldDeclaration enumConstant = typeDeclaration.allocation.enumConstant;
-					int offset = enumConstant.sourceStart;
-					SearchMatch match = newDeclarationMatch(this.enclosingElement, this.enclosingElementBinding, level.intValue(), offset, enumConstant.sourceEnd-offset+1);
-					report(match);
-				}
+				reportMatching(typeDeclaration, this.enclosingElement, level != null ? level.intValue() : -1, nodeSet, occurrenceCount);
 			}
 			return false; // don't visit members as this was done during reportMatching(...)
 		} catch (CoreException e) {
@@ -406,36 +402,6 @@
 	}
 	return this.basicParser;
 }
-/**
- * Add the possibleMatch to the loop
- *  ->  build compilation unit declarations, their bindings and record their results.
- */
-protected void parseAndBuildBindings(PossibleMatch possibleMatch, boolean mustResolve) {
-	if (this.progressMonitor != null && this.progressMonitor.isCanceled())
-		throw new OperationCanceledException();
-
-	try {
-		if (BasicSearchEngine.VERBOSE)
-			System.out.println("Parsing " + possibleMatch.openable.toStringWithAncestors()); //$NON-NLS-1$
-
-		this.parser.nodeSet = possibleMatch.nodeSet;
-		CompilationResult unitResult = new CompilationResult(possibleMatch, 1, 1, this.options.maxProblemsPerUnit);
-		CompilationUnitDeclaration parsedUnit = this.parser.dietParse(possibleMatch, unitResult);
-		if (parsedUnit != null) {
-			if (mustResolve && !parsedUnit.isEmpty())
-				this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/);
-
-			// add the possibleMatch with its parsedUnit to matchesToProcess
-			possibleMatch.parsedUnit = parsedUnit;
-			int size = this.matchesToProcess.length;
-			if (this.numberOfMatches == size)
-				System.arraycopy(this.matchesToProcess, 0, this.matchesToProcess = new PossibleMatch[size == 0 ? 1 : size * 2], 0, this.numberOfMatches);
-			this.matchesToProcess[this.numberOfMatches++] = possibleMatch;
-		}
-	} finally {
-		this.parser.nodeSet = null;
-	}
-}
 /*
  * Caches the given binary type in the lookup environment and returns it.
  * Returns the existing one if already cached.
@@ -515,7 +481,9 @@
 					IBinaryMethod binaryMethod = methods[i];
 					char[] selector = binaryMethod.isConstructor() ? type.getElementName().toCharArray() : binaryMethod.getSelector();
 					if (CharOperation.equals(selector, method.selector)) {
-						char[][] parameterTypes = Signature.getParameterTypes(binaryMethod.getMethodDescriptor());
+						char[] signature = binaryMethod.getGenericSignature();
+						if (signature == null) signature = binaryMethod.getMethodDescriptor();
+						char[][] parameterTypes = Signature.getParameterTypes(signature);
 						if (argCount != parameterTypes.length) continue nextMethod;
 						for (int j = 0; j < argCount; j++) {
 							char[] typeName;
@@ -528,11 +496,11 @@
 									typeName = CharOperation.concat(typeName, new char[] {'[', ']'});
 							}
 							char[] parameterTypeName = ClassFileMatchLocator.convertClassFileFormat(parameterTypes[j]);
-							if (!CharOperation.endsWith(Signature.toCharArray(parameterTypeName), typeName))
+							if (!CharOperation.endsWith(Signature.toCharArray(Signature.getTypeErasure(parameterTypeName)), typeName))
 								continue nextMethod;
 							parameterTypes[j] = parameterTypeName;
 						}
-						return type.getMethod(new String(selector), CharOperation.toStrings(parameterTypes));
+						return createMethodHandle(type, new String(selector), CharOperation.toStrings(parameterTypes));
 					}
 				}
 			}
@@ -548,19 +516,41 @@
 //			typeName = CharOperation.concat(typeName, new char[] {'[', ']'});
 		parameterTypeSignatures[i] = Signature.createTypeSignature(typeName, false);
 	}
-	return type.getMethod(new String(method.selector), parameterTypeSignatures);
+
+	return createMethodHandle(type, new String(method.selector), parameterTypeSignatures);
+}
+
+/*
+ * Create method handle.
+ * Store occurences for create handle to retrieve possible duplicate ones.
+ */
+private IJavaElement createMethodHandle(IType type, String methodName, String[] parameterTypeSignatures) {
+	IMethod methodHandle = type.getMethod(methodName, parameterTypeSignatures);
+	if (methodHandle instanceof SourceMethod) {
+		while (this.methodHandles.contains(methodHandle)) {
+			((SourceMethod) methodHandle).occurrenceCount++;
+		}
+	}
+	this.methodHandles.add(methodHandle);
+	return methodHandle;
 }
 /**
  * Creates an IField from the given field declaration and type. 
  */
 protected IJavaElement createHandle(FieldDeclaration fieldDeclaration, TypeDeclaration typeDeclaration, IJavaElement parent) {
 	if (!(parent instanceof IType)) return parent;
+	IType type = (IType) parent;
 
 	switch (fieldDeclaration.getKind()) {
 		case AbstractVariableDeclaration.FIELD :
 		case AbstractVariableDeclaration.ENUM_CONSTANT :
 			return ((IType) parent).getField(new String(fieldDeclaration.name));
 	}
+	if (type.isBinary()) {
+		// do not return initializer for binary types
+		// see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=98378
+		return type;
+	}
 	// find occurence count of the given initializer in its type declaration
 	int occurrenceCount = 0;
 	FieldDeclaration[] fields = typeDeclaration.fields;
@@ -623,6 +613,19 @@
 	return createTypeHandle(typeName.substring(0, lastDollar));
 }
 /**
+ * Creates an IImportDeclaration from the given import statement
+ */
+protected IJavaElement createPackageDeclarationHandle(CompilationUnitDeclaration unit) {
+	if (unit.isPackageInfo()) {
+		char[] packName = CharOperation.concatWith(unit.currentPackage.getImportName(), '.');
+		Openable openable = this.currentPossibleMatch.openable;
+		if (openable instanceof CompilationUnit) {
+			return ((CompilationUnit) openable).getPackageDeclaration(new String(packName));
+		}
+	}
+	return createTypeHandle(new String(unit.getMainTypeName()));
+}
+/**
  * Creates an IType from the given simple top level type name. 
  */
 protected IType createTypeHandle(String simpleTypeName) {
@@ -719,7 +722,7 @@
 protected IType getFocusType() {
 	return this.scope instanceof HierarchyScope ? ((HierarchyScope) this.scope).focusType : null;
 }
-protected void getMethodBodies(CompilationUnitDeclaration unit) {
+protected void getMethodBodies(CompilationUnitDeclaration unit, MatchingNodeSet nodeSet) {
 	if (unit.ignoreMethodBodies) {
 		unit.ignoreFurtherInvestigation = true;
 		return; // if initial diet parse did not work, no need to dig into method bodies.
@@ -738,7 +741,7 @@
 			char[] contents = compilationResult.compilationUnit.getContents();
 			this.parser.javadocParser.scanner.setSource(contents);
 		}
-		this.parser.nodeSet = this.currentPossibleMatch.nodeSet;
+		this.parser.nodeSet = nodeSet;
 		this.parser.parseBodies(unit);
 	} finally {
 		this.parser.nodeSet = null;
@@ -763,31 +766,32 @@
 	this.bindings.put(typeKey, typeBinding);
 	return typeBinding.isValidBinding() ? typeBinding : null;
 }
-public MethodBinding getMethodBinding(IMethod method) {
+public MethodBinding getMethodBinding(MethodPattern methodPattern) {
 	if (this.unitScope == null) return null;
 	// Try to get binding from cache
-	Binding binding = (Binding) this.bindings.get(method);
+	Binding binding = (Binding) this.bindings.get(methodPattern);
 	if (binding != null) {
 		if (binding instanceof MethodBinding && binding.isValidBinding())
 			return (MethodBinding) binding;
 		return null;
 	}
 	//	Get binding from unit scope
-	String typeName = method.getDeclaringType().getElementName();
-	TypeBinding declaringTypeBinding = getType(typeName, typeName.toCharArray());
+	char[] typeName = PatternLocator.qualifiedPattern(methodPattern.declaringSimpleName, methodPattern.declaringQualification);
+	if (typeName == null) {
+		if (methodPattern.declaringType == null) return null;
+		typeName = methodPattern.declaringType.getFullyQualifiedName().toCharArray();
+	}
+	TypeBinding declaringTypeBinding = getType(typeName, typeName);
 	if (declaringTypeBinding != null) {
 		if (declaringTypeBinding.isArrayType()) {
 			declaringTypeBinding = declaringTypeBinding.leafComponentType();
 		}
 		if (!declaringTypeBinding.isBaseType()) {
-			String[] parameterTypes = method.getParameterTypes();
+			char[][] parameterTypes = methodPattern.parameterSimpleNames;
+			if (parameterTypes == null) return null;
 			int paramTypeslength = parameterTypes.length;
-			char[][] paramTypesChars = new char[paramTypeslength][];
-			for (int i=0;  i<paramTypeslength; i++) {
-				paramTypesChars[i] = Signature.toCharArray(parameterTypes[i].toCharArray());
-			}
 			ReferenceBinding referenceBinding = (ReferenceBinding) declaringTypeBinding;
-			MethodBinding[] methods = referenceBinding.getMethods(method.getElementName().toCharArray());
+			MethodBinding[] methods = referenceBinding.getMethods(methodPattern.selector);
 			int methodsLength = methods.length;
 			TypeVariableBinding[] refTypeVariables = referenceBinding.typeVariables();
 			int typeVarLength = refTypeVariables==null ? 0 : refTypeVariables.length;
@@ -796,42 +800,43 @@
 				int paramLength = methodParameters==null ? 0 : methodParameters.length;
 				TypeVariableBinding[] methodTypeVariables = methods[i].typeVariables;
 				int methTypeVarLength = methodTypeVariables==null ? 0 : methodTypeVariables.length;
-				boolean found = paramLength == paramTypeslength;
-				if (found) {
-					for (int p=0; found && p<paramLength; p++) {
-						if (CharOperation.equals(methodParameters[p].erasure().shortReadableName(), paramTypesChars[p])) {
+				boolean found = false;
+				if (paramLength == paramTypeslength) {
+					for (int p=0; p<paramLength; p++) {
+						if (CharOperation.equals(methodParameters[p].sourceName(), parameterTypes[p])) {
 							// param erasure match
+							found = true;
 						} else {
 							// type variable
-							boolean foundVar = true;
-							for (int v=0; foundVar && v<typeVarLength; v++) {
-								if (!CharOperation.equals(refTypeVariables[v].sourceName, paramTypesChars[p])) {
-									foundVar = false;
+							found = false;
+							for (int v=0; v<typeVarLength; v++) {
+								if (!CharOperation.equals(refTypeVariables[v].sourceName, parameterTypes[p])) {
+									found = false;
+									break;
 								}
+								found = true;
 							}
-							if (!foundVar) {
-								foundVar = true;
-								for (int v=0; foundVar && v<methTypeVarLength; v++) {
-									if (!CharOperation.equals(methodTypeVariables[v].sourceName, paramTypesChars[p])) {
-										foundVar = false;
+							if (!found) {
+								for (int v=0; v<methTypeVarLength; v++) {
+									if (!CharOperation.equals(methodTypeVariables[v].sourceName, parameterTypes[p])) {
+										found = false;
+										break;
 									}
+									found = true;
 								}
-								if (!foundVar) found = false;
 							}
+							if (!found) break;
 						}
 					}
 				}
 				if (found) {
-					this.bindings.put(method, methods[i]);
+					this.bindings.put(methodPattern, methods[i]);
 					return methods[i];
 				}
 			}
-//			methodBinding = referenceBinding.getExactMethod(method.getElementName().toCharArray(), parameters);
-//			this.bindings.put(method, methodBinding);
-//			return methodBinding;
 		}
 	}
-	this.bindings.put(method, new ProblemMethodBinding(method.getElementName().toCharArray(), null, ProblemReasons.NotFound));
+	this.bindings.put(methodPattern, new ProblemMethodBinding(methodPattern.selector, null, ProblemReasons.NotFound));
 	return null;
 }
 protected boolean hasAlreadyDefinedType(CompilationUnitDeclaration parsedUnit) {
@@ -884,22 +889,43 @@
 	initialize(javaProject, length);
 
 	// create and resolve binding (equivalent to beginCompilation() in Compiler)
-	boolean mustResolve = ((InternalSearchPattern)this.pattern).mustResolve;
+	boolean mustResolvePattern = ((InternalSearchPattern)this.pattern).mustResolve;
+	boolean mustResolve = mustResolvePattern;
+	this.patternLocator.mayBeGeneric = this.options.sourceLevel >= ClassFileConstants.JDK1_5;
 	boolean bindingsWereCreated = mustResolve;
 	try {
 		for (int i = start, maxUnits = start + length; i < maxUnits; i++) {
 			PossibleMatch possibleMatch = possibleMatches[i];
 			try {
-				parseAndBuildBindings(possibleMatch, mustResolve);
-				if (!mustResolve) {
+				if (!parseAndBuildBindings(possibleMatch, mustResolvePattern)) continue;
+				// Currently we only need to resolve over pattern flag if there's potential parameterized types
+				if (this.patternLocator.mayBeGeneric) {
+					// If pattern does not resolve then rely on possible match node set resolution
+					// which may have been modified while locator was adding possible matches to it
+					if (!mustResolvePattern && !mustResolve) {
+						mustResolve = possibleMatch.nodeSet.mustResolve;
+						bindingsWereCreated = mustResolve;
+					}
+				} else {
+					// Reset matching node resolution with pattern one if there's no potential parameterized type
+					// to minimize side effect on previous search behavior
+					possibleMatch.nodeSet.mustResolve = mustResolvePattern;
+				}
+				// possible match node resolution has been merged with pattern one, so rely on it to know
+				// whether we need to process compilation unit now or later
+				if (!possibleMatch.nodeSet.mustResolve) {
 					if (this.progressMonitor != null) {
 						this.progressWorked++;
 						if ((this.progressWorked%this.progressStep)==0) this.progressMonitor.worked(this.progressStep);
 					}
 					process(possibleMatch, bindingsWereCreated);
+					if (this.numberOfMatches>0 && this.matchesToProcess[this.numberOfMatches-1] == possibleMatch) {
+						// forget last possible match as it was processed
+						this.numberOfMatches--;
+					}
 				}
 			} finally {
-				if (!mustResolve)
+				if (!possibleMatch.nodeSet.mustResolve)
 					possibleMatch.cleanUp();
 			}
 		}
@@ -1081,7 +1107,7 @@
 				}
 				previousJavaProject = javaProject;
 			}
-			matchSet.add(new PossibleMatch(this, resource, openable, searchDocument));
+			matchSet.add(new PossibleMatch(this, resource, openable, searchDocument, ((InternalSearchPattern) this.pattern).mustResolve));
 		}
 
 		// last project
@@ -1100,6 +1126,7 @@
 			this.nameEnvironment.cleanup();
 		manager.flushZipFiles();
 		this.bindings = null;
+		this.patternLocator.clear();
 	}
 }
 /**
@@ -1120,7 +1147,7 @@
 		IJavaElement focus = ((InternalSearchPattern) searchPattern).focus;
 		if (focus != null) {
 			SearchDocument document = participant.getDocument(focus.getPath().toString());
-			this.currentPossibleMatch = new PossibleMatch(this, focus.getResource(), null, document);
+			this.currentPossibleMatch = new PossibleMatch(this, focus.getResource(), null, document, ((InternalSearchPattern) searchPattern).mustResolve);
 			if (encloses(focus)) {
 				SearchMatch match = newDeclarationMatch(focus.getAncestor(IJavaElement.PACKAGE_FRAGMENT), null/*no binding*/, SearchMatch.A_ACCURATE, -1, -1);
 				report(match);
@@ -1161,7 +1188,7 @@
 						if (resource == null) // case of a file in an external jar
 							resource = javaProject.getProject();
 						SearchDocument document = participant.getDocument(resource.getFullPath().toString());
-						this.currentPossibleMatch = new PossibleMatch(this, resource, null, document);
+						this.currentPossibleMatch = new PossibleMatch(this, resource, null, document, ((InternalSearchPattern) searchPattern).mustResolve);
 						try {
 							if (encloses(pkg)) {
 								SearchMatch match = newDeclarationMatch(pkg, null/*no binding*/, SearchMatch.A_ACCURATE, -1, -1);
@@ -1360,6 +1387,47 @@
 	return newTypeReferenceMatch(enclosingElement, enclosingBinding, accuracy, reference.sourceStart, reference.sourceEnd-reference.sourceStart+1, reference);
 }
 
+/**
+ * Add the possibleMatch to the loop
+ *  ->  build compilation unit declarations, their bindings and record their results.
+ */
+protected boolean parseAndBuildBindings(PossibleMatch possibleMatch, boolean mustResolve) throws CoreException {
+	if (this.progressMonitor != null && this.progressMonitor.isCanceled())
+		throw new OperationCanceledException();
+
+	try {
+		if (BasicSearchEngine.VERBOSE)
+			System.out.println("Parsing " + possibleMatch.openable.toStringWithAncestors()); //$NON-NLS-1$
+
+		this.parser.nodeSet = possibleMatch.nodeSet;
+		CompilationResult unitResult = new CompilationResult(possibleMatch, 1, 1, this.options.maxProblemsPerUnit);
+		CompilationUnitDeclaration parsedUnit = this.parser.dietParse(possibleMatch, unitResult);
+		if (parsedUnit != null) {
+			if (!parsedUnit.isEmpty()) {
+				if (mustResolve) {
+					this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/);
+				}
+				if (hasAlreadyDefinedType(parsedUnit)) return false; // skip type has it is hidden so not visible
+				getMethodBodies(parsedUnit, possibleMatch.nodeSet);
+				if (this.patternLocator.mayBeGeneric && !mustResolve && possibleMatch.nodeSet.mustResolve) {
+					// special case: possible match node set force resolution although pattern does not
+					// => we need to build types for this compilation unit
+					this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/);
+				}
+			}
+	
+			// add the possibleMatch with its parsedUnit to matchesToProcess
+			possibleMatch.parsedUnit = parsedUnit;
+			int size = this.matchesToProcess.length;
+			if (this.numberOfMatches == size)
+				System.arraycopy(this.matchesToProcess, 0, this.matchesToProcess = new PossibleMatch[size == 0 ? 1 : size * 2], 0, this.numberOfMatches);
+			this.matchesToProcess[this.numberOfMatches++] = possibleMatch;
+		}
+	} finally {
+		this.parser.nodeSet = null;
+	}
+	return true;
+}
 /*
  * Process a compilation unit already parsed and build.
  */
@@ -1378,26 +1446,31 @@
 		}
 		if (hasAlreadyDefinedType(unit)) return; // skip type has it is hidden so not visible
 
-		getMethodBodies(unit);
+		// Move getMethodBodies to #parseAndBuildings(...) method to allow possible match resolution management
+		//getMethodBodies(unit);
 
-		if (bindingsWereCreated && ((InternalSearchPattern)this.pattern).mustResolve && unit.types != null) {
-			if (BasicSearchEngine.VERBOSE)
-				System.out.println("Resolving " + this.currentPossibleMatch.openable.toStringWithAncestors()); //$NON-NLS-1$
-
-			reduceParseTree(unit);
-
-			if (unit.scope != null) {
-				// fault in fields & methods
-				unit.scope.faultInTypes();
+		boolean mustResolve = ((InternalSearchPattern)this.pattern).mustResolve || possibleMatch.nodeSet.mustResolve;
+		if (bindingsWereCreated &&  mustResolve) {
+			if (unit.types != null) {
+				if (BasicSearchEngine.VERBOSE)
+					System.out.println("Resolving " + this.currentPossibleMatch.openable.toStringWithAncestors()); //$NON-NLS-1$
+	
+				reduceParseTree(unit);
+	
+				if (unit.scope != null) {
+					// fault in fields & methods
+					unit.scope.faultInTypes();
+				}
+				unit.resolve();
+			} else if (unit.isPackageInfo()) {
+				if (BasicSearchEngine.VERBOSE)
+					System.out.println("Resolving " + this.currentPossibleMatch.openable.toStringWithAncestors()); //$NON-NLS-1$
+				unit.resolve();
 			}
-			unit.resolve();
-
-			reportMatching(unit, true);
-		} else {
-			reportMatching(unit, ((InternalSearchPattern)this.pattern).mustResolve);
 		}
+		reportMatching(unit, mustResolve);
 	} catch (AbortCompilation e) {
-		// could not resolve: report innacurate matches
+		// could not resolve: report inaccurate matches
 		reportMatching(unit, true); // was partially resolved
 		if (!(e instanceof AbortCompilationUnit)) {
 			// problem with class path
@@ -1453,11 +1526,21 @@
 		System.out.println("Reporting match"); //$NON-NLS-1$
 		System.out.println("\tResource: " + match.getResource()); //$NON-NLS-2$//$NON-NLS-1$
 		System.out.println("\tPositions: [offset=" + match.getOffset() + ", length=" + match.getLength() + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
-		if (this.parser != null && match.getOffset() > 0 && match.getLength() > 0 && !(match.getElement() instanceof BinaryMember)) {
-			String selection = new String(this.parser.scanner.source, match.getOffset(), match.getLength());
-			System.out.println("\tSelection: -->" + selection + "<--"); //$NON-NLS-1$ //$NON-NLS-2$
+		try {
+			if (this.parser != null && match.getOffset() > 0 && match.getLength() > 0 && !(match.getElement() instanceof BinaryMember)) {
+				String selection = new String(this.parser.scanner.source, match.getOffset(), match.getLength());
+				System.out.println("\tSelection: -->" + selection + "<--"); //$NON-NLS-1$ //$NON-NLS-2$
+			}
+		} catch (Exception e) {
+			// it's just for debug purposes... ignore all exceptions in this area
 		}
-		System.out.println("\tJava element: " + ((JavaElement)match.getElement()).toStringWithAncestors()); //$NON-NLS-1$
+		try {
+			JavaElement javaElement = (JavaElement)match.getElement();
+			System.out.println("\tJava element: "+ javaElement.toStringWithAncestors()); //$NON-NLS-1$
+			if (!javaElement.exists()) System.out.println("\t\tWARNING: this element does NOT exist!"); //$NON-NLS-1$
+		} catch (Exception e) {
+			// it's just for debug purposes... ignore all exceptions in this area
+		}
 		System.out.println(match.getAccuracy() == SearchMatch.A_ACCURATE
 			? "\tAccuracy: EXACT_MATCH" //$NON-NLS-1$
 			: "\tAccuracy: POTENTIAL_MATCH"); //$NON-NLS-1$
@@ -1748,7 +1831,7 @@
 			if (encloses(enclosingElement)) {
 				int length = scanner.currentPosition - nameSourceStart;
 				SearchMatch match = this.patternLocator.newDeclarationMatch(method, enclosingElement, method.binding, accuracy, length, this);
-				report(match);
+				if (match != null) report(match);
 			}
 		}
 	}
@@ -1767,15 +1850,10 @@
 
 	// report annotations
 	if (method.annotations != null) {
-		for (int i=0, al=method.annotations.length; i<al; i++) {
-			TypeReference typeRef = method.annotations[i].type;
-			Integer level = (Integer) nodeSet.matchingNodes.removeKey(typeRef);
-			if (level != null) {
-				if (enclosingElement == null)
-					enclosingElement = createHandle(method, parent);
-				this.patternLocator.matchReportReference(typeRef, enclosingElement, method.binding, level.intValue(), this);
-			}
+		if (enclosingElement == null) {
+			enclosingElement = createHandle(method, parent);
 		}
+		reportMatching(method.annotations, enclosingElement, method.binding, nodeSet, true, true);
 	}
 
 	// references in this method
@@ -1800,10 +1878,66 @@
 	}
 }
 /**
+ * Report matching in annotations.
+ */
+protected void reportMatching(Annotation[] annotations, IJavaElement enclosingElement, Binding elementBinding, MatchingNodeSet nodeSet, boolean matchedContainer, boolean enclosesElement) throws CoreException {
+	for (int i=0, al=annotations.length; i<al; i++) {
+		Annotation annotationType = annotations[i];
+
+		// Look for annotation type ref
+		TypeReference typeRef = annotationType.type;
+		Integer level = (Integer) nodeSet.matchingNodes.removeKey(typeRef);
+		if (level != null && matchedContainer) {
+			this.patternLocator.matchReportReference(typeRef, enclosingElement, elementBinding, level.intValue(), this);
+		}
+		
+		// Look for attribute ref
+		MemberValuePair[] pairs = annotationType.memberValuePairs();
+		for (int j = 0, pl = pairs.length; j < pl; j++) {
+			MemberValuePair pair = pairs[j];
+			level = (Integer) nodeSet.matchingNodes.removeKey(pair);
+			if (level != null && enclosesElement) {
+				ASTNode reference = (annotationType instanceof SingleMemberAnnotation) ? (ASTNode) annotationType: pair;
+				this.patternLocator.matchReportReference(reference, enclosingElement, pair.binding, level.intValue(), this);
+			}
+		}
+		
+		// Look for reference inside annotation
+		ASTNode[] nodes = nodeSet.matchingNodes(annotationType.sourceStart, annotationType.declarationSourceEnd);
+		if (nodes != null) {
+			if (!matchedContainer) {
+				for (int j = 0, nl = nodes.length; j < nl; j++) {
+					nodeSet.matchingNodes.removeKey(nodes[j]);
+				}
+			} else {
+				for (int j = 0, nl = nodes.length; j < nl; j++) {
+					ASTNode node = nodes[j];
+					level = (Integer) nodeSet.matchingNodes.removeKey(node);
+					if (enclosesElement) {
+						this.patternLocator.matchReportReference(node, enclosingElement, elementBinding, level.intValue(), this);
+					}
+				}
+			}
+		}
+	}
+}
+/**
  * Visit the given resolved parse tree and report the nodes that match the search pattern.
  */
 protected void reportMatching(CompilationUnitDeclaration unit, boolean mustResolve) throws CoreException {
 	MatchingNodeSet nodeSet = this.currentPossibleMatch.nodeSet;
+	boolean locatorMustResolve = this.patternLocator.mustResolve;
+	if (nodeSet.mustResolve) this.patternLocator.mustResolve = true;
+	if (BasicSearchEngine.VERBOSE) {
+		System.out.println("Report matching: "); //$NON-NLS-1$
+		int size = nodeSet.matchingNodes==null ? 0 : nodeSet.matchingNodes.elementSize;
+		System.out.print("	- node set: accurate="+ size); //$NON-NLS-1$
+		size = nodeSet.possibleMatchingNodesSet==null ? 0 : nodeSet.possibleMatchingNodesSet.elementSize;
+		System.out.println(", possible="+size); //$NON-NLS-1$
+		System.out.print("	- must resolve: "+mustResolve); //$NON-NLS-1$
+		System.out.print(" (locator: "+this.patternLocator.mustResolve); //$NON-NLS-1$
+		System.out.println(", nodeSet: "+nodeSet.mustResolve+')'); //$NON-NLS-1$
+	}
 	if (mustResolve) {
 		this.unitScope= unit.scope.compilationUnitScope();
 		// move the possible matching nodes that exactly match the search pattern to the matching nodes set
@@ -1825,18 +1959,48 @@
 			nodeSet.addMatch(node, this.patternLocator.resolveLevel(node));
 		}
 		nodeSet.possibleMatchingNodesSet = new SimpleSet(3);
+		if (BasicSearchEngine.VERBOSE) {
+			int size = nodeSet.matchingNodes==null ? 0 : nodeSet.matchingNodes.elementSize;
+			System.out.print("	- node set: accurate="+size); //$NON-NLS-1$
+			size = nodeSet.possibleMatchingNodesSet==null ? 0 : nodeSet.possibleMatchingNodesSet.elementSize;
+			System.out.println(", possible="+size); //$NON-NLS-1$
+		}
 	} else {
 		this.unitScope = null;
 	}
 
 	if (nodeSet.matchingNodes.elementSize == 0) return; // no matching nodes were found
+	this.methodHandles = new HashSet();
 
 	boolean matchedUnitContainer = (this.matchContainer & PatternLocator.COMPILATION_UNIT_CONTAINER) != 0;
+
+	// report references in javadoc
+	if (unit.javadoc != null) {
+		ASTNode[] nodes = nodeSet.matchingNodes(unit.javadoc.sourceStart, unit.javadoc.sourceEnd);
+		if (nodes != null) {
+			if (!matchedUnitContainer) {
+				for (int i = 0, l = nodes.length; i < l; i++)
+					nodeSet.matchingNodes.removeKey(nodes[i]);
+			} else {
+				IJavaElement element = createPackageDeclarationHandle(unit);
+				for (int i = 0, l = nodes.length; i < l; i++) {
+					ASTNode node = nodes[i];
+					Integer level = (Integer) nodeSet.matchingNodes.removeKey(node);
+					if (encloses(element))
+						this.patternLocator.matchReportReference(node, element, null/*no binding*/, level.intValue(), this);
+				}
+			}
+		}
+	}
+
 	if (matchedUnitContainer) {
-// Currently a no-op
-//	ImportReference pkg = unit.currentPackage;
-//	if (pkg != null && nodeSet.matchingNodes.removeKey(pkg) != null)
-//		reportPackageDeclaration(pkg);
+		ImportReference pkg = unit.currentPackage;
+		if (pkg != null && pkg.annotations != null) {
+			IJavaElement element = createPackageDeclarationHandle(unit);
+			if (element != null) {
+				reportMatching(pkg.annotations, element, null, nodeSet, true, encloses(element));
+			}
+		}
 
 		ImportReference[] imports = unit.imports;
 		if (imports != null) {
@@ -1859,6 +2023,10 @@
 			reportMatching(type, null, accuracy, nodeSet, 1);
 		}
 	}
+	
+	// Clear handle cache
+	this.methodHandles = null;
+	this.patternLocator.mustResolve = locatorMustResolve;
 }
 /**
  * Visit the given field declaration and report the nodes that match exactly the
@@ -1889,15 +2057,10 @@
 
 	// report annotations
 	if (field.annotations != null) {
-		for (int i=0, al=field.annotations.length; i<al; i++) {
-			TypeReference typeRef = field.annotations[i].type;
-			Integer level = (Integer) nodeSet.matchingNodes.removeKey(typeRef);
-			if (level != null) {
-				if (enclosingElement == null)
-					enclosingElement = createHandle(field, type, parent);
-				this.patternLocator.matchReportReference(typeRef, enclosingElement, field.binding, level.intValue(), this);
-			}
+		if (enclosingElement == null) {
+			enclosingElement = createHandle(field, type, parent);
 		}
+		reportMatching(field.annotations, enclosingElement, field.binding, nodeSet, true, true);
 	}
 
 	if (typeInHierarchy) {
@@ -1915,6 +2078,13 @@
 					for (int i = 0, l = nodes.length; i < l; i++) {
 						ASTNode node = nodes[i];
 						Integer level = (Integer) nodeSet.matchingNodes.removeKey(node);
+						if (node instanceof TypeDeclaration) {
+							// use field declaration to report match (see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=88174)
+							AllocationExpression allocation = ((TypeDeclaration)node).allocation;
+							if (allocation != null && allocation.enumConstant != null) {
+								node = field;
+							}
+						}
 						this.patternLocator.matchReportReference(node, enclosingElement, field.binding, level.intValue(), this);
 					}
 			}
@@ -1940,9 +2110,10 @@
 			enclosingElement = member.getType(new String(type.name), occurrenceCount);
 	}
 	if (enclosingElement == null) return;
+	boolean enclosesElement = encloses(enclosingElement);
 
 	// report the type declaration
-	if (accuracy > -1 && encloses(enclosingElement)) {
+	if (accuracy > -1 && enclosesElement) {
 		int offset = type.sourceStart;
 		SearchMatch match = this.patternLocator.newDeclarationMatch(type, enclosingElement, type.binding, accuracy, type.sourceEnd-offset+1, this);
 		report(match);
@@ -1957,7 +2128,7 @@
 			if (typeParameter != null) {
 				Integer level = (Integer) nodeSet.matchingNodes.removeKey(typeParameter);
 				if (level != null && matchedClassContainer) {
-					if (level.intValue() > -1 && encloses(enclosingElement)) {
+					if (level.intValue() > -1 && enclosesElement) {
 						int offset = typeParameter.sourceStart;
 						SearchMatch match = this.patternLocator.newDeclarationMatch(typeParameter, enclosingElement, type.binding, level.intValue(), typeParameter.sourceEnd-offset+1, this);
 						report(match);
@@ -1983,13 +2154,7 @@
 
 	// report annotations
 	if (type.annotations != null) {
-		for (int i=0, al=type.annotations.length; i<al; i++) {
-			TypeReference typeRef = type.annotations[i].type;
-			Integer level = (Integer) nodeSet.matchingNodes.removeKey(typeRef);
-			if (level != null && matchedClassContainer) {
-				this.patternLocator.matchReportReference(typeRef, enclosingElement, type.binding, level.intValue(), this);
-			}
-		}
+		reportMatching(type.annotations, enclosingElement, type.binding, nodeSet, matchedClassContainer, enclosesElement);
 	}
 
 	// report references in javadoc
@@ -2003,8 +2168,9 @@
 				for (int i = 0, l = nodes.length; i < l; i++) {
 					ASTNode node = nodes[i];
 					Integer level = (Integer) nodeSet.matchingNodes.removeKey(node);
-					if (encloses(enclosingElement))
+					if (enclosesElement) {
 						this.patternLocator.matchReportReference(node, enclosingElement, type.binding, level.intValue(), this);
+					}
 				}
 			}
 		}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocatorParser.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocatorParser.java
index b0d0635..775403c 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocatorParser.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocatorParser.java
@@ -75,6 +75,10 @@
 		patternLocator.match(methodDeclaration, nodeSet);
 		return (methodDeclaration.bits & ASTNode.HasLocalTypeMASK) != 0; // continue only if it has local type
 	}
+	public boolean visit(AnnotationMethodDeclaration methodDeclaration, ClassScope scope) {
+		patternLocator.match(methodDeclaration, nodeSet);
+		return false; // no local type for annotation type members
+	}
 }
 public class ClassAndMethodDeclarationVisitor extends ClassButNoMethodDeclarationVisitor {
 	public boolean visit(TypeDeclaration localTypeDeclaration, BlockScope scope) {
@@ -175,13 +179,6 @@
 	super.classInstanceCreation(alwaysQualified);
 	this.patternLocator.match(this.expressionStack[this.expressionPtr], this.nodeSet);
 }
-protected void consumeAnnotationAsModifier() {
-	super.consumeAnnotationAsModifier();
-	Expression expression = this.expressionStack[this.expressionPtr];
-	if (expression instanceof Annotation) {
-		this.patternLocator.match(((Annotation)expression).type, this.nodeSet);
-	}
-}
 protected void consumeAssignment() {
 	super.consumeAssignment();
 	this.patternLocator.match(this.expressionStack[this.expressionPtr], this.nodeSet);
@@ -208,30 +205,24 @@
 	// this is always a Reference
 	this.patternLocator.match((Reference) this.expressionStack[this.expressionPtr], this.nodeSet);
 }
-protected void consumeInternalCompilationUnit() {
-	// InternalCompilationUnit ::= PackageDeclaration
-	// InternalCompilationUnit ::= PackageDeclaration ImportDeclarations ReduceImports
-	// InternalCompilationUnit ::= ImportDeclarations ReduceImports
-}
-protected void consumeInternalCompilationUnitWithTypes() {
-	// InternalCompilationUnit ::= PackageDeclaration ImportDeclarations ReduceImports TypeDeclarations
-	// InternalCompilationUnit ::= PackageDeclaration TypeDeclarations
-	// InternalCompilationUnit ::= TypeDeclarations
-	// InternalCompilationUnit ::= ImportDeclarations ReduceImports TypeDeclarations
-	// consume type declarations
-	int length;
-	if ((length = this.astLengthStack[this.astLengthPtr--]) != 0) {
-		this.compilationUnit.types = new TypeDeclaration[length];
-		this.astPtr -= length;
-		System.arraycopy(this.astStack, this.astPtr + 1, this.compilationUnit.types, 0, length);
-	}
-}
 protected void consumeLocalVariableDeclaration() {
 	super.consumeLocalVariableDeclaration();
 
 	// this is always a LocalDeclaration
 	this.patternLocator.match((LocalDeclaration) this.astStack[this.astPtr], this.nodeSet);
 }
+protected void consumeMarkerAnnotation() {
+	super.consumeMarkerAnnotation();
+	// this is always an Annotation
+	Annotation annotation = (Annotation) expressionStack[expressionPtr];
+	this.patternLocator.match(annotation, nodeSet);
+}
+protected void consumeMemberValuePair() {
+	super.consumeMemberValuePair();
+
+	// this is always a MemberValuePair
+	this.patternLocator.match((MemberValuePair) this.astStack[this.astPtr], this.nodeSet);
+}
 protected void consumeMethodInvocationName() {
 	super.consumeMethodInvocationName();
 
@@ -268,6 +259,12 @@
 	// this is always a MessageSend
 	this.patternLocator.match((MessageSend) this.expressionStack[this.expressionPtr], this.nodeSet);
 }
+protected void consumeNormalAnnotation() {
+	super.consumeNormalAnnotation();
+	// this is always an Annotation
+	Annotation annotation = (Annotation) expressionStack[expressionPtr];
+	this.patternLocator.match(annotation, nodeSet);
+}
 protected void consumePrimaryNoNewArray() {
 	// pop parenthesis positions (and don't update expression positions
 	// (see http://bugs.eclipse.org/bugs/show_bug.cgi?id=23329)
@@ -283,6 +280,12 @@
 	intPtr--;
 	intPtr--;
 }
+protected void consumeSingleMemberAnnotation() {
+	super.consumeSingleMemberAnnotation();
+	// this is always an Annotation
+	Annotation annotation = (Annotation) expressionStack[expressionPtr];
+	this.patternLocator.match(annotation, nodeSet);
+}
 protected void consumeTypeArgument() {
 	super.consumeTypeArgument();
 	patternLocator.match((TypeReference)genericsStack[genericsPtr], nodeSet);
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchingNodeSet.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchingNodeSet.java
index fd4da6e..796efc9 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchingNodeSet.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchingNodeSet.java
@@ -36,12 +36,23 @@
 static Integer ERASURE_MATCH = new Integer(SearchPattern.R_ERASURE_MATCH);
 
 /**
+ * Tell whether locators need to resolve or not for current matching node set.
+ */
+public boolean mustResolve;
+
+/**
  * Set of possible matching ast nodes. They need to be resolved
  * to determine if they really match the search pattern.
  */
 SimpleSet possibleMatchingNodesSet = new SimpleSet(7);
 private HashtableOfLong possibleMatchingNodesKeys = new HashtableOfLong(7);
 
+
+public MatchingNodeSet(boolean mustResolvePattern) {
+	super();
+	mustResolve = mustResolvePattern;
+}
+
 public int addMatch(ASTNode node, int matchLevel) {
 	switch (matchLevel) {
 		case PatternLocator.INACCURATE_MATCH:
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java
index 2fc4632..437d78e 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java
@@ -10,12 +10,13 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.search.matching;
 
+import java.util.HashMap;
+
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.*;
 import org.eclipse.jdt.core.*;
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.search.*;
-import org.eclipse.jdt.core.search.SearchMatch;
 import org.eclipse.jdt.internal.compiler.ast.*;
 import org.eclipse.jdt.internal.compiler.env.IBinaryType;
 import org.eclipse.jdt.internal.compiler.lookup.*;
@@ -30,12 +31,21 @@
 //extra reference info
 public char[][][] allSuperDeclaringTypeNames;
 
+//method declarations which parameters verification fail
+private HashMap methodDeclarationsWithInvalidParam = new HashMap();
+
 public MethodLocator(MethodPattern pattern) {
 	super(pattern);
 
 	this.pattern = pattern;
 	this.isDeclarationOfReferencedMethodsPattern = this.pattern instanceof DeclarationOfReferencedMethodsPattern;
 }
+/*
+ * Clear caches
+ */
+protected void clear() {
+	this.methodDeclarationsWithInvalidParam = new HashMap();
+}
 public void initializePolymorphicSearch(MatchLocator locator) {
 	try {
 		this.allSuperDeclaringTypeNames =
@@ -50,6 +60,19 @@
 		// inaccurate matches will be found
 	}
 }
+/*
+ * Return whether a type name is in pattern all super declaring types names.
+ */
+boolean isTypeInSuperDeclaringTypeNames(char[][] typeName) {
+	if (allSuperDeclaringTypeNames == null) return false;
+	int length = allSuperDeclaringTypeNames.length;
+	for (int i= 0; i<length; i++) {
+		if (CharOperation.equals(allSuperDeclaringTypeNames[i], typeName)) {
+			return true;
+		}
+	}
+	return false;
+}
 /**
  * Returns whether the code gen will use an invoke virtual for 
  * this message send or not.
@@ -86,13 +109,27 @@
 	if (!matchesName(this.pattern.selector, node.selector)) return IMPOSSIBLE_MATCH;
 	
 	// Verify parameters types
+	boolean resolve = ((InternalSearchPattern)this.pattern).mustResolve;
 	if (this.pattern.parameterSimpleNames != null) {
 		int length = this.pattern.parameterSimpleNames.length;
 		ASTNode[] args = node.arguments;
 		int argsLength = args == null ? 0 : args.length;
 		if (length != argsLength) return IMPOSSIBLE_MATCH;
 		for (int i = 0; i < argsLength; i++) {
-			if (!matchesTypeReference(this.pattern.parameterSimpleNames[i], ((Argument) args[i]).type)) return IMPOSSIBLE_MATCH;
+			if (!matchesTypeReference(this.pattern.parameterSimpleNames[i], ((Argument) args[i]).type)) {
+				// Do not return as impossible when source level is at least 1.5
+				if (this.mayBeGeneric) {
+					if (!((InternalSearchPattern)this.pattern).mustResolve) {
+						// Set resolution flag on node set in case of types was inferred in parameterized types from generic ones...
+					 	// (see  bugs https://bugs.eclipse.org/bugs/show_bug.cgi?id=79990, 96761, 96763)
+						nodeSet.mustResolve = true;
+						resolve = true;
+					}
+					this.methodDeclarationsWithInvalidParam.put(node, null);
+				} else {
+					return IMPOSSIBLE_MATCH;
+				}
+			}
 		}
 	}
 
@@ -102,6 +139,13 @@
 	}
 
 	// Method declaration may match pattern
+	return nodeSet.addMatch(node, resolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
+}
+public int match(MemberValuePair node, MatchingNodeSet nodeSet) {
+	if (!this.pattern.findReferences) return IMPOSSIBLE_MATCH;
+
+	if (!matchesName(this.pattern.selector, node.name)) return IMPOSSIBLE_MATCH;
+
 	return nodeSet.addMatch(node, ((InternalSearchPattern)this.pattern).mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
 }
 public int match(MessageSend node, MatchingNodeSet nodeSet) {
@@ -118,6 +162,22 @@
 	return nodeSet.addMatch(node, ((InternalSearchPattern)this.pattern).mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
 }
 //public int match(Reference node, MatchingNodeSet nodeSet) - SKIP IT
+public int match(Annotation node, MatchingNodeSet nodeSet) {
+	if (!this.pattern.findReferences) return IMPOSSIBLE_MATCH;
+	MemberValuePair[] pairs = node.memberValuePairs();
+	if (pairs == null || pairs.length == 0) return IMPOSSIBLE_MATCH;
+
+	int length = pairs.length;
+	MemberValuePair pair = null;
+	for (int i=0; i<length; i++) {
+		pair = node.memberValuePairs()[i];
+		if (matchesName(this.pattern.selector, pair.name)) {
+			ASTNode possibleNode = (node instanceof SingleMemberAnnotation) ? (ASTNode) node : pair;
+			return nodeSet.addMatch(possibleNode, ((InternalSearchPattern)this.pattern).mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
+		}
+	}
+	return IMPOSSIBLE_MATCH;
+}
 //public int match(TypeDeclaration node, MatchingNodeSet nodeSet) - SKIP IT
 //public int match(TypeReference node, MatchingNodeSet nodeSet) - SKIP IT
 
@@ -137,7 +197,7 @@
 		super.matchLevelAndReportImportRef(importRef, binding, locator);
 	}
 }
-protected int matchMethod(MethodBinding method) {
+protected int matchMethod(MethodBinding method, boolean skipImpossibleArg) {
 	if (!matchesName(this.pattern.selector, method.selector)) return IMPOSSIBLE_MATCH;
 
 	int level = ACCURATE_MATCH;
@@ -179,10 +239,13 @@
 			}
 			if (level > newLevel) {
 				if (newLevel == IMPOSSIBLE_MATCH) {
-//					if (isErasureMatch) {
-//						return ERASURE_MATCH;
-//					}
-					return IMPOSSIBLE_MATCH;
+					if (skipImpossibleArg) {
+						// Do not consider match as impossible while finding declarations and source level >= 1.5
+					 	// (see  bugs https://bugs.eclipse.org/bugs/show_bug.cgi?id=79990, 96761, 96763)
+						newLevel = level;
+					} else {
+						return IMPOSSIBLE_MATCH;
+					}
 				}
 				level = newLevel; // can only be downgraded
 			}
@@ -191,11 +254,61 @@
 
 	return level;
 }
+private boolean matchOverriddenMethod(ReferenceBinding type, MethodBinding method, MethodBinding matchMethod) {
+	if (type == null) return false;
+
+	// matches superclass
+	if (!type.isInterface() && !CharOperation.equals(type.compoundName, TypeConstants.JAVA_LANG_OBJECT)) {
+		ReferenceBinding superClass = type.superclass();
+		if (superClass.isParameterizedType()) {
+			MethodBinding[] methods = superClass.getMethods(this.pattern.selector);
+			int length = methods.length;
+			for (int i = 0; i<length; i++) {
+				if (methods[i].areParametersEqual(method)) {
+					if (matchMethod == null) {
+						if (methodParametersEqualsPattern(methods[i].original())) return true;
+					} else {
+						if (methodsHaveSameParameters(methods[i].original(), matchMethod)) return true;
+					}
+				}
+			}
+		}
+		if (matchOverriddenMethod(superClass, method, matchMethod)) {
+			return true;
+		}
+	}
+
+	// matches interfaces
+	ReferenceBinding[] interfaces = type.superInterfaces();
+	if (interfaces == null) return false;
+	int iLength = interfaces.length;
+	for (int i = 0; i<iLength; i++) {
+		if (interfaces[i].isParameterizedType()) {
+			MethodBinding[] methods = interfaces[i].getMethods(this.pattern.selector);
+			int length = methods.length;
+			for (int j = 0; j<length; j++) {
+				if (methods[j].areParametersEqual(method)) {
+					if (matchMethod == null) {
+						if (methodParametersEqualsPattern(methods[j].original())) return true;
+					} else {
+						if (methodsHaveSameParameters(methods[j].original(), matchMethod)) return true;
+					}
+				}
+			}
+		}
+		if (matchOverriddenMethod(interfaces[i], method, matchMethod)) {
+			return true;
+		}
+	}
+	return false;
+}
 /**
  * @see org.eclipse.jdt.internal.core.search.matching.PatternLocator#matchReportReference(org.eclipse.jdt.internal.compiler.ast.ASTNode, org.eclipse.jdt.core.IJavaElement, Binding, int, org.eclipse.jdt.internal.core.search.matching.MatchLocator)
  */
 protected void matchReportReference(ASTNode reference, IJavaElement element, Binding elementBinding, int accuracy, MatchLocator locator) throws CoreException {
+	MethodBinding methodBinding = (reference instanceof MessageSend) ? ((MessageSend)reference).binding: ((elementBinding instanceof MethodBinding) ? (MethodBinding) elementBinding : null);
 	if (this.isDeclarationOfReferencedMethodsPattern) {
+		if (methodBinding == null) return;
 		// need exact match to be able to open on type ref
 		if (accuracy != SearchMatch.A_ACCURATE) return;
 
@@ -204,7 +317,7 @@
 		while (element != null && !declPattern.enclosingElement.equals(element))
 			element = element.getParent();
 		if (element != null) {
-			reportDeclaration(((MessageSend) reference).binding, locator, declPattern.knownMethods);
+			reportDeclaration(methodBinding, locator, declPattern.knownMethods);
 		}
 	} else {
 		match = locator.newMethodReferenceMatch(element, elementBinding, accuracy, -1, -1, false /*not constructor*/, false/*not synthetic*/, reference);
@@ -213,17 +326,23 @@
 			// verify closest match if pattern was bound
 			// (see bug 70827)
 			if (focus != null && focus.getElementType() == IJavaElement.METHOD) {
-				MethodBinding method = ((MessageSend)reference).binding;
-				boolean isPrivate = Flags.isPrivate(((IMethod) focus).getFlags());
-				if (isPrivate && !CharOperation.equals(method.declaringClass.sourceName, focus.getParent().getElementName().toCharArray())) {
-					return; // finally the match was not possible
+				if (methodBinding != null) {
+					boolean isPrivate = Flags.isPrivate(((IMethod) focus).getFlags());
+					if (isPrivate && !CharOperation.equals(methodBinding.declaringClass.sourceName, focus.getParent().getElementName().toCharArray())) {
+						return; // finally the match was not possible
+					}
 				}
 			}
 			matchReportReference((MessageSend)reference, locator, ((MessageSend)reference).binding);
 		} else {
+			if (reference instanceof SingleMemberAnnotation) {
+				reference = ((SingleMemberAnnotation)reference).memberValuePairs()[0];
+				match.setImplicit(true);
+			}
 			int offset = reference.sourceStart;
+			int length =  reference.sourceEnd - offset + 1;
 			match.setOffset(offset);
-			match.setLength(reference.sourceEnd-offset+1);
+			match.setLength(length);
 			locator.report(match);
 		}
 	}
@@ -302,6 +421,71 @@
 		locator.report(match);
 	}
 }
+/*
+ * Return whether method parameters are equals to pattern ones.
+ */
+private boolean methodParametersEqualsPattern(MethodBinding method) {
+	TypeBinding[] methodParameters = method.parameters;
+
+	int length = methodParameters==null ? 0 : methodParameters.length;
+	int patternLength = this.pattern.parameterSimpleNames==null ? 0 : this.pattern.parameterSimpleNames.length;
+	if (length != patternLength) return false;
+
+	for (int i = 0; i < length; i++) {
+		char[] paramQualifiedName = qualifiedPattern(this.pattern.parameterSimpleNames[i], this.pattern.parameterQualifications[i]);
+		if (!CharOperation.match(paramQualifiedName, methodParameters[i].readableName(), this.isCaseSensitive)) {
+			return false;
+		}
+	}
+	return true;
+}
+private boolean methodsHaveSameParameters(MethodBinding method, MethodBinding matchMethod) {
+	TypeBinding[] methodParameters = method.parameters;
+	TypeBinding[] matchMethodParameters = matchMethod.parameters;
+
+	int length = methodParameters==null ? 0 : methodParameters.length;
+	int matchLength = matchMethodParameters==null ? 0 : matchMethodParameters.length;
+	if (length != matchLength) return false;
+
+	for (int i = 0; i < length; i++) {
+		if (!CharOperation.equals(methodParameters[i].readableName(), matchMethodParameters[i].readableName(), this.isCaseSensitive)) {
+			return false;
+		}
+	}
+	return true;
+}
+public SearchMatch newDeclarationMatch(ASTNode reference, IJavaElement element, Binding elementBinding, int accuracy, int length, MatchLocator locator) {
+	if (elementBinding != null) {
+		MethodBinding methodBinding = (MethodBinding) elementBinding;
+		// If method parameters verification was not valid, then try to see if method arguments can match a method in hierarchy
+		if (this.methodDeclarationsWithInvalidParam.containsKey(reference)) {
+			// First see if this reference has already been resolved => report match if validated
+			Boolean report = (Boolean) this.methodDeclarationsWithInvalidParam.get(reference);
+			if (report != null) {
+				if (report.booleanValue()) {
+					return super.newDeclarationMatch(reference, element, elementBinding, accuracy, length, locator);
+				}
+				return null;
+			}
+			// If method binding override a method in super hierarchy which original match pattern then report match
+			if (matchOverriddenMethod(methodBinding.declaringClass, methodBinding, null)) {
+				this.methodDeclarationsWithInvalidParam.put(reference, Boolean.TRUE);
+				return super.newDeclarationMatch(reference, element, elementBinding, accuracy, length, locator);
+			}
+			// If pattern binding override a method in super hierarchy which original match method binding then report match
+			MethodBinding patternBinding = locator.getMethodBinding(this.pattern);
+			if (patternBinding != null) {
+				if (matchOverriddenMethod(patternBinding.declaringClass, patternBinding, methodBinding)) {
+					this.methodDeclarationsWithInvalidParam.put(reference, Boolean.TRUE);
+					return super.newDeclarationMatch(reference, element, elementBinding, accuracy, length, locator);
+				}
+			}
+			this.methodDeclarationsWithInvalidParam.put(reference, Boolean.FALSE);
+			return null;
+		}
+	}
+	return super.newDeclarationMatch(reference, element, elementBinding, accuracy, length, locator);
+}
 protected int referenceType() {
 	return IJavaElement.METHOD;
 }
@@ -311,11 +495,16 @@
 	if (type == null) return; // case of a secondary type
 
 	char[] bindingSelector = methodBinding.selector;
-	TypeBinding[] parameters = methodBinding.parameters;
+	TypeBinding[] parameters = methodBinding.original().parameters;
 	int parameterLength = parameters.length;
 	String[] parameterTypes = new String[parameterLength];
-	for (int i = 0; i  < parameterLength; i++)
-		parameterTypes[i] = Signature.createTypeSignature(parameters[i].sourceName(), false);
+	for (int i = 0; i  < parameterLength; i++) {
+		char[] typeName = parameters[i].shortReadableName();
+		if (parameters[i].isMemberType()) {
+			typeName = CharOperation.subarray(typeName, CharOperation.indexOf('.', typeName)+1, typeName.length);
+		}
+		parameterTypes[i] = Signature.createTypeSignature(typeName, false);
+	}
 	IMethod method = type.getMethod(new String(bindingSelector), parameterTypes);
 	if (knownMethods.includes(method)) return;
 
@@ -354,10 +543,24 @@
 	}
 }
 public int resolveLevel(ASTNode possibleMatchingNode) {
-	if (this.pattern.findReferences && possibleMatchingNode instanceof MessageSend)
-		return resolveLevel((MessageSend) possibleMatchingNode);
-	if (this.pattern.findDeclarations && possibleMatchingNode instanceof MethodDeclaration)
-		return resolveLevel(((MethodDeclaration) possibleMatchingNode).binding);
+	if (this.pattern.findReferences) {
+		if (possibleMatchingNode instanceof MessageSend) {
+			return resolveLevel((MessageSend) possibleMatchingNode);
+		}
+		if (possibleMatchingNode instanceof SingleMemberAnnotation) {
+			SingleMemberAnnotation annotation = (SingleMemberAnnotation) possibleMatchingNode;
+			return resolveLevel(annotation.memberValuePairs()[0].binding);
+		}
+		if (possibleMatchingNode instanceof MemberValuePair) {
+			MemberValuePair memberValuePair = (MemberValuePair) possibleMatchingNode;
+			return resolveLevel(memberValuePair.binding);
+		}
+	}
+	if (this.pattern.findDeclarations) {
+		if (possibleMatchingNode instanceof MethodDeclaration) {
+			return resolveLevel(((MethodDeclaration) possibleMatchingNode).binding);
+		}
+	}
 	return IMPOSSIBLE_MATCH;
 }
 public int resolveLevel(Binding binding) {
@@ -365,11 +568,15 @@
 	if (!(binding instanceof MethodBinding)) return IMPOSSIBLE_MATCH;
 
 	MethodBinding method = (MethodBinding) binding;
-	int methodLevel = matchMethod(method);
+	boolean skipVerif = this.pattern.findDeclarations && this.mayBeGeneric;
+	int methodLevel = matchMethod(method, skipVerif);
 	if (methodLevel == IMPOSSIBLE_MATCH) {
-		if (method != method.original()) methodLevel = matchMethod(method.original());
-		if (methodLevel == IMPOSSIBLE_MATCH) return IMPOSSIBLE_MATCH;
-		method = method.original();
+		if (method != method.original()) methodLevel = matchMethod(method.original(), skipVerif);
+		if (methodLevel == IMPOSSIBLE_MATCH) {
+			return IMPOSSIBLE_MATCH;
+		} else {
+			method = method.original();
+		}
 	}
 
 	// declaring type
@@ -387,11 +594,21 @@
 }
 protected int resolveLevel(MessageSend messageSend) {
 	MethodBinding method = messageSend.binding;
-	if (method == null || messageSend.resolvedType == null) return INACCURATE_MATCH;
+	if (method == null) return INACCURATE_MATCH;
+	if (messageSend.resolvedType == null) {
+		// Closest match may have different argument numbers when ProblemReason is NotFound
+		// see MessageSend#resolveType(BlockScope)
+		// see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=97322
+		int argLength = messageSend.arguments == null ? 0 : messageSend.arguments.length;
+		if (pattern.parameterSimpleNames == null || argLength == pattern.parameterSimpleNames.length) {
+			return INACCURATE_MATCH;
+		}
+		return IMPOSSIBLE_MATCH;
+	}
 	
-	int methodLevel = matchMethod(method);
+	int methodLevel = matchMethod(method, false);
 	if (methodLevel == IMPOSSIBLE_MATCH) {
-		if (method != method.original()) methodLevel = matchMethod(method.original());
+		if (method != method.original()) methodLevel = matchMethod(method.original(), false);
 		if (methodLevel == IMPOSSIBLE_MATCH) return IMPOSSIBLE_MATCH;
 		method = method.original();
 	}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodPattern.java
index 14497dc..83a8828 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodPattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodPattern.java
@@ -143,9 +143,9 @@
 	// Get unique key for parameterized constructors
 	String genericDeclaringTypeSignature = null;
 //	String genericSignature = null;
-	BindingKey key;
-	if (method.isResolved() && (key = new BindingKey(method.getKey())).isParameterizedType()) {
-		genericDeclaringTypeSignature = key.getDeclaringTypeSignature();
+	String key;
+	if (method.isResolved() && (new BindingKey(key = method.getKey())).isParameterizedType()) {
+		genericDeclaringTypeSignature = Util.getDeclaringTypeSignature(key);
 	} else {
 		methodParameters = true;
 	}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MultiTypeDeclarationPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MultiTypeDeclarationPattern.java
index 8573e4c..545e07a 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MultiTypeDeclarationPattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MultiTypeDeclarationPattern.java
@@ -59,7 +59,7 @@
 	}
 	this.typeSuffix = typeSuffix;
 
-	((InternalSearchPattern)this).mustResolve = false; // only used to report type declarations, not their positions
+	((InternalSearchPattern)this).mustResolve = typeSuffix != TYPE_SUFFIX; // only used to report type declarations, not their positions
 }
 MultiTypeDeclarationPattern(int matchRule) {
 	super(TYPE_DECL_PATTERN, matchRule);
@@ -74,10 +74,56 @@
 	QualifiedTypeDeclarationPattern pattern = (QualifiedTypeDeclarationPattern) decodedPattern;
 	switch(this.typeSuffix) {
 		case CLASS_SUFFIX :
+			switch (pattern.typeSuffix) {
+				case CLASS_SUFFIX :
+				case CLASS_AND_INTERFACE_SUFFIX :
+				case CLASS_AND_ENUM_SUFFIX :
+					break;
+				default:
+					return false;
+			}
+			break;
 		case INTERFACE_SUFFIX :
+			switch (pattern.typeSuffix) {
+				case INTERFACE_SUFFIX :
+				case CLASS_AND_INTERFACE_SUFFIX :
+					break;
+				default:
+					return false;
+			}
+			break;
 		case ENUM_SUFFIX :
+			switch (pattern.typeSuffix) {
+				case ENUM_SUFFIX :
+				case CLASS_AND_ENUM_SUFFIX :
+					break;
+				default:
+					return false;
+			}
+			break;
 		case ANNOTATION_TYPE_SUFFIX :
 			if (this.typeSuffix != pattern.typeSuffix) return false;
+			break;
+		case CLASS_AND_INTERFACE_SUFFIX :
+			switch (pattern.typeSuffix) {
+				case CLASS_SUFFIX :
+				case INTERFACE_SUFFIX :
+				case CLASS_AND_INTERFACE_SUFFIX :
+					break;
+				default:
+					return false;
+			}
+			break;
+		case CLASS_AND_ENUM_SUFFIX :
+			switch (pattern.typeSuffix) {
+				case CLASS_SUFFIX :
+				case ENUM_SUFFIX :
+				case CLASS_AND_ENUM_SUFFIX :
+					break;
+				default:
+					return false;
+			}
+			break;
 	}
 
 	if (this.qualifications != null) {
@@ -143,6 +189,12 @@
 		case CLASS_SUFFIX :
 			output.append("MultiClassDeclarationPattern: "); //$NON-NLS-1$
 			break;
+		case CLASS_AND_INTERFACE_SUFFIX :
+			output.append("MultiClassAndInterfaceDeclarationPattern: "); //$NON-NLS-1$
+			break;
+		case CLASS_AND_ENUM_SUFFIX :
+			output.append("MultiClassAndEnumDeclarationPattern: "); //$NON-NLS-1$
+			break;
 		case INTERFACE_SUFFIX :
 			output.append("MultiInterfaceDeclarationPattern: "); //$NON-NLS-1$
 			break;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/OrLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/OrLocator.java
index db30052..3fecf99 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/OrLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/OrLocator.java
@@ -12,9 +12,23 @@
 
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.jdt.core.IJavaElement;
-import org.eclipse.jdt.core.search.*;
-import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.core.search.SearchMatch;
+import org.eclipse.jdt.core.search.SearchPattern;
+import org.eclipse.jdt.internal.compiler.ast.ASTNode;
+import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.Expression;
+import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.ImportReference;
+import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.MessageSend;
+import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.Reference;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.TypeReference;
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
+import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
+import org.eclipse.jdt.internal.compiler.lookup.MemberTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
 
 public class OrLocator extends PatternLocator {
 
@@ -150,19 +164,40 @@
 	return result;
 }
 protected void matchLevelAndReportImportRef(ImportReference importRef, Binding binding, MatchLocator locator) throws CoreException {
+	
+	// for static import, binding can be a field binding or a member type binding
+	// verify that in this case binding is static and use declaring class for fields
+	Binding refBinding = binding;
+	if (importRef.isStatic()) {
+		if (binding instanceof FieldBinding) {
+			FieldBinding fieldBinding = (FieldBinding) binding;
+			if (!fieldBinding.isStatic()) return;
+			refBinding = fieldBinding.declaringClass;
+		} else if (binding instanceof MethodBinding) {
+			MethodBinding methodBinding = (MethodBinding) binding;
+			if (!methodBinding.isStatic()) return;
+			refBinding = methodBinding.declaringClass;
+		} else if (binding instanceof MemberTypeBinding) {
+			MemberTypeBinding memberBinding = (MemberTypeBinding) binding;
+			if (!memberBinding.isStatic()) return;
+		}
+	}
+	
+	// Look for closest pattern
 	PatternLocator closestPattern = null;
 	int level = IMPOSSIBLE_MATCH;
 	for (int i = 0, length = this.patternLocators.length; i < length; i++) {
 		PatternLocator patternLocator = this.patternLocators[i];
-		int newLevel = patternLocator.referenceType() == 0 ? IMPOSSIBLE_MATCH : patternLocator.resolveLevel(binding);
+		int newLevel = patternLocator.referenceType() == 0 ? IMPOSSIBLE_MATCH : patternLocator.resolveLevel(refBinding);
 		if (newLevel > level) {
 			closestPattern = patternLocator;
 			if (newLevel == ACCURATE_MATCH) break;
 			level = newLevel;
 		}
 	}
-	if (closestPattern != null)
+	if (closestPattern != null) {
 		closestPattern.matchLevelAndReportImportRef(importRef, binding, locator);
+	}
 }
 protected void matchReportImportRef(ImportReference importRef, Binding binding, IJavaElement element, int accuracy, MatchLocator locator) throws CoreException {
 	PatternLocator closestPattern = null;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PackageReferenceLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PackageReferenceLocator.java
index 8d5ef8a..f1a58f2 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PackageReferenceLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PackageReferenceLocator.java
@@ -90,13 +90,7 @@
 }
 
 protected int matchLevel(ImportReference importRef) {
-	// Compare prefix also for static import
-	if (!importRef.onDemand || importRef.isStatic())
-		return matchLevelForTokens(importRef.tokens);
-
-	return matchesName(this.pattern.pkgName, CharOperation.concatWith(importRef.tokens, '.'))
-		? ACCURATE_MATCH
-		: IMPOSSIBLE_MATCH;
+	return matchLevelForTokens(importRef.tokens);
 }
 protected int matchLevelForTokens(char[][] tokens) {
 	if (this.pattern.pkgName == null) return ACCURATE_MATCH;
@@ -148,7 +142,7 @@
 			long[] positions = importRef.sourcePositions;
 			int last = positions.length - 1;
 			if (binding instanceof ProblemReferenceBinding)
-				binding = ((ProblemReferenceBinding) binding).original;
+				binding = ((ProblemReferenceBinding) binding).closestMatch;
 			if (binding instanceof ReferenceBinding) {
 				PackageBinding pkgBinding = ((ReferenceBinding) binding).fPackage;
 				if (pkgBinding != null)
@@ -211,12 +205,23 @@
 		if (typeBinding instanceof ArrayBinding)
 			typeBinding = ((ArrayBinding) typeBinding).leafComponentType;
 		if (typeBinding instanceof ProblemReferenceBinding)
-			typeBinding = ((ProblemReferenceBinding) typeBinding).original;
+			typeBinding = ((ProblemReferenceBinding) typeBinding).closestMatch;
 		if (typeBinding instanceof ReferenceBinding) {
 			PackageBinding pkgBinding = ((ReferenceBinding) typeBinding).fPackage;
 			if (pkgBinding != null)
 				last = pkgBinding.compoundName.length;
 		}
+		// Do not report qualified references which are only enclosing type
+		// (see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=91078)
+		ReferenceBinding enclosingType = typeBinding == null ? null: typeBinding.enclosingType();
+		if (enclosingType != null) {
+			int length = positions.length;
+			while (enclosingType != null && length > 0) {
+				length--;
+				enclosingType = enclosingType.enclosingType();
+			}
+			if (length <= 1) return;
+		}
 	}
 	if (last == -1) {
 		last = this.pattern.segments.length;
@@ -263,7 +268,7 @@
 		if (binding instanceof ArrayBinding)
 			binding = ((ArrayBinding) binding).leafComponentType;
 		if (binding instanceof ProblemReferenceBinding)
-			binding = ((ProblemReferenceBinding) binding).original;
+			binding = ((ProblemReferenceBinding) binding).closestMatch;
 		if (binding == null) return INACCURATE_MATCH;
 
 		if (binding instanceof ReferenceBinding) {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PatternLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PatternLocator.java
index 0513a84..c41fc42 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PatternLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PatternLocator.java
@@ -26,6 +26,7 @@
 protected boolean isEquivalentMatch;
 protected boolean isErasureMatch;
 protected boolean mustResolve;
+protected boolean mayBeGeneric;
 
 // match to report
 SearchMatch match = null;
@@ -106,6 +107,12 @@
 	this.matchMode = matchRule & JavaSearchPattern.MATCH_MODE_MASK;
 	this.mustResolve = ((InternalSearchPattern)pattern).mustResolve;
 }
+/*
+ * Clear caches
+ */
+protected void clear() {
+	// nothing to clear by default
+}
 /* (non-Javadoc)
  * Modify PatternLocator.qualifiedPattern behavior:
  * do not add star before simple name pattern when qualification pattern is null.
@@ -151,6 +158,10 @@
 public void initializePolymorphicSearch(MatchLocator locator) {
 	// default is to do nothing
 }
+public int match(Annotation node, MatchingNodeSet nodeSet) {
+	// each subtype should override if needed
+	return IMPOSSIBLE_MATCH;
+}
 /**
  * Check if the given ast node syntactically matches this pattern.
  * If it does, add it to the match set.
@@ -180,6 +191,10 @@
 	// each subtype should override if needed
 	return IMPOSSIBLE_MATCH;
 }
+public int match(MemberValuePair node, MatchingNodeSet nodeSet) {
+	// each subtype should override if needed
+	return IMPOSSIBLE_MATCH;
+}
 public int match(MessageSend node, MatchingNodeSet nodeSet) {
 	// each subtype should override if needed
 	return IMPOSSIBLE_MATCH;
@@ -642,7 +657,6 @@
 	int impossible = this.isErasureMatch ? ERASURE_MATCH : IMPOSSIBLE_MATCH;
 
 	// pattern has type parameter(s) or type argument(s)
-	boolean isRawType = type.isRawType();
 	if (type.isGenericType()) {
 		// Binding is generic, get its type variable(s)
 		TypeVariableBinding[] typeVariables = null;
@@ -660,14 +674,16 @@
 		}
 		// TODO (frederic) do we need to verify each parameter?
 		return level; // we can't do better
-	} else if (isRawType) {
+	} else if (type.isRawType()) {
 		return level; // raw type always match
-	} else if (!type.isParameterizedType()) {
-		// Standard types (ie. neither generic nor parameterized nor raw types)
-		// cannot match pattern with type parameters or arguments
-		return (patternTypeArguments[depth]==null || patternTypeArguments[depth].length==0) ? level : IMPOSSIBLE_MATCH;
 	} else {
-		ParameterizedTypeBinding paramTypeBinding = (ParameterizedTypeBinding) type;
+		TypeBinding leafType = type.leafComponentType();
+		if (!leafType.isParameterizedType()) {
+			// Standard types (ie. neither generic nor parameterized nor raw types)
+			// cannot match pattern with type parameters or arguments
+			return (patternTypeArguments[depth]==null || patternTypeArguments[depth].length==0) ? level : IMPOSSIBLE_MATCH;
+		}
+		ParameterizedTypeBinding paramTypeBinding = (ParameterizedTypeBinding) leafType;
 
 		// Compare arguments only if there ones on both sides
 		if (patternTypeArguments[depth] != null && patternTypeArguments[depth].length > 0 &&
@@ -756,31 +772,21 @@
 				// If pattern is not exact then match fails
 				if (patternTypeArgHasAnyChars) return impossible;
 
-				// Get reference binding
-				ReferenceBinding refBinding = null;
-				if (argTypeBinding.isArrayType()) {
-					TypeBinding leafBinding = ((ArrayBinding) argTypeBinding).leafComponentType;
-					if (!leafBinding.isBaseType()) {
-						refBinding = (ReferenceBinding) leafBinding;
-					}
-				} else if (!argTypeBinding.isBaseType()) {
-					refBinding = (ReferenceBinding) argTypeBinding;
-				}
 				// Scan hierarchy
-				if (refBinding != null) {
-					refBinding = refBinding.superclass();
-					while (refBinding != null) {
-						if (CharOperation.equals(patternTypeArgument, refBinding.shortReadableName(), this.isCaseSensitive) ||
-							CharOperation.equals(patternTypeArgument, refBinding.readableName(), this.isCaseSensitive)) {
-							// found name in hierarchy => match
+				TypeBinding leafTypeBinding = argTypeBinding.leafComponentType();
+				if (leafTypeBinding.isBaseType()) return impossible;
+				ReferenceBinding refBinding = ((ReferenceBinding) leafTypeBinding).superclass();
+				while (refBinding != null) {
+					if (CharOperation.equals(patternTypeArgument, refBinding.shortReadableName(), this.isCaseSensitive) ||
+						CharOperation.equals(patternTypeArgument, refBinding.readableName(), this.isCaseSensitive)) {
+						// found name in hierarchy => match
+						continue nextTypeArgument;
+					} else if (refBinding.isLocalType() || refBinding.isMemberType()) {
+						// for local or member type, verify also source name (bug 81084)
+						if (CharOperation.match(patternTypeArgument, refBinding.sourceName(), this.isCaseSensitive))
 							continue nextTypeArgument;
-						} else if (refBinding.isLocalType() || refBinding.isMemberType()) {
-							// for local or member type, verify also source name (bug 81084)
-							if (CharOperation.match(patternTypeArgument, refBinding.sourceName(), this.isCaseSensitive))
-								continue nextTypeArgument;
-						}
-						refBinding = refBinding.superclass();
 					}
+					refBinding = refBinding.superclass();
 				}
 				return impossible;
 			}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PossibleMatch.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PossibleMatch.java
index 1b2021e..e9694d6 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PossibleMatch.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PossibleMatch.java
@@ -33,11 +33,11 @@
 private String sourceFileName;
 private char[] source;
 
-public PossibleMatch(MatchLocator locator, IResource resource, Openable openable, SearchDocument document) {
+public PossibleMatch(MatchLocator locator, IResource resource, Openable openable, SearchDocument document, boolean mustResolve) {
 	this.resource = resource;
 	this.openable = openable;
 	this.document = document;
-	this.nodeSet = new MatchingNodeSet();
+	this.nodeSet = new MatchingNodeSet(mustResolve);
 	char[] qualifiedName = getQualifiedName();
 	if (qualifiedName != null)
 		this.compoundName = CharOperation.splitOn('.', qualifiedName);
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/QualifiedTypeDeclarationPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/QualifiedTypeDeclarationPattern.java
index 1c0d908..8c5aeca 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/QualifiedTypeDeclarationPattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/QualifiedTypeDeclarationPattern.java
@@ -26,7 +26,7 @@
 	this.simpleName = isCaseSensitive() ? simpleName : CharOperation.toLowerCase(simpleName);
 	this.typeSuffix = typeSuffix;
 
-	((InternalSearchPattern)this).mustResolve = this.qualification != null;
+	((InternalSearchPattern)this).mustResolve = this.qualification != null || typeSuffix != TYPE_SUFFIX;
 }
 QualifiedTypeDeclarationPattern(int matchRule) {
 	super(matchRule);
@@ -60,7 +60,7 @@
 public char[] getPackageName() {
 	if (this.packageIndex == -1)
 		return this.qualification;
-	return CharOperation.subarray(this.qualification, 0, this.packageIndex);
+	return internedPackageNames.add(CharOperation.subarray(this.qualification, 0, this.packageIndex));
 }
 public char[][] getEnclosingTypeNames() {
 	if (this.packageIndex == -1)
@@ -75,10 +75,56 @@
 	QualifiedTypeDeclarationPattern pattern = (QualifiedTypeDeclarationPattern) decodedPattern;
 	switch(this.typeSuffix) {
 		case CLASS_SUFFIX :
+			switch (pattern.typeSuffix) {
+				case CLASS_SUFFIX :
+				case CLASS_AND_INTERFACE_SUFFIX :
+				case CLASS_AND_ENUM_SUFFIX :
+					break;
+				default:
+					return false;
+			}
+			break;
 		case INTERFACE_SUFFIX :
+			switch (pattern.typeSuffix) {
+				case INTERFACE_SUFFIX :
+				case CLASS_AND_INTERFACE_SUFFIX :
+					break;
+				default:
+					return false;
+			}
+			break;
 		case ENUM_SUFFIX :
+			switch (pattern.typeSuffix) {
+				case ENUM_SUFFIX :
+				case CLASS_AND_ENUM_SUFFIX :
+					break;
+				default:
+					return false;
+			}
+			break;
 		case ANNOTATION_TYPE_SUFFIX :
 			if (this.typeSuffix != pattern.typeSuffix) return false;
+			break;
+		case CLASS_AND_INTERFACE_SUFFIX :
+			switch (pattern.typeSuffix) {
+				case CLASS_SUFFIX :
+				case INTERFACE_SUFFIX :
+				case CLASS_AND_INTERFACE_SUFFIX :
+					break;
+				default:
+					return false;
+			}
+			break;
+		case CLASS_AND_ENUM_SUFFIX :
+			switch (pattern.typeSuffix) {
+				case CLASS_SUFFIX :
+				case ENUM_SUFFIX :
+				case CLASS_AND_ENUM_SUFFIX :
+					break;
+				default:
+					return false;
+			}
+			break;
 	}
 
 	return matchesName(this.simpleName, pattern.simpleName) && matchesName(this.qualification, pattern.qualification);
@@ -88,6 +134,12 @@
 		case CLASS_SUFFIX :
 			output.append("ClassDeclarationPattern: qualification<"); //$NON-NLS-1$
 			break;
+		case CLASS_AND_INTERFACE_SUFFIX:
+			output.append("ClassAndInterfaceDeclarationPattern: qualification<"); //$NON-NLS-1$
+			break;
+		case CLASS_AND_ENUM_SUFFIX :
+			output.append("ClassAndEnumDeclarationPattern: qualification<"); //$NON-NLS-1$
+			break;
 		case INTERFACE_SUFFIX :
 			output.append("InterfaceDeclarationPattern: qualification<"); //$NON-NLS-1$
 			break;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationLocator.java
index 1a52791..a50bcf1 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationLocator.java
@@ -52,10 +52,22 @@
 
 	switch (this.pattern.typeSuffix) {
 		case CLASS_SUFFIX:
-			if (type.isInterface()) return IMPOSSIBLE_MATCH;
+			if (!type.isClass()) return IMPOSSIBLE_MATCH;
+			break;
+		case CLASS_AND_INTERFACE_SUFFIX:
+			if (!(type.isClass() || (type.isInterface() && !type.isAnnotationType()))) return IMPOSSIBLE_MATCH;
+			break;
+		case CLASS_AND_ENUM_SUFFIX:
+			if (!(type.isClass() || type.isEnum())) return IMPOSSIBLE_MATCH;
 			break;
 		case INTERFACE_SUFFIX:
-			if (!type.isInterface()) return IMPOSSIBLE_MATCH;
+			if (!type.isInterface() || type.isAnnotationType()) return IMPOSSIBLE_MATCH;
+			break;
+		case ENUM_SUFFIX:
+			if (!type.isEnum()) return IMPOSSIBLE_MATCH;
+			break;
+		case ANNOTATION_TYPE_SUFFIX:
+			if (!type.isAnnotationType()) return IMPOSSIBLE_MATCH;
 			break;
 		case TYPE_SUFFIX : // nothing
 	}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationPattern.java
index 0ceee8a..8e9aa24 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationPattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationPattern.java
@@ -34,6 +34,51 @@
 
 protected static char[][] CATEGORIES = { TYPE_DECL };
 
+// want to save space by interning the package names for each match
+static PackageNameSet internedPackageNames = new PackageNameSet(1001);
+static class PackageNameSet {
+
+public char[][] names;
+public int elementSize; // number of elements in the table
+public int threshold;
+
+PackageNameSet(int size) {
+	this.elementSize = 0;
+	this.threshold = size; // size represents the expected number of elements
+	int extraRoom = (int) (size * 1.5f);
+	if (this.threshold == extraRoom)
+		extraRoom++;
+	this.names = new char[extraRoom][];
+}
+
+char[] add(char[] name) {
+	int length = names.length;
+	int index = CharOperation.hashCode(name) % length;
+	char[] current;
+	while ((current = names[index]) != null) {
+		if (CharOperation.equals(current, name)) return current;
+		if (++index == length) index = 0;
+	}
+	names[index] = name;
+
+	// assumes the threshold is never equal to the size of the table
+	if (++elementSize > threshold) rehash();
+	return name;
+}
+
+void rehash() {
+	PackageNameSet newSet = new PackageNameSet(elementSize * 2); // double the number of expected elements
+	char[] current;
+	for (int i = names.length; --i >= 0;)
+		if ((current = names[i]) != null)
+			newSet.add(current);
+
+	this.names = newSet.names;
+	this.elementSize = newSet.elementSize;
+	this.threshold = newSet.threshold;
+}
+}
+
 /*
  * Create index key for type declaration pattern:
  *		key = typeName / packageName / enclosingTypeName / typeSuffix modifiers
@@ -98,7 +143,7 @@
 	this.simpleName = isCaseSensitive() ? simpleName : CharOperation.toLowerCase(simpleName);
 	this.typeSuffix = typeSuffix;
 
-	((InternalSearchPattern)this).mustResolve = this.pkg != null && this.enclosingTypeNames != null;
+	((InternalSearchPattern)this).mustResolve = (this.pkg != null && this.enclosingTypeNames != null) || typeSuffix != TYPE_SUFFIX;
 }
 TypeDeclarationPattern(int matchRule) {
 	super(TYPE_DECL_PATTERN, matchRule);
@@ -115,7 +160,7 @@
 
 	int start = slash + 1;
 	slash = CharOperation.indexOf(SEPARATOR, key, start);
-	this.pkg = slash == start ? CharOperation.NO_CHAR : CharOperation.subarray(key, start, slash);
+	this.pkg = slash == start ? CharOperation.NO_CHAR : internedPackageNames.add(CharOperation.subarray(key, start, slash));
 
 	slash = CharOperation.indexOf(SEPARATOR, key, start = slash + 1);
 	if (slash == start) {
@@ -158,10 +203,56 @@
 	TypeDeclarationPattern pattern = (TypeDeclarationPattern) decodedPattern;
 	switch(this.typeSuffix) {
 		case CLASS_SUFFIX :
+			switch (pattern.typeSuffix) {
+				case CLASS_SUFFIX :
+				case CLASS_AND_INTERFACE_SUFFIX :
+				case CLASS_AND_ENUM_SUFFIX :
+					break;
+				default:
+					return false;
+			}
+			break;
 		case INTERFACE_SUFFIX :
+			switch (pattern.typeSuffix) {
+				case INTERFACE_SUFFIX :
+				case CLASS_AND_INTERFACE_SUFFIX :
+					break;
+				default:
+					return false;
+			}
+			break;
 		case ENUM_SUFFIX :
+			switch (pattern.typeSuffix) {
+				case ENUM_SUFFIX :
+				case CLASS_AND_ENUM_SUFFIX :
+					break;
+				default:
+					return false;
+			}
+			break;
 		case ANNOTATION_TYPE_SUFFIX :
 			if (this.typeSuffix != pattern.typeSuffix) return false;
+			break;
+		case CLASS_AND_INTERFACE_SUFFIX :
+			switch (pattern.typeSuffix) {
+				case CLASS_SUFFIX :
+				case INTERFACE_SUFFIX :
+				case CLASS_AND_INTERFACE_SUFFIX :
+					break;
+				default:
+					return false;
+			}
+			break;
+		case CLASS_AND_ENUM_SUFFIX :
+			switch (pattern.typeSuffix) {
+				case CLASS_SUFFIX :
+				case ENUM_SUFFIX :
+				case CLASS_AND_ENUM_SUFFIX :
+					break;
+				default:
+					return false;
+			}
+			break;
 	}
 
 	if (!matchesName(this.simpleName, pattern.simpleName))
@@ -209,8 +300,9 @@
 						case INTERFACE_SUFFIX :
 						case ENUM_SUFFIX :
 						case ANNOTATION_TYPE_SUFFIX :
-							key = new char[] {ONE_STAR[0],  SEPARATOR,
-								isCaseSensitive() ? this.typeSuffix : Character.toLowerCase(this.typeSuffix)}; // find all classes or all interfaces
+						case CLASS_AND_INTERFACE_SUFFIX :
+						case CLASS_AND_ENUM_SUFFIX :
+							key = new char[] {ONE_STAR[0],  SEPARATOR, ONE_STAR[0]};
 							break;
 					}
 				} else if (this.simpleName[this.simpleName.length - 1] != '*') {
@@ -231,6 +323,12 @@
 		case CLASS_SUFFIX :
 			output.append("ClassDeclarationPattern: pkg<"); //$NON-NLS-1$
 			break;
+		case CLASS_AND_INTERFACE_SUFFIX:
+			output.append("ClassAndInterfaceDeclarationPattern: pkg<"); //$NON-NLS-1$
+			break;
+		case CLASS_AND_ENUM_SUFFIX :
+			output.append("ClassAndEnumDeclarationPattern: pkg<"); //$NON-NLS-1$
+			break;
 		case INTERFACE_SUFFIX :
 			output.append("InterfaceDeclarationPattern: pkg<"); //$NON-NLS-1$
 			break;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeReferenceLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeReferenceLocator.java
index 8588f90..685c0d4 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeReferenceLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeReferenceLocator.java
@@ -43,6 +43,9 @@
 		element = element.getParent();
 	return element;
 }
+public int match(Annotation node, MatchingNodeSet nodeSet) {
+	return match(node.type, nodeSet);
+}
 public int match(ASTNode node, MatchingNodeSet nodeSet) { // interested in ImportReference
 	if (!(node instanceof ImportReference)) return IMPOSSIBLE_MATCH;
 
@@ -196,7 +199,7 @@
 		}
 		if (typeBinding instanceof ProblemReferenceBinding) {
 			ProblemReferenceBinding pbBinding = (ProblemReferenceBinding) typeBinding;
-			typeBinding = pbBinding.original;
+			typeBinding = pbBinding.closestMatch;
 			lastIndex = pbBinding.compoundName.length - 1;
 		}
 		// try to match all enclosing types for which the token matches as well.
@@ -295,7 +298,7 @@
 	}
 	if (typeBinding instanceof ProblemReferenceBinding) {
 		ProblemReferenceBinding pbBinding = (ProblemReferenceBinding) typeBinding;
-		typeBinding = pbBinding.original;
+		typeBinding = pbBinding.closestMatch;
 		lastIndex = pbBinding.compoundName.length - 1;
 	}
 
@@ -309,11 +312,19 @@
 			if (resolveLevelForType(refBinding) == ACCURATE_MATCH) {
 				if (locator.encloses(element)) {
 					long[] positions = qNameRef.sourcePositions;
-					int start = (int) ((positions[this.pattern.qualification == null ? lastIndex : 0]) >>> 32);
+					// index now depends on pattern type signature
+					int index = lastIndex;
+					if (this.pattern.qualification != null) {
+						index = lastIndex - this.pattern.segmentsSize;
+					}
+					if (index < 0) index = 0;
+					int start = (int) ((positions[index]) >>> 32);
 					int end = (int) positions[lastIndex];
 					match.setOffset(start);
 					match.setLength(end-start+1);
-					locator.report(match);
+
+					//  Look if there's a need to special report for parameterized type
+					matchReportReference(qNameRef, lastIndex, refBinding, locator);
 				}
 				return;
 			}
@@ -330,7 +341,7 @@
 		typeBinding = ((ArrayBinding) typeBinding).leafComponentType;
 	if (typeBinding instanceof ProblemReferenceBinding) {
 		ProblemReferenceBinding pbBinding = (ProblemReferenceBinding) typeBinding;
-		typeBinding = pbBinding.original;
+		typeBinding = pbBinding.closestMatch;
 		lastIndex = pbBinding.compoundName.length - 1;
 	}
 
@@ -404,9 +415,20 @@
 	// Report match
 	if (expr instanceof ArrayTypeReference) {
 		locator.reportAccurateTypeReference(match, expr, this.pattern.simpleName);
-	} else {
-		locator.report(match);
+		return;
 	}
+	if (refBinding.isLocalType()) {
+		// see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=82673
+		LocalTypeBinding local = (LocalTypeBinding) refBinding;
+		IJavaElement focus = ((InternalSearchPattern)pattern).focus;
+		if (focus != null && local.enclosingMethod != null && focus.getParent().getElementType() == IJavaElement.METHOD) {
+			IMethod method = (IMethod) focus.getParent();
+			if (!CharOperation.equals(local.enclosingMethod.selector, method.getElementName().toCharArray())) {
+				return;
+			}
+		}
+	}
+	locator.report(match);
 }
 protected int referenceType() {
 	return IJavaElement.TYPE;
@@ -453,7 +475,7 @@
 		typeBinding = ((ArrayBinding) typeBinding).leafComponentType;
 	if (typeBinding == null || typeBinding instanceof BaseTypeBinding) return;
 	if (typeBinding instanceof ProblemReferenceBinding) {
-		ReferenceBinding original = ((ProblemReferenceBinding) typeBinding).original;
+		ReferenceBinding original = ((ProblemReferenceBinding) typeBinding).closestMatch;
 		if (original == null) return; // original may not be set (bug 71279)
 		typeBinding = original;
 	}
@@ -515,7 +537,7 @@
 	if (typeBinding instanceof ArrayBinding)
 		typeBinding = ((ArrayBinding) typeBinding).leafComponentType;
 	if (typeBinding instanceof ProblemReferenceBinding)
-		typeBinding = ((ProblemReferenceBinding) typeBinding).original;
+		typeBinding = ((ProblemReferenceBinding) typeBinding).closestMatch;
 
 	if (((InternalSearchPattern) this.pattern).focus instanceof IType && typeBinding instanceof ReferenceBinding) {
 		IPackageFragment pkg = ((IType) ((InternalSearchPattern) this.pattern).focus).getPackageFragment();
@@ -531,7 +553,7 @@
 
 	if (nameRef instanceof SingleNameReference) {
 		if (binding instanceof ProblemReferenceBinding)
-			binding = ((ProblemReferenceBinding) binding).original;
+			binding = ((ProblemReferenceBinding) binding).closestMatch;
 		if (binding instanceof ReferenceBinding)
 			return resolveLevelForType((ReferenceBinding) binding);
 		return binding == null || binding instanceof ProblemBinding ? INACCURATE_MATCH : IMPOSSIBLE_MATCH;
@@ -578,7 +600,7 @@
 	if (typeBinding instanceof ArrayBinding)
 		typeBinding = ((ArrayBinding) typeBinding).leafComponentType;
 	if (typeBinding instanceof ProblemReferenceBinding)
-		typeBinding = ((ProblemReferenceBinding) typeBinding).original;
+		typeBinding = ((ProblemReferenceBinding) typeBinding).closestMatch;
 
 	if (typeRef instanceof SingleTypeReference) {
 		return resolveLevelForType(typeBinding);
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/JobManager.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/JobManager.java
index e523a16..6f752e1 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/JobManager.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/JobManager.java
@@ -28,6 +28,7 @@
 
 	/* background processing */
 	protected Thread processingThread;
+	protected Job progressJob;
 
 	/* counter indicating whether job execution is enabled or not, disabled if <= 0 
 	    it cannot go beyond 1 */
@@ -198,7 +199,6 @@
 				case IJob.CancelIfNotReady :
 					if (VERBOSE)
 						Util.verbose("-> NOT READY - cancelling - " + searchJob); //$NON-NLS-1$
-					if (progress != null) progress.setCanceled(true);
 					if (VERBOSE)
 						Util.verbose("CANCELED concurrent job - " + searchJob); //$NON-NLS-1$
 					throw new OperationCanceledException();
@@ -317,7 +317,7 @@
 				}
 				protected IStatus run(IProgressMonitor monitor) {
 					int awaitingJobsCount;
-					while ((awaitingJobsCount = awaitingJobsCount()) > 0) {
+					while (!monitor.isCanceled() && (awaitingJobsCount = awaitingJobsCount()) > 0) {
 						monitor.subTask(Messages.bind(Messages.manager_filesToIndex, Integer.toString(awaitingJobsCount))); 
 						try {
 							Thread.sleep(500);
@@ -328,7 +328,7 @@
 					return Status.OK_STATUS;
 				}
 			}
-			ProgressJob progressJob = null;
+			this.progressJob = null;
 			while (this.processingThread != null) {
 				try {
 					IJob job;
@@ -338,7 +338,10 @@
 
 						// must check for new job inside this sync block to avoid timing hole
 						if ((job = currentJob()) == null) {
-							if (progressJob != null) progressJob = null;
+							if (this.progressJob != null) {
+								this.progressJob.cancel();
+								this.progressJob = null;
+							}
 							if (idlingStart < 0)
 								idlingStart = System.currentTimeMillis();
 							else
@@ -360,11 +363,11 @@
 					}
 					try {
 						this.executing = true;
-						if (progressJob == null) {
-							progressJob = new ProgressJob(Messages.manager_indexingInProgress); 
-							progressJob.setPriority(Job.LONG);
-							progressJob.setSystem(true);
-							progressJob.schedule();
+						if (this.progressJob == null) {
+							this.progressJob = new ProgressJob(Messages.manager_indexingInProgress); 
+							this.progressJob.setPriority(Job.LONG);
+							this.progressJob.setSystem(true);
+							this.progressJob.schedule();
 						}
 						/*boolean status = */job.execute(null);
 						//if (status == FAILED) request(job);
@@ -423,6 +426,11 @@
 				// in case processing thread is handling a job
 				thread.join();
 			}
+			Job job = this.progressJob;
+			if (job != null) {
+				job.cancel();
+				job.join();
+			}
 		} catch (InterruptedException e) {
 			// ignore
 		}