Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.jdt.core/model/org/eclipse/jdt')
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/IOpenable.java14
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/IType.java5
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java2
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/CompilationParticipant.java7
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ExternalAnnotationUtil.java2
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryType.java2
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java191
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessingState.java16
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java66
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementDelta.java4
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelCache.java35
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java193
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavadocConstants.java6
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavadocContents.java31
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathDirectory.java13
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJar.java29
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/BindingMap.java100
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyBinaryType.java43
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyBuilder.java41
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyResolver.java24
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/IndexBasedHierarchyBuilder.java114
21 files changed, 716 insertions, 222 deletions
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IOpenable.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IOpenable.java
index 070206105..515a8ffda 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IOpenable.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IOpenable.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2008 IBM Corporation and others.
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -10,6 +10,7 @@
*******************************************************************************/
package org.eclipse.jdt.core;
+import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IProgressMonitor;
/**
@@ -46,7 +47,7 @@ public interface IOpenable {
* Closes this element and its buffer (if any).
* Closing an element which is not open has no effect.
*
- * <p>Note: although {@link #close} is exposed in the API, clients are
+ * <p>Note: Although {@link #close} is exposed in the API, clients are
* not expected to open and close elements - the Java model does this automatically
* as elements are accessed.
*
@@ -114,6 +115,13 @@ boolean hasUnsavedChanges() throws JavaModelException;
boolean isConsistent() throws JavaModelException;
/**
* Returns whether this openable is open. This is a handle-only method.
+ *
+ * <p>Note: This method doesn't tell whether an {@link IJavaProject}'s {@link IJavaProject#getProject() getProject()} is open.
+ * It is <b>not</b> equivalent to {@link IProject#isOpen()}!</p>
+ *
+ * <p>Note: Although {@link #isOpen} is exposed in the API, clients
+ * rarely have a need to rely on this internal state of the Java model.</p>
+
* @return true if this openable is open, false otherwise
*/
boolean isOpen();
@@ -142,7 +150,7 @@ void makeConsistent(IProgressMonitor progress) throws JavaModelException;
* Opens this element and all parent elements that are not already open.
* For compilation units, a buffer is opened on the contents of the underlying resource.
*
- * <p>Note: although {@link #open} is exposed in the API, clients are
+ * <p>Note: Although {@link #open} is exposed in the API, clients are
* not expected to open and close elements - the Java model does this automatically
* as elements are accessed.
*
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 5ee63a6ad..f2156427f 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
@@ -36,6 +36,11 @@ import org.eclipse.core.runtime.IProgressMonitor;
* <code>IMethod</code>, <code>IInitializer</code> and <code>IType</code>.
* The children are listed in the order in which they appear in the source or class file.
* </p>
+ * <p>
+ * Caveat: The {@link #getChildren() children} of a {@link #isBinary() binary} type include
+ * nested types. However, the {@link #getParent() parent} of such a nested binary type is
+ * <em>not</em> the enclosing type, but that nested type's {@link IClassFile}!
+ * </p>
*
* @noimplement This interface is not intended to be implemented by clients.
*/
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 84bd065e9..5eef53310 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
@@ -157,6 +157,7 @@ import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
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.nd.indexer.Indexer;
import org.eclipse.jdt.internal.core.util.MementoTokenizer;
import org.eclipse.jdt.internal.core.util.Messages;
import org.eclipse.jdt.internal.core.util.Util;
@@ -5877,5 +5878,6 @@ public final class JavaCore extends Plugin {
super.start(context);
JavaModelManager.registerDebugOptionsListener(context);
JavaModelManager.getJavaModelManager().startup();
+ Indexer.getInstance().rescanAll();
}
}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/CompilationParticipant.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/CompilationParticipant.java
index c40c1392e..34ae1a2cc 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/CompilationParticipant.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/CompilationParticipant.java
@@ -101,8 +101,11 @@ public void cleanStarting(IJavaProject project) {
* given project should return <code>false</code> for that project.
* </p><p>
* Note: In {@link org.eclipse.jdt.core.WorkingCopyOwner#newWorkingCopy(String, org.eclipse.jdt.core.IClasspathEntry[], org.eclipse.core.runtime.IProgressMonitor)
- * special cases}, the project may be closed and not exist. Participants typically return false for projects that are
- * !{@link IJavaProject#isOpen()}.
+ * special cases}, the project may be closed and not exist. Participants typically return false when the
+ * underlying project is closed. I.e. when the following check returns false:
+ * <pre>
+ * javaProject.getProject().isOpen();
+ * </pre>
* </p>
* @param project the project to participate in
* @return whether this participant is active for a given project
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ExternalAnnotationUtil.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ExternalAnnotationUtil.java
index 6d15fb255..dad83972d 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ExternalAnnotationUtil.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ExternalAnnotationUtil.java
@@ -294,7 +294,7 @@ public final class ExternalAnnotationUtil {
newContent.append('\n');
continue;
}
- if (!Character.isJavaIdentifierStart(line.charAt(0))) {
+ if (!Character.isJavaIdentifierStart(line.charAt(0)) && line.charAt(0) != '<') {
newContent.append(line).append('\n');
continue;
}
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 f895be97f..978704c96 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryType.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryType.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java
index 000c46382..9871f47cd 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -37,11 +37,15 @@ import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.*;
import org.eclipse.jdt.core.compiler.IProblem;
-import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
+import org.eclipse.jdt.internal.compiler.classfmt.ExternalAnnotationDecorator;
+import org.eclipse.jdt.internal.compiler.classfmt.ExternalAnnotationProvider;
import org.eclipse.jdt.internal.compiler.env.IBinaryType;
-import org.eclipse.jdt.internal.compiler.env.IDependent;
import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
+import org.eclipse.jdt.internal.core.nd.java.JavaNames;
+import org.eclipse.jdt.internal.core.nd.java.model.BinaryTypeDescriptor;
+import org.eclipse.jdt.internal.core.nd.java.model.BinaryTypeFactory;
+import org.eclipse.jdt.internal.core.nd.util.CharArrayUtils;
import org.eclipse.jdt.internal.core.util.MementoTokenizer;
import org.eclipse.jdt.internal.core.util.Util;
import org.eclipse.objectteams.otdt.core.OTModelManager;
@@ -93,8 +97,9 @@ public ICompilationUnit becomeWorkingCopy(IProblemRequestor problemRequestor, Wo
* @see Openable
* @see Signature
*/
+@Override
protected boolean buildStructure(OpenableElementInfo info, IProgressMonitor pm, Map newElements, IResource underlyingResource) throws JavaModelException {
- IBinaryType typeInfo = getBinaryTypeInfo((IFile) underlyingResource);
+ IBinaryType typeInfo = getBinaryTypeInfo();
if (typeInfo == null) {
// The structure of a class file is unknown if a class file format errors occurred
//during the creation of the diet class file representative of this ClassFile.
@@ -124,6 +129,7 @@ protected boolean buildStructure(OpenableElementInfo info, IProgressMonitor pm,
* @see ICodeAssist#codeComplete(int, ICompletionRequestor)
* @deprecated
*/
+@Deprecated
public void codeComplete(int offset, ICompletionRequestor requestor) throws JavaModelException {
codeComplete(offset, requestor, DefaultWorkingCopyOwner.PRIMARY);
}
@@ -131,6 +137,7 @@ public void codeComplete(int offset, ICompletionRequestor requestor) throws Java
* @see ICodeAssist#codeComplete(int, ICompletionRequestor, WorkingCopyOwner)
* @deprecated
*/
+@Deprecated
public void codeComplete(int offset, ICompletionRequestor requestor, WorkingCopyOwner owner) throws JavaModelException {
if (requestor == null) {
throw new IllegalArgumentException("Completion requestor cannot be null"); //$NON-NLS-1$
@@ -197,9 +204,11 @@ public IJavaElement[] codeSelect(int offset, int length, WorkingCopyOwner owner)
/**
* Returns a new element info for this element.
*/
+@Override
protected Object createElementInfo() {
return new ClassFileInfo();
}
+@Override
public boolean equals(Object o) {
if (!(o instanceof ClassFile)) return false;
ClassFile other = (ClassFile) o;
@@ -227,7 +236,7 @@ public boolean existsUsingJarTypeCache() {
return false;
}
try {
- info = getJarBinaryTypeInfo((PackageFragment) getParent(), true/*fully initialize so as to not keep a reference to the byte array*/);
+ info = getJarBinaryTypeInfo();
} catch (CoreException e) {
// leave info null
} catch (IOException e) {
@@ -277,6 +286,7 @@ public IType findPrimaryType() {
}
return null;
}
+@Override
public String getAttachedJavadoc(IProgressMonitor monitor) throws JavaModelException {
return getType().getAttachedJavadoc(monitor);
}
@@ -292,40 +302,26 @@ public String getAttachedJavadoc(IProgressMonitor monitor) throws JavaModelExcep
* @exception JavaModelException when the IFile resource or JAR is not available
* or when this class file is not present in the JAR
*/
-public IBinaryType getBinaryTypeInfo(IFile file) throws JavaModelException {
- return getBinaryTypeInfo(file, true/*fully initialize so as to not keep a reference to the byte array*/);
-}
-public IBinaryType getBinaryTypeInfo(IFile file, boolean fullyInitialize) throws JavaModelException {
- JavaElement pkg = (JavaElement) getParent();
- if (pkg instanceof JarPackageFragment) {
- try {
- IBinaryType info = getJarBinaryTypeInfo((PackageFragment) pkg, fullyInitialize);
- if (info == null) {
- throw newNotPresentException();
- }
- return info;
- } catch (ClassFormatException cfe) {
- //the structure remains unknown
- if (JavaCore.getPlugin().isDebugging()) {
- cfe.printStackTrace(System.err);
- }
- return null;
- } catch (IOException ioe) {
- throw new JavaModelException(ioe, IJavaModelStatusConstants.IO_EXCEPTION);
- } catch (CoreException e) {
- if (e instanceof JavaModelException) {
- throw (JavaModelException)e;
- } else {
- throw new JavaModelException(e);
- }
+public IBinaryType getBinaryTypeInfo() throws JavaModelException {
+ try {
+ IBinaryType info = getJarBinaryTypeInfo();
+ if (info == null) {
+ throw newNotPresentException();
}
- } else {
- byte[] contents = Util.getResourceContentsAsByteArray(file);
- try {
- return new ClassFileReader(contents, file.getFullPath().toString().toCharArray(), fullyInitialize);
- } catch (ClassFormatException cfe) {
- //the structure remains unknown
- return null;
+ return info;
+ } catch (ClassFormatException cfe) {
+ //the structure remains unknown
+ if (JavaCore.getPlugin().isDebugging()) {
+ cfe.printStackTrace(System.err);
+ }
+ return null;
+ } catch (IOException ioe) {
+ throw new JavaModelException(ioe, IJavaModelStatusConstants.IO_EXCEPTION);
+ } catch (CoreException e) {
+ if (e instanceof JavaModelException) {
+ throw (JavaModelException)e;
+ } else {
+ throw new JavaModelException(e);
}
}
}
@@ -359,44 +355,58 @@ public byte[] getBytes() throws JavaModelException {
return Util.getResourceContentsAsByteArray(file);
}
}
-private IBinaryType getJarBinaryTypeInfo(PackageFragment pkg, boolean fullyInitialize) throws CoreException, IOException, ClassFormatException {
- JarPackageFragmentRoot root = (JarPackageFragmentRoot) pkg.getParent();
- ZipFile zip = null;
- ZipFile annotationZip = null;
- try {
- zip = root.getJar();
- String entryName = Util.concatWith(pkg.names, getElementName(), '/');
- ZipEntry ze = zip.getEntry(entryName);
- if (ze != null) {
- byte contents[] = org.eclipse.jdt.internal.compiler.util.Util.getZipEntryByteContent(ze, zip);
- String fileName = root.getHandleIdentifier() + IDependent.JAR_FILE_ENTRY_SEPARATOR + entryName;
- ClassFileReader reader = new ClassFileReader(contents, fileName.toCharArray(), fullyInitialize);
- if (root.getKind() == IPackageFragmentRoot.K_BINARY) {
- JavaProject javaProject = (JavaProject) getAncestor(IJavaElement.JAVA_PROJECT);
- IClasspathEntry entry = javaProject.getClasspathEntryFor(getPath());
- if (entry != null) {
- IProject project = javaProject.getProject();
- IPath externalAnnotationPath = ClasspathEntry.getExternalAnnotationPath(entry, project, false); // unresolved for use in ExternalAnnotationTracker
- if (externalAnnotationPath != null) {
- setupExternalAnnotationProvider(project, externalAnnotationPath, annotationZip, reader,
- entryName.substring(0, entryName.length() - SuffixConstants.SUFFIX_CLASS.length));
- } else if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
- reader.markAsFromSource();
- }
+
+public String getName() {
+ return this.name;
+}
+
+private IBinaryType getJarBinaryTypeInfo() throws CoreException, IOException, ClassFormatException {
+ BinaryTypeDescriptor descriptor = BinaryTypeFactory.createDescriptor(this);
+
+ if (descriptor == null) {
+ return null;
+ }
+
+ IBinaryType result = BinaryTypeFactory.readType(descriptor, null);
+
+ if (result == null) {
+ return null;
+ }
+
+ // TODO(sxenos): setup the external annotation provider if the IBinaryType came from the index
+ // TODO(sxenos): the old code always passed null as the third argument to setupExternalAnnotationProvider,
+ // but this looks like a bug. I've preserved it for now but we need to figure out what was supposed to go
+ // there.
+ PackageFragment pkg = (PackageFragment) getParent();
+ IJavaElement grandparent = pkg.getParent();
+ if (grandparent instanceof JarPackageFragmentRoot) {
+ JarPackageFragmentRoot root = (JarPackageFragmentRoot) grandparent;
+
+ if (root.getKind() == IPackageFragmentRoot.K_BINARY) {
+ JavaProject javaProject = (JavaProject) getAncestor(IJavaElement.JAVA_PROJECT);
+ IClasspathEntry entry = javaProject.getClasspathEntryFor(getPath());
+ if (entry != null) {
+ String entryName = new String(CharArrayUtils.concat(
+ JavaNames.fieldDescriptorToBinaryName(descriptor.fieldDescriptor), SuffixConstants.SUFFIX_CLASS));
+ IProject project = javaProject.getProject();
+ IPath externalAnnotationPath = ClasspathEntry.getExternalAnnotationPath(entry, project, false); // unresolved for use in ExternalAnnotationTracker
+ if (externalAnnotationPath != null) {
+ result = setupExternalAnnotationProvider(project, externalAnnotationPath, null, result,
+ entryName.substring(0, entryName.length() - SuffixConstants.SUFFIX_CLASS.length));
+ } else if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
+ result = new ExternalAnnotationDecorator(result, true);
}
}
- return reader;
}
- } finally {
- JavaModelManager.getJavaModelManager().closeZipFile(zip);
- JavaModelManager.getJavaModelManager().closeZipFile(annotationZip);
}
- return null;
+
+ return result;
}
-private void setupExternalAnnotationProvider(IProject project, final IPath externalAnnotationPath,
- ZipFile annotationZip, ClassFileReader reader, final String typeName)
+private IBinaryType setupExternalAnnotationProvider(IProject project, final IPath externalAnnotationPath,
+ ZipFile annotationZip, IBinaryType reader, final String typeName)
{
+ IBinaryType result = reader;
// try resolve path within the workspace:
IWorkspaceRoot root = project.getWorkspace().getRoot();
IResource resource;
@@ -410,26 +420,32 @@ private void setupExternalAnnotationProvider(IProject project, final IPath exter
String resolvedPath;
if (resource.exists()) {
if (resource.isVirtual()) {
- Util.log(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID,
+ Util.log(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID,
"Virtual resource "+externalAnnotationPath+" cannot be used as annotationpath for project "+project.getName())); //$NON-NLS-1$ //$NON-NLS-2$
- return;
+ return reader;
}
resolvedPath = resource.getLocation().toString(); // workspace lookup succeeded -> resolve it
} else {
resolvedPath = externalAnnotationPath.toString(); // not in workspace, use as is
}
try {
- annotationZip = reader.setExternalAnnotationProvider(resolvedPath, typeName, annotationZip, new ClassFileReader.ZipFileProducer() {
- @Override public ZipFile produce() throws IOException {
- try {
- return JavaModelManager.getJavaModelManager().getZipFile(externalAnnotationPath); // use (absolute, but) unresolved path here
- } catch (CoreException e) {
- throw new IOException("Failed to read annotation file for "+typeName+" from "+externalAnnotationPath.toString(), e); //$NON-NLS-1$ //$NON-NLS-2$
- }
- }});
+ if (annotationZip == null) {
+ annotationZip = ExternalAnnotationDecorator.getAnnotationZipFile(resolvedPath, new ExternalAnnotationDecorator.ZipFileProducer() {
+ @Override public ZipFile produce() throws IOException {
+ try {
+ return JavaModelManager.getJavaModelManager().getZipFile(externalAnnotationPath); // use (absolute, but) unresolved path here
+ } catch (CoreException e) {
+ throw new IOException("Failed to read annotation file for "+typeName+" from "+externalAnnotationPath.toString(), e); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }});
+ }
+
+ ExternalAnnotationProvider annotationProvider = ExternalAnnotationDecorator
+ .externalAnnotationProvider(resolvedPath, typeName, annotationZip);
+ result = new ExternalAnnotationDecorator(reader, annotationProvider);
} catch (IOException e) {
Util.log(e);
- return;
+ return result;
}
if (annotationZip == null) {
// Additional change listening for individual types only when annotations are in individual files.
@@ -437,6 +453,7 @@ private void setupExternalAnnotationProvider(IProject project, final IPath exter
this.externalAnnotationBase = externalAnnotationPath; // remember so we can unregister later
ExternalAnnotationTracker.registerClassFile(externalAnnotationPath, new Path(typeName), this);
}
+ return result;
}
void closeAndRemoveFromJarTypeCache() throws JavaModelException {
super.close();
@@ -451,6 +468,7 @@ public void close() throws JavaModelException {
}
super.close();
}
+@Override
public IBuffer getBuffer() throws JavaModelException {
IStatus status = validateClassFile();
if (status.isOK()) {
@@ -468,6 +486,7 @@ public IBuffer getBuffer() throws JavaModelException {
/**
* @see IMember
*/
+@Override
public IClassFile getClassFile() {
return this;
}
@@ -483,6 +502,7 @@ public ITypeRoot getTypeRoot() {
*
* @see IJavaElement
*/
+@Override
public IResource getCorrespondingResource() throws JavaModelException {
IPackageFragmentRoot root= (IPackageFragmentRoot)getParent().getParent();
if (root.isArchive()) {
@@ -554,6 +574,7 @@ public IJavaElement getElementAtConsideringSibling(int position) throws JavaMode
return null;
}
}
+@Override
public String getElementName() {
return this.name + SuffixConstants.SUFFIX_STRING_class;
}
@@ -566,6 +587,7 @@ public int getElementType() {
/*
* @see JavaElement
*/
+@Override
public IJavaElement getHandleFromMemento(String token, MementoTokenizer memento, WorkingCopyOwner owner) {
switch (token.charAt(0)) {
case JEM_TYPE:
@@ -579,6 +601,7 @@ public IJavaElement getHandleFromMemento(String token, MementoTokenizer memento,
/**
* @see JavaElement#getHandleMemento()
*/
+@Override
protected char getHandleMementoDelimiter() {
return JavaElement.JEM_CLASSFILE;
}
@@ -596,6 +619,7 @@ public IPath getPath() {
/*
* @see IJavaElement
*/
+@Override
public IResource resource(PackageFragmentRoot root) {
return ((IContainer) ((Openable) this.parent).resource(root)).getFile(new Path(getElementName()));
}
@@ -707,15 +731,18 @@ public ICompilationUnit getWorkingCopy(WorkingCopyOwner owner, IProgressMonitor
* @see IClassFile
* @deprecated
*/
+@Deprecated
public IJavaElement getWorkingCopy(IProgressMonitor monitor, org.eclipse.jdt.core.IBufferFactory factory) throws JavaModelException {
return getWorkingCopy(BufferFactoryWrapper.create(factory), monitor);
}
/**
* @see Openable
*/
+@Override
protected boolean hasBuffer() {
return true;
}
+@Override
public int hashCode() {
return Util.combineHashCodes(this.name.hashCode(), this.parent.hashCode());
}
@@ -734,6 +761,7 @@ public boolean isInterface() throws JavaModelException {
/**
* Returns true - class files are always read only.
*/
+@Override
public boolean isReadOnly() {
return true;
}
@@ -756,6 +784,7 @@ private IStatus validateClassFile() {
*
* @see Openable
*/
+@Override
protected IBuffer openBuffer(IProgressMonitor pm, Object info) throws JavaModelException {
// Check the cache for the top-level type first
IType outerMostEnclosingType = getOuterMostEnclosingType();
@@ -896,6 +925,7 @@ public static char[] translatedName(char[] name) {
* @see ICodeAssist#codeComplete(int, ICodeCompletionRequestor)
* @deprecated - should use codeComplete(int, ICompletionRequestor) instead
*/
+@Deprecated
public void codeComplete(int offset, final org.eclipse.jdt.core.ICodeCompletionRequestor requestor) throws JavaModelException {
if (requestor == null){
@@ -951,6 +981,7 @@ public void codeComplete(int offset, final org.eclipse.jdt.core.ICodeCompletionR
});
}
+@Override
protected IStatus validateExistence(IResource underlyingResource) {
// check whether the class file can be opened
IStatus status = validateClassFile();
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 1854aeea6..a8e3b27d0 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
@@ -24,13 +24,16 @@ import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
import org.eclipse.jdt.core.*;
import org.eclipse.jdt.internal.core.JavaModelManager.PerProjectInfo;
+import org.eclipse.jdt.internal.core.nd.indexer.Indexer;
+import org.eclipse.jdt.internal.core.nd.indexer.IndexerEvent;
+import org.eclipse.jdt.internal.core.nd.java.JavaIndex;
import org.eclipse.jdt.internal.core.util.Util;
/**
* Keep the global states used during Java element delta processing.
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
-public class DeltaProcessingState implements IResourceChangeListener {
+public class DeltaProcessingState implements IResourceChangeListener, Indexer.Listener {
/*
* Collection of listeners for Java element deltas
@@ -643,4 +646,15 @@ public class DeltaProcessingState implements IResourceChangeListener {
}
}
+ @Override
+ public void consume(IndexerEvent event) {
+ if (JavaIndex.isEnabled()) {
+ DeltaProcessor processor = getDeltaProcessor();
+ JavaElementDelta delta = (JavaElementDelta) event.getDelta();
+ delta.ignoreFromTests = true;
+ processor.notifyAndFire(delta);
+ this.deltaProcessors.set(null);
+ }
+ }
+
}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java
index 18f5b752a..0e2c59896 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
@@ -502,8 +502,24 @@ public class DeltaProcessor {
break;
case IResource.FOLDER:
- if (delta.getKind() == IResourceDelta.CHANGED) { // look for .jar file change to update classpath
- children = delta.getAffectedChildren();
+ switch (delta.getKind()) {
+ case IResourceDelta.ADDED:
+ case IResourceDelta.REMOVED:
+ // Close the containing package fragment root to reset its cached children.
+ // See http://bugs.eclipse.org/500714
+ IPackageFragmentRoot root = findContainingPackageFragmentRoot(resource);
+ if (root != null && root.isOpen()) {
+ try {
+ root.close();
+ } catch (JavaModelException e) {
+ Util.log(e);
+ }
+ }
+ break;
+
+ case IResourceDelta.CHANGED: // look for .jar file change to update classpath
+ children = delta.getAffectedChildren();
+ break;
}
break;
case IResource.FILE :
@@ -548,6 +564,27 @@ public class DeltaProcessor {
}
}
+ private IPackageFragmentRoot findContainingPackageFragmentRoot(IResource resource) {
+ IProject project = resource.getProject();
+ if (JavaProject.hasJavaNature(project)) {
+ IJavaProject javaProject = JavaCore.create(project);
+ try {
+ IPath path = resource.getProjectRelativePath();
+ IPackageFragmentRoot[] roots = javaProject.getPackageFragmentRoots();
+ for (IPackageFragmentRoot root : roots) {
+ IResource rootResource = root.getUnderlyingResource();
+ if (rootResource != null && !resource.equals(rootResource) &&
+ rootResource.getProjectRelativePath().isPrefixOf(path)) {
+ return root;
+ }
+ }
+ } catch (JavaModelException e) {
+ Util.log(e);
+ }
+ }
+ return null;
+ }
+
private void checkExternalFolderChange(IProject project, JavaProject javaProject) {
ClasspathChange change = this.state.getClasspathChange(project);
this.state.addExternalFolderChange(javaProject, change == null ? null : change.oldResolvedClasspath);
@@ -1020,6 +1057,9 @@ public class DeltaProcessor {
if (VERBOSE){
System.out.println("- External JAR CHANGED, affecting root: "+root.getElementName()); //$NON-NLS-1$
}
+ // TODO(sxenos): this is causing each change event for an external jar file to be fired twice.
+ // We need to preserve the clearing of cached information in the jar but defer the actual firing of
+ // the event until after the indexer has processed the jar.
contentChanged(root);
deltaContainsModifiedJar = true;
hasDelta = true;
@@ -1908,7 +1948,7 @@ public class DeltaProcessor {
* caches and their dependents
*/
public void resetProjectCaches() {
- if (this.projectCachesToReset.size() == 0)
+ if (this.projectCachesToReset.isEmpty())
return;
JavaModelManager.getJavaModelManager().resetJarTypeCache();
@@ -2064,14 +2104,7 @@ public class DeltaProcessor {
this.sourceElementParserCache = null; // don't hold onto parser longer than necessary
startDeltas();
}
- IElementChangedListener[] listeners;
- int listenerCount;
- synchronized (this.state) {
- listeners = this.state.elementChangedListeners;
- listenerCount = this.state.elementChangedListenerCount;
- }
- notifyTypeHierarchies(listeners, listenerCount);
- fire(null, ElementChangedEvent.POST_CHANGE);
+ notifyAndFire(null);
} finally {
// workaround for bug 15168 circular errors not reported
this.state.resetOldJavaProjectNames();
@@ -2180,6 +2213,17 @@ public class DeltaProcessor {
}
}
+ public void notifyAndFire(IJavaElementDelta delta) {
+ IElementChangedListener[] listeners;
+ int listenerCount;
+ synchronized (this.state) {
+ listeners = this.state.elementChangedListeners;
+ listenerCount = this.state.elementChangedListenerCount;
+ }
+ notifyTypeHierarchies(listeners, listenerCount);
+ fire(delta, ElementChangedEvent.POST_CHANGE);
+ }
+
/*
* Returns the root info for the given path. Look in the old roots table if kind is REMOVED.
*/
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementDelta.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementDelta.java
index a7beb47bc..86abfafba 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementDelta.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementDelta.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -82,6 +82,8 @@ public class JavaElementDelta extends SimpleDelta implements IJavaElementDelta {
*/
Map<Key, Integer> childIndex;
+ public boolean ignoreFromTests = false;
+
/**
* The delta key
*/
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelCache.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelCache.java
index c2ad7c360..5c6ca12da 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelCache.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelCache.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -28,6 +28,7 @@ import org.eclipse.objectteams.otdt.internal.core.OTType;
@SuppressWarnings({"rawtypes", "unchecked"})
public class JavaModelCache {
public static boolean VERBOSE = false;
+ public static boolean DEBUG_CACHE_INSERTIONS = false;
public static final int DEFAULT_PROJECT_SIZE = 5; // average 25552 bytes per project.
public static final int DEFAULT_ROOT_SIZE = 50; // average 2590 bytes per root -> maximum size : 25900*BASE_VALUE bytes
@@ -224,6 +225,9 @@ protected Object peekAtInfo(IJavaElement element) {
* Remember the info for the element.
*/
protected void putInfo(IJavaElement element, Object info) {
+ if (DEBUG_CACHE_INSERTIONS) {
+ System.out.println(Thread.currentThread() + " cache putInfo (" + getElementType(element) + " " + element.toString() + ", " + info + ")"); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$
+ }
switch (element.getElementType()) {
case IJavaElement.JAVA_MODEL:
this.modelInfo = info;
@@ -248,10 +252,39 @@ protected void putInfo(IJavaElement element, Object info) {
this.childrenCache.put(element, info);
}
}
+
+public static String getElementType(IJavaElement element) {
+ String elementType;
+ switch (element.getElementType()) {
+ case IJavaElement.JAVA_PROJECT:
+ elementType = "project"; //$NON-NLS-1$
+ break;
+ case IJavaElement.PACKAGE_FRAGMENT_ROOT:
+ elementType = "root"; //$NON-NLS-1$
+ break;
+ case IJavaElement.PACKAGE_FRAGMENT:
+ elementType = "package"; //$NON-NLS-1$
+ break;
+ case IJavaElement.CLASS_FILE:
+ elementType = "class file"; //$NON-NLS-1$
+ break;
+ case IJavaElement.COMPILATION_UNIT:
+ elementType = "compilation unit"; //$NON-NLS-1$
+ break;
+ default:
+ elementType = "element"; //$NON-NLS-1$
+ }
+ return elementType;
+}
+
/**
* Removes the info of the element from the cache.
*/
protected void removeInfo(JavaElement element) {
+ if (DEBUG_CACHE_INSERTIONS) {
+ String elementToString = element.toString();
+ System.out.println(Thread.currentThread() + " cache removeInfo " + getElementType(element) + " " + elementToString); //$NON-NLS-1$//$NON-NLS-2$
+ }
switch (element.getElementType()) {
case IJavaElement.JAVA_MODEL:
this.modelInfo = 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 cdb4157ef..8b4feaa1a 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
@@ -130,6 +130,8 @@ import org.eclipse.jdt.internal.core.builder.JavaBuilder;
import org.eclipse.jdt.internal.core.dom.SourceRangeVerifier;
import org.eclipse.jdt.internal.core.dom.rewrite.RewriteEventStore;
import org.eclipse.jdt.internal.core.hierarchy.TypeHierarchy;
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.indexer.Indexer;
import org.eclipse.jdt.internal.core.search.AbstractSearchScope;
import org.eclipse.jdt.internal.core.search.BasicSearchEngine;
import org.eclipse.jdt.internal.core.search.IRestrictedAccessTypeRequestor;
@@ -176,6 +178,14 @@ public class JavaModelManager implements ISaveParticipant, IContentTypeChangeLis
private static final String EXTERNAL_FILES_CACHE = "externalFilesCache"; //$NON-NLS-1$
private static final String ASSUMED_EXTERNAL_FILES_CACHE = "assumedExternalFilesCache"; //$NON-NLS-1$
+ public static enum ArchiveValidity {
+ BAD_FORMAT, UNABLE_TO_READ, VALID;
+
+ public boolean isValid() {
+ return this == VALID;
+ }
+ }
+
/**
* Define a zip cache object.
*/
@@ -333,8 +343,11 @@ public class JavaModelManager implements ISaveParticipant, IContentTypeChangeLis
private static final String INDEX_MANAGER_DEBUG = JavaCore.PLUGIN_ID + "/debug/indexmanager" ; //$NON-NLS-1$
private static final String INDEX_MANAGER_ADVANCED_DEBUG = JavaCore.PLUGIN_ID + "/debug/indexmanager/advanced" ; //$NON-NLS-1$
private static final String COMPILER_DEBUG = JavaCore.PLUGIN_ID + "/debug/compiler" ; //$NON-NLS-1$
+ private static final String JAVAMODEL_CLASSPATH = JavaCore.PLUGIN_ID + "/debug/javamodel/classpath" ; //$NON-NLS-1$
private static final String JAVAMODEL_DEBUG = JavaCore.PLUGIN_ID + "/debug/javamodel" ; //$NON-NLS-1$
+ private static final String JAVAMODEL_INVALID_ARCHIVES = JavaCore.PLUGIN_ID + "/debug/javamodel/invalid_archives" ; //$NON-NLS-1$
private static final String JAVAMODELCACHE_DEBUG = JavaCore.PLUGIN_ID + "/debug/javamodel/cache" ; //$NON-NLS-1$
+ private static final String JAVAMODELCACHE_INSERTIONS_DEBUG = JavaCore.PLUGIN_ID + "/debug/javamodel/insertions" ; //$NON-NLS-1$
private static final String CP_RESOLVE_DEBUG = JavaCore.PLUGIN_ID + "/debug/cpresolution" ; //$NON-NLS-1$
private static final String CP_RESOLVE_ADVANCED_DEBUG = JavaCore.PLUGIN_ID + "/debug/cpresolution/advanced" ; //$NON-NLS-1$
private static final String CP_RESOLVE_FAILURE_DEBUG = JavaCore.PLUGIN_ID + "/debug/cpresolution/failure" ; //$NON-NLS-1$
@@ -354,6 +367,12 @@ public class JavaModelManager implements ISaveParticipant, IContentTypeChangeLis
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$
private static final String FORMATTER_DEBUG = JavaCore.PLUGIN_ID + "/debug/formatter" ; //$NON-NLS-1$
+ private static final String INDEX_INDEXER_DEBUG = JavaCore.PLUGIN_ID + "/debug/index/indexer" ; //$NON-NLS-1$
+ private static final String INDEX_INDEXER_INSERTIONS = JavaCore.PLUGIN_ID + "/debug/index/insertions" ; //$NON-NLS-1$
+ private static final String INDEX_INDEXER_SELFTEST = JavaCore.PLUGIN_ID + "/debug/index/selftest" ; //$NON-NLS-1$
+ private static final String INDEX_LOCKS_DEBUG = JavaCore.PLUGIN_ID + "/debug/index/locks" ; //$NON-NLS-1$
+ private static final String INDEX_INDEXER_SPACE = JavaCore.PLUGIN_ID + "/debug/index/space" ; //$NON-NLS-1$
+ private static final String INDEX_INDEXER_TIMING = JavaCore.PLUGIN_ID + "/debug/index/timing" ; //$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$
@@ -1290,6 +1309,16 @@ public class JavaModelManager implements ISaveParticipant, IContentTypeChangeLis
}
private ClasspathChange setClasspath(IClasspathEntry[] newRawClasspath, IClasspathEntry[] referencedEntries, IPath newOutputLocation, IJavaModelStatus newRawClasspathStatus, IClasspathEntry[] newResolvedClasspath, Map newRootPathToRawEntries, Map newRootPathToResolvedEntries, IJavaModelStatus newUnresolvedEntryStatus, boolean addClasspathChange) {
+ if (DEBUG_CLASSPATH) {
+ System.out.println("Setting resolved classpath for " + this.project.getFullPath()); //$NON-NLS-1$
+ if (newResolvedClasspath == null) {
+ System.out.println("New classpath = null"); //$NON-NLS-1$
+ } else {
+ for (IClasspathEntry next : newResolvedClasspath) {
+ System.out.println(" " + next); //$NON-NLS-1$
+ }
+ }
+ }
ClasspathChange classpathChange = addClasspathChange ? addClasspathChange() : null;
if (referencedEntries != null) this.referencedEntries = referencedEntries;
@@ -1510,6 +1539,8 @@ public class JavaModelManager implements ISaveParticipant, IContentTypeChangeLis
}
public static boolean VERBOSE = false;
+ public static boolean DEBUG_CLASSPATH = false;
+ public static boolean DEBUG_INVALID_ARCHIVES = false;
public static boolean CP_RESOLVE_VERBOSE = false;
public static boolean CP_RESOLVE_VERBOSE_ADVANCED = false;
public static boolean CP_RESOLVE_VERBOSE_FAILURE = false;
@@ -1531,10 +1562,29 @@ public class JavaModelManager implements ISaveParticipant, IContentTypeChangeLis
// The amount of time from when an invalid archive is first sensed until that state is considered stale.
private static long INVALID_ARCHIVE_TTL_MILLISECONDS = 2 * 60 * 1000;
+ private static class InvalidArchiveInfo {
+ /**
+ * Time at which this entry will be removed from the invalid archive list.
+ */
+ final long evictionTimestamp;
+
+ /**
+ * Reason the entry was added to the invalid archive list.
+ */
+ final ArchiveValidity reason;
+
+ InvalidArchiveInfo(long evictionTimestamp, ArchiveValidity reason) {
+ this.evictionTimestamp = evictionTimestamp;
+ this.reason = reason;
+ }
+ }
+
/*
* A map of IPaths for jars that are known to be invalid (such as not being in a valid/known format), to an eviction timestamp.
+ * Synchronize on invalidArchivesMutex before accessing.
*/
- private Map<IPath, Long> invalidArchives;
+ private final Map<IPath, InvalidArchiveInfo> invalidArchives = new HashMap<IPath, InvalidArchiveInfo>();
+ private final Object invalidArchivesMutex = new Object();
/*
* A set of IPaths for files that are known to be external to the workspace.
@@ -1698,12 +1748,13 @@ public class JavaModelManager implements ISaveParticipant, IContentTypeChangeLis
this.nonChainingJars.add(path);
}
- public void addInvalidArchive(IPath path) {
- // unlikely to be null
- if (this.invalidArchives == null) {
- this.invalidArchives = Collections.synchronizedMap(new HashMap());
+ public void addInvalidArchive(IPath path, ArchiveValidity reason) {
+ if (DEBUG_INVALID_ARCHIVES) {
+ System.out.println("Invalid JAR cache: adding " + path + ", reason: " + reason); //$NON-NLS-1$//$NON-NLS-2$
+ }
+ synchronized (this.invalidArchivesMutex) {
+ this.invalidArchives.put(path, new InvalidArchiveInfo(System.currentTimeMillis() + INVALID_ARCHIVE_TTL_MILLISECONDS, reason));
}
- this.invalidArchives.put(path, System.currentTimeMillis() + INVALID_ARCHIVE_TTL_MILLISECONDS);
}
/**
@@ -1773,8 +1824,11 @@ public class JavaModelManager implements ISaveParticipant, IContentTypeChangeLis
TypeHierarchy.DEBUG = debug && options.getBooleanOption(HIERARCHY_DEBUG, false);
JobManager.VERBOSE = debug && options.getBooleanOption(INDEX_MANAGER_DEBUG, false);
IndexManager.DEBUG = debug && options.getBooleanOption(INDEX_MANAGER_ADVANCED_DEBUG, false);
+ JavaModelManager.DEBUG_CLASSPATH = debug && options.getBooleanOption(JAVAMODEL_CLASSPATH, false);
+ JavaModelManager.DEBUG_INVALID_ARCHIVES = debug && options.getBooleanOption(JAVAMODEL_INVALID_ARCHIVES, false);
JavaModelManager.VERBOSE = debug && options.getBooleanOption(JAVAMODEL_DEBUG, false);
JavaModelCache.VERBOSE = debug && options.getBooleanOption(JAVAMODELCACHE_DEBUG, false);
+ JavaModelCache.DEBUG_CACHE_INSERTIONS = debug && options.getBooleanOption(JAVAMODELCACHE_INSERTIONS_DEBUG, false);
JavaModelOperation.POST_ACTION_VERBOSE = debug && options.getBooleanOption(POST_ACTION_DEBUG, false);
NameLookup.VERBOSE = debug && options.getBooleanOption(RESOLUTION_DEBUG, false);
BasicSearchEngine.VERBOSE = debug && options.getBooleanOption(SEARCH_DEBUG, false);
@@ -1782,6 +1836,12 @@ public class JavaModelManager implements ISaveParticipant, IContentTypeChangeLis
JavaModelManager.ZIP_ACCESS_VERBOSE = debug && options.getBooleanOption(ZIP_ACCESS_DEBUG, false);
SourceMapper.VERBOSE = debug && options.getBooleanOption(SOURCE_MAPPER_DEBUG_VERBOSE, false);
DefaultCodeFormatter.DEBUG = debug && options.getBooleanOption(FORMATTER_DEBUG, false);
+ Indexer.DEBUG = debug && options.getBooleanOption(INDEX_INDEXER_DEBUG, false);
+ Indexer.DEBUG_INSERTIONS = debug && options.getBooleanOption(INDEX_INDEXER_INSERTIONS, false);
+ Indexer.DEBUG_ALLOCATIONS = debug && options.getBooleanOption(INDEX_INDEXER_SPACE, false);
+ Indexer.DEBUG_TIMING = debug && options.getBooleanOption(INDEX_INDEXER_TIMING, false);
+ Indexer.DEBUG_SELFTEST = debug && options.getBooleanOption(INDEX_INDEXER_SELFTEST, false);
+ Nd.sDEBUG_LOCKS = debug && options.getBooleanOption(INDEX_LOCKS_DEBUG, false);
// configure performance options
if(PerformanceStats.ENABLED) {
@@ -2702,9 +2762,7 @@ public class JavaModelManager implements ISaveParticipant, IContentTypeChangeLis
}
public void verifyArchiveContent(IPath path) throws CoreException {
- if (isInvalidArchive(path)) {
- throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.status_IOException, new ZipException()));
- }
+ throwExceptionIfArchiveInvalid(path);
ZipFile file = getZipFile(path);
closeZipFile(file);
}
@@ -2724,16 +2782,47 @@ public class JavaModelManager implements ISaveParticipant, IContentTypeChangeLis
return getZipFile(path, true);
}
+ /**
+ * For use in the JDT unit tests only. Used for testing error handling. Causes an
+ * {@link IOException} to be thrown in {@link #getZipFile} whenever it attempts to
+ * read a zip file.
+ *
+ * @noreference This field is not intended to be referenced by clients.
+ */
+ public static boolean throwIoExceptionsInGetZipFile = false;
+
private ZipFile getZipFile(IPath path, boolean checkInvalidArchiveCache) throws CoreException {
- if (checkInvalidArchiveCache && isInvalidArchive(path))
- throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.status_IOException, new ZipException()));
-
+ if (checkInvalidArchiveCache) {
+ throwExceptionIfArchiveInvalid(path);
+ }
ZipCache zipCache;
ZipFile zipFile;
if ((zipCache = (ZipCache)this.zipFiles.get()) != null
&& (zipFile = zipCache.getCache(path)) != null) {
return zipFile;
}
+ File localFile = getLocalFile(path);
+
+ try {
+ if (ZIP_ACCESS_VERBOSE) {
+ System.out.println("(" + Thread.currentThread() + ") [JavaModelManager.getZipFile(IPath)] Creating ZipFile on " + localFile ); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ if (throwIoExceptionsInGetZipFile) {
+ throw new IOException();
+ }
+ zipFile = new ZipFile(localFile);
+ if (zipCache != null) {
+ zipCache.setCache(path, zipFile);
+ }
+ return zipFile;
+ } catch (IOException e) {
+ ArchiveValidity reason = (e instanceof ZipException) ? ArchiveValidity.BAD_FORMAT : ArchiveValidity.UNABLE_TO_READ;
+ addInvalidArchive(path, reason);
+ throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.status_IOException, e));
+ }
+ }
+
+ public static File getLocalFile(IPath path) throws CoreException {
File localFile = null;
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
IResource file = root.findMember(path);
@@ -2750,19 +2839,19 @@ public class JavaModelManager implements ISaveParticipant, IContentTypeChangeLis
// external resource -> it is ok to use toFile()
localFile= path.toFile();
}
+ return localFile;
+ }
- try {
- if (ZIP_ACCESS_VERBOSE) {
- System.out.println("(" + Thread.currentThread() + ") [JavaModelManager.getZipFile(IPath)] Creating ZipFile on " + localFile ); //$NON-NLS-1$ //$NON-NLS-2$
- }
- zipFile = new ZipFile(localFile);
- if (zipCache != null) {
- zipCache.setCache(path, zipFile);
+ private void throwExceptionIfArchiveInvalid(IPath path) throws CoreException {
+ ArchiveValidity validity = getArchiveValidity(path);
+ if (!validity.isValid()) {
+ IOException reason;
+ if (validity == ArchiveValidity.BAD_FORMAT) {
+ reason = new ZipException();
+ } else {
+ reason = new IOException();
}
- return zipFile;
- } catch (IOException e) {
- addInvalidArchive(path);
- throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.status_IOException, e));
+ throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.status_IOException, reason));
}
}
@@ -3186,31 +3275,36 @@ public class JavaModelManager implements ISaveParticipant, IContentTypeChangeLis
return this.nonChainingJars != null && this.nonChainingJars.contains(path);
}
- public boolean isInvalidArchive(IPath path) {
- if (this.invalidArchives == null)
- return false;
- Long evictionTime = this.invalidArchives.get(path);
- if (evictionTime == null)
- return false;
+ public ArchiveValidity getArchiveValidity(IPath path) {
+ InvalidArchiveInfo invalidArchiveInfo;
+ synchronized (this.invalidArchivesMutex) {
+ invalidArchiveInfo = this.invalidArchives.get(path);
+ }
+ if (invalidArchiveInfo == null)
+ return ArchiveValidity.VALID;
long now = System.currentTimeMillis();
// If the TTL for this cache entry has expired, directly check whether the archive is still invalid.
// If it transitioned to being valid, remove it from the cache and force an update to project caches.
- if (now > evictionTime) {
+ if (now > invalidArchiveInfo.evictionTimestamp) {
try {
getZipFile(path, false);
removeFromInvalidArchiveCache(path);
- return false;
} catch (CoreException e) {
// Archive is still invalid, fall through to reporting it is invalid.
}
+ // Retry the test from the start, now that we have an up-to-date result
+ return getArchiveValidity(path);
}
- return true;
+ return invalidArchiveInfo.reason;
}
public void removeFromInvalidArchiveCache(IPath path) {
- if (this.invalidArchives != null) {
+ synchronized(this.invalidArchivesMutex) {
if (this.invalidArchives.remove(path) != null) {
+ if (DEBUG_INVALID_ARCHIVES) {
+ System.out.println("Invalid JAR cache: removed " + path); //$NON-NLS-1$
+ }
try {
// Bug 455042: Force an update of the JavaProjectElementInfo project caches.
for (IJavaProject project : getJavaModel().getJavaProjects()) {
@@ -3985,26 +4079,7 @@ public class JavaModelManager implements ISaveParticipant, IContentTypeChangeLis
boolean wasVerbose = false;
try {
if (JavaModelCache.VERBOSE) {
- String elementType;
- switch (element.getElementType()) {
- case IJavaElement.JAVA_PROJECT:
- elementType = "project"; //$NON-NLS-1$
- break;
- case IJavaElement.PACKAGE_FRAGMENT_ROOT:
- elementType = "root"; //$NON-NLS-1$
- break;
- case IJavaElement.PACKAGE_FRAGMENT:
- elementType = "package"; //$NON-NLS-1$
- break;
- case IJavaElement.CLASS_FILE:
- elementType = "class file"; //$NON-NLS-1$
- break;
- case IJavaElement.COMPILATION_UNIT:
- elementType = "compilation unit"; //$NON-NLS-1$
- break;
- default:
- elementType = "element"; //$NON-NLS-1$
- }
+ String elementType = JavaModelCache.getElementType(element);
System.out.println(Thread.currentThread() + " CLOSING "+ elementType + " " + element.toStringWithAncestors()); //$NON-NLS-1$//$NON-NLS-2$
wasVerbose = true;
JavaModelCache.VERBOSE = false;
@@ -4085,8 +4160,16 @@ public class JavaModelManager implements ISaveParticipant, IContentTypeChangeLis
public void resetClasspathListCache() {
if (this.nonChainingJars != null)
this.nonChainingJars.clear();
- if (this.invalidArchives != null)
+ if (DEBUG_INVALID_ARCHIVES) {
+ synchronized(this.invalidArchivesMutex) {
+ if (!this.invalidArchives.isEmpty()) {
+ System.out.println("Invalid JAR cache: clearing cache"); //$NON-NLS-1$
+ }
+ }
+ }
+ synchronized(this.invalidArchivesMutex) {
this.invalidArchives.clear();
+ }
if (this.externalFiles != null)
this.externalFiles.clear();
if (this.assumedExternalFiles != null)
@@ -5163,6 +5246,8 @@ public class JavaModelManager implements ISaveParticipant, IContentTypeChangeLis
| IResourceChangeEvent.PRE_CLOSE
| IResourceChangeEvent.PRE_REFRESH);
+ Indexer.getInstance().addListener(this.deltaState);
+
// listen to resource changes affecting external annotations
ExternalAnnotationTracker.start(workspace);
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavadocConstants.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavadocConstants.java
index ed53500c3..e52d2e190 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavadocConstants.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavadocConstants.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2005, 2014 IBM Corporation and others.
+ * Copyright (c) 2005, 2016 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -14,7 +14,9 @@ public interface JavadocConstants {
String ANCHOR_PREFIX_END = "\""; //$NON-NLS-1$
char[] ANCHOR_PREFIX_START = "<A NAME=\"".toCharArray(); //$NON-NLS-1$
- int ANCHOR_PREFIX_START_LENGHT = ANCHOR_PREFIX_START.length;
+ char[] ANCHOR_PREFIX_START_2 = "<A ID=\"".toCharArray(); //$NON-NLS-1$
+ int ANCHOR_PREFIX_START_LENGTH = ANCHOR_PREFIX_START.length;
+ int ANCHOR_PREFIX_START2_LENGTH = ANCHOR_PREFIX_START_2.length;
char[] ANCHOR_SUFFIX = "</A>".toCharArray(); //$NON-NLS-1$
int ANCHOR_SUFFIX_LENGTH = JavadocConstants.ANCHOR_SUFFIX.length;
char[] CONSTRUCTOR_DETAIL = "<!-- ========= CONSTRUCTOR DETAIL ======== -->".toCharArray(); //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavadocContents.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavadocContents.java
index 02341d5b1..e29b96de1 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavadocContents.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavadocContents.java
@@ -185,14 +185,15 @@ public class JavadocContents {
}
int fromIndex = this.tempLastAnchorFoundIndex;
- int index;
+ int[] index;
// check each next unknown anchor locations
- while ((index = CharOperation.indexOf(JavadocConstants.ANCHOR_PREFIX_START, this.content, false, fromIndex)) != -1 && (index < indexOfSectionBottom || indexOfSectionBottom == -1)) {
- fromIndex = index + 1;
-
- int anchorEndStart = index + JavadocConstants.ANCHOR_PREFIX_START_LENGHT;
-
+ index = getAnchorIndex(fromIndex);
+ while (index[0] != -1 && (index[0] < indexOfSectionBottom || indexOfSectionBottom == -1)) {
+ fromIndex = index[0] + 1;
+
+ int anchorEndStart = index[0] + index[1];
+
this.tempLastAnchorFoundIndex = anchorEndStart;
if (CharOperation.prefixEquals(anchor, this.content, false, anchorEndStart)) {
@@ -204,11 +205,25 @@ public class JavadocContents {
this.tempAnchorIndexes[this.tempAnchorIndexesCount++] = anchorEndStart;
}
+ index = getAnchorIndex(fromIndex);
}
return null;
}
-
+ private int[] getAnchorIndex(int fromIndex) {
+ int index = CharOperation.indexOf(JavadocConstants.ANCHOR_PREFIX_START, this.content, false, fromIndex);
+ if (index != -1) {
+ return new int[]{index, JavadocConstants.ANCHOR_PREFIX_START_LENGTH};
+ }
+ if (index == -1) {
+ index = CharOperation.indexOf(JavadocConstants.ANCHOR_PREFIX_START_2, this.content, false, fromIndex);
+ }
+ if (index == -1) {
+ return new int[]{-1, -1};
+ } else {
+ return new int[]{index, JavadocConstants.ANCHOR_PREFIX_START2_LENGTH};
+ }
+ }
private int[] computeChildRange(int anchorEndStart, char[] anchor, int indexOfBottom) {
int[] range = null;
@@ -218,7 +233,7 @@ public class JavadocContents {
int indexOfEndLink = CharOperation.indexOf(JavadocConstants.ANCHOR_SUFFIX, this.content, false, anchorEndStart + anchor.length);
if (indexOfEndLink != -1) {
// try to find the next anchor
- int indexOfNextElement = CharOperation.indexOf(JavadocConstants.ANCHOR_PREFIX_START, this.content, false, indexOfEndLink);
+ int indexOfNextElement = getAnchorIndex(indexOfEndLink)[0];
int javadocStart = indexOfEndLink + JavadocConstants.ANCHOR_SUFFIX_LENGTH;
int javadocEnd = indexOfNextElement == -1 ? indexOfBottom : Math.min(indexOfNextElement, indexOfBottom);
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 72917d571..fa1e11d10 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
@@ -15,10 +15,10 @@ import java.util.zip.ZipFile;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
-
-import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
+import org.eclipse.jdt.internal.compiler.classfmt.ExternalAnnotationDecorator;
import org.eclipse.jdt.internal.compiler.env.AccessRuleSet;
+import org.eclipse.jdt.internal.compiler.env.IBinaryType;
import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
@@ -107,7 +107,7 @@ public boolean equals(Object o) {
public NameEnvironmentAnswer findClass(String binaryFileName, String qualifiedPackageName, String qualifiedBinaryFileName) {
if (!doesFileExist(binaryFileName, qualifiedPackageName, qualifiedBinaryFileName)) return null; // most common case
- ClassFileReader reader = null;
+ IBinaryType reader = null;
try {
reader = Util.newClassFileReader(this.binaryFolder.getFile(new Path(qualifiedBinaryFileName)));
} catch (CoreException e) {
@@ -121,7 +121,12 @@ public NameEnvironmentAnswer findClass(String binaryFileName, String qualifiedPa
String fileNameWithoutExtension = qualifiedBinaryFileName.substring(0, qualifiedBinaryFileName.length() - SuffixConstants.SUFFIX_CLASS.length);
if (this.externalAnnotationPath != null) {
try {
- this.annotationZipFile = reader.setExternalAnnotationProvider(this.externalAnnotationPath, fileNameWithoutExtension, this.annotationZipFile, null);
+ if (this.annotationZipFile == null) {
+ this.annotationZipFile = ExternalAnnotationDecorator
+ .getAnnotationZipFile(this.externalAnnotationPath, null);
+ }
+ reader = ExternalAnnotationDecorator.create(reader, this.externalAnnotationPath,
+ fileNameWithoutExtension, this.annotationZipFile);
} catch (IOException e) {
// don't let error on annotations fail class reading
}
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 1bda5fb27..657567583 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJar.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJar.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -13,22 +13,27 @@
*******************************************************************************/
package org.eclipse.jdt.internal.core.builder;
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.runtime.*;
+import java.io.File;
+import java.io.IOException;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
+import org.eclipse.jdt.internal.compiler.classfmt.ExternalAnnotationDecorator;
import org.eclipse.jdt.internal.compiler.env.AccessRuleSet;
+import org.eclipse.jdt.internal.compiler.env.IBinaryType;
import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
import org.eclipse.jdt.internal.compiler.util.SimpleSet;
import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
import org.eclipse.jdt.internal.core.util.Util;
-import java.io.*;
-import java.util.*;
-import java.util.zip.*;
-
@SuppressWarnings("rawtypes")
public class ClasspathJar extends ClasspathLocation {
@@ -165,12 +170,18 @@ public NameEnvironmentAnswer findClass(String binaryFileName, String qualifiedPa
if (!isPackage(qualifiedPackageName)) return null; // most common case
try {
- ClassFileReader reader = ClassFileReader.read(this.zipFile, qualifiedBinaryFileName);
+ IBinaryType reader = ClassFileReader.read(this.zipFile, qualifiedBinaryFileName);
if (reader != null) {
String fileNameWithoutExtension = qualifiedBinaryFileName.substring(0, qualifiedBinaryFileName.length() - SuffixConstants.SUFFIX_CLASS.length);
if (this.externalAnnotationPath != null) {
try {
- this.annotationZipFile = reader.setExternalAnnotationProvider(this.externalAnnotationPath, fileNameWithoutExtension, this.annotationZipFile, null);
+ if (this.annotationZipFile == null) {
+ this.annotationZipFile = ExternalAnnotationDecorator
+ .getAnnotationZipFile(this.externalAnnotationPath, null);
+ }
+
+ reader = ExternalAnnotationDecorator.create(reader, this.externalAnnotationPath,
+ fileNameWithoutExtension, this.annotationZipFile);
} catch (IOException e) {
// don't let error on annotations fail class reading
}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/BindingMap.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/BindingMap.java
new file mode 100644
index 000000000..3070193d8
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/BindingMap.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Google, Inc and others.
+ * All rights reserved. This program and 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:
+ * Stefan Xenos (Google) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core.hierarchy;
+
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
+
+/**
+ * Maps a {@link TypeBinding} onto values. Two {@link TypeBinding}s are considered equivalent
+ * if their IDs are the same or if they have TypeIds.NoId and they are identical objects.
+ * <p>
+ * Takes into account the fact that a ReferenceBinding may have its ID change from NoId
+ * to a real ID at any time without notice. (This is a behavior that was observed in
+ * TypeHierarchyTests.testAnonymousType01 -- if type IDs could be made invariant then it
+ * would be possible to implement a more efficient map that never needs to perform an
+ * exhaustive search.)
+ */
+public class BindingMap<V> {
+ private Map<TypeBinding, V> identityMap = new IdentityHashMap<>();
+ private Object[] mapIdToValue = new Object[0];
+ private Set<TypeBinding> bindingsWithoutAnId = new HashSet<>();
+
+ public void put(TypeBinding key, V value) {
+ this.identityMap.put(key, value);
+ if (key.id != TypeIds.NoId) {
+ int targetId = key.id;
+ insertIntoIdMap(targetId, value);
+ } else {
+ this.bindingsWithoutAnId.add(key);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public V get(TypeBinding key) {
+ // Check if we can find this binding by identity
+ V value = this.identityMap.get(key);
+ if (value != null) {
+ return value;
+ }
+ int targetId = key.id;
+ if (targetId != TypeIds.NoId) {
+ // Check if we can find this binding by value
+ if (targetId < this.mapIdToValue.length) {
+ value = (V)this.mapIdToValue[targetId];
+ }
+ if (value != null) {
+ return value;
+ }
+
+ // Check if there are any bindings that previously had no ID that have
+ // subsequently been assigned one.
+ for (Iterator<TypeBinding> bindingIter = this.bindingsWithoutAnId.iterator(); bindingIter.hasNext();) {
+ TypeBinding nextBinding = bindingIter.next();
+
+ if (nextBinding.id != TypeIds.NoId) {
+ insertIntoIdMap(nextBinding.id, this.identityMap.get(nextBinding));
+ bindingIter.remove();
+ }
+ }
+
+ // Now look again to see if this binding can be found
+ if (targetId < this.mapIdToValue.length) {
+ value = (V)this.mapIdToValue[targetId];
+ }
+ }
+
+ return value;
+ }
+
+ private void insertIntoIdMap(int targetId, V value) {
+ int requiredSize = targetId + 1;
+ if (this.mapIdToValue.length < requiredSize) {
+ int newSize = requiredSize * 2;
+ Object[] newArray = new Object[newSize];
+ System.arraycopy(this.mapIdToValue, 0, newArray, 0, this.mapIdToValue.length);
+ this.mapIdToValue = newArray;
+ }
+ this.mapIdToValue[targetId] = value;
+ }
+
+ public void clear() {
+ this.identityMap.clear();
+ this.bindingsWithoutAnId.clear();
+ this.mapIdToValue = new Object[0];
+ }
+}
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 932c0494f..0427355e3 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
@@ -53,6 +53,23 @@ public HierarchyBinaryType(int modifiers, char[] qualification, char[] sourceNam
this.typeParameterSignatures = typeParameterSignatures;
CharOperation.replace(this.name, '.', '/');
}
+
+public HierarchyBinaryType(int modifiers, char[] binaryName, char[] sourceName, char[] enclosingTypeBinaryName, char[][] typeParameterSignatures) {
+ this.modifiers = modifiers;
+ this.sourceName = sourceName;
+ this.name = binaryName;
+ this.enclosingTypeName = enclosingTypeBinaryName;
+ this.typeParameterSignatures = typeParameterSignatures;
+
+ if (typeParameterSignatures != null) {
+ for (char[] next : typeParameterSignatures) {
+ if (next == null) {
+ throw new IllegalArgumentException("Parameter's type signature must not be null"); //$NON-NLS-1$
+ }
+ }
+ }
+}
+
/**
* @see org.eclipse.jdt.internal.compiler.env.IBinaryType
*/
@@ -197,6 +214,7 @@ public boolean isMember() {
return false; // index did not record this information (since unused for hierarchies)
}
+
public void recordSuperType(char[] superTypeName, char[] superQualification, char superClassOrInterface){
// index encoding of p.A$B was B/p.A$, rebuild the proper name
@@ -215,17 +233,25 @@ public void recordSuperType(char[] superTypeName, char[] superQualification, cha
if (TypeDeclaration.kind(this.modifiers) == TypeDeclaration.INTERFACE_DECL) return;
char[] encodedName = CharOperation.concat(superQualification, superTypeName, '/');
CharOperation.replace(encodedName, '.', '/');
- this.superclass = encodedName;
+ recordSuperclass(encodedName);
} else {
char[] encodedName = CharOperation.concat(superQualification, superTypeName, '/');
CharOperation.replace(encodedName, '.', '/');
- if (this.superInterfaces == NoInterface){
- this.superInterfaces = new char[][] { encodedName };
- } else {
- int length = this.superInterfaces.length;
- System.arraycopy(this.superInterfaces, 0, this.superInterfaces = new char[length+1][], 0, length);
- this.superInterfaces[length] = encodedName;
- }
+ recordInterface(encodedName);
+ }
+}
+
+public void recordSuperclass(char[] binaryName) {
+ this.superclass = binaryName;
+}
+
+public void recordInterface(char[] binaryName) {
+ if (this.superInterfaces == NoInterface){
+ this.superInterfaces = new char[][] { binaryName };
+ } else {
+ int length = this.superInterfaces.length;
+ System.arraycopy(this.superInterfaces, 0, this.superInterfaces = new char[length+1][], 0, length);
+ this.superInterfaces[length] = binaryName;
}
}
@@ -235,6 +261,7 @@ public void recordSuperType(char[] superTypeName, char[] superQualification, cha
public char[] sourceFileName() {
return null;
}
+@Override
public String toString() {
StringBuffer buffer = new StringBuffer();
if (this.modifiers == ClassFileConstants.AccPublic) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyBuilder.java
index 41fb754a1..46fd72d2e 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyBuilder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyBuilder.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -18,15 +18,25 @@ import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
import org.eclipse.jdt.internal.compiler.env.IBinaryType;
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
import org.eclipse.jdt.internal.compiler.env.IGenericType;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
-import org.eclipse.jdt.internal.core.*;
+import org.eclipse.jdt.internal.core.ClassFile;
+import org.eclipse.jdt.internal.core.JavaElement;
+import org.eclipse.jdt.internal.core.JavaProject;
+import org.eclipse.jdt.internal.core.NameLookup;
+import org.eclipse.jdt.internal.core.Openable;
+import org.eclipse.jdt.internal.core.ResolvedBinaryType;
+import org.eclipse.jdt.internal.core.SearchableEnvironment;
+import org.eclipse.jdt.internal.core.SourceTypeElementInfo;
+import org.eclipse.jdt.internal.core.nd.java.model.BinaryTypeFactory;
import org.eclipse.jdt.internal.core.util.ResourceCompilationUnit;
import org.eclipse.jdt.internal.core.util.Util;
@@ -280,6 +290,7 @@ public abstract class HierarchyBuilder {
protected ICompilationUnit createCompilationUnitFromPath(Openable handle, IFile file) {
final char[] elementName = handle.getElementName().toCharArray();
return new ResourceCompilationUnit(file) {
+ @Override
public char[] getFileName() {
return elementName;
}
@@ -316,33 +327,17 @@ protected IBinaryType createInfoFromClassFile(Openable handle, IResource file) {
* Create a type info from the given class file in a jar and adds it to the given list of infos.
*/
protected IBinaryType createInfoFromClassFileInJar(Openable classFile) {
- PackageFragment pkg = (PackageFragment) classFile.getParent();
- String classFilePath = Util.concatWith(pkg.names, classFile.getElementName(), '/');
- IBinaryType info = null;
- java.util.zip.ZipFile zipFile = null;
+ IClassFile cf = (IClassFile)classFile;
+ IBinaryType info;
try {
- zipFile = ((JarPackageFragmentRoot)pkg.getParent()).getJar();
- info = org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader.read(
- zipFile,
- classFilePath);
- } catch (org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException e) {
- if (TypeHierarchy.DEBUG) {
- e.printStackTrace();
- }
- return null;
- } catch (java.io.IOException e) {
+ info = BinaryTypeFactory.create(cf, null);
+ } catch (JavaModelException | ClassFormatException e) {
if (TypeHierarchy.DEBUG) {
e.printStackTrace();
}
return null;
- } catch (CoreException e) {
- if (TypeHierarchy.DEBUG) {
- e.printStackTrace();
- }
- return null;
- } finally {
- JavaModelManager.getJavaModelManager().closeZipFile(zipFile);
}
+
this.infoToHandle.put(info, classFile);
return info;
}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyResolver.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyResolver.java
index b57e2d5ec..d9a99ff85 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyResolver.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyResolver.java
@@ -87,6 +87,7 @@ public class HierarchyResolver implements ITypeRequestor {
private CompilerOptions options;
HierarchyBuilder builder;
private ReferenceBinding[] typeBindings;
+ private BindingMap<IGenericType> bindingMap = new BindingMap<>();
private int typeIndex;
private IGenericType[] typeModels;
@@ -230,10 +231,9 @@ private IType findSuperClass(IGenericType type, ReferenceBinding typeBinding) {
}
}
}
- for (int t = this.typeIndex; t >= 0; t--) {
- if (TypeBinding.equalsEquals(this.typeBindings[t], superBinding)) {
- return this.builder.getHandle(this.typeModels[t], superBinding);
- }
+ IGenericType typeModel = this.bindingMap.get(superBinding);
+ if (typeModel != null) {
+ return this.builder.getHandle(typeModel, superBinding);
}
}
return null;
@@ -336,13 +336,12 @@ private IType[] findSuperInterfaces(IGenericType type, ReferenceBinding typeBind
// ensure that the binding corresponds to the interface defined by the user
if (CharOperation.equals(simpleName, interfaceBinding.sourceName)) {
bindingIndex++;
- for (int t = this.typeIndex; t >= 0; t--) {
- if (TypeBinding.equalsEquals(this.typeBindings[t], interfaceBinding)) {
- IType handle = this.builder.getHandle(this.typeModels[t], interfaceBinding);
- if (handle != null) {
- superinterfaces[index++] = handle;
- continue next;
- }
+ IGenericType genericType = this.bindingMap.get(interfaceBinding);
+ if (genericType != null) {
+ IType handle = this.builder.getHandle(genericType, interfaceBinding);
+ if (handle != null) {
+ superinterfaces[index++] = handle;
+ continue next;
}
}
}
@@ -438,6 +437,7 @@ private void remember(IGenericType suppliedType, ReferenceBinding typeBinding) {
}
this.typeModels[this.typeIndex] = suppliedType;
this.typeBindings[this.typeIndex] = typeBinding;
+ this.bindingMap.put(typeBinding, suppliedType);
}
private void remember(IType type, ReferenceBinding typeBinding) {
//{ObjectTeams: for phantom roles avoid hitting the JME (phantom has no info) but proceed into else as to record what we have
@@ -740,6 +740,7 @@ private void reset(){
this.typeIndex = -1;
this.typeModels = new IGenericType[5];
this.typeBindings = new ReferenceBinding[5];
+ this.bindingMap.clear();
}
/**
@@ -1062,6 +1063,7 @@ private void setEnvironment(LookupEnvironment lookupEnvironment, HierarchyBuilde
this.typeIndex = -1;
this.typeModels = new IGenericType[5];
this.typeBindings = new ReferenceBinding[5];
+ this.bindingMap.clear();
}
/*
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 4c9d1e7f4..a2342ebc1 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/IndexBasedHierarchyBuilder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/IndexBasedHierarchyBuilder.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -10,6 +10,7 @@
*******************************************************************************/
package org.eclipse.jdt.internal.core.hierarchy;
+import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
@@ -17,9 +18,12 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
+import java.util.Set;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubMonitor;
@@ -50,9 +54,19 @@ import org.eclipse.jdt.internal.core.Member;
import org.eclipse.jdt.internal.core.Openable;
import org.eclipse.jdt.internal.core.PackageFragment;
import org.eclipse.jdt.internal.core.SearchableEnvironment;
+import org.eclipse.jdt.internal.core.nd.IReader;
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.indexer.Indexer;
+import org.eclipse.jdt.internal.core.nd.java.JavaIndex;
+import org.eclipse.jdt.internal.core.nd.java.JavaNames;
+import org.eclipse.jdt.internal.core.nd.java.NdType;
+import org.eclipse.jdt.internal.core.nd.java.NdTypeId;
+import org.eclipse.jdt.internal.core.nd.java.NdTypeInterface;
+import org.eclipse.jdt.internal.core.nd.java.NdTypeSignature;
import org.eclipse.jdt.internal.core.search.IndexQueryRequestor;
import org.eclipse.jdt.internal.core.search.JavaSearchParticipant;
import org.eclipse.jdt.internal.core.search.SubTypeSearchJob;
+import org.eclipse.jdt.internal.core.search.UnindexedSearchScope;
import org.eclipse.jdt.internal.core.search.indexing.IIndexConstants;
import org.eclipse.jdt.internal.core.search.indexing.IndexManager;
import org.eclipse.jdt.internal.core.search.matching.MatchLocator;
@@ -467,7 +481,103 @@ public static void searchAllPossibleSubTypes(
int waitingPolicy, // WaitUntilReadyToSearch | ForceImmediateSearch | CancelIfNotReadyToSearch
final IProgressMonitor monitor) {
- SubMonitor subMonitor = SubMonitor.convert(monitor);
+ if (JavaIndex.isEnabled()) {
+ SubMonitor subMonitor = SubMonitor.convert(monitor, 2);
+ newSearchAllPossibleSubTypes(type, scope, binariesFromIndexMatches, pathRequestor, waitingPolicy,
+ subMonitor.split(1));
+ legacySearchAllPossibleSubTypes(type, UnindexedSearchScope.filterEntriesCoveredByTheNewIndex(scope),
+ binariesFromIndexMatches, pathRequestor, waitingPolicy, subMonitor.split(1));
+ } else {
+ legacySearchAllPossibleSubTypes(type, scope, binariesFromIndexMatches, pathRequestor, waitingPolicy,
+ monitor);
+ }
+}
+
+private static void newSearchAllPossibleSubTypes(IType type, IJavaSearchScope scope2, Map binariesFromIndexMatches2,
+ IPathRequestor pathRequestor, int waitingPolicy, IProgressMonitor progressMonitor) {
+ SubMonitor subMonitor = SubMonitor.convert(progressMonitor, 2);
+ JavaIndex index = JavaIndex.getIndex();
+
+ Indexer.getInstance().waitForIndex(waitingPolicy, subMonitor.split(1));
+
+ Nd nd = index.getNd();
+ char[] fieldDefinition = JavaNames.fullyQualifiedNameToFieldDescriptor(type.getFullyQualifiedName().toCharArray());
+
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+
+ try (IReader reader = nd.acquireReadLock()) {
+ NdTypeId foundType = index.findType(fieldDefinition);
+
+ if (foundType == null) {
+ return;
+ }
+
+ ArrayDeque<NdType> typesToVisit = new ArrayDeque<>();
+ Set<NdType> discoveredTypes = new HashSet<>();
+ typesToVisit.addAll(foundType.getTypes());
+ discoveredTypes.addAll(typesToVisit);
+
+ while (!typesToVisit.isEmpty()) {
+ NdType nextType = typesToVisit.removeFirst();
+ NdTypeId typeId = nextType.getTypeId();
+
+ String typePath = new String(JavaNames.getIndexPathFor(nextType, root));
+ if (!scope2.encloses(typePath)) {
+ continue;
+ }
+
+ subMonitor.setWorkRemaining(Math.max(typesToVisit.size(), 3000)).split(1);
+
+ boolean isLocalClass = nextType.isLocal() || nextType.isAnonymous();
+ pathRequestor.acceptPath(typePath, isLocalClass);
+
+ HierarchyBinaryType binaryType = (HierarchyBinaryType)binariesFromIndexMatches2.get(typePath);
+ if (binaryType == null) {
+ binaryType = createBinaryTypeFrom(nextType);
+ binariesFromIndexMatches2.put(typePath, binaryType);
+ }
+
+ for (NdType subType : typeId.getSubTypes()) {
+ if (discoveredTypes.add(subType)) {
+ typesToVisit.add(subType);
+ }
+ }
+ }
+ }
+}
+
+private static HierarchyBinaryType createBinaryTypeFrom(NdType type) {
+ char[] enclosingTypeName = null;
+ NdTypeSignature enclosingType = type.getDeclaringType();
+ if (enclosingType != null) {
+ enclosingTypeName = enclosingType.getRawType().getBinaryName();
+ }
+ char[][] typeParameters = type.getTypeParameterSignatures();
+ NdTypeId typeId = type.getTypeId();
+ HierarchyBinaryType result = new HierarchyBinaryType(type.getModifiers(), typeId.getBinaryName(),
+ type.getSourceName(), enclosingTypeName, typeParameters.length == 0 ? null : typeParameters);
+
+ NdTypeSignature superClass = type.getSuperclass();
+ if (superClass != null) {
+ result.recordSuperclass(superClass.getRawType().getBinaryName());
+ }
+
+ for (NdTypeInterface interf : type.getInterfaces()) {
+ result.recordInterface(interf.getInterface().getRawType().getBinaryName());
+ }
+ return result;
+}
+
+private static void legacySearchAllPossibleSubTypes(
+ IType type,
+ IJavaSearchScope scope,
+ final Map binariesFromIndexMatches,
+ final IPathRequestor pathRequestor,
+ int waitingPolicy, // WaitUntilReadyToSearch | ForceImmediateSearch | CancelIfNotReadyToSearch
+ final IProgressMonitor progressMonitor) {
+
+ SubMonitor subMonitor = SubMonitor.convert(progressMonitor, 100);
+
/* embed constructs inside arrays so as to pass them to (inner) collector */
final Queue queue = new Queue();
final HashtableOfObject foundSuperNames = new HashtableOfObject(5);

Back to the top