Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java')
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/ClasspathResolver.java25
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/FileFingerprint.java250
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/IndexFilter.java43
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/JavaIndex.java300
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/JavaNames.java222
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotation.java54
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInConstant.java37
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInMethod.java39
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInMethodParameter.java39
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInType.java39
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInVariable.java39
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationValuePair.java70
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdBinding.java122
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdComplexTypeSignature.java201
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstant.java99
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantAnnotation.java56
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantArray.java48
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantBoolean.java57
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantByte.java57
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantChar.java57
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantClass.java56
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantDouble.java57
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantEnum.java68
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantFloat.java57
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantInt.java57
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantLong.java57
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantShort.java57
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantString.java58
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethod.java192
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodException.java61
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodId.java107
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodParameter.java105
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdResourceFile.java260
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTreeNode.java99
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdType.java266
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotation.java122
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotationInMethod.java39
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotationInType.java39
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotationInVariable.java39
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeArgument.java88
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeBound.java61
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeId.java184
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeInterface.java55
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeParameter.java111
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeSignature.java157
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdVariable.java141
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdWorkspaceLocation.java66
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/Package.java44
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/TagTreeReader.java134
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/TypeRef.java97
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeDescriptor.java51
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeFactory.java228
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/ITypeAnnotationBuilder.java32
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/IndexBinaryField.java80
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/IndexBinaryMethod.java182
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/IndexBinaryNestedType.java42
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/IndexBinaryType.java672
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/IndexBinaryTypeAnnotation.java90
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/TypeAnnotationBuilder.java150
59 files changed, 6315 insertions, 0 deletions
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/ClasspathResolver.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/ClasspathResolver.java
new file mode 100644
index 000000000..5e5f638b9
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/ClasspathResolver.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java;
+
+/**
+ * Used for filtering and disambiguating bindings in the index to match the classpath.
+ */
+public interface ClasspathResolver {
+ public static final int NOT_ON_CLASSPATH = -1;
+
+ /**
+ * Returns the priority of the given resource file on the classpath or {@link #NOT_ON_CLASSPATH} if the given file
+ * is not onthe classpath. In the event that the same fully-qualified class name is found in multiple resource
+ * files, the one with the higher priority number is preferred.
+ */
+ int resolve(NdResourceFile sourceOfReference, NdResourceFile toTest);
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/FileFingerprint.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/FileFingerprint.java
new file mode 100644
index 000000000..f1b02622f
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/FileFingerprint.java
@@ -0,0 +1,250 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.eclipse.core.filesystem.EFS;
+import org.eclipse.core.filesystem.IFileInfo;
+import org.eclipse.core.filesystem.IFileStore;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.jdt.internal.core.nd.StreamHasher;
+
+public class FileFingerprint {
+ /**
+ * Sentinel value for {@link #time} indicating a nonexistent fingerprint. This is used for the timestamp of
+ * nonexistent files and for the {@link #getEmpty()} singleton.
+ */
+ public static final long NEVER_MODIFIED = 0;
+
+ /**
+ * Sentinel value for {@link #time} indicating that the timestamp was not recorded as part of the fingerprint.
+ * This is normally used to indicate that the file's timestamp was so close to the current system time at the time
+ * the fingerprint was computed that subsequent changes in the file might not be detected. In such cases, timestamps
+ * are an unreliable method for determining if the file has changed and so are not included as part of the fingerprint.
+ */
+ public static final long UNKNOWN = 1;
+
+ /**
+ * Worst-case accuracy of filesystem timestamps, among all supported platforms (this is currently 1s on linux, 2s on
+ * FAT systems).
+ */
+ private static final long WORST_FILESYSTEM_TIMESTAMP_ACCURACY_MS = 2000;
+
+ private long time;
+ private long hash;
+ private long size;
+
+ private static final FileFingerprint EMPTY = new FileFingerprint(NEVER_MODIFIED,0,0);
+
+ public static final FileFingerprint getEmpty() {
+ return EMPTY;
+ }
+
+ public static final FileFingerprint create(IPath path, IProgressMonitor monitor) throws CoreException {
+ return getEmpty().test(path, monitor).getNewFingerprint();
+ }
+
+ public FileFingerprint(long time, long size, long hash) {
+ super();
+ this.time = time;
+ this.size = size;
+ this.hash = hash;
+ }
+
+ public long getTime() {
+ return this.time;
+ }
+
+ public long getHash() {
+ return this.hash;
+ }
+
+ public long getSize() {
+ return this.size;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + (int) (this.hash ^ (this.hash >>> 32));
+ result = prime * result + (int) (this.size ^ (this.size >>> 32));
+ result = prime * result + (int) (this.time ^ (this.time >>> 32));
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ FileFingerprint other = (FileFingerprint) obj;
+ if (this.hash != other.hash)
+ return false;
+ if (this.size != other.size)
+ return false;
+ if (this.time != other.time)
+ return false;
+ return true;
+ }
+
+ public static class FingerprintTestResult {
+ private boolean matches;
+ private boolean needsNewFingerprint;
+ private FileFingerprint newFingerprint;
+
+ public FingerprintTestResult(boolean matches, boolean needsNewFingerprint, FileFingerprint newFingerprint) {
+ super();
+ this.matches = matches;
+ this.newFingerprint = newFingerprint;
+ this.needsNewFingerprint = needsNewFingerprint;
+ }
+
+ public boolean needsNewFingerprint() {
+ return this.needsNewFingerprint;
+ }
+
+ public boolean matches() {
+ return this.matches;
+ }
+
+ public FileFingerprint getNewFingerprint() {
+ return this.newFingerprint;
+ }
+
+ @Override
+ public String toString() {
+ return "FingerprintTestResult [matches=" + this.matches + ", needsNewFingerprint=" //$NON-NLS-1$//$NON-NLS-2$
+ + this.needsNewFingerprint + ", newFingerprint=" + this.newFingerprint + "]"; //$NON-NLS-1$//$NON-NLS-2$
+ }
+ }
+
+ /**
+ * Compares the given File with the receiver. If the fingerprint matches (ie: the file
+ */
+ public FingerprintTestResult test(IPath path, IProgressMonitor monitor) throws CoreException {
+ SubMonitor subMonitor = SubMonitor.convert(monitor, 100);
+ long currentTime = System.currentTimeMillis();
+ IFileStore store = EFS.getLocalFileSystem().getStore(path);
+ IFileInfo fileInfo = store.fetchInfo();
+
+ long lastModified = fileInfo.getLastModified();
+ if (Math.abs(currentTime - lastModified) < WORST_FILESYSTEM_TIMESTAMP_ACCURACY_MS) {
+ // If the file was modified so recently that it's within our ability to measure it, don't include
+ // the timestamp as part of the fingerprint. If another change were to happen to the file immediately
+ // afterward, we might not be able to detect it using the timestamp.
+ lastModified = UNKNOWN;
+ }
+ subMonitor.split(5);
+
+ long fileSize = fileInfo.getLength();
+ subMonitor.split(5);
+ if (lastModified != UNKNOWN && lastModified == this.time && fileSize == this.size) {
+ return new FingerprintTestResult(true, false, this);
+ }
+
+ long hashCode;
+ try {
+ hashCode = fileSize == 0 ? 0 : computeHashCode(path.toFile(), fileSize, subMonitor.split(90));
+ } catch (IOException e) {
+ throw new CoreException(Package.createStatus("An error occurred computing a hash code", e)); //$NON-NLS-1$
+ }
+ boolean matches = (hashCode == this.hash && fileSize == this.size);
+
+ FileFingerprint newFingerprint = new FileFingerprint(lastModified, fileSize, hashCode);
+ return new FingerprintTestResult(matches, !equals(newFingerprint), newFingerprint);
+ }
+
+ private long computeHashCode(File toTest, long fileSize, IProgressMonitor monitor) throws IOException {
+ final int BUFFER_SIZE = 2048;
+ char[] charBuffer = new char[BUFFER_SIZE];
+ byte[] byteBuffer = new byte[BUFFER_SIZE * 2];
+
+ SubMonitor subMonitor = SubMonitor.convert(monitor, (int) (fileSize / (BUFFER_SIZE * 2)));
+ StreamHasher hasher = new StreamHasher();
+ try {
+ InputStream inputStream = new FileInputStream(toTest);
+ try {
+ while (true) {
+ subMonitor.split(1);
+ int bytesRead = readUntilBufferFull(inputStream, byteBuffer);
+
+ if (bytesRead < byteBuffer.length) {
+ charBuffer = new char[(bytesRead + 1) / 2];
+ copyByteArrayToCharArray(charBuffer, byteBuffer, bytesRead);
+ hasher.addChunk(charBuffer);
+ break;
+ }
+
+ copyByteArrayToCharArray(charBuffer, byteBuffer, bytesRead);
+ hasher.addChunk(charBuffer);
+ }
+ } finally {
+ inputStream.close();
+ }
+
+ } catch (FileNotFoundException e) {
+ return 0;
+ }
+
+ return hasher.computeHash();
+ }
+
+ private void copyByteArrayToCharArray(char[] charBuffer, byte[] byteBuffer, int bytesToCopy) {
+ for (int ch = 0; ch < bytesToCopy / 2; ch++) {
+ char next = (char) (byteBuffer[ch * 2] + byteBuffer[ch * 2 + 1]);
+ charBuffer[ch] = next;
+ }
+
+ if (bytesToCopy % 2 != 0) {
+ charBuffer[bytesToCopy / 2] = (char) byteBuffer[bytesToCopy - 1];
+ }
+ }
+
+ int readUntilBufferFull(InputStream inputStream, byte[] buffer) throws IOException {
+ int bytesRead = 0;
+ while (bytesRead < buffer.length) {
+ int thisRead = inputStream.read(buffer, bytesRead, buffer.length - bytesRead);
+
+ if (thisRead == -1) {
+ return bytesRead;
+ }
+
+ bytesRead += thisRead;
+ }
+ return bytesRead;
+ }
+
+ private static String getTimeString(long timestamp) {
+ if (timestamp == UNKNOWN) {
+ return "UNKNOWN"; //$NON-NLS-1$
+ } else if (timestamp == NEVER_MODIFIED) {
+ return "NEVER_MODIFIED"; //$NON-NLS-1$
+ }
+ return Long.toString(timestamp);
+ }
+
+ @Override
+ public String toString() {
+ return "FileFingerprint [time=" + getTimeString(this.time) + ", size=" + this.size + ", hash=" + this.hash + "]"; //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/IndexFilter.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/IndexFilter.java
new file mode 100644
index 000000000..cc6a90d85
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/IndexFilter.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2016 Wind River Systems, 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:
+ * Markus Schorn - initial API and implementation
+ * Andrew Ferguson (Symbian)
+ * Bryan Wilkinson (QNX)
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core.nd.java;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jdt.core.dom.IBinding;
+
+/**
+ * Can be subclassed and used for queries in the index.
+ */
+public class IndexFilter {
+ public static final IndexFilter ALL = new IndexFilter();
+
+ /**
+ * Get an IndexFilter that accepts everything
+ *
+ * @return an IndexFilter instance
+ */
+ public static IndexFilter getFilter() {
+ return new IndexFilter();
+ }
+
+ /**
+ * Determines whether or not a binding is valid.
+ *
+ * @param binding the binding being checked for validity
+ * @return whether or not the binding is valid
+ * @throws CoreException
+ */
+ public boolean acceptBinding(IBinding binding) throws CoreException {
+ return true;
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/JavaIndex.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/JavaIndex.java
new file mode 100644
index 000000000..006aeff10
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/JavaIndex.java
@@ -0,0 +1,300 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java;
+
+import java.io.File;
+import java.util.List;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.preferences.IPreferencesService;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.NdNode;
+import org.eclipse.jdt.internal.core.nd.NdNodeTypeRegistry;
+import org.eclipse.jdt.internal.core.nd.db.ChunkCache;
+import org.eclipse.jdt.internal.core.nd.db.Database;
+import org.eclipse.jdt.internal.core.nd.field.FieldSearchIndex;
+import org.eclipse.jdt.internal.core.nd.field.FieldSearchIndex.IResultRank;
+import org.eclipse.jdt.internal.core.nd.field.FieldSearchIndex.SearchCriteria;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+import org.eclipse.jdt.internal.core.nd.util.CharArrayUtils;
+
+public class JavaIndex {
+ // Version constants
+ static final int CURRENT_VERSION = Nd.version(1, 37);
+ static final int MAX_SUPPORTED_VERSION = Nd.version(1, 37);
+ static final int MIN_SUPPORTED_VERSION = Nd.version(1, 37);
+
+ // Fields for the search header
+ public static final FieldSearchIndex<NdResourceFile> FILES;
+ public static final FieldSearchIndex<NdTypeId> SIMPLE_INDEX;
+ public static final FieldSearchIndex<NdTypeId> TYPES;
+ public static final FieldSearchIndex<NdMethodId> METHODS;
+
+ public static final StructDef<JavaIndex> type;
+
+ static {
+ type = StructDef.create(JavaIndex.class);
+ FILES = FieldSearchIndex.create(type, NdResourceFile.FILENAME);
+ SIMPLE_INDEX = FieldSearchIndex.create(type, NdTypeId.SIMPLE_NAME);
+ TYPES = FieldSearchIndex.create(type, NdTypeId.FIELD_DESCRIPTOR);
+ METHODS = FieldSearchIndex.create(type, NdMethodId.METHOD_NAME);
+ type.done();
+
+ // This struct needs to fit within the first database chunk.
+ assert type.getFactory().getRecordSize() <= Database.CHUNK_SIZE;
+ }
+
+ private final static class BestResourceFile implements FieldSearchIndex.IResultRank {
+ public BestResourceFile() {
+ }
+
+ @Override
+ public long getRank(Nd resourceFileNd, long resourceFileAddress) {
+ return NdResourceFile.TIME_LAST_SCANNED.get(resourceFileNd, resourceFileAddress);
+ }
+ }
+
+ private static final BestResourceFile bestResourceFile = new BestResourceFile();
+ private final long address;
+ private Nd nd;
+ private IResultRank anyResult = new IResultRank() {
+ @Override
+ public long getRank(Nd dom, long address1) {
+ return 1;
+ }
+ };
+ private static Nd globalNd;
+ private static final String INDEX_FILENAME = "index.db"; //$NON-NLS-1$
+ private final static Object ndMutex = new Object();
+
+ public JavaIndex(Nd dom, long address) {
+ this.address = address;
+ this.nd = dom;
+ }
+
+ /**
+ * Returns the most-recently-scanned resource file with the given name or null if none
+ */
+ public NdResourceFile getResourceFile(char[] location) {
+ return FILES.findBest(this.nd, this.address, FieldSearchIndex.SearchCriteria.create(location),
+ bestResourceFile);
+ }
+
+ /**
+ * Returns true iff the given resource file is up-to-date with the filesystem. Returns false
+ * if the argument is out-of-date with the file system or null.
+ *
+ * @param file the index file to look up or null
+ * @throws CoreException
+ */
+ public boolean isUpToDate(NdResourceFile file) throws CoreException {
+ if (file != null && file.isDoneIndexing()) {
+ // TODO(sxenos): It would be much more efficient to mark files as being in one
+ // of three states: unknown, dirty, or clean. Files would start in the unknown
+ // state and move into the dirty state when we see them in a java model change
+ // event. They would move into the clean state after passing this sort of
+ // fingerprint test... but by caching the state of all tested files (in memory),
+ // it would eliminate the vast majority of these (slow) fingerprint tests.
+
+ Path locationPath = new Path(file.getLocation().getString());
+ if (file.getFingerprint().test(locationPath, null).matches()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public List<NdResourceFile> findResourcesWithPath(String thePath) {
+ return FILES.findAll(this.nd, this.address, FieldSearchIndex.SearchCriteria.create(thePath.toCharArray()));
+ }
+
+ public List<NdResourceFile> getAllResourceFiles() {
+ return FILES.asList(this.nd, this.address);
+ }
+
+ public NdTypeId findType(char[] fieldDescriptor) {
+ SearchCriteria searchCriteria = SearchCriteria.create(fieldDescriptor);
+ return TYPES.findBest(this.nd, this.address, searchCriteria, this.anyResult);
+ }
+
+ public boolean visitFieldDescriptorsStartingWith(char[] fieldDescriptorPrefix, FieldSearchIndex.Visitor<NdTypeId> visitor) {
+ SearchCriteria searchCriteria = SearchCriteria.create(fieldDescriptorPrefix).prefix(true);
+ return TYPES.visitAll(this.nd, this.address, searchCriteria, visitor);
+ }
+
+ /**
+ * Returns a type ID or creates a new one if it does not exist. The caller must
+ * attach a reference to it after calling this method or it may leak.
+ */
+ public NdTypeId createTypeId(char[] fieldDescriptor) {
+ NdTypeId existingType = findType(fieldDescriptor);
+
+ if (existingType != null) {
+ return existingType;
+ }
+
+ if (fieldDescriptor.length > 1) {
+ if (fieldDescriptor[0] == 'L') {
+ if (fieldDescriptor[fieldDescriptor.length - 1] != ';') {
+ throw new IllegalStateException(new String(fieldDescriptor) + " is not a valid field descriptor"); //$NON-NLS-1$
+ }
+ }
+ }
+
+ NdTypeId result = new NdTypeId(this.nd, fieldDescriptor);
+ if (!CharArrayUtils.equals(result.getFieldDescriptor().getChars(), fieldDescriptor)) {
+ throw new IllegalStateException("Field descriptor didn't match"); //$NON-NLS-1$
+ }
+ return result;
+ }
+
+ public Nd getNd() {
+ return this.nd;
+ }
+
+ public NdMethodId findMethodId(char[] methodId) {
+ SearchCriteria searchCriteria = SearchCriteria.create(methodId);
+
+ return METHODS.findBest(this.nd, this.address, searchCriteria, this.anyResult);
+ }
+
+ public NdMethodId createMethodId(char[] methodId) {
+ NdMethodId existingMethod = findMethodId(methodId);
+
+ if (existingMethod != null) {
+ return existingMethod;
+ }
+
+ return new NdMethodId(this.nd, methodId);
+ }
+
+ /**
+ * Returns the absolute filesystem location of the given element or null if none
+ */
+ public static IPath getLocationForElement(IJavaElement next) {
+ IResource resource = next.getResource();
+
+ if (resource != null) {
+ return resource.getLocation() == null ? new Path("") : resource.getLocation(); //$NON-NLS-1$
+ }
+
+ return next.getPath();
+ }
+
+ public static boolean isEnabled() {
+ IPreferencesService preferenceService = Platform.getPreferencesService();
+ if (preferenceService == null) {
+ return true;
+ }
+ return !preferenceService.getBoolean(JavaCore.PLUGIN_ID, "disableNewJavaIndex", false, //$NON-NLS-1$
+ null);
+ }
+
+ public static Nd createNd(File databaseFile, ChunkCache chunkCache) {
+ return new Nd(databaseFile, chunkCache, createTypeRegistry(),
+ MIN_SUPPORTED_VERSION, MAX_SUPPORTED_VERSION, CURRENT_VERSION);
+ }
+
+ public static Nd getGlobalNd() {
+ Nd localNd;
+ synchronized (ndMutex) {
+ localNd = globalNd;
+ }
+
+ if (localNd != null) {
+ return localNd;
+ }
+
+ localNd = createNd(getDBFile(), ChunkCache.getSharedInstance());
+
+ synchronized (ndMutex) {
+ if (globalNd == null) {
+ globalNd = localNd;
+ }
+ return globalNd;
+ }
+ }
+
+ public static JavaIndex getIndex(Nd nd) {
+ return new JavaIndex(nd, Database.DATA_AREA_OFFSET);
+ }
+
+ public static JavaIndex getIndex() {
+ return getIndex(getGlobalNd());
+ }
+
+ public static int getCurrentVersion() {
+ return CURRENT_VERSION;
+ }
+
+ static File getDBFile() {
+ IPath stateLocation = JavaCore.getPlugin().getStateLocation();
+ return stateLocation.append(INDEX_FILENAME).toFile();
+ }
+
+ static NdNodeTypeRegistry<NdNode> createTypeRegistry() {
+ NdNodeTypeRegistry<NdNode> registry = new NdNodeTypeRegistry<>();
+ registry.register(0x0001, NdAnnotation.type.getFactory());
+ registry.register(0x0004, NdAnnotationInConstant.type.getFactory());
+ registry.register(0x0008, NdAnnotationInMethod.type.getFactory());
+ registry.register(0x000c, NdAnnotationInMethodParameter.type.getFactory());
+ registry.register(0x0010, NdAnnotationInType.type.getFactory());
+ registry.register(0x0014, NdAnnotationInVariable.type.getFactory());
+ registry.register(0x0020, NdAnnotationValuePair.type.getFactory());
+ registry.register(0x0028, NdBinding.type.getFactory());
+ registry.register(0x0030, NdComplexTypeSignature.type.getFactory());
+ registry.register(0x0038, NdConstant.type.getFactory());
+ registry.register(0x0040, NdConstantAnnotation.type.getFactory());
+ registry.register(0x0050, NdConstantArray.type.getFactory());
+ registry.register(0x0060, NdConstantBoolean.type.getFactory());
+ registry.register(0x0070, NdConstantByte.type.getFactory());
+ registry.register(0x0080, NdConstantChar.type.getFactory());
+ registry.register(0x0090, NdConstantClass.type.getFactory());
+ registry.register(0x00A0, NdConstantDouble.type.getFactory());
+ registry.register(0x00B0, NdConstantEnum.type.getFactory());
+ registry.register(0x00C0, NdConstantFloat.type.getFactory());
+ registry.register(0x00D0, NdConstantInt.type.getFactory());
+ registry.register(0x00E0, NdConstantLong.type.getFactory());
+ registry.register(0x00F0, NdConstantShort.type.getFactory());
+ registry.register(0x0100, NdConstantString.type.getFactory());
+ registry.register(0x0110, NdMethod.type.getFactory());
+ registry.register(0x0120, NdMethodException.type.getFactory());
+ registry.register(0x0130, NdMethodId.type.getFactory());
+ registry.register(0x0140, NdMethodParameter.type.getFactory());
+ registry.register(0x0150, NdResourceFile.type.getFactory());
+ registry.register(0x0160, NdTreeNode.type.getFactory());
+ registry.register(0x0170, NdType.type.getFactory());
+ registry.register(0x0180, NdTypeAnnotation.type.getFactory());
+ registry.register(0x0184, NdTypeAnnotationInMethod.type.getFactory());
+ registry.register(0x0188, NdTypeAnnotationInType.type.getFactory());
+ registry.register(0x018c, NdTypeAnnotationInVariable.type.getFactory());
+ registry.register(0x0190, NdTypeArgument.type.getFactory());
+ registry.register(0x0194, NdTypeBound.type.getFactory());
+ registry.register(0x01A0, NdTypeInterface.type.getFactory());
+ registry.register(0x01B0, NdTypeParameter.type.getFactory());
+ registry.register(0x01C0, NdTypeSignature.type.getFactory());
+ registry.register(0x01D0, NdTypeId.type.getFactory());
+ registry.register(0x01E0, NdTypeInterface.type.getFactory());
+ registry.register(0x01F0, NdVariable.type.getFactory());
+ registry.register(0x0200, NdWorkspaceLocation.type.getFactory());
+ return registry;
+ }
+
+ public void rebuildIndex() {
+ // TODO: delete and recreate the index
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/JavaNames.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/JavaNames.java
new file mode 100644
index 000000000..0211cb89c
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/JavaNames.java
@@ -0,0 +1,222 @@
+package org.eclipse.jdt.internal.core.nd.java;
+/*******************************************************************************
+ * Copyright (c) 2015, 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
+ *******************************************************************************/
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.core.search.IJavaSearchScope;
+import org.eclipse.jdt.internal.compiler.env.IBinaryType;
+import org.eclipse.jdt.internal.core.nd.util.CharArrayUtils;
+import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
+
+public class JavaNames {
+ private static final char[] CLASS_FILE_SUFFIX = ".class".toCharArray(); //$NON-NLS-1$
+ public static final char[] FIELD_DESCRIPTOR_PREFIX = new char[] { 'L' };
+ private static final char[] FIELD_DESCRIPTOR_SUFFIX = new char[] { ';' };
+ private static final char[] METHOD_ID_SEPARATOR = new char[] { '#' };
+ private static final char[] JAR_FILE_ENTRY_SEPARATOR = IJavaSearchScope.JAR_FILE_ENTRY_SEPARATOR.toCharArray();
+ public static final char[] ARRAY_FIELD_DESCRIPTOR_PREFIX = new char[] { '[' };
+
+ /**
+ * Converts a java binary name to a simple name.
+ */
+ public static char[] binaryNameToSimpleName(char[] binaryName) {
+ int skipIndex = Math.max(
+ Math.max(CharOperation.lastIndexOf('$', binaryName), CharOperation.lastIndexOf('.', binaryName)),
+ CharOperation.lastIndexOf('/', binaryName)) + 1;
+
+ return CharArrayUtils.subarray(binaryName, skipIndex);
+ }
+
+ /**
+ * Given the binary name of a class, returns the jar-relative path of the class file within that
+ * jar, including the .class extension.
+ */
+ public static char[] binaryNameToResourceRelativePath(char[] binaryName) {
+ return CharOperation.concat(binaryName, CLASS_FILE_SUFFIX);
+ }
+
+ public static char[] fullyQualifiedNameToBinaryName(char[] fullyQualifiedName) {
+ return CharOperation.replaceOnCopy(fullyQualifiedName, '.', '/');
+ }
+
+ public static char[] fullyQualifiedNameToFieldDescriptor(char[] fullyQualifiedName) {
+ char[] result = CharArrayUtils.concat(FIELD_DESCRIPTOR_PREFIX, fullyQualifiedName, FIELD_DESCRIPTOR_SUFFIX);
+ CharOperation.replace(result, '.', '/');
+ return result;
+ }
+
+ /**
+ * Given a NdType, returns its identifier in the form accepted by {@link IJavaSearchScope#encloses(String)}
+ */
+ public static char[] getIndexPathFor(NdType type, IWorkspaceRoot root) {
+ NdResourceFile resourceFile = type.getResourceFile();
+
+ char[] binaryName = type.getTypeId().getBinaryName();
+
+ char[] workspaceLocation = null;
+ if (root != null) {
+ workspaceLocation = resourceFile.getAnyOpenWorkspaceLocation(root).toString().toCharArray();
+ }
+
+ if (workspaceLocation == null || workspaceLocation.length == 0) {
+ workspaceLocation = resourceFile.getLocation().getChars();
+ }
+
+ return CharArrayUtils.concat(workspaceLocation, JAR_FILE_ENTRY_SEPARATOR,
+ binaryNameToResourceRelativePath(binaryName));
+ }
+
+ /**
+ * Converts a binary name to a field descriptor (without the trailing ';')
+ */
+ public static char[] binaryNameToFieldDescriptor(char[] binaryName) {
+ return CharArrayUtils.concat(FIELD_DESCRIPTOR_PREFIX, binaryName, FIELD_DESCRIPTOR_SUFFIX);
+ }
+
+ /**
+ * Converts a field descriptor to a simple class name. Returns null if the given field descriptor
+ * doesn't refer to a class or is badly-formed.
+ */
+ public static char[] fieldDescriptorToSimpleName(char[] fieldDescriptor) {
+ if (!CharArrayUtils.startsWith(fieldDescriptor, 'L')) {
+ return null;
+ }
+
+ if (!CharArrayUtils.endsWith(fieldDescriptor, ';')) {
+ return null;
+ }
+
+ int separatorPosition = CharArrayUtils.lastIndexOf('/', fieldDescriptor);
+ if (separatorPosition == -1) {
+ separatorPosition = 0;
+ }
+
+ char[] className = CharArrayUtils.subarray(fieldDescriptor, separatorPosition + 1, fieldDescriptor.length - 1);
+ return className;
+ }
+
+ /**
+ * Converts a field descriptor to a java name. If fullyQualified is true, it returns a fully qualified class name.
+ * If it is false, it returns a source name.
+ */
+ public static char[] fieldDescriptorToJavaName(char[] fieldDescriptor, boolean fullyQualified) {
+ int arrayCount = 0;
+ CharArrayBuffer result = new CharArrayBuffer();
+ for(int scanPosition = 0; scanPosition < fieldDescriptor.length; scanPosition++) {
+ char nextChar = fieldDescriptor[scanPosition];
+
+ switch (nextChar) {
+ case 'B' : result.append("byte"); break; //$NON-NLS-1$
+ case 'C' : result.append("char"); break; //$NON-NLS-1$
+ case 'D' : result.append("double"); break; //$NON-NLS-1$
+ case 'F' : result.append("float"); break; //$NON-NLS-1$
+ case 'I' : result.append("int"); break; //$NON-NLS-1$
+ case 'J' : result.append("long"); break; //$NON-NLS-1$
+ case 'L' : {
+ int end = fieldDescriptor.length - 1;
+ char[] binaryName = CharArrayUtils.subarray(fieldDescriptor, scanPosition + 1, end);
+ if (fullyQualified) {
+ // Modify the binaryName string in-place to change it into a fully qualified name
+ CharOperation.replace(binaryName, '/', '.');
+ result.append(binaryName);
+ } else {
+ result.append(binaryNameToSimpleName(binaryName));
+ }
+ scanPosition += binaryName.length;
+ break;
+ }
+ case 'S' : result.append("short"); break; //$NON-NLS-1$
+ case 'Z' : result.append("boolean"); break; //$NON-NLS-1$
+ case '[' : arrayCount++; break;
+ }
+ }
+
+ while (--arrayCount >= 0) {
+ result.append("[]"); //$NON-NLS-1$
+ }
+
+ return CharArrayUtils.notNull(result.getContents());
+ }
+
+ public static char[] binaryNameToFullyQualifiedName(char[] binaryName) {
+ return CharOperation.replaceOnCopy(binaryName, '/', '.');
+ }
+
+ /**
+ * Returns a method id (suitable for constructing a {@link NdMethodId}) given a field descriptor for its parent type
+ * and a combined method selector and method descriptor for the method
+ *
+ * @param parentTypeBinaryName a field descriptor of the sort returned by the other *ToFieldDescriptor methods.
+ * @param methodSelectorAndDescriptor a method selector and descriptor of the form returned by {@link IBinaryType#getEnclosingMethod()}
+ * @return a method id suitable for looking up a {@link NdMethodId}
+ */
+ public static char[] getMethodId(char[] parentTypeBinaryName, char[] methodSelectorAndDescriptor) {
+ return CharArrayUtils.concat(FIELD_DESCRIPTOR_PREFIX, parentTypeBinaryName, METHOD_ID_SEPARATOR,
+ methodSelectorAndDescriptor);
+ }
+
+ public static char[] getMethodId(char[] parentTypeBinaryName, char[] methodSelector, char[] methodDescriptor) {
+ return CharArrayUtils.concat(FIELD_DESCRIPTOR_PREFIX, parentTypeBinaryName, METHOD_ID_SEPARATOR, methodSelector,
+ methodDescriptor);
+ }
+
+ /**
+ * Given a field descriptor, if the field descriptor points to a class this returns the binary name of the class. If
+ * the field descriptor points to any other type, this returns the empty string. The field descriptor may optionally
+ * contain a trailing ';'.
+ *
+ * @param fieldDescriptor
+ * @return ""
+ */
+ public static char[] fieldDescriptorToBinaryName(char[] fieldDescriptor) {
+ if (CharArrayUtils.startsWith(fieldDescriptor, 'L')) {
+ int end = fieldDescriptor.length - 1;
+ return CharArrayUtils.subarray(fieldDescriptor, 1, end);
+ }
+ return CharArrayUtils.EMPTY_CHAR_ARRAY;
+ }
+
+ /**
+ * Given a simple name, this returns the source name for the type. Note that this won't work for classes that
+ * contain a $ in their source name.
+ */
+ public static char[] simpleNameToSourceName(char[] chars) {
+ int lastSlash = CharOperation.lastIndexOf('/', chars);
+ int lastDollar = CharOperation.lastIndexOf('$', chars);
+ int lastDot = CharOperation.lastIndexOf('.', chars);
+ int startPosition = Math.max(Math.max(lastSlash, lastDollar), lastDot) + 1;
+ while (startPosition < chars.length && Character.isDigit(chars[startPosition])) {
+ startPosition++;
+ }
+ return CharArrayUtils.subarray(chars, startPosition);
+ }
+
+ /**
+ * Returns true iff the given method selector is a constructor.
+ */
+ public static boolean isConstructor(char[] selector) {
+ return selector[0] == '<' && selector.length == 6; // Can only match <init>
+ }
+
+ /**
+ * Returns true iff the given method selector is clinit.
+ */
+ public static boolean isClinit(char[] selector) {
+ return selector[0] == '<' && selector.length == 8; // Can only match <clinit>
+ }
+
+ public static String classFilePathToBinaryName(String classFilePath) {
+ if (classFilePath.endsWith(".class")) { //$NON-NLS-1$
+ return classFilePath.substring(0, classFilePath.length() - 6);
+ }
+ return classFilePath;
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotation.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotation.java
new file mode 100644
index 000000000..9715c100e
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotation.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java;
+
+import java.util.List;
+
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.NdNode;
+import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
+import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+
+public class NdAnnotation extends NdNode {
+ public static final FieldManyToOne<NdTypeSignature> ANNOTATION_TYPE;
+ public static final FieldOneToMany<NdAnnotationValuePair> ELEMENT_VALUE_PAIRS;
+
+ @SuppressWarnings("hiding")
+ public static final StructDef<NdAnnotation> type;
+
+ static {
+ type = StructDef.create(NdAnnotation.class, NdNode.type);
+ ANNOTATION_TYPE = FieldManyToOne.create(type, NdTypeSignature.ANNOTATIONS_OF_THIS_TYPE);
+ ELEMENT_VALUE_PAIRS = FieldOneToMany.create(type, NdAnnotationValuePair.APPLIES_TO);
+ type.done();
+ }
+
+ public NdAnnotation(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ public NdAnnotation(Nd nd) {
+ super(nd);
+ }
+
+ public NdTypeSignature getType() {
+ return ANNOTATION_TYPE.get(getNd(), this.address);
+ }
+
+ public void setType(NdTypeSignature type) {
+ ANNOTATION_TYPE.put(getNd(), this.address, type);
+ }
+
+ public List<NdAnnotationValuePair> getElementValuePairs() {
+ return ELEMENT_VALUE_PAIRS.asList(getNd(), this.address);
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInConstant.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInConstant.java
new file mode 100644
index 000000000..2328a49e8
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInConstant.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * 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.nd.java;
+
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.field.FieldOneToOne;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+
+public class NdAnnotationInConstant extends NdAnnotation {
+ public static final FieldOneToOne<NdConstantAnnotation> OWNER;
+
+ @SuppressWarnings("hiding")
+ public static final StructDef<NdAnnotationInConstant> type;
+
+ static {
+ type = StructDef.create(NdAnnotationInConstant.class, NdAnnotation.type);
+ OWNER = FieldOneToOne.createOwner(type, NdConstantAnnotation.class, NdConstantAnnotation.VALUE);
+ type.done();
+ }
+
+ public NdAnnotationInConstant(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ public NdAnnotationInConstant(Nd nd) {
+ super(nd);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInMethod.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInMethod.java
new file mode 100644
index 000000000..e7e48ebc8
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInMethod.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * 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.nd.java;
+
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+
+public class NdAnnotationInMethod extends NdAnnotation {
+ public static final FieldManyToOne<NdMethod> OWNER;
+
+ @SuppressWarnings("hiding")
+ public static final StructDef<NdAnnotationInMethod> type;
+
+ static {
+ type = StructDef.create(NdAnnotationInMethod.class, NdAnnotation.type);
+ OWNER = FieldManyToOne.createOwner(type, NdMethod.ANNOTATIONS);
+ type.done();
+ }
+
+ public NdAnnotationInMethod(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ public NdAnnotationInMethod(Nd nd, NdMethod owner) {
+ super(nd);
+
+ OWNER.put(getNd(), this.address, owner);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInMethodParameter.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInMethodParameter.java
new file mode 100644
index 000000000..0a4f3fb68
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInMethodParameter.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * 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.nd.java;
+
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+
+public class NdAnnotationInMethodParameter extends NdAnnotation {
+ public static final FieldManyToOne<NdMethodParameter> OWNER;
+
+ @SuppressWarnings("hiding")
+ public static final StructDef<NdAnnotationInMethodParameter> type;
+
+ static {
+ type = StructDef.create(NdAnnotationInMethodParameter.class, NdAnnotation.type);
+ OWNER = FieldManyToOne.createOwner(type, NdMethodParameter.ANNOTATIONS);
+ type.done();
+ }
+
+ public NdAnnotationInMethodParameter(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ public NdAnnotationInMethodParameter(Nd nd, NdMethodParameter owner) {
+ super(nd);
+
+ OWNER.put(getNd(), this.address, owner);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInType.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInType.java
new file mode 100644
index 000000000..c220ed9f0
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInType.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * 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.nd.java;
+
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+
+public class NdAnnotationInType extends NdAnnotation {
+ public static final FieldManyToOne<NdType> OWNER;
+
+ @SuppressWarnings("hiding")
+ public static final StructDef<NdAnnotationInType> type;
+
+ static {
+ type = StructDef.create(NdAnnotationInType.class, NdAnnotation.type);
+ OWNER = FieldManyToOne.createOwner(type, NdType.ANNOTATIONS);
+ type.done();
+ }
+
+ public NdAnnotationInType(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ public NdAnnotationInType(Nd nd, NdType owner) {
+ super(nd);
+
+ OWNER.put(getNd(), this.address, owner);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInVariable.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInVariable.java
new file mode 100644
index 000000000..378b2d44a
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationInVariable.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * 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.nd.java;
+
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+
+public class NdAnnotationInVariable extends NdAnnotation {
+ public static final FieldManyToOne<NdVariable> OWNER;
+
+ @SuppressWarnings("hiding")
+ public static final StructDef<NdAnnotationInVariable> type;
+
+ static {
+ type = StructDef.create(NdAnnotationInVariable.class, NdAnnotation.type);
+ OWNER = FieldManyToOne.createOwner(type, NdVariable.ANNOTATIONS);
+ type.done();
+ }
+
+ public NdAnnotationInVariable(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ public NdAnnotationInVariable(Nd nd, NdVariable owner) {
+ super(nd);
+
+ OWNER.put(getNd(), this.address, owner);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationValuePair.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationValuePair.java
new file mode 100644
index 000000000..f62ceb37b
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdAnnotationValuePair.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java;
+
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.NdNode;
+import org.eclipse.jdt.internal.core.nd.db.IString;
+import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
+import org.eclipse.jdt.internal.core.nd.field.FieldOneToOne;
+import org.eclipse.jdt.internal.core.nd.field.FieldString;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+
+public class NdAnnotationValuePair extends NdNode {
+ public static final FieldManyToOne<NdAnnotation> APPLIES_TO;
+ public static final FieldString NAME;
+ public static final FieldOneToOne<NdConstant> VALUE;
+
+ @SuppressWarnings("hiding")
+ public static final StructDef<NdAnnotationValuePair> type;
+
+ static {
+ type = StructDef.create(NdAnnotationValuePair.class, NdNode.type);
+ APPLIES_TO = FieldManyToOne.createOwner(type, NdAnnotation.ELEMENT_VALUE_PAIRS);
+ NAME = type.addString();
+ VALUE = FieldOneToOne.create(type, NdConstant.class, NdConstant.PARENT_ANNOTATION_VALUE);
+ type.done();
+ }
+
+ public NdAnnotationValuePair(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ public NdAnnotationValuePair(NdAnnotation annotation, char[] name) {
+ super(annotation.getNd());
+ Nd nd = annotation.getNd();
+ APPLIES_TO.put(nd, this.address, annotation);
+ NAME.put(nd, this.address, name);
+ }
+
+ public NdAnnotation getAnnotation() {
+ return APPLIES_TO.get(getNd(), this.address);
+ }
+
+ public IString getName() {
+ return NAME.get(getNd(), this.address);
+ }
+
+ public void setName(String name) {
+ NAME.put(getNd(), this.address, name);
+ }
+
+ /**
+ * Returns the value of this annotation or null if none
+ */
+ public NdConstant getValue() {
+ return VALUE.get(getNd(), this.address);
+ }
+
+ public void setValue(NdConstant value) {
+ VALUE.put(getNd(), this.address, value);
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdBinding.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdBinding.java
new file mode 100644
index 000000000..25938a102
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdBinding.java
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java;
+
+import java.util.List;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.jdt.core.Flags;
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.NdNode;
+import org.eclipse.jdt.internal.core.nd.field.FieldInt;
+import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
+import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
+
+/**
+ * Base class for bindings in the {@link Nd}.
+ */
+public abstract class NdBinding extends NdNode implements IAdaptable {
+ public static final FieldInt MODIFIERS;
+ public static final FieldOneToMany<NdTypeParameter> TYPE_PARAMETERS;
+ public static final FieldManyToOne<NdResourceFile> FILE;
+ public static final FieldOneToMany<NdVariable> VARIABLES;
+
+ @SuppressWarnings("hiding")
+ public static final StructDef<NdBinding> type;
+
+ static {
+ type = StructDef.create(NdBinding.class, NdNode.type);
+ MODIFIERS = type.addInt();
+ TYPE_PARAMETERS = FieldOneToMany.create(type, NdTypeParameter.PARENT);
+ FILE = FieldManyToOne.createOwner(type, NdResourceFile.ALL_NODES);
+ VARIABLES = FieldOneToMany.create(type, NdVariable.PARENT);
+ type.done();
+ }
+
+ public NdBinding(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ public NdBinding(Nd nd, NdResourceFile resource) {
+ super(nd);
+
+ FILE.put(nd, this.address, resource);
+ }
+
+ public List<NdVariable> getVariables() {
+ return VARIABLES.asList(getNd(), this.address);
+ }
+
+ /**
+ * Tests whether this binding has one of the flags defined in {@link Flags}
+ */
+ public boolean hasModifier(int toTest) {
+ return (MODIFIERS.get(getNd(), this.address) & toTest) != 0;
+ }
+
+ /**
+ * Sets the modifiers for this binding (defined in {@link Flags})
+ */
+ public void setModifiers(int toSet) {
+ MODIFIERS.put(getNd(), this.address, toSet);
+ }
+
+ public int getModifiers() {
+ return MODIFIERS.get(getNd(), this.address);
+ }
+
+ @Override
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public Object getAdapter(Class adapter) {
+ if (adapter.isAssignableFrom(NdBinding.class))
+ return this;
+
+ return null;
+ }
+
+ public final int getBindingConstant() {
+ return getNodeType();
+ }
+
+ public void setFile(NdResourceFile file) {
+ FILE.put(getNd(), this.address, file);
+ }
+
+ public NdResourceFile getFile() {
+ return FILE.get(getNd(), this.address);
+ }
+
+ public char[][] getTypeParameterSignatures() {
+ List<NdTypeParameter> parameters = getTypeParameters();
+ char[][] result = new char[parameters.size()][];
+
+ int idx = 0;
+ for (NdTypeParameter next : parameters) {
+ char[] nextContents = getSignatureFor(next);
+ result[idx] = nextContents;
+ idx++;
+ }
+ return result;
+ }
+
+ private char[] getSignatureFor(NdTypeParameter next) {
+ CharArrayBuffer nextArray = new CharArrayBuffer();
+ next.getSignature(nextArray);
+ char[] nextContents = nextArray.getContents();
+ return nextContents;
+ }
+
+ public List<NdTypeParameter> getTypeParameters() {
+ return TYPE_PARAMETERS.asList(getNd(), this.address);
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdComplexTypeSignature.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdComplexTypeSignature.java
new file mode 100644
index 000000000..b348f4ea7
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdComplexTypeSignature.java
@@ -0,0 +1,201 @@
+/*******************************************************************************
+ * 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.nd.java;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.db.IString;
+import org.eclipse.jdt.internal.core.nd.db.IndexException;
+import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
+import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany;
+import org.eclipse.jdt.internal.core.nd.field.FieldString;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
+
+/**
+ * Represents a type signature that is anything other than a trivial reference to a concrete
+ * type. If a type reference includes annotations, generic arguments, wildcards, or is a
+ * type variable, this object represents it.
+ * <p>
+ * Arrays are encoded in a special way. The RAW_TYPE points to a sentinel type called '['
+ * and the first type argument holds the array type.
+ */
+public class NdComplexTypeSignature extends NdTypeSignature {
+ public static final FieldString VARIABLE_IDENTIFIER;
+ public static final FieldManyToOne<NdTypeId> RAW_TYPE;
+ public static final FieldOneToMany<NdTypeArgument> TYPE_ARGUMENTS;
+ public static final FieldManyToOne<NdComplexTypeSignature> DECLARING_TYPE;
+ public static final FieldOneToMany<NdComplexTypeSignature> DECLARED_TYPES;
+
+ @SuppressWarnings("hiding")
+ public static final StructDef<NdComplexTypeSignature> type;
+
+ static {
+ type = StructDef.create(NdComplexTypeSignature.class, NdTypeSignature.type);
+ VARIABLE_IDENTIFIER = type.addString();
+ RAW_TYPE = FieldManyToOne.create(type, NdTypeId.USED_AS_COMPLEX_TYPE);
+ TYPE_ARGUMENTS = FieldOneToMany.create(type, NdTypeArgument.PARENT);
+ DECLARING_TYPE = FieldManyToOne.create(type, null);
+ DECLARED_TYPES = FieldOneToMany.create(type, DECLARING_TYPE);
+
+ type.useStandardRefCounting().done();
+ }
+
+ public NdComplexTypeSignature(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ public NdComplexTypeSignature(Nd nd) {
+ super(nd);
+ }
+
+ @Override
+ public NdTypeId getRawType() {
+ return RAW_TYPE.get(getNd(), this.address);
+ }
+
+ public void setVariableIdentifier(char[] variableIdentifier) {
+ VARIABLE_IDENTIFIER.put(getNd(), this.address, variableIdentifier);
+ }
+
+ /**
+ * If this type is a type variable, this returns the variable's identifier.
+ */
+ public IString getVariableIdentifier() {
+ return VARIABLE_IDENTIFIER.get(getNd(), this.address);
+ }
+
+ public void setRawType(NdTypeId rawType) {
+ RAW_TYPE.put(getNd(), this.address, rawType);
+ }
+
+ public void setGenericDeclaringType(NdComplexTypeSignature enclosingType) {
+ DECLARING_TYPE.put(getNd(), this.address, enclosingType);
+ }
+
+ /**
+ * Returns the declaring type (as reported by the type's generic signature).
+ * Not to be confused with the declaring type as stored in the class file.
+ * That is stored in {@link NdType#getDeclaringType}. Any class that is
+ * nested inside another class with generic arguments will have one of
+ * these. Classes nested inside non-generic classes won't have one of these,
+ * and neither will non-nested classes.
+ */
+ public NdComplexTypeSignature getGenericDeclaringType() {
+ return DECLARING_TYPE.get(getNd(), this.address);
+ }
+
+ @Override
+ public List<NdTypeArgument> getTypeArguments() {
+ return TYPE_ARGUMENTS.asList(getNd(), this.address);
+ }
+
+ @Override
+ public NdTypeSignature getArrayDimensionType() {
+ if (isArrayType()) {
+ long size = TYPE_ARGUMENTS.size(getNd(), this.address);
+
+ if (size != 1) {
+ throw new IndexException("Array types should have exactly one argument"); //$NON-NLS-1$
+ }
+
+ return TYPE_ARGUMENTS.get(getNd(), this.address, 0).getType();
+ }
+ return null;
+ }
+
+ @Override
+ public void getSignature(CharArrayBuffer result, boolean includeTrailingSemicolon) {
+ NdComplexTypeSignature parentSignature = getGenericDeclaringType();
+
+ if (isTypeVariable()) {
+ result.append('T');
+ result.append(getVariableIdentifier().getChars());
+ if (includeTrailingSemicolon) {
+ result.append(';');
+ }
+ return;
+ }
+
+ NdTypeSignature arrayDimension = getArrayDimensionType();
+ if (arrayDimension != null) {
+ result.append('[');
+ arrayDimension.getSignature(result);
+ return;
+ }
+ if (parentSignature != null) {
+ parentSignature.getSignature(result, false);
+ result.append('.');
+ char[] simpleName = getRawType().getSimpleName().getChars();
+ result.append(simpleName);
+ } else {
+ result.append(getRawType().getFieldDescriptorWithoutTrailingSemicolon());
+ }
+
+ List<NdTypeArgument> arguments = getTypeArguments();
+ if (!arguments.isEmpty()) {
+ result.append('<');
+ for (NdTypeArgument next : arguments) {
+ next.getSignature(result);
+ }
+ result.append('>');
+ }
+ if (includeTrailingSemicolon) {
+ result.append(';');
+ }
+ }
+
+ @Override
+ public boolean isTypeVariable() {
+ return getVariableIdentifier().length() != 0;
+ }
+
+ @Override
+ public List<NdTypeSignature> getDeclaringTypeChain() {
+ NdComplexTypeSignature declaringType = getGenericDeclaringType();
+
+ if (declaringType == null) {
+ return Collections.singletonList((NdTypeSignature)this);
+ }
+
+ List<NdTypeSignature> result = new ArrayList<>();
+ computeDeclaringTypes(result);
+ return result;
+ }
+
+ private void computeDeclaringTypes(List<NdTypeSignature> result) {
+ NdComplexTypeSignature declaringType = getGenericDeclaringType();
+
+ if (declaringType != null) {
+ declaringType.computeDeclaringTypes(result);
+ }
+
+ result.add(this);
+ }
+
+ @Override
+ public boolean isArrayType() {
+ NdTypeId rawType = getRawType();
+
+ if (rawType == null) {
+ return false;
+ }
+
+ if (rawType.getFieldDescriptor().comparePrefix(JavaNames.ARRAY_FIELD_DESCRIPTOR_PREFIX, true) == 0) { // $NON-NLS-1$
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstant.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstant.java
new file mode 100644
index 000000000..96e604588
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstant.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java;
+
+import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.NdNode;
+import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
+import org.eclipse.jdt.internal.core.nd.field.FieldOneToOne;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+
+public abstract class NdConstant extends NdNode {
+ // Parent pointers. Only one will be non-null.
+ // TODO(sxenos): Create something like a union to hold these, to eliminate this
+ // sparse data
+ public static final FieldManyToOne<NdConstantArray> PARENT_ARRAY;
+ public static final FieldOneToOne<NdAnnotationValuePair> PARENT_ANNOTATION_VALUE;
+ public static final FieldOneToOne<NdVariable> PARENT_VARIABLE;
+ public static final FieldOneToOne<NdMethod> PARENT_METHOD;
+
+ @SuppressWarnings("hiding")
+ public static StructDef<NdConstant> type;
+
+ static {
+ type = StructDef.createAbstract(NdConstant.class, NdNode.type);
+ PARENT_ARRAY = FieldManyToOne.createOwner(type, NdConstantArray.ELEMENTS);
+ PARENT_ANNOTATION_VALUE = FieldOneToOne.createOwner(type, NdAnnotationValuePair.class,
+ NdAnnotationValuePair.VALUE);
+ PARENT_VARIABLE = FieldOneToOne.createOwner(type, NdVariable.class, NdVariable.CONSTANT);
+ PARENT_METHOD = FieldOneToOne.createOwner(type, NdMethod.class, NdMethod.DEFAULT_VALUE);
+ type.done();
+ }
+
+ public NdConstant(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ protected NdConstant(Nd nd) {
+ super(nd);
+ }
+
+ public static NdConstant create(Nd nd, Constant constant) {
+ if (constant == Constant.NotAConstant) {
+ return null;
+ }
+
+ switch (constant.typeID()) {
+ case TypeIds.T_boolean:
+ return NdConstantBoolean.create(nd, constant.booleanValue());
+ case TypeIds.T_byte:
+ return NdConstantByte.create(nd, constant.byteValue());
+ case TypeIds.T_char:
+ return NdConstantChar.create(nd, constant.charValue());
+ case TypeIds.T_double:
+ return NdConstantDouble.create(nd, constant.doubleValue());
+ case TypeIds.T_float:
+ return NdConstantFloat.create(nd, constant.floatValue());
+ case TypeIds.T_int:
+ return NdConstantInt.create(nd, constant.intValue());
+ case TypeIds.T_long:
+ return NdConstantLong.create(nd, constant.longValue());
+ case TypeIds.T_short:
+ return NdConstantShort.create(nd, constant.shortValue());
+ case TypeIds.T_JavaLangString:
+ return NdConstantString.create(nd, constant.stringValue());
+ default:
+ throw new IllegalArgumentException("Unknown typeID() " + constant.typeID()); //$NON-NLS-1$
+ }
+ }
+
+ public void setParent(NdConstantArray result) {
+ PARENT_ARRAY.put(getNd(), this.address, result);
+ }
+
+ /**
+ * Returns the {@link Constant} corresponding to the value of this {@link NdConstant} or null if the receiver
+ * corresponds to a {@link Constant}.
+ */
+ public abstract Constant getConstant();
+
+ public String toString() {
+ try {
+ return getConstant().toString();
+ } catch (RuntimeException e) {
+ // This is called most often from the debugger, so we want to return something meaningful even
+ // if the code is buggy, the database is corrupt, or we don't have a read lock.
+ return super.toString();
+ }
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantAnnotation.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantAnnotation.java
new file mode 100644
index 000000000..a69e52c4c
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantAnnotation.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java;
+
+import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.field.FieldOneToOne;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+
+public final class NdConstantAnnotation extends NdConstant {
+ public static final FieldOneToOne<NdAnnotationInConstant> VALUE;
+
+ @SuppressWarnings("hiding")
+ public static StructDef<NdConstantAnnotation> type;
+
+ static {
+ type = StructDef.create(NdConstantAnnotation.class, NdConstant.type);
+ VALUE = FieldOneToOne.create(type, NdAnnotationInConstant.class, NdAnnotationInConstant.OWNER);
+ type.done();
+ }
+
+ public NdConstantAnnotation(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ protected NdConstantAnnotation(Nd nd) {
+ super(nd);
+ }
+
+ public static NdConstantAnnotation create(Nd nd, NdAnnotationInConstant value) {
+ NdConstantAnnotation result = new NdConstantAnnotation(nd);
+ result.setValue(value);
+ return result;
+ }
+
+ public void setValue(NdAnnotationInConstant value) {
+ VALUE.put(getNd(), this.address, value);
+ }
+
+ public NdAnnotation getValue() {
+ return VALUE.get(getNd(), this.address);
+ }
+
+ @Override
+ public Constant getConstant() {
+ return null;
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantArray.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantArray.java
new file mode 100644
index 000000000..b9833ce02
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantArray.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java;
+
+import java.util.List;
+
+import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+
+public final class NdConstantArray extends NdConstant {
+ public static final FieldOneToMany<NdConstant> ELEMENTS;
+
+ @SuppressWarnings("hiding")
+ public static StructDef<NdConstantArray> type;
+
+ static {
+ type = StructDef.create(NdConstantArray.class, NdConstant.type);
+ ELEMENTS = FieldOneToMany.create(type, NdConstant.PARENT_ARRAY, 2);
+ type.done();
+ }
+
+ public NdConstantArray(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ public NdConstantArray(Nd nd) {
+ super(nd);
+ }
+
+ public List<NdConstant> getValue() {
+ return ELEMENTS.asList(getNd(), this.address);
+ }
+
+ @Override
+ public Constant getConstant() {
+ return null;
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantBoolean.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantBoolean.java
new file mode 100644
index 000000000..564f7a79b
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantBoolean.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java;
+
+import org.eclipse.jdt.internal.compiler.impl.BooleanConstant;
+import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.field.FieldByte;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+
+public final class NdConstantBoolean extends NdConstant {
+ public static final FieldByte VALUE;
+
+ @SuppressWarnings("hiding")
+ public static StructDef<NdConstantBoolean> type;
+
+ static {
+ type = StructDef.create(NdConstantBoolean.class, NdConstant.type);
+ VALUE = type.addByte();
+ type.done();
+ }
+
+ public NdConstantBoolean(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ protected NdConstantBoolean(Nd nd) {
+ super(nd);
+ }
+
+ public static NdConstantBoolean create(Nd nd, boolean value) {
+ NdConstantBoolean result = new NdConstantBoolean(nd);
+ result.setValue(value);
+ return result;
+ }
+
+ public void setValue(boolean value) {
+ VALUE.put(getNd(), this.address, value ? (byte)1 : (byte)0);
+ }
+
+ public boolean getValue() {
+ return VALUE.get(getNd(), this.address) != 0;
+ }
+
+ @Override
+ public Constant getConstant() {
+ return BooleanConstant.fromValue(getValue());
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantByte.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantByte.java
new file mode 100644
index 000000000..77c99ec56
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantByte.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java;
+
+import org.eclipse.jdt.internal.compiler.impl.ByteConstant;
+import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.field.FieldByte;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+
+public final class NdConstantByte extends NdConstant {
+ public static final FieldByte VALUE;
+
+ @SuppressWarnings("hiding")
+ public static StructDef<NdConstantByte> type;
+
+ static {
+ type = StructDef.create(NdConstantByte.class, NdConstant.type);
+ VALUE = type.addByte();
+ type.done();
+ }
+
+ public NdConstantByte(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ protected NdConstantByte(Nd nd) {
+ super(nd);
+ }
+
+ public static NdConstantByte create(Nd nd, byte value) {
+ NdConstantByte result = new NdConstantByte(nd);
+ result.setValue(value);
+ return result;
+ }
+
+ public void setValue(byte value) {
+ VALUE.put(getNd(), this.address, value);
+ }
+
+ public byte getValue() {
+ return VALUE.get(getNd(), this.address);
+ }
+
+ @Override
+ public Constant getConstant() {
+ return ByteConstant.fromValue(getValue());
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantChar.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantChar.java
new file mode 100644
index 000000000..f54975add
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantChar.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java;
+
+import org.eclipse.jdt.internal.compiler.impl.CharConstant;
+import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.field.FieldChar;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+
+public final class NdConstantChar extends NdConstant {
+ public static final FieldChar VALUE;
+
+ @SuppressWarnings("hiding")
+ public static StructDef<NdConstantChar> type;
+
+ static {
+ type = StructDef.create(NdConstantChar.class, NdConstant.type);
+ VALUE = type.addChar();
+ type.done();
+ }
+
+ public NdConstantChar(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ protected NdConstantChar(Nd nd) {
+ super(nd);
+ }
+
+ public static NdConstantChar create(Nd nd, char value) {
+ NdConstantChar result = new NdConstantChar(nd);
+ result.setValue(value);
+ return result;
+ }
+
+ public void setValue(char value) {
+ VALUE.put(getNd(), this.address, value);
+ }
+
+ public char getValue() {
+ return VALUE.get(getNd(), this.address);
+ }
+
+ @Override
+ public Constant getConstant() {
+ return CharConstant.fromValue(getValue());
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantClass.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantClass.java
new file mode 100644
index 000000000..fc6fc6c90
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantClass.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java;
+
+import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+
+public final class NdConstantClass extends NdConstant {
+ public static final FieldManyToOne<NdTypeSignature> VALUE;
+
+ @SuppressWarnings("hiding")
+ public static StructDef<NdConstantClass> type;
+
+ static {
+ type = StructDef.create(NdConstantClass.class, NdConstant.type);
+ VALUE = FieldManyToOne.create(type, NdTypeSignature.USED_AS_CONSTANT);
+ type.done();
+ }
+
+ public NdConstantClass(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ protected NdConstantClass(Nd nd) {
+ super(nd);
+ }
+
+ public static NdConstantClass create(Nd nd, NdTypeSignature value) {
+ NdConstantClass result = new NdConstantClass(nd);
+ result.setValue(value);
+ return result;
+ }
+
+ public void setValue(NdTypeSignature value) {
+ VALUE.put(getNd(), this.address, value);
+ }
+
+ public NdTypeSignature getValue() {
+ return VALUE.get(getNd(), this.address);
+ }
+
+ @Override
+ public Constant getConstant() {
+ return null;
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantDouble.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantDouble.java
new file mode 100644
index 000000000..56354ba0a
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantDouble.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java;
+
+import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.compiler.impl.DoubleConstant;
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.field.FieldDouble;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+
+public final class NdConstantDouble extends NdConstant {
+ public static final FieldDouble VALUE;
+
+ @SuppressWarnings("hiding")
+ public static StructDef<NdConstantDouble> type;
+
+ static {
+ type = StructDef.create(NdConstantDouble.class, NdConstant.type);
+ VALUE = type.addDouble();
+ type.done();
+ }
+
+ public NdConstantDouble(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ protected NdConstantDouble(Nd nd) {
+ super(nd);
+ }
+
+ public static NdConstantDouble create(Nd nd, double value) {
+ NdConstantDouble result = new NdConstantDouble(nd);
+ result.setValue(value);
+ return result;
+ }
+
+ public void setValue(double value) {
+ VALUE.put(getNd(), this.address, value);
+ }
+
+ public double getValue() {
+ return VALUE.get(getNd(), this.address);
+ }
+
+ @Override
+ public Constant getConstant() {
+ return DoubleConstant.fromValue(getValue());
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantEnum.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantEnum.java
new file mode 100644
index 000000000..c4e9c8e99
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantEnum.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java;
+
+import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
+import org.eclipse.jdt.internal.core.nd.field.FieldString;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+
+public final class NdConstantEnum extends NdConstant {
+ public static final FieldManyToOne<NdTypeSignature> ENUM_TYPE;
+ public static final FieldString ENUM_VALUE;
+
+ @SuppressWarnings("hiding")
+ public static StructDef<NdConstantEnum> type;
+
+ static {
+ type = StructDef.create(NdConstantEnum.class, NdConstant.type);
+ ENUM_TYPE = FieldManyToOne.create(type, NdTypeSignature.USED_AS_ENUM_CONSTANT);
+ ENUM_VALUE = type.addString();
+ type.done();
+ }
+
+ public NdConstantEnum(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ protected NdConstantEnum(Nd nd) {
+ super(nd);
+ }
+
+ public static NdConstantEnum create(NdTypeSignature enumType, String enumValue) {
+ NdConstantEnum result = new NdConstantEnum(enumType.getNd());
+ result.setEnumType(enumType);
+ result.setEnumValue(enumValue);
+ return result;
+ }
+
+ public void setEnumType(NdTypeSignature enumType) {
+ ENUM_TYPE.put(getNd(), this.address, enumType);
+ }
+
+ public void setEnumValue(String enumType) {
+ ENUM_VALUE.put(getNd(), this.address, enumType);
+ }
+
+ public NdTypeSignature getType() {
+ return ENUM_TYPE.get(getNd(), this.address);
+ }
+
+ public char[] getValue() {
+ return ENUM_VALUE.get(getNd(), this.address).getChars();
+ }
+
+ @Override
+ public Constant getConstant() {
+ return null;
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantFloat.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantFloat.java
new file mode 100644
index 000000000..731405eeb
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantFloat.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java;
+
+import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.compiler.impl.FloatConstant;
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.field.FieldFloat;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+
+public final class NdConstantFloat extends NdConstant {
+ public static final FieldFloat VALUE;
+
+ @SuppressWarnings("hiding")
+ public static StructDef<NdConstantFloat> type;
+
+ static {
+ type = StructDef.create(NdConstantFloat.class, NdConstant.type);
+ VALUE = type.addFloat();
+ type.done();
+ }
+
+ public NdConstantFloat(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ protected NdConstantFloat(Nd nd) {
+ super(nd);
+ }
+
+ public static NdConstantFloat create(Nd nd, float value) {
+ NdConstantFloat result = new NdConstantFloat(nd);
+ result.setValue(value);
+ return result;
+ }
+
+ public void setValue(float value) {
+ VALUE.put(getNd(), this.address, value);
+ }
+
+ public float getValue() {
+ return VALUE.get(getNd(), this.address);
+ }
+
+ @Override
+ public Constant getConstant() {
+ return FloatConstant.fromValue(getValue());
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantInt.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantInt.java
new file mode 100644
index 000000000..f66367500
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantInt.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java;
+
+import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.compiler.impl.IntConstant;
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.field.FieldInt;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+
+public final class NdConstantInt extends NdConstant {
+ public static final FieldInt VALUE;
+
+ @SuppressWarnings("hiding")
+ public static StructDef<NdConstantInt> type;
+
+ static {
+ type = StructDef.create(NdConstantInt.class, NdConstant.type);
+ VALUE = type.addInt();
+ type.done();
+ }
+
+ public NdConstantInt(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ protected NdConstantInt(Nd nd) {
+ super(nd);
+ }
+
+ public static NdConstantInt create(Nd nd, int value) {
+ NdConstantInt result = new NdConstantInt(nd);
+ result.setValue(value);
+ return result;
+ }
+
+ public void setValue(int value) {
+ VALUE.put(getNd(), this.address, value);
+ }
+
+ public int getValue() {
+ return VALUE.get(getNd(), this.address);
+ }
+
+ @Override
+ public Constant getConstant() {
+ return IntConstant.fromValue(getValue());
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantLong.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantLong.java
new file mode 100644
index 000000000..9bed54698
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantLong.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java;
+
+import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.compiler.impl.LongConstant;
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.field.FieldLong;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+
+public final class NdConstantLong extends NdConstant {
+ public static final FieldLong VALUE;
+
+ @SuppressWarnings("hiding")
+ public static StructDef<NdConstantLong> type;
+
+ static {
+ type = StructDef.create(NdConstantLong.class, NdConstant.type);
+ VALUE = type.addLong();
+ type.done();
+ }
+
+ public NdConstantLong(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ protected NdConstantLong(Nd nd) {
+ super(nd);
+ }
+
+ public static NdConstantLong create(Nd nd, long value) {
+ NdConstantLong result = new NdConstantLong(nd);
+ result.setValue(value);
+ return result;
+ }
+
+ public void setValue(long value) {
+ VALUE.put(getNd(), this.address, value);
+ }
+
+ public long getValue() {
+ return VALUE.get(getNd(), this.address);
+ }
+
+ @Override
+ public Constant getConstant() {
+ return LongConstant.fromValue(getValue());
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantShort.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantShort.java
new file mode 100644
index 000000000..3c9fa0f8f
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantShort.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java;
+
+import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.compiler.impl.ShortConstant;
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.field.FieldShort;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+
+public final class NdConstantShort extends NdConstant {
+ public static final FieldShort VALUE;
+
+ @SuppressWarnings("hiding")
+ public static StructDef<NdConstantShort> type;
+
+ static {
+ type = StructDef.create(NdConstantShort.class, NdConstant.type);
+ VALUE = type.addShort();
+ type.done();
+ }
+
+ public NdConstantShort(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ protected NdConstantShort(Nd nd) {
+ super(nd);
+ }
+
+ public static NdConstantShort create(Nd nd, short value) {
+ NdConstantShort result = new NdConstantShort(nd);
+ result.setValue(value);
+ return result;
+ }
+
+ public void setValue(short value) {
+ VALUE.put(getNd(), this.address, value);
+ }
+
+ public short getValue() {
+ return VALUE.get(getNd(), this.address);
+ }
+
+ @Override
+ public Constant getConstant() {
+ return ShortConstant.fromValue(getValue());
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantString.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantString.java
new file mode 100644
index 000000000..4c1aeffbc
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdConstantString.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java;
+
+import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.compiler.impl.StringConstant;
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.db.IString;
+import org.eclipse.jdt.internal.core.nd.field.FieldString;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+
+public final class NdConstantString extends NdConstant {
+ public static final FieldString VALUE;
+
+ @SuppressWarnings("hiding")
+ public static StructDef<NdConstantString> type;
+
+ static {
+ type = StructDef.create(NdConstantString.class, NdConstant.type);
+ VALUE = type.addString();
+ type.done();
+ }
+
+ public NdConstantString(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ protected NdConstantString(Nd nd) {
+ super(nd);
+ }
+
+ public static NdConstantString create(Nd nd, String value) {
+ NdConstantString result = new NdConstantString(nd);
+ result.setValue(value);
+ return result;
+ }
+
+ public void setValue(String value) {
+ VALUE.put(getNd(), this.address, value);
+ }
+
+ public IString getValue() {
+ return VALUE.get(getNd(), this.address);
+ }
+
+ @Override
+ public Constant getConstant() {
+ return StringConstant.fromValue(getValue().getString());
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethod.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethod.java
new file mode 100644
index 000000000..77991be21
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethod.java
@@ -0,0 +1,192 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java;
+
+import java.util.List;
+
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.field.FieldLong;
+import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
+import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany;
+import org.eclipse.jdt.internal.core.nd.field.FieldOneToOne;
+import org.eclipse.jdt.internal.core.nd.field.FieldShort;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+import org.eclipse.jdt.internal.core.nd.util.CharArrayUtils;
+import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
+
+public class NdMethod extends NdBinding {
+ public static final FieldManyToOne<NdMethodId> METHOD_ID;
+ public static final FieldShort METHOD_FLAGS;
+ public static final FieldManyToOne<NdType> PARENT;
+ public static final FieldOneToMany<NdVariable> DECLARED_VARIABLES;
+ public static final FieldOneToMany<NdMethodParameter> PARAMETERS;
+ public static final FieldOneToOne<NdConstant> DEFAULT_VALUE;
+ public static final FieldOneToMany<NdMethodException> EXCEPTIONS;
+ public static final FieldManyToOne<NdTypeSignature> RETURN_TYPE;
+ public static final FieldLong TAG_BITS;
+ public static final FieldOneToMany<NdAnnotationInMethod> ANNOTATIONS;
+ public static final FieldOneToMany<NdTypeAnnotationInMethod> TYPE_ANNOTATIONS;
+
+ @SuppressWarnings("hiding")
+ public static final StructDef<NdMethod> type;
+
+ static {
+ type = StructDef.create(NdMethod.class, NdBinding.type);
+ METHOD_ID = FieldManyToOne.create(type, NdMethodId.METHODS);
+ METHOD_FLAGS = type.addShort();
+ PARENT = FieldManyToOne.create(type, NdType.METHODS);
+ PARAMETERS = FieldOneToMany.create(type, NdMethodParameter.PARENT);
+ DECLARED_VARIABLES = FieldOneToMany.create(type, NdVariable.DECLARING_METHOD);
+ DEFAULT_VALUE = FieldOneToOne.create(type, NdConstant.class, NdConstant.PARENT_METHOD);
+ EXCEPTIONS = FieldOneToMany.create(type, NdMethodException.PARENT);
+ RETURN_TYPE = FieldManyToOne.create(type, NdTypeSignature.USED_AS_RETURN_TYPE);
+ TAG_BITS = type.addLong();
+ ANNOTATIONS = FieldOneToMany.create(type, NdAnnotationInMethod.OWNER);
+ TYPE_ANNOTATIONS = FieldOneToMany.create(type, NdTypeAnnotationInMethod.OWNER);
+ type.done();
+ }
+
+ public static final byte FLG_GENERIC_SIGNATURE_PRESENT = 0x0001;
+ public static final byte FLG_THROWS_SIGNATURE_PRESENT = 0x0002;
+
+ public NdMethod(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ public NdMethod(NdType parent) {
+ super(parent.getNd(), parent.getFile());
+
+ PARENT.put(getNd(), this.address, parent);
+ }
+
+ public NdMethodId getMethodId() {
+ return METHOD_ID.get(getNd(), this.address);
+ }
+
+ /**
+ * Returns method parameter names that were not defined by the compiler.
+ */
+ public char[][] getParameterNames() {
+ List<NdMethodParameter> params = getMethodParameters();
+
+ // Use index to count the "real" parameters.
+ int index = 0;
+ char[][] result = new char[params.size()][];
+ for (int idx = 0; idx < result.length; idx++) {
+ NdMethodParameter param = params.get(idx);
+ if (!param.isCompilerDefined()) {
+ result[index] = param.getName().getChars();
+ index++;
+ }
+ }
+ return CharArrayUtils.subarray(result, 0, index);
+ }
+
+ public List<NdMethodParameter> getMethodParameters() {
+ return PARAMETERS.asList(getNd(), this.address);
+ }
+
+ public List<NdAnnotationInMethod> getAnnotations() {
+ return ANNOTATIONS.asList(getNd(), this.address);
+ }
+
+ public void setDefaultValue(NdConstant value) {
+ DEFAULT_VALUE.put(getNd(), this.address, value);
+ }
+
+ public NdConstant getDefaultValue() {
+ return DEFAULT_VALUE.get(getNd(), this.address);
+ }
+
+ public void setReturnType(NdTypeSignature createTypeSignature) {
+ RETURN_TYPE.put(getNd(), this.address, createTypeSignature);
+ }
+
+ public void setMethodId(NdMethodId methodId) {
+ METHOD_ID.put(getNd(), this.address, methodId);
+ }
+
+ public List<NdTypeAnnotationInMethod> getTypeAnnotations() {
+ return TYPE_ANNOTATIONS.asList(getNd(), this.address);
+ }
+
+ public List<NdMethodException> getExceptions() {
+ return EXCEPTIONS.asList(getNd(), this.address);
+ }
+
+ /**
+ * Returns the return type for this method or null if the method returns void
+ */
+ public NdTypeSignature getReturnType() {
+ return RETURN_TYPE.get(getNd(), this.address);
+ }
+
+ public int getFlags() {
+ return METHOD_FLAGS.get(getNd(), this.address);
+ }
+
+ public boolean hasAllFlags(int flags) {
+ int ourFlags = getFlags();
+
+ return (ourFlags & flags) == flags;
+ }
+
+ public void setFlags(int flags) {
+ METHOD_FLAGS.put(getNd(), this.address, (short) (getFlags() | flags));
+ }
+
+ public void setTagBits(long bits) {
+ TAG_BITS.put(getNd(), this.address, bits);
+ }
+
+ public long getTagBits() {
+ return TAG_BITS.get(getNd(), this.address);
+ }
+
+ public String toString() {
+ try {
+ CharArrayBuffer arrayBuffer = new CharArrayBuffer();
+ arrayBuffer.append(getMethodId().getSelector());
+ getGenericSignature(arrayBuffer, true);
+ return arrayBuffer.toString();
+ } catch (RuntimeException e) {
+ // This is called most often from the debugger, so we want to return something meaningful even
+ // if the code is buggy, the database is corrupt, or we don't have a read lock.
+ return super.toString();
+ }
+ }
+
+ public void getGenericSignature(CharArrayBuffer result, boolean includeExceptions) {
+ NdTypeParameter.getSignature(result, getTypeParameters());
+
+ result.append('(');
+ for (NdMethodParameter next : getMethodParameters()) {
+ // Compiler-defined arguments don't show up in the generic signature
+ if (!next.isCompilerDefined()) {
+ next.getType().getSignature(result);
+ }
+ }
+ result.append(')');
+ NdTypeSignature returnType = getReturnType();
+ if (returnType == null) {
+ result.append('V');
+ } else {
+ returnType.getSignature(result);
+ }
+ if (includeExceptions) {
+ List<NdMethodException> exceptions = getExceptions();
+ for (NdMethodException next : exceptions) {
+ result.append('^');
+ next.getExceptionType().getSignature(result);
+ }
+ }
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodException.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodException.java
new file mode 100644
index 000000000..4c7cfe5a2
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodException.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java;
+
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.NdNode;
+import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+
+public class NdMethodException extends NdNode {
+
+ public static final FieldManyToOne<NdMethod> PARENT;
+ public static final FieldManyToOne<NdTypeSignature> EXCEPTION_TYPE;
+
+ @SuppressWarnings("hiding")
+ public static StructDef<NdMethodException> type;
+
+ static {
+ type = StructDef.create(NdMethodException.class, NdNode.type);
+ PARENT = FieldManyToOne.createOwner(type, NdMethod.EXCEPTIONS);
+ EXCEPTION_TYPE = FieldManyToOne.create(type, NdTypeSignature.USED_AS_EXCEPTION);
+ type.done();
+ }
+
+ public NdMethodException(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ public NdMethodException(NdMethod method, NdTypeSignature createTypeSignature) {
+ super(method.getNd());
+
+ PARENT.put(getNd(), this.address, method);
+ EXCEPTION_TYPE.put(getNd(), this.address, createTypeSignature);
+ }
+
+ public NdTypeSignature getExceptionType() {
+ return EXCEPTION_TYPE.get(getNd(), this.address);
+ }
+
+ public NdMethod getParent() {
+ return PARENT.get(getNd(), this.address);
+ }
+
+ public String toString() {
+ try {
+ return getExceptionType().toString();
+ } catch (RuntimeException e) {
+ // This is called most often from the debugger, so we want to return something meaningful even
+ // if the code is buggy, the database is corrupt, or we don't have a read lock.
+ return super.toString();
+ }
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodId.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodId.java
new file mode 100644
index 000000000..f554b8003
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodId.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java;
+
+import java.util.List;
+
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.NdNode;
+import org.eclipse.jdt.internal.core.nd.db.IString;
+import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany;
+import org.eclipse.jdt.internal.core.nd.field.FieldSearchKey;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+import org.eclipse.jdt.internal.core.nd.util.CharArrayUtils;
+
+/**
+ * Represents the fully-qualified signature a method. Holds back-pointers to all the entities that refer to the name,
+ * along with pointers to all methods that have this fully-qualified name. Note that this isn't the class declaration
+ * itself. If there are multiple jar files containing a class of the same fully-qualified name, there may also be
+ * multiple methods with the same method ID.
+ */
+public class NdMethodId extends NdNode {
+ public static final FieldSearchKey<JavaIndex> METHOD_NAME;
+ public static final FieldOneToMany<NdMethod> METHODS;
+ public static final FieldOneToMany<NdType> DECLARED_TYPES;
+
+ @SuppressWarnings("hiding")
+ public static final StructDef<NdMethodId> type;
+
+ static {
+ type = StructDef.create(NdMethodId.class, NdNode.type);
+ METHOD_NAME = FieldSearchKey.create(type, JavaIndex.METHODS);
+ METHODS = FieldOneToMany.create(type, NdMethod.METHOD_ID, 2);
+ DECLARED_TYPES = FieldOneToMany.create(type, NdType.DECLARING_METHOD);
+
+ type.useStandardRefCounting().done();
+ }
+
+ public NdMethodId(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ /**
+ *
+ * @param nd
+ * @param methodIdentifier a field descriptor for the method type followed by a "#" followed by a method selector
+ * followed by method descriptor. For example, "Lorg/eclipse/MyClass#foo()Ljava/lang/Object;V"
+ */
+ public NdMethodId(Nd nd, char[] methodIdentifier) {
+ super(nd);
+
+ METHOD_NAME.put(nd, this.address, methodIdentifier);
+ }
+
+ public List<NdType> getDeclaredTypes() {
+ return DECLARED_TYPES.asList(getNd(), this.address);
+ }
+
+ /**
+ * Returns the field descriptor for the type (without a trailing ';') followed by a # followed by the method
+ * selector followed by the method descriptor. For example, "Lorg/eclipse/MyClass#foo()Ljava/lang/Object;V"
+ */
+ public IString getMethodName() {
+ return METHOD_NAME.get(getNd(), this.address);
+ }
+
+ public char[] getSelector() {
+ char[] name = getMethodName().getChars();
+ int selectorStart = CharArrayUtils.indexOf('#', name) + 1;
+ int selectorEnd = CharArrayUtils.indexOf('(', name, selectorStart, name.length);
+ if (selectorEnd == -1) {
+ selectorEnd = name.length;
+ }
+ return CharArrayUtils.subarray(name, selectorStart, selectorEnd);
+ }
+
+ public boolean isConstructor() {
+ return JavaNames.isConstructor(getSelector());
+ }
+
+ public char[] getMethodDescriptor() {
+ char[] name = getMethodName().getChars();
+ int descriptorStart = CharArrayUtils.indexOf('(', name, 0, name.length);
+ return CharArrayUtils.subarray(name, descriptorStart, name.length);
+ }
+
+ public boolean isClInit() {
+ return JavaNames.isClinit(getSelector());
+ }
+
+ public String toString() {
+ try {
+ return new String(getSelector());
+ } catch (RuntimeException e) {
+ // This is called most often from the debugger, so we want to return something meaningful even
+ // if the code is buggy, the database is corrupt, or we don't have a read lock.
+ return super.toString();
+ }
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodParameter.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodParameter.java
new file mode 100644
index 000000000..bdcd8324d
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethodParameter.java
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * 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.nd.java;
+
+import java.util.List;
+
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.NdNode;
+import org.eclipse.jdt.internal.core.nd.db.IString;
+import org.eclipse.jdt.internal.core.nd.field.FieldByte;
+import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
+import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany;
+import org.eclipse.jdt.internal.core.nd.field.FieldString;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
+
+public class NdMethodParameter extends NdNode {
+ public static final FieldManyToOne<NdMethod> PARENT;
+ public static final FieldManyToOne<NdTypeSignature> ARGUMENT_TYPE;
+ public static final FieldString NAME;
+ public static final FieldOneToMany<NdAnnotationInMethodParameter> ANNOTATIONS;
+ public static final FieldByte FLAGS;
+
+ private static final byte FLG_COMPILER_DEFINED = 0x01;
+
+ @SuppressWarnings("hiding")
+ public static StructDef<NdMethodParameter> type;
+
+ static {
+ type = StructDef.create(NdMethodParameter.class, NdNode.type);
+ PARENT = FieldManyToOne.create(type, NdMethod.PARAMETERS);
+ ARGUMENT_TYPE = FieldManyToOne.create(type, NdTypeSignature.USED_AS_METHOD_ARGUMENT);
+ NAME = type.addString();
+ ANNOTATIONS = FieldOneToMany.create(type, NdAnnotationInMethodParameter.OWNER);
+ FLAGS = type.addByte();
+ type.done();
+ }
+
+ public NdMethodParameter(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ public NdMethodParameter(NdMethod parent, NdTypeSignature argumentType) {
+ super(parent.getNd());
+
+ PARENT.put(getNd(), this.address, parent);
+ ARGUMENT_TYPE.put(getNd(), this.address, argumentType);
+ }
+
+ public NdTypeSignature getType() {
+ return ARGUMENT_TYPE.get(getNd(), this.address);
+ }
+
+ public void setName(char[] name) {
+ NAME.put(getNd(), this.address, name);
+ }
+
+ public IString getName() {
+ return NAME.get(getNd(), this.address);
+ }
+
+ public List<NdAnnotationInMethodParameter> getAnnotations() {
+ return ANNOTATIONS.asList(getNd(), this.address);
+ }
+
+ private void setFlag(byte flagConstant, boolean value) {
+ int oldFlags = FLAGS.get(getNd(), this.address);
+ int newFlags = ((oldFlags & ~flagConstant) | (value ? flagConstant : 0));
+ FLAGS.put(getNd(), this.address, (byte) newFlags);
+ }
+
+ private boolean getFlag(byte flagConstant) {
+ return (FLAGS.get(getNd(), this.address) & flagConstant) != 0;
+ }
+
+ public void setCompilerDefined(boolean isCompilerDefined) {
+ setFlag(FLG_COMPILER_DEFINED, isCompilerDefined);
+ }
+
+ public boolean isCompilerDefined() {
+ return getFlag(FLG_COMPILER_DEFINED);
+ }
+
+ public String toString() {
+ try {
+ CharArrayBuffer buf = new CharArrayBuffer();
+ buf.append(getType().toString());
+ buf.append(" "); //$NON-NLS-1$
+ buf.append(getName().toString());
+ return buf.toString();
+ } catch (RuntimeException e) {
+ // This is called most often from the debugger, so we want to return something meaningful even
+ // if the code is buggy, the database is corrupt, or we don't have a read lock.
+ return super.toString();
+ }
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdResourceFile.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdResourceFile.java
new file mode 100644
index 000000000..14e2e5362
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdResourceFile.java
@@ -0,0 +1,260 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.db.Database;
+import org.eclipse.jdt.internal.core.nd.db.IString;
+import org.eclipse.jdt.internal.core.nd.db.IndexException;
+import org.eclipse.jdt.internal.core.nd.field.FieldLong;
+import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany;
+import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany.Visitor;
+import org.eclipse.jdt.internal.core.nd.field.FieldSearchIndex.IResultRank;
+import org.eclipse.jdt.internal.core.nd.field.FieldSearchIndex.SearchCriteria;
+import org.eclipse.jdt.internal.core.nd.field.FieldSearchKey;
+import org.eclipse.jdt.internal.core.nd.field.FieldString;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+
+/**
+ * Represents a source of java classes (such as a .jar or .class file).
+ */
+public class NdResourceFile extends NdTreeNode {
+ public static final FieldSearchKey<JavaIndex> FILENAME;
+ public static final FieldOneToMany<NdBinding> ALL_NODES;
+ public static final FieldLong TIME_LAST_USED;
+ public static final FieldLong TIME_LAST_SCANNED;
+ public static final FieldLong SIZE_LAST_SCANNED;
+ public static final FieldLong HASHCODE_LAST_SCANNED;
+ public static final FieldOneToMany<NdWorkspaceLocation> WORKSPACE_MAPPINGS;
+ public static final FieldString JAVA_ROOT;
+
+ @SuppressWarnings("hiding")
+ public static final StructDef<NdResourceFile> type;
+
+ static {
+ type = StructDef.create(NdResourceFile.class, NdTreeNode.type);
+ FILENAME = FieldSearchKey.create(type, JavaIndex.FILES);
+ ALL_NODES = FieldOneToMany.create(type, NdBinding.FILE, 16);
+ TIME_LAST_USED = type.addLong();
+ TIME_LAST_SCANNED = type.addLong();
+ SIZE_LAST_SCANNED = type.addLong();
+ HASHCODE_LAST_SCANNED = type.addLong();
+ WORKSPACE_MAPPINGS = FieldOneToMany.create(type, NdWorkspaceLocation.RESOURCE);
+ JAVA_ROOT = type.addString();
+ type.done();
+ }
+
+ public NdResourceFile(Nd dom, long address) {
+ super(dom, address);
+ }
+
+ public NdResourceFile(Nd nd) {
+ super(nd, null);
+ }
+
+ public List<NdTreeNode> getChildren() {
+ return CHILDREN.asList(this.getNd(), this.address);
+ }
+
+ /**
+ * Determines whether this file is still in the index. If a {@link NdResourceFile} instance is retained while the
+ * database lock is released and reobtained, this method should be invoked to ensure that the {@link NdResourceFile}
+ * has not been deleted in the meantime.
+ */
+ public boolean isInIndex() {
+ try {
+ Nd nd = getNd();
+ // In the common case where the resource file was deleted and the memory hasn't yet been reused,
+ // this will fail.
+ if (NODE_TYPE.get(nd, this.address) != nd.getNodeType(getClass())) {
+ return false;
+ }
+
+ char[] filename = FILENAME.get(getNd(), this.address).getChars();
+
+ NdResourceFile result = JavaIndex.FILES.findBest(nd, Database.DATA_AREA_OFFSET,
+ SearchCriteria.create(filename), new IResultRank() {
+ @Override
+ public long getRank(Nd testNd, long testAddress) {
+ if (testAddress == NdResourceFile.this.address) {
+ return 1;
+ }
+ return -1;
+ }
+ });
+
+ return (this.equals(result));
+ } catch (IndexException e) {
+ // Read errors are expected here. It's possible that the resource file has been deleted and something
+ // new was written to this address, in which case we may be reading random gibberish from the database.
+ // This is likely to cause an exception.
+ return false;
+ }
+ }
+
+ public List<IPath> getAllWorkspaceLocations() {
+ final List<IPath> result = new ArrayList<>();
+
+ WORKSPACE_MAPPINGS.accept(getNd(), this.address, new Visitor<NdWorkspaceLocation>() {
+ @Override
+ public void visit(int index, NdWorkspaceLocation toVisit) {
+ result.add(new Path(toVisit.getPath().getString()));
+ }
+ });
+
+ return result;
+ }
+
+ public IPath getFirstWorkspaceLocation() {
+ if (WORKSPACE_MAPPINGS.isEmpty(getNd(), this.address)) {
+ return Path.EMPTY;
+ }
+
+ return new Path(WORKSPACE_MAPPINGS.get(getNd(), this.address, 0).getPath().toString());
+ }
+
+ public IPath getAnyOpenWorkspaceLocation(IWorkspaceRoot root) {
+ int numMappings = WORKSPACE_MAPPINGS.size(getNd(), this.address);
+
+ for (int mapping = 0; mapping < numMappings; mapping++) {
+ NdWorkspaceLocation nextMapping = WORKSPACE_MAPPINGS.get(getNd(), this.address, mapping);
+
+ IPath nextPath = new Path(nextMapping.getPath().getString());
+ if (nextPath.isEmpty()) {
+ continue;
+ }
+
+ IProject project = root.getProject(nextPath.segment(0));
+ if (project.isOpen()) {
+ return nextPath;
+ }
+ }
+
+ return Path.EMPTY;
+ }
+
+ /**
+ * Returns a workspace path to this resource if possible and the absolute filesystem location if not.
+ */
+ public IPath getPath() {
+ IPath workspacePath = getFirstWorkspaceLocation();
+
+ if (workspacePath.isEmpty()) {
+ return new Path(getLocation().getString());
+ }
+
+ return workspacePath;
+ }
+
+ public List<NdWorkspaceLocation> getWorkspaceMappings() {
+ return WORKSPACE_MAPPINGS.asList(getNd(), this.address);
+ }
+
+ public IString getLocation() {
+ return FILENAME.get(getNd(), this.address);
+ }
+
+ public void setLocation(String filename) {
+ FILENAME.put(getNd(), this.address, filename);
+ }
+
+ public FileFingerprint getFingerprint() {
+ return new FileFingerprint(
+ getTimeLastScanned(),
+ getSizeLastScanned(),
+ getHashcodeLastScanned());
+ }
+
+ private long getHashcodeLastScanned() {
+ return HASHCODE_LAST_SCANNED.get(getNd(), this.address);
+ }
+
+ /**
+ * Returns true iff the indexer has finished writing the contents of this file to the index. Returns false if
+ * indexing may still be going on. If this returns false, readers should ignore all contents of this file.
+ *
+ * @return true iff the contents of this file are usable
+ */
+ public boolean isDoneIndexing() {
+ return getTimeLastScanned() != 0;
+ }
+
+ public long getTimeLastScanned() {
+ return TIME_LAST_SCANNED.get(getNd(), this.address);
+ }
+
+ public long getSizeLastScanned() {
+ return SIZE_LAST_SCANNED.get(getNd(), this.address);
+ }
+
+ public long getTimeLastUsed() {
+ return TIME_LAST_USED.get(getNd(), this.address);
+ }
+
+ public void setTimeLastUsed(long timeLastUsed) {
+ TIME_LAST_USED.put(getNd(), this.address, timeLastUsed);
+ }
+
+ public void setFingerprint(FileFingerprint newFingerprint) {
+ TIME_LAST_SCANNED.put(getNd(), this.address, newFingerprint.getTime());
+ HASHCODE_LAST_SCANNED.put(getNd(), this.address, newFingerprint.getHash());
+ SIZE_LAST_SCANNED.put(getNd(), this.address, newFingerprint.getSize());
+ }
+
+ public void setPackageFragmentRoot(char[] javaRoot) {
+ JAVA_ROOT.put(getNd(), this.address, javaRoot);
+ }
+
+ /**
+ * Returns the absolute path to the java root for this .jar or .class file. If this is a .jar file, it returns its
+ * own filename.
+ */
+ public IString getPackageFragmentRoot() {
+ IString javaRoot = JAVA_ROOT.get(getNd(), this.address);
+ if (javaRoot.length() == 0) {
+ return getLocation();
+ }
+ return javaRoot;
+ }
+
+ public void markAsInvalid() {
+ TIME_LAST_SCANNED.put(getNd(), this.address, 0);
+ }
+
+ public int getBindingCount() {
+ return ALL_NODES.size(getNd(), this.address);
+ }
+
+ public List<NdBinding> getBindings() {
+ return ALL_NODES.asList(getNd(), this.address);
+ }
+
+ public NdBinding getBinding(int index) {
+ return ALL_NODES.get(getNd(), this.address, index);
+ }
+
+ public String toString() {
+ try {
+ return FILENAME.get(getNd(), this.address).toString();
+ } catch (RuntimeException e) {
+ // This is called most often from the debugger, so we want to return something meaningful even
+ // if the code is buggy, the database is corrupt, or we don't have a read lock.
+ return super.toString();
+ }
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTreeNode.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTreeNode.java
new file mode 100644
index 000000000..d9e33db80
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTreeNode.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java;
+
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.NdNode;
+import org.eclipse.jdt.internal.core.nd.db.IndexException;
+import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
+import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+
+/**
+ * {@link NdTreeNode} elements form a tree of nodes rooted at a {@link NdResourceFile}. Each node contains a list of
+ * children which it declares and has a pointer to the most specific node which declares it.
+ */
+public abstract class NdTreeNode extends NdNode {
+ public static final FieldManyToOne<NdTreeNode> PARENT;
+ public static final FieldOneToMany<NdTreeNode> CHILDREN;
+
+ @SuppressWarnings("hiding")
+ public static final StructDef<NdTreeNode> type;
+
+ static {
+ type = StructDef.create(NdTreeNode.class, NdNode.type);
+ PARENT = FieldManyToOne.create(type, null);
+ CHILDREN = FieldOneToMany.create(type, PARENT, 16);
+ type.done();
+ }
+
+ public NdTreeNode(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ protected NdTreeNode(Nd nd, NdTreeNode parent) {
+ super(nd);
+
+ PARENT.put(nd, this.address, parent == null ? 0 : parent.address);
+ }
+
+ public int getChildrenCount() {
+ return CHILDREN.size(getNd(), this.address);
+ }
+
+ public NdTreeNode getChild(int index) {
+ return CHILDREN.get(getNd(), this.address, index);
+ }
+
+ /**
+ * Returns the closest ancestor of the given type, or null if none. Note that
+ * this looks for an exact match. It will not return subtypes of the given type.
+ */
+ @SuppressWarnings("unchecked")
+ public <T extends NdTreeNode> T getAncestorOfType(Class<T> ancestorType) {
+ long targetType = getNd().getNodeType(ancestorType);
+
+ Nd nd = getNd();
+ long current = PARENT.getAddress(nd, this.address);
+
+ while (current != 0) {
+ short currentType = NODE_TYPE.get(nd, current);
+
+ if (currentType == targetType) {
+ NdNode result = load(nd, current);
+
+ if (ancestorType.isInstance(result)) {
+ return (T) result;
+ } else {
+ throw new IndexException("The node at address " + current + //$NON-NLS-1$
+ " should have been an instance of " + ancestorType.getName() + //$NON-NLS-1$
+ " but was an instance of " + result.getClass().getName()); //$NON-NLS-1$
+ }
+ }
+
+ current = PARENT.getAddress(nd, current);
+ }
+
+ return null;
+ }
+
+ NdTreeNode getParentNode() {
+ return PARENT.get(getNd(), this.address);
+ }
+
+ public NdBinding getParentBinding() throws IndexException {
+ NdNode parent= getParentNode();
+ if (parent instanceof NdBinding) {
+ return (NdBinding) parent;
+ }
+ return null;
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdType.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdType.java
new file mode 100644
index 000000000..5d2836399
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdType.java
@@ -0,0 +1,266 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java;
+
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jdt.internal.core.nd.INdVisitor;
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.db.IString;
+import org.eclipse.jdt.internal.core.nd.field.FieldByte;
+import org.eclipse.jdt.internal.core.nd.field.FieldLong;
+import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
+import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany;
+import org.eclipse.jdt.internal.core.nd.field.FieldString;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+import org.eclipse.jdt.internal.core.nd.util.CharArrayUtils;
+
+public class NdType extends NdBinding {
+ public static final FieldManyToOne<NdTypeId> TYPENAME;
+ public static final FieldManyToOne<NdTypeSignature> SUPERCLASS;
+ public static final FieldOneToMany<NdTypeInterface> INTERFACES;
+ public static final FieldManyToOne<NdTypeId> DECLARING_TYPE;
+ public static final FieldManyToOne<NdMethodId> DECLARING_METHOD;
+ public static final FieldOneToMany<NdMethod> METHODS;
+ public static final FieldOneToMany<NdTypeAnnotationInType> TYPE_ANNOTATIONS;
+ public static final FieldOneToMany<NdAnnotationInType> ANNOTATIONS;
+ public static final FieldString MISSING_TYPE_NAMES;
+ public static final FieldString SOURCE_FILE_NAME;
+ public static final FieldString INNER_CLASS_SOURCE_NAME;
+ public static final FieldByte FLAGS;
+ public static final FieldLong TAG_BITS;
+ /**
+ * Binary name that was recorded in the .class file if different from the binary
+ * name that was determined by the .class's name and location. This is only set for
+ * .class files that have been moved to the wrong folder.
+ */
+ public static final FieldString FIELD_DESCRIPTOR_FROM_CLASS;
+
+ @SuppressWarnings("hiding")
+ public static final StructDef<NdType> type;
+
+ static {
+ type = StructDef.create(NdType.class, NdBinding.type);
+ TYPENAME = FieldManyToOne.create(type, NdTypeId.TYPES);
+ DECLARING_TYPE = FieldManyToOne.create(type, NdTypeId.DECLARED_TYPES);
+ INTERFACES = FieldOneToMany.create(type, NdTypeInterface.APPLIES_TO);
+ SUPERCLASS = FieldManyToOne.create(type, NdTypeSignature.SUBCLASSES);
+ DECLARING_METHOD = FieldManyToOne.create(type, NdMethodId.DECLARED_TYPES);
+ METHODS = FieldOneToMany.create(type, NdMethod.PARENT, 6);
+ TYPE_ANNOTATIONS = FieldOneToMany.create(type, NdTypeAnnotationInType.OWNER);
+ ANNOTATIONS = FieldOneToMany.create(type, NdAnnotationInType.OWNER);
+ MISSING_TYPE_NAMES = type.addString();
+ SOURCE_FILE_NAME = type.addString();
+ INNER_CLASS_SOURCE_NAME = type.addString();
+ FLAGS = type.addByte();
+ TAG_BITS = type.addLong();
+ FIELD_DESCRIPTOR_FROM_CLASS = type.addString();
+ type.done();
+ }
+
+ public static final byte FLG_TYPE_ANONYMOUS = 0x0001;
+ public static final byte FLG_TYPE_LOCAL = 0x0002;
+ public static final byte FLG_TYPE_MEMBER = 0x0004;
+ public static final byte FLG_GENERIC_SIGNATURE_PRESENT = 0x0008;
+
+ public NdType(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ public NdType(Nd nd, NdResourceFile resource) {
+ super(nd, resource);
+ }
+
+ /**
+ * Called to populate the cache for the bindings in the class scope.
+ */
+ public void acceptUncached(INdVisitor visitor) throws CoreException {
+ super.accept(visitor);
+ }
+
+ public NdTypeId getTypeId() {
+ return TYPENAME.get(getNd(), this.address);
+ }
+
+ public void setTypeId(NdTypeId typeId) {
+ TYPENAME.put(getNd(), this.address, typeId);
+ }
+
+ /**
+ * Sets the source name for this type.
+ */
+ public void setSourceNameOverride(char[] sourceName) {
+ char[] oldSourceName = getSourceName();
+ if (!CharArrayUtils.equals(oldSourceName, sourceName)) {
+ INNER_CLASS_SOURCE_NAME.put(getNd(), this.address, sourceName);
+ }
+ }
+
+ public IString getSourceNameOverride() {
+ return INNER_CLASS_SOURCE_NAME.get(getNd(), this.address);
+ }
+
+ public long getResourceAddress() {
+ return FILE.getAddress(getNd(), this.address);
+ }
+
+ public void setSuperclass(NdTypeSignature superclassTypeName) {
+ SUPERCLASS.put(getNd(), this.address, superclassTypeName);
+ }
+
+ public NdTypeSignature getSuperclass() {
+ return SUPERCLASS.get(getNd(), this.address);
+ }
+
+ public List<NdTypeInterface> getInterfaces() {
+ return INTERFACES.asList(getNd(), this.address);
+ }
+
+ public NdResourceFile getResourceFile() {
+ return FILE.get(getNd(), this.address);
+ }
+
+ public void setDeclaringMethod(NdMethodId createMethodId) {
+ DECLARING_METHOD.put(getNd(), this.address, createMethodId);
+ }
+
+ /**
+ * @param createTypeIdFromBinaryName
+ */
+ public void setDeclaringType(NdTypeId createTypeIdFromBinaryName) {
+ DECLARING_TYPE.put(getNd(), this.address, createTypeIdFromBinaryName);
+ }
+
+ public NdTypeId getDeclaringType() {
+ return DECLARING_TYPE.get(getNd(), this.address);
+ }
+
+ /**
+ * Sets the missing type names (if any) for this class. The names are encoded in a comma-separated list.
+ */
+ public void setMissingTypeNames(char[] contents) {
+ MISSING_TYPE_NAMES.put(getNd(), this.address, contents);
+ }
+
+ /**
+ * Returns the missing type names as a comma-separated list
+ */
+ public IString getMissingTypeNames() {
+ return MISSING_TYPE_NAMES.get(getNd(), this.address);
+ }
+
+ public void setSourceFileName(char[] sourceFileName) {
+ SOURCE_FILE_NAME.put(getNd(), this.address, sourceFileName);
+ }
+
+ public IString getSourceFileName() {
+ return SOURCE_FILE_NAME.get(getNd(), this.address);
+ }
+
+ public void setAnonymous(boolean anonymous) {
+ setFlag(FLG_TYPE_ANONYMOUS, anonymous);
+ }
+
+ public void setIsLocal(boolean local) {
+ setFlag(FLG_TYPE_LOCAL, local);
+ }
+
+ public void setIsMember(boolean member) {
+ setFlag(FLG_TYPE_MEMBER, member);
+ }
+
+ public boolean isAnonymous() {
+ return getFlag(FLG_TYPE_ANONYMOUS);
+ }
+
+ public boolean isLocal() {
+ return getFlag(FLG_TYPE_LOCAL);
+ }
+
+ public boolean isMember() {
+ return getFlag(FLG_TYPE_MEMBER);
+ }
+
+ public void setFlag(byte flagConstant, boolean value) {
+ int oldFlags = FLAGS.get(getNd(), this.address);
+ int newFlags = ((oldFlags & ~flagConstant) | (value ? flagConstant : 0));
+ FLAGS.put(getNd(), this.address, (byte)newFlags);
+ }
+
+ public boolean getFlag(byte flagConstant) {
+ return (FLAGS.get(getNd(), this.address) & flagConstant) != 0;
+ }
+
+ public char[] getSourceName() {
+ IString sourceName = getSourceNameOverride();
+ if (sourceName.length() != 0) {
+ return sourceName.getChars();
+ }
+ char[] simpleName = getTypeId().getSimpleNameCharArray();
+ return JavaNames.simpleNameToSourceName(simpleName);
+ }
+
+ public NdMethodId getDeclaringMethod() {
+ return DECLARING_METHOD.get(getNd(), this.address);
+ }
+
+ @Override
+ public List<NdTypeParameter> getTypeParameters() {
+ return TYPE_PARAMETERS.asList(getNd(), this.address);
+ }
+
+ public List<NdTypeAnnotationInType> getTypeAnnotations() {
+ return TYPE_ANNOTATIONS.asList(getNd(), this.address);
+ }
+
+ public List<NdAnnotationInType> getAnnotations() {
+ return ANNOTATIONS.asList(getNd(), this.address);
+ }
+
+ public List<NdMethod> getMethods() {
+ return METHODS.asList(getNd(), this.address);
+ }
+
+ @Override
+ public String toString() {
+ try {
+ return "class " + new String(getSourceName()); //$NON-NLS-1$
+ } catch (RuntimeException e) {
+ return super.toString();
+ }
+ }
+
+ public void setTagBits(long tagBits) {
+ TAG_BITS.put(getNd(), this.address, tagBits);
+ }
+
+ public long getTagBits() {
+ return TAG_BITS.get(getNd(), this.address);
+ }
+
+ public void setFieldDescriptorFromClass(char[] fieldDescriptorFromClass) {
+ FIELD_DESCRIPTOR_FROM_CLASS.put(getNd(), this.address, fieldDescriptorFromClass);
+ }
+
+ /**
+ * Returns the field descriptor for this type, based on the binary type information stored in the
+ * .class file itself. Note that this may differ from the field descriptor of this type's typeId in
+ * the event that the .class file has been moved.
+ */
+ public IString getFieldDescriptor() {
+ IString descriptorFromClass = FIELD_DESCRIPTOR_FROM_CLASS.get(getNd(), this.address);
+ if (descriptorFromClass.length() == 0) {
+ return getTypeId().getFieldDescriptor();
+ }
+ return descriptorFromClass;
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotation.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotation.java
new file mode 100644
index 000000000..e9bfa4a4d
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotation.java
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * 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.nd.java;
+
+import org.eclipse.jdt.internal.compiler.codegen.AnnotationTargetTypeConstants;
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.db.Database;
+import org.eclipse.jdt.internal.core.nd.field.FieldByte;
+import org.eclipse.jdt.internal.core.nd.field.FieldPointer;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+
+public class NdTypeAnnotation extends NdAnnotation {
+ public static final FieldByte TARGET_TYPE;
+ public static final FieldByte TARGET_ARG0;
+ public static final FieldByte TARGET_ARG1;
+ public static final FieldByte PATH_LENGTH;
+ public static final FieldPointer PATH;
+
+ @SuppressWarnings("hiding")
+ public static final StructDef<NdTypeAnnotation> type;
+
+ static {
+ type = StructDef.create(NdTypeAnnotation.class, NdAnnotation.type);
+ TARGET_TYPE = type.addByte();
+ TARGET_ARG0 = type.addByte();
+ TARGET_ARG1 = type.addByte();
+ PATH_LENGTH = type.addByte();
+ PATH = type.addPointer();
+ type.done();
+ }
+
+ private static final byte[] NO_TYPE_PATH = new byte[0];
+
+ public NdTypeAnnotation(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ public NdTypeAnnotation(Nd nd) {
+ super(nd);
+ }
+
+ public void setPath(byte[] path) {
+ freePath();
+ Nd nd = getNd();
+ PATH_LENGTH.put(nd, this.address, (byte)path.length);
+ if (path.length > 0) {
+ long pathArray = nd.getDB().malloc(path.length, Database.POOL_MISC);
+ PATH.put(nd, this.address, pathArray);
+ nd.getDB().putBytes(pathArray, path, path.length);
+ }
+ }
+
+ public void setTargetInfo(int arg) {
+ TARGET_ARG0.put(getNd(), this.address, (byte)((arg >> 8) & 0xff));
+ TARGET_ARG1.put(getNd(), this.address, (byte)(arg & 0xff));
+ }
+
+ public byte getTargetInfoArg0() {
+ return TARGET_ARG0.get(getNd(), this.address);
+ }
+
+ public byte getTargetInfoArg1() {
+ return TARGET_ARG1.get(getNd(), this.address);
+ }
+
+ public int getTarget() {
+ int arg0 = TARGET_ARG0.get(getNd(), this.address) & 0xff;
+ int arg1 = TARGET_ARG1.get(getNd(), this.address) & 0xff;
+ int result = (arg0 << 8) | arg1;
+ return result;
+ }
+
+ public void setTargetInfo(byte arg0, byte arg1) {
+ TARGET_ARG0.put(getNd(), this.address, arg0);
+ TARGET_ARG1.put(getNd(), this.address, arg1);
+ }
+
+ /**
+ * @param targetType one of the constants from {@link AnnotationTargetTypeConstants}
+ */
+ public void setTargetType(int targetType) {
+ TARGET_TYPE.put(getNd(), this.address, (byte)targetType);
+ }
+
+ /**
+ * @return one of the constants from {@link AnnotationTargetTypeConstants}
+ */
+ public int getTargetType() {
+ return TARGET_TYPE.get(getNd(), this.address);
+ }
+
+ public byte[] getTypePath() {
+ long pathPointer = PATH.get(getNd(), this.address);
+ if (pathPointer == 0) {
+ return NO_TYPE_PATH;
+ }
+ int pathLength = PATH_LENGTH.get(getNd(), this.address);
+ byte[] result = new byte[pathLength];
+ getNd().getDB().getBytes(pathPointer, result);
+ return result;
+ }
+
+ @Override
+ public void destruct() {
+ freePath();
+ super.destruct();
+ }
+
+ private void freePath() {
+ Nd nd = getNd();
+ long pathPointer = PATH.get(nd, this.address);
+ nd.getDB().free(pathPointer, Database.POOL_MISC);
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotationInMethod.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotationInMethod.java
new file mode 100644
index 000000000..894a1d549
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotationInMethod.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * 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.nd.java;
+
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+
+public class NdTypeAnnotationInMethod extends NdTypeAnnotation {
+ public static final FieldManyToOne<NdMethod> OWNER;
+
+ @SuppressWarnings("hiding")
+ public static final StructDef<NdTypeAnnotationInMethod> type;
+
+ static {
+ type = StructDef.create(NdTypeAnnotationInMethod.class, NdTypeAnnotation.type);
+ OWNER = FieldManyToOne.createOwner(type, NdMethod.TYPE_ANNOTATIONS);
+ type.done();
+ }
+
+ public NdTypeAnnotationInMethod(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ public NdTypeAnnotationInMethod(Nd nd, NdMethod variable) {
+ super(nd);
+
+ OWNER.put(getNd(), this.address, variable);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotationInType.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotationInType.java
new file mode 100644
index 000000000..7aff10908
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotationInType.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * 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.nd.java;
+
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+
+public class NdTypeAnnotationInType extends NdTypeAnnotation {
+ public static final FieldManyToOne<NdType> OWNER;
+
+ @SuppressWarnings("hiding")
+ public static final StructDef<NdTypeAnnotationInType> type;
+
+ static {
+ type = StructDef.create(NdTypeAnnotationInType.class, NdTypeAnnotation.type);
+ OWNER = FieldManyToOne.createOwner(type, NdType.TYPE_ANNOTATIONS);
+ type.done();
+ }
+
+ public NdTypeAnnotationInType(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ public NdTypeAnnotationInType(Nd nd, NdType type) {
+ super(nd);
+
+ OWNER.put(getNd(), this.address, type);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotationInVariable.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotationInVariable.java
new file mode 100644
index 000000000..eb591fe06
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeAnnotationInVariable.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * 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.nd.java;
+
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+
+public class NdTypeAnnotationInVariable extends NdTypeAnnotation {
+ public static final FieldManyToOne<NdVariable> OWNER;
+
+ @SuppressWarnings("hiding")
+ public static final StructDef<NdTypeAnnotationInVariable> type;
+
+ static {
+ type = StructDef.create(NdTypeAnnotationInVariable.class, NdTypeAnnotation.type);
+ OWNER = FieldManyToOne.createOwner(type, NdVariable.TYPE_ANNOTATIONS);
+ type.done();
+ }
+
+ public NdTypeAnnotationInVariable(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ public NdTypeAnnotationInVariable(Nd nd, NdVariable variable) {
+ super(nd);
+
+ OWNER.put(getNd(), this.address, variable);
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeArgument.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeArgument.java
new file mode 100644
index 000000000..37af73ac3
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeArgument.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java;
+
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.NdNode;
+import org.eclipse.jdt.internal.core.nd.field.FieldByte;
+import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
+
+public class NdTypeArgument extends NdNode {
+ public static final FieldManyToOne<NdComplexTypeSignature> PARENT;
+ public static final FieldManyToOne<NdTypeSignature> TYPE_SIGNATURE;
+ public static final FieldByte WILDCARD;
+
+ @SuppressWarnings("hiding")
+ public static final StructDef<NdTypeArgument> type;
+
+ static {
+ type = StructDef.create(NdTypeArgument.class, NdNode.type);
+ PARENT = FieldManyToOne.createOwner(type, NdComplexTypeSignature.TYPE_ARGUMENTS);
+ TYPE_SIGNATURE = FieldManyToOne.create(type, NdTypeSignature.USED_AS_TYPE_ARGUMENT);
+ WILDCARD = type.addByte();
+ type.done();
+ }
+
+ public static final int WILDCARD_NONE = 0;
+ public static final int WILDCARD_EXTENDS = 1;
+ public static final int WILDCARD_SUPER = 2;
+ public static final int WILDCARD_QUESTION = 3;
+
+ public NdTypeArgument(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ public NdTypeArgument(Nd nd, NdComplexTypeSignature typeSignature) {
+ super(nd);
+
+ PARENT.put(nd, this.address, typeSignature);
+ }
+
+ /**
+ * Sets the wildcard to use, one of the WILDCARD_* constants.
+ *
+ * @param wildcard
+ */
+ public void setWildcard(int wildcard) {
+ WILDCARD.put(getNd(), this.address, (byte) wildcard);
+ }
+
+ public void setType(NdTypeSignature typeSignature) {
+ TYPE_SIGNATURE.put(getNd(), this.address, typeSignature);
+ }
+
+ public int getWildcard() {
+ return WILDCARD.get(getNd(), this.address);
+ }
+
+ public NdComplexTypeSignature getParent() {
+ return PARENT.get(getNd(), this.address);
+ }
+
+ public NdTypeSignature getType() {
+ return TYPE_SIGNATURE.get(getNd(), this.address);
+ }
+
+ public void getSignature(CharArrayBuffer result) {
+ switch (getWildcard()) {
+ case NdTypeArgument.WILDCARD_EXTENDS: result.append('-'); break;
+ case NdTypeArgument.WILDCARD_QUESTION: result.append('*'); return;
+ case NdTypeArgument.WILDCARD_SUPER: result.append('+'); break;
+ }
+
+ NdTypeSignature theType = getType();
+ if (theType != null) {
+ theType.getSignature(result);
+ }
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeBound.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeBound.java
new file mode 100644
index 000000000..c6c827eee
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeBound.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java;
+
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.NdNode;
+import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
+
+/**
+ * Represents the bound on a generic parameter (a ClassBound or InterfaceBound in
+ * the sense of the Java VM spec Java SE 8 Edition, section 4.7.9.1).
+ */
+public class NdTypeBound extends NdNode {
+ public static final FieldManyToOne<NdTypeParameter> PARENT;
+ public static final FieldManyToOne<NdTypeSignature> TYPE;
+
+ @SuppressWarnings("hiding")
+ public static final StructDef<NdTypeBound> type;
+
+ static {
+ type = StructDef.create(NdTypeBound.class, NdNode.type);
+ PARENT = FieldManyToOne.createOwner(type, NdTypeParameter.BOUNDS);
+ TYPE = FieldManyToOne.create(type, NdTypeSignature.USED_AS_TYPE_BOUND);
+
+ type.done();
+ }
+
+ public NdTypeBound(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ public NdTypeBound(NdTypeParameter parent, NdTypeSignature signature) {
+ super(parent.getNd());
+
+ PARENT.put(getNd(), this.address, parent);
+ TYPE.put(getNd(), this.address, signature);
+ }
+
+ public NdTypeParameter getParent() {
+ return PARENT.get(getNd(), this.address);
+ }
+
+ public NdTypeSignature getType() {
+ return TYPE.get(getNd(), this.address);
+ }
+
+ public void getSignature(CharArrayBuffer result) {
+ result.append(':');
+ getType().getSignature(result);
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeId.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeId.java
new file mode 100644
index 000000000..a132f97f9
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeId.java
@@ -0,0 +1,184 @@
+/*******************************************************************************
+ * 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.nd.java;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.db.IString;
+import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany;
+import org.eclipse.jdt.internal.core.nd.field.FieldSearchKey;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+import org.eclipse.jdt.internal.core.nd.util.CharArrayUtils;
+import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
+
+public class NdTypeId extends NdTypeSignature {
+ public static final FieldSearchKey<JavaIndex> FIELD_DESCRIPTOR;
+ public static final FieldSearchKey<JavaIndex> SIMPLE_NAME;
+ public static final FieldOneToMany<NdType> TYPES;
+ public static final FieldOneToMany<NdComplexTypeSignature> USED_AS_COMPLEX_TYPE;
+ public static final FieldOneToMany<NdType> DECLARED_TYPES;
+
+ @SuppressWarnings("hiding")
+ public static final StructDef<NdTypeId> type;
+
+ private String fName;
+
+ static {
+ type = StructDef.create(NdTypeId.class, NdTypeSignature.type);
+ FIELD_DESCRIPTOR = FieldSearchKey.create(type, JavaIndex.TYPES);
+ SIMPLE_NAME = FieldSearchKey.create(type, JavaIndex.SIMPLE_INDEX);
+ TYPES = FieldOneToMany.create(type, NdType.TYPENAME, 2);
+ USED_AS_COMPLEX_TYPE = FieldOneToMany.create(type, NdComplexTypeSignature.RAW_TYPE);
+ DECLARED_TYPES = FieldOneToMany.create(type, NdType.DECLARING_TYPE);
+ type.useStandardRefCounting().done();
+ }
+
+ public NdTypeId(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ public NdTypeId(Nd nd, char[] fieldDescriptor) {
+ super(nd);
+
+ char[] simpleName = JavaNames.fieldDescriptorToJavaName(fieldDescriptor, false);
+ FIELD_DESCRIPTOR.put(nd, this.address, fieldDescriptor);
+ SIMPLE_NAME.put(nd, this.address, simpleName);
+ }
+
+ @Override
+ public List<NdType> getSubTypes() {
+ List<NdType> result = new ArrayList<>();
+ result.addAll(super.getSubTypes());
+ for (NdComplexTypeSignature next : getComplexTypes()) {
+ result.addAll(next.getSubTypes());
+ }
+ return result;
+ }
+
+ public List<NdComplexTypeSignature> getComplexTypes() {
+ return USED_AS_COMPLEX_TYPE.asList(getNd(), this.address);
+ }
+
+ public NdType findTypeByResourceAddress(long resourceAddress) {
+ int size = TYPES.size(getNd(), this.address);
+ for (int idx = 0; idx < size; idx++) {
+ NdType next = TYPES.get(getNd(), this.address, idx);
+
+ if (next.getResourceAddress() == resourceAddress) {
+ return next;
+ }
+ }
+ return null;
+ }
+
+ public List<NdType> getTypes() {
+ return TYPES.asList(getNd(), this.address);
+ }
+
+ /**
+ * Returns the field descriptor.
+ */
+ public IString getFieldDescriptor() {
+ return FIELD_DESCRIPTOR.get(getNd(), this.address);
+ }
+
+ public char[] getFieldDescriptorWithoutTrailingSemicolon() {
+ char[] fieldDescriptor = getFieldDescriptor().getChars();
+
+ int end = fieldDescriptor.length;
+ if (fieldDescriptor.length > 0 && fieldDescriptor[end - 1] == ';') {
+ end--;
+ }
+
+ return CharArrayUtils.subarray(fieldDescriptor, 0, end);
+ }
+
+ public char[] getBinaryName() {
+ return JavaNames.fieldDescriptorToBinaryName(getFieldDescriptor().getChars());
+ }
+
+ public IString getSimpleName() {
+ return SIMPLE_NAME.get(getNd(), this.address);
+ }
+
+ public char[] getSimpleNameCharArray() {
+ if (this.fName == null) {
+ this.fName= getSimpleName().getString();
+ }
+ return this.fName.toCharArray();
+ }
+
+ public boolean hasFieldDescriptor(String name) {
+ return this.getFieldDescriptor().compare(name, true) == 0;
+ }
+
+ public boolean hasSimpleName(String name) {
+ if (this.fName != null)
+ return this.fName.equals(name);
+
+ return getSimpleName().equals(name);
+ }
+
+ public void setSimpleName(String name) {
+ if (Objects.equals(name, this.fName)) {
+ return;
+ }
+ this.fName = name;
+ SIMPLE_NAME.put(getNd(), this.address, name);
+ }
+
+ public List<NdType> getDeclaredTypes() {
+ return DECLARED_TYPES.asList(getNd(), this.address);
+ }
+
+ @Override
+ public NdTypeId getRawType() {
+ return this;
+ }
+
+ @Override
+ public void getSignature(CharArrayBuffer result, boolean includeTrailingSemicolon) {
+ if (includeTrailingSemicolon) {
+ result.append(getFieldDescriptor().getChars());
+ } else {
+ result.append(getFieldDescriptorWithoutTrailingSemicolon());
+ }
+ }
+
+ @Override
+ public boolean isTypeVariable() {
+ return false;
+ }
+
+ @Override
+ public List<NdTypeSignature> getDeclaringTypeChain() {
+ return Collections.singletonList((NdTypeSignature)this);
+ }
+
+ @Override
+ public NdTypeSignature getArrayDimensionType() {
+ return null;
+ }
+
+ @Override
+ public List<NdTypeArgument> getTypeArguments() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public boolean isArrayType() {
+ return false;
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeInterface.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeInterface.java
new file mode 100644
index 000000000..ca8ae778f
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeInterface.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java;
+
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.NdNode;
+import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+
+/**
+ * Represents one interface implemented by a specific type. This is an intermediate object between a {@link NdType} and
+ * the {@link NdTypeId}s corresponding to its interfaces, which is necessary in order to implement the many-to-many
+ * relationship between them.
+ */
+public class NdTypeInterface extends NdNode {
+ public static final FieldManyToOne<NdType> APPLIES_TO;
+ public static final FieldManyToOne<NdTypeSignature> IMPLEMENTS;
+
+ @SuppressWarnings("hiding")
+ public static StructDef<NdTypeInterface> type;
+
+ static {
+ type = StructDef.create(NdTypeInterface.class, NdNode.type);
+ APPLIES_TO = FieldManyToOne.createOwner(type, NdType.INTERFACES);
+ IMPLEMENTS = FieldManyToOne.create(type, NdTypeSignature.IMPLEMENTATIONS);
+ type.done();
+ }
+
+ public NdTypeInterface(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ public NdTypeInterface(Nd nd, NdType targetType, NdTypeSignature makeTypeId) {
+ super(nd);
+
+ APPLIES_TO.put(nd, this.address, targetType);
+ IMPLEMENTS.put(nd, this.address, makeTypeId);
+ }
+
+ public NdType getImplementation() {
+ return APPLIES_TO.get(getNd(), this.address);
+ }
+
+ public NdTypeSignature getInterface() {
+ return IMPLEMENTS.get(getNd(), this.address);
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeParameter.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeParameter.java
new file mode 100644
index 000000000..fda4676b1
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeParameter.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * 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.nd.java;
+
+import java.util.List;
+
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.NdNode;
+import org.eclipse.jdt.internal.core.nd.field.FieldByte;
+import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
+import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany;
+import org.eclipse.jdt.internal.core.nd.field.FieldString;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
+
+/**
+ * Represents a TypeParameter, as described in Section 4.7.9.1 of the java VM specification, Java SE 8 edititon.
+ */
+public class NdTypeParameter extends NdNode {
+ public static final FieldManyToOne<NdBinding> PARENT;
+ public static final FieldString IDENTIFIER;
+ public static final FieldOneToMany<NdTypeBound> BOUNDS;
+ public static final FieldByte TYPE_PARAMETER_FLAGS;
+
+ public static final byte FLG_FIRST_BOUND_IS_A_CLASS = 0x01;
+
+ @SuppressWarnings("hiding")
+ public static final StructDef<NdTypeParameter> type;
+
+ static {
+ type = StructDef.create(NdTypeParameter.class, NdNode.type);
+ PARENT = FieldManyToOne.createOwner(type, NdBinding.TYPE_PARAMETERS);
+ IDENTIFIER = type.addString();
+ BOUNDS = FieldOneToMany.create(type, NdTypeBound.PARENT);
+ TYPE_PARAMETER_FLAGS = type.addByte();
+
+ type.done();
+ }
+
+ public NdTypeParameter(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ public NdTypeParameter(NdBinding parent, char[] identifier) {
+ super(parent.getNd());
+
+ PARENT.put(getNd(), this.address, parent);
+ IDENTIFIER.put(getNd(), this.address, identifier);
+ }
+
+ public char[] getIdentifier() {
+ return IDENTIFIER.get(getNd(), this.address).getChars();
+ }
+
+ public void setFirstBoundIsClass(boolean isClass) {
+ setFlag(FLG_FIRST_BOUND_IS_A_CLASS, isClass);
+ }
+
+ public boolean isFirstBoundAClass() {
+ return (TYPE_PARAMETER_FLAGS.get(getNd(), this.address) & FLG_FIRST_BOUND_IS_A_CLASS) != 0;
+ }
+
+ private void setFlag(byte flag, boolean value) {
+ byte oldValue = TYPE_PARAMETER_FLAGS.get(getNd(), this.address);
+ byte newValue;
+ if (value) {
+ newValue = (byte) (oldValue | flag);
+ } else {
+ newValue = (byte) (oldValue & ~flag);
+ }
+ TYPE_PARAMETER_FLAGS.put(getNd(), this.address, newValue);
+ }
+
+ public List<NdTypeBound> getBounds() {
+ return BOUNDS.asList(getNd(), this.address);
+ }
+
+ public void getSignature(CharArrayBuffer result) {
+ result.append(getIdentifier());
+
+ List<NdTypeBound> bounds = getBounds();
+
+ // If none of the bounds are classes and there is at least one bound, then insert a double-colon
+ // in the type signature.
+ if (!bounds.isEmpty() && !isFirstBoundAClass()) {
+ result.append(':');
+ }
+
+ for (NdTypeBound next : bounds) {
+ next.getSignature(result);
+ }
+ }
+
+ public static void getSignature(CharArrayBuffer buffer, List<NdTypeParameter> params) {
+ if (!params.isEmpty()) {
+ buffer.append('<');
+ for (NdTypeParameter next : params) {
+ next.getSignature(buffer);
+ }
+ buffer.append('>');
+ }
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeSignature.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeSignature.java
new file mode 100644
index 000000000..207963684
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeSignature.java
@@ -0,0 +1,157 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.NdNode;
+import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
+
+/**
+ * Corresponds roughly to a JavaTypeSignature, as described in section 4.7.9.1 of the Java VM spec version 4, with the
+ * addition of annotations and backpointers to locations where the type is used.
+ * <p>
+ * Holds back-pointers to all the entities that refer to the name, along with pointers to all classes that have this
+ * name. Note that this isn't the class declaration itself. The same index can hold multiple jar files, some of which
+ * may contain classes with the same name. All classes that use this fully-qualified name point to the same
+ * {@link NdTypeSignature}.
+ * <p>
+ * Other entities should refer to a type via its TypeId if there is any possiblity that the type may change based on the
+ * classpath. It should refer to the type directly if there is no possibility for a type lookup. For example, nested
+ * classes refer to their enclosing class directly since they live in the same file and there is no possibility for the
+ * enclosing class to change based on the classpath. Classes refer to their base class via its TypeId since the parent
+ * class might live in a different jar and need to be resolved on the classpath.
+ */
+public abstract class NdTypeSignature extends NdNode {
+ public static final FieldOneToMany<NdType> SUBCLASSES;
+ public static final FieldOneToMany<NdAnnotation> ANNOTATIONS_OF_THIS_TYPE;
+ public static final FieldOneToMany<NdTypeInterface> IMPLEMENTATIONS;
+ public static final FieldOneToMany<NdVariable> VARIABLES_OF_TYPE;
+ public static final FieldOneToMany<NdConstantClass> USED_AS_CONSTANT;
+ public static final FieldOneToMany<NdConstantEnum> USED_AS_ENUM_CONSTANT;
+ public static final FieldOneToMany<NdTypeArgument> USED_AS_TYPE_ARGUMENT;
+ public static final FieldOneToMany<NdTypeBound> USED_AS_TYPE_BOUND;
+ public static final FieldOneToMany<NdMethodParameter> USED_AS_METHOD_ARGUMENT;
+ public static final FieldOneToMany<NdMethodException> USED_AS_EXCEPTION;
+ public static final FieldOneToMany<NdMethod> USED_AS_RETURN_TYPE;
+
+ @SuppressWarnings("hiding")
+ public static StructDef<NdTypeSignature> type;
+
+ static {
+ type = StructDef.createAbstract(NdTypeSignature.class, NdNode.type);
+ SUBCLASSES = FieldOneToMany.create(type, NdType.SUPERCLASS);
+ ANNOTATIONS_OF_THIS_TYPE = FieldOneToMany.create(type, NdAnnotation.ANNOTATION_TYPE);
+ IMPLEMENTATIONS = FieldOneToMany.create(type, NdTypeInterface.IMPLEMENTS);
+ VARIABLES_OF_TYPE = FieldOneToMany.create(type, NdVariable.TYPE);
+ USED_AS_CONSTANT = FieldOneToMany.create(type, NdConstantClass.VALUE);
+ USED_AS_ENUM_CONSTANT = FieldOneToMany.create(type, NdConstantEnum.ENUM_TYPE);
+ USED_AS_TYPE_ARGUMENT = FieldOneToMany.create(type, NdTypeArgument.TYPE_SIGNATURE);
+ USED_AS_TYPE_BOUND = FieldOneToMany.create(type, NdTypeBound.TYPE);
+ USED_AS_METHOD_ARGUMENT = FieldOneToMany.create(type, NdMethodParameter.ARGUMENT_TYPE);
+ USED_AS_EXCEPTION = FieldOneToMany.create(type, NdMethodException.EXCEPTION_TYPE);
+ USED_AS_RETURN_TYPE = FieldOneToMany.create(type, NdMethod.RETURN_TYPE);
+ type.useStandardRefCounting().done();
+ }
+
+ public NdTypeSignature(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ public NdTypeSignature(Nd nd) {
+ super(nd);
+ }
+
+ public List<NdType> getSubclasses() {
+ return SUBCLASSES.asList(getNd(), this.address);
+ }
+
+ public List<NdTypeInterface> getImplementations() {
+ return IMPLEMENTATIONS.asList(getNd(), this.address);
+ }
+
+ /**
+ * Returns all subclasses (for classes) and implementations (for interfaces) of this type
+ */
+ public List<NdType> getSubTypes() {
+ List<NdType> result = new ArrayList<>();
+ result.addAll(getSubclasses());
+
+ for (NdTypeInterface next : getImplementations()) {
+ result.add(next.getImplementation());
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns the raw version of this type, if one exists. That is, the version of this type
+ * without any generic arguments or annotations, which the java runtime sees. Returns null
+ * of this signature doesn't have a raw type, for example if it is a type variable.
+ */
+ public abstract NdTypeId getRawType();
+
+ public final void getSignature(CharArrayBuffer result) {
+ getSignature(result, true);
+ }
+
+ public abstract void getSignature(CharArrayBuffer result, boolean includeTrailingSemicolon);
+
+ /**
+ * Returns true iff this is an array type signature (ie: that getArrayDimensionType() will return a non-null
+ * answer). Note that this only returns true for the type signature that holds the reference to the array dimension
+ * type. The raw type for that signature will return false, even though it has a field descriptor starting with '['.
+ * <p>
+ * In other words:
+ *
+ * <pre>
+ * NdVariable someVariable = getSomeVariableWithAnArrayType()
+ * System.out.println(someVariable.getType().isArrayType()); // true
+ * System.out.println(someVariable.getType().getRawType().isArrayType()); // false
+ * </pre>
+ */
+ public abstract boolean isArrayType();
+
+ public abstract boolean isTypeVariable();
+
+ /**
+ * Returns the chain of declaring generic types. The first element in the chain is a top-level type and the
+ * receiver is the last element in the chain.
+ */
+ public abstract List<NdTypeSignature> getDeclaringTypeChain();
+
+ /**
+ * If the receiver is an array type, it returns the signature of the array's next dimension. Returns null if
+ * this is not an array type.
+ */
+ public abstract NdTypeSignature getArrayDimensionType();
+
+ /**
+ * Returns the type arguments for this type signature, if any. Returns the empty list if none.
+ */
+ public abstract List<NdTypeArgument> getTypeArguments();
+
+ public String toString() {
+ try {
+ CharArrayBuffer result = new CharArrayBuffer();
+ getSignature(result);
+ return result.toString();
+ } catch (RuntimeException e) {
+ // This is called most often from the debugger, so we want to return something meaningful even
+ // if the code is buggy, the database is corrupt, or we don't have a read lock.
+ return super.toString();
+ }
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdVariable.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdVariable.java
new file mode 100644
index 000000000..e85f805ac
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdVariable.java
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java;
+
+import java.util.List;
+
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.db.IString;
+import org.eclipse.jdt.internal.core.nd.field.FieldByte;
+import org.eclipse.jdt.internal.core.nd.field.FieldInt;
+import org.eclipse.jdt.internal.core.nd.field.FieldLong;
+import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
+import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany;
+import org.eclipse.jdt.internal.core.nd.field.FieldOneToOne;
+import org.eclipse.jdt.internal.core.nd.field.FieldString;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+
+public class NdVariable extends NdBinding {
+ public static final FieldManyToOne<NdTypeSignature> TYPE;
+ public static final FieldInt VARIABLE_ID;
+ public static final FieldManyToOne<NdMethod> DECLARING_METHOD;
+ public static final FieldManyToOne<NdBinding> PARENT;
+ public static final FieldString NAME;
+ public static final FieldOneToOne<NdConstant> CONSTANT;
+ public static final FieldLong TAG_BITS;
+ public static final FieldByte VARIABLE_FLAGS;
+ public static final FieldOneToMany<NdAnnotationInVariable> ANNOTATIONS;
+ public static final FieldOneToMany<NdTypeAnnotationInVariable> TYPE_ANNOTATIONS;
+
+ @SuppressWarnings("hiding")
+ public static StructDef<NdVariable> type;
+
+ public static final byte FLG_GENERIC_SIGNATURE_PRESENT = 0x01;
+
+ static {
+ type = StructDef.create(NdVariable.class, NdBinding.type);
+ TYPE = FieldManyToOne.create(type, NdTypeSignature.VARIABLES_OF_TYPE);
+ VARIABLE_ID = type.addInt();
+ DECLARING_METHOD = FieldManyToOne.create(type, NdMethod.DECLARED_VARIABLES);
+ PARENT = FieldManyToOne.create(type, NdBinding.VARIABLES);
+ NAME = type.addString();
+ CONSTANT = FieldOneToOne.create(type, NdConstant.class, NdConstant.PARENT_VARIABLE);
+ TAG_BITS = type.addLong();
+ VARIABLE_FLAGS = type.addByte();
+ ANNOTATIONS = FieldOneToMany.create(type, NdAnnotationInVariable.OWNER);
+ TYPE_ANNOTATIONS = FieldOneToMany.create(type, NdTypeAnnotationInVariable.OWNER);
+ type.done();
+ }
+
+ public NdVariable(Nd nd, long bindingRecord) {
+ super(nd, bindingRecord);
+ }
+
+ public NdVariable(NdBinding parent) {
+ super(parent.getNd(), parent.getFile());
+
+ PARENT.put(getNd(), this.address, parent);
+ }
+
+ public boolean hasVariableFlag(int toTest) {
+ return (VARIABLE_FLAGS.get(getNd(), this.address) & toTest) != 0;
+ }
+
+ public void setVariableFlag(byte toSet) {
+ int newFlags = VARIABLE_FLAGS.get(getNd(), this.address) | toSet;
+ VARIABLE_FLAGS.put(getNd(), this.address, (byte)newFlags);
+ }
+
+ public void setName(char[] name) {
+ NAME.put(getNd(), this.address, name);
+ }
+
+ public IString getName() {
+ return NAME.get(getNd(), this.address);
+ }
+
+ public void setType(NdTypeSignature typeId) {
+ TYPE.put(getNd(), this.address, typeId);
+ }
+
+ public void setConstant(NdConstant constant) {
+ CONSTANT.put(getNd(), this.address, constant);
+ }
+
+ public NdConstant getConstant() {
+ return CONSTANT.get(getNd(), this.address);
+ }
+
+ public NdTypeSignature getType() {
+ return TYPE.get(getNd(), this.address);
+ }
+
+ public long getTagBits() {
+ return TAG_BITS.get(getNd(), this.address);
+ }
+
+ public void setTagBits(long tagBits) {
+ TAG_BITS.put(getNd(), this.address, tagBits);
+ }
+
+ public List<NdTypeAnnotationInVariable> getTypeAnnotations() {
+ return TYPE_ANNOTATIONS.asList(getNd(), this.address);
+ }
+
+ public List<NdAnnotationInVariable> getAnnotations() {
+ return ANNOTATIONS.asList(getNd(), this.address);
+ }
+
+ public String toString() {
+ try {
+ StringBuilder result = new StringBuilder();
+ NdTypeSignature localType = getType();
+ if (localType != null) {
+ result.append(localType.toString());
+ result.append(" "); //$NON-NLS-1$
+ }
+ IString name = getName();
+ if (name != null) {
+ result.append(name.toString());
+ }
+ NdConstant constant = getConstant();
+ if (constant != null) {
+ result.append(" = "); //$NON-NLS-1$
+ result.append(constant.toString());
+ }
+ return result.toString();
+ } catch (RuntimeException e) {
+ // This is called most often from the debugger, so we want to return something meaningful even
+ // if the code is buggy, the database is corrupt, or we don't have a read lock.
+ return super.toString();
+ }
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdWorkspaceLocation.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdWorkspaceLocation.java
new file mode 100644
index 000000000..8e52b8bfd
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdWorkspaceLocation.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * 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.nd.java;
+
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.NdNode;
+import org.eclipse.jdt.internal.core.nd.db.IString;
+import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
+import org.eclipse.jdt.internal.core.nd.field.FieldString;
+import org.eclipse.jdt.internal.core.nd.field.StructDef;
+
+/**
+ * Holds a location in the Eclipse workspace where a given resource was found. Note that a given
+ * resource might be mapped to multiple locations in the workspace.
+ */
+public class NdWorkspaceLocation extends NdNode {
+ public static final FieldManyToOne<NdResourceFile> RESOURCE;
+ public static final FieldString PATH;
+
+ @SuppressWarnings("hiding")
+ public static final StructDef<NdWorkspaceLocation> type;
+
+ static {
+ type = StructDef.create(NdWorkspaceLocation.class, NdNode.type);
+ RESOURCE = FieldManyToOne.createOwner(type, NdResourceFile.WORKSPACE_MAPPINGS);
+ PATH = type.addString();
+ type.done();
+ }
+
+ public NdWorkspaceLocation(Nd nd, long address) {
+ super(nd, address);
+ }
+
+ public NdWorkspaceLocation(Nd nd, NdResourceFile resource, char[] path) {
+ super(nd);
+
+ RESOURCE.put(getNd(), this.address, resource);
+ PATH.put(getNd(), this.address, path);
+ }
+
+ public IString getPath() {
+ return PATH.get(getNd(), this.address);
+ }
+
+ public NdResourceFile getResourceFile() {
+ return RESOURCE.get(getNd(), this.address);
+ }
+
+ public String toString() {
+ try {
+ return getPath().toString();
+ } catch (RuntimeException e) {
+ // This is called most often from the debugger, so we want to return something meaningful even
+ // if the code is buggy, the database is corrupt, or we don't have a read lock.
+ return super.toString();
+ }
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/Package.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/Package.java
new file mode 100644
index 000000000..9903317bc
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/Package.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jdt.core.JavaCore;
+
+/* package */ class Package {
+ public static String PLUGIN_ID = JavaCore.PLUGIN_ID;
+
+ public static void log(Throwable e) {
+ String msg= e.getMessage();
+ if (msg == null) {
+ log("Error", e); //$NON-NLS-1$
+ } else {
+ log("Error: " + msg, e); //$NON-NLS-1$
+ }
+ }
+
+ public static void log(String message, Throwable e) {
+ log(createStatus(message, e));
+ }
+
+ public static IStatus createStatus(String msg, Throwable e) {
+ return new Status(IStatus.ERROR, PLUGIN_ID, msg, e);
+ }
+
+ public static IStatus createStatus(String msg) {
+ return new Status(IStatus.ERROR, PLUGIN_ID, msg);
+ }
+
+ public static void log(IStatus status) {
+ JavaCore.getPlugin().getLog().log(status);
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/TagTreeReader.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/TagTreeReader.java
new file mode 100644
index 000000000..9ad5a6095
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/TagTreeReader.java
@@ -0,0 +1,134 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.db.Database;
+import org.eclipse.jdt.internal.core.nd.db.IndexException;
+
+public abstract class TagTreeReader {
+ public static final int[] UNUSED_RESULT = new int[1];
+
+ public static abstract class TagHandler<T> {
+ abstract public T read(Nd nd, long address, TagTreeReader reader, int[] bytesRead);
+ abstract public void write(Nd nd, long address, TagTreeReader reader, T toWrite, int[] bytesWritten);
+ abstract public int getSize(Nd nd, T object, TagTreeReader reader);
+ public void destruct(Nd nd, long address, TagTreeReader reader) {
+ // Nothing to do by default
+ }
+ }
+
+ public static abstract class FixedSizeTagHandler<T> extends TagHandler<T> {
+ protected abstract T read(Nd nd, long address);
+ protected abstract void write(Nd nd, long address, T value);
+ protected abstract int getSize();
+ protected void destruct(Nd nd, long address) {
+ // Nothing to do by default
+ }
+
+ public final T read(Nd nd, long address, TagTreeReader reader, int[] bytesRead) {
+ bytesRead[0] = getSize();
+ return read(nd, address);
+ }
+
+ @Override
+ public final void write(Nd nd, long address, TagTreeReader reader, T value, int[] bytesWritten) {
+ bytesWritten[0] = getSize();
+ write(nd, address, value);
+ }
+
+ @Override
+ public final int getSize(Nd nd, T object, TagTreeReader reader) {
+ return getSize();
+ }
+
+ @Override
+ public final void destruct(Nd nd, long address, TagTreeReader reader) {
+ destruct(nd, address);
+ }
+ }
+
+ private TagHandler<?> readers[] = new TagHandler[256];
+ private Map<TagHandler<?>, Integer> values = new HashMap<>();
+
+ public final void add(byte key, TagHandler<?> reader) {
+ this.readers[key] = reader;
+ this.values.put(reader, (int) key);
+ }
+
+ public final Object read(Nd nd, long address) {
+ return read(nd, address, UNUSED_RESULT);
+ }
+
+ public final Object read(Nd nd, long address, int[] bytesRead) {
+ long readAddress = address;
+ Database db = nd.getDB();
+ byte nextByte = db.getByte(address);
+ readAddress += Database.BYTE_SIZE;
+ TagHandler<?> reader = this.readers[nextByte];
+ if (reader == null) {
+ throw new IndexException("Found unknown tag with value " + nextByte + " at address " + address); //$NON-NLS-1$//$NON-NLS-2$
+ }
+
+ return reader.read(nd, readAddress, this, bytesRead);
+ }
+
+ protected abstract byte getKeyFor(Object toWrite);
+
+ public final void write(Nd nd, long address, Object toWrite) {
+ write(nd, address, toWrite, UNUSED_RESULT);
+ }
+
+ @SuppressWarnings("unchecked")
+ public final void write(Nd nd, long address, Object toWrite, int[] bytesWritten) {
+ byte key = getKeyFor(toWrite);
+
+ @SuppressWarnings("rawtypes")
+ TagHandler handler = this.readers[key];
+
+ if (handler == null) {
+ throw new IndexException("Invalid key " + key + " returned from getKeyFor(...)"); //$NON-NLS-1$//$NON-NLS-2$
+ }
+
+ handler.write(nd, address, this, toWrite, bytesWritten);
+ }
+
+ public final void destruct(Nd nd, long address) {
+ Database db = nd.getDB();
+ long readAddress = address;
+ byte nextByte = db.getByte(readAddress);
+ readAddress += Database.BYTE_SIZE;
+
+ TagHandler<?> handler = this.readers[nextByte];
+ if (handler == null) {
+ throw new IndexException("Found unknown tag with value " + nextByte + " at address " + address); //$NON-NLS-1$//$NON-NLS-2$
+ }
+
+ handler.destruct(nd, readAddress, this);
+ }
+
+ @SuppressWarnings("unchecked")
+ public final int getSize(Nd nd, Object toMeasure) {
+ byte key = getKeyFor(toMeasure);
+
+ @SuppressWarnings("rawtypes")
+ TagHandler handler = this.readers[key];
+ if (handler == null) {
+ throw new IndexException("Attempted to get size of object " + toMeasure.toString() + " with unknown key " //$NON-NLS-1$//$NON-NLS-2$
+ + key);
+ }
+
+ return handler.getSize(nd, toMeasure, this);
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/TypeRef.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/TypeRef.java
new file mode 100644
index 000000000..4e65b4b05
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/TypeRef.java
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java;
+
+import java.util.List;
+import java.util.function.Supplier;
+
+import org.eclipse.jdt.internal.core.nd.DatabaseRef;
+import org.eclipse.jdt.internal.core.nd.IReader;
+import org.eclipse.jdt.internal.core.nd.Nd;
+
+/**
+ * Holds a reference to an NdType that can be retained while releasing and reacquiring a read lock.
+ */
+public final class TypeRef implements Supplier<NdType> {
+ final DatabaseRef<NdType> ref;
+ final char[] fileName;
+ final char[] fieldDescriptor;
+ final TypeSupplier typeSupplier = new TypeSupplier();
+ private final class TypeSupplier implements Supplier<NdType> {
+ public TypeSupplier() {
+ }
+
+ @Override
+ public NdType get() {
+ NdTypeId typeId = JavaIndex.getIndex(TypeRef.this.ref.getNd()).findType(TypeRef.this.fieldDescriptor);
+
+ if (typeId == null) {
+ return null;
+ }
+
+ List<NdType> implementations = typeId.getTypes();
+ for (NdType next : implementations) {
+ NdResourceFile nextResourceFile = next.getResourceFile();
+ if (nextResourceFile.getLocation().compare(TypeRef.this.fileName, false) == 0) {
+ if (nextResourceFile.isDoneIndexing()) {
+ return next;
+ }
+ }
+ }
+ return null;
+ }
+ }
+
+ private TypeRef(NdType type) {
+ super();
+ this.fieldDescriptor = type.getTypeId().getRawType().getFieldDescriptor().getChars();
+ this.fileName = type.getResourceFile().getLocation().getChars();
+ this.ref = new DatabaseRef<NdType>(type.getNd(), this.typeSupplier, type);
+ }
+
+ private TypeRef(Nd nd, char[] resourcePath, char[] fieldDescriptor) {
+ super();
+ this.fieldDescriptor = fieldDescriptor;
+ this.fileName = resourcePath;
+ this.ref = new DatabaseRef<NdType>(nd, this.typeSupplier);
+ }
+
+ public char[] getFieldDescriptor() {
+ return this.fieldDescriptor;
+ }
+
+ public char[] getFileName() {
+ return this.fileName;
+ }
+
+ /**
+ * Creates a {@link DatabaseRef} to the given {@link NdType}.
+ */
+ public static TypeRef create(NdType type) {
+ return new TypeRef(type);
+ }
+
+ /**
+ * Creates a {@link DatabaseRef} to the {@link NdType} with the given resource path and field descriptor.
+ */
+ public static TypeRef create(Nd nd, char[] resourcePath, char[] fieldDescriptor) {
+ return new TypeRef(nd, resourcePath, fieldDescriptor);
+ }
+
+ public IReader lock() {
+ return this.ref.lock();
+ }
+
+ @Override
+ public NdType get() {
+ return this.ref.get();
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeDescriptor.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeDescriptor.java
new file mode 100644
index 000000000..393537b21
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeDescriptor.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java.model;
+
+import org.eclipse.jdt.internal.compiler.env.IDependent;
+import org.eclipse.jdt.internal.core.nd.util.CharArrayUtils;
+
+/**
+ * Holds a lightweight identifier for an IBinaryType, with sufficient information to either read it from
+ * disk or read it from the index.
+ */
+public final class BinaryTypeDescriptor {
+ public final char[] indexPath;
+ public final char[] fieldDescriptor;
+ public final char[] location;
+ public final char[] workspacePath;
+
+ /**
+ * Constructs a new descriptor
+ *
+ * @param location
+ * location where the archive (.jar or .class) can be found in the local filesystem
+ * @param fieldDescriptor
+ * field descriptor for the type (see the JVM specification)
+ * @param workspacePath
+ * location where the archive (.jar or class) can be found in the workspace. If it is not in the
+ * workspace, this is the path where it can be found on the local filesystem.
+ * @param indexPath
+ * index path for the new type (workspace-or-local path to jar optionally followed by a | and a relative
+ * path within the .jar)
+ */
+ public BinaryTypeDescriptor(char[] location, char[] fieldDescriptor, char[] workspacePath, char[] indexPath) {
+ super();
+ this.location = location;
+ this.fieldDescriptor = fieldDescriptor;
+ this.indexPath = indexPath;
+ this.workspacePath = workspacePath;
+ }
+
+ public boolean isInJarFile() {
+ return CharArrayUtils.indexOf(IDependent.JAR_FILE_ENTRY_SEPARATOR, this.indexPath) != -1;
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeFactory.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeFactory.java
new file mode 100644
index 000000000..d6d3981a7
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeFactory.java
@@ -0,0 +1,228 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java.model;
+
+import java.io.IOException;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jdt.core.IClassFile;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IJavaModelStatusConstants;
+import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
+import org.eclipse.jdt.internal.compiler.env.IBinaryType;
+import org.eclipse.jdt.internal.compiler.env.IDependent;
+import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
+import org.eclipse.jdt.internal.core.ClassFile;
+import org.eclipse.jdt.internal.core.JarPackageFragmentRoot;
+import org.eclipse.jdt.internal.core.JavaModelManager;
+import org.eclipse.jdt.internal.core.PackageFragment;
+import org.eclipse.jdt.internal.core.nd.IReader;
+import org.eclipse.jdt.internal.core.nd.Nd;
+import org.eclipse.jdt.internal.core.nd.db.IndexException;
+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.NdResourceFile;
+import org.eclipse.jdt.internal.core.nd.java.NdType;
+import org.eclipse.jdt.internal.core.nd.java.TypeRef;
+import org.eclipse.jdt.internal.core.nd.util.CharArrayUtils;
+import org.eclipse.jdt.internal.core.util.Util;
+
+public class BinaryTypeFactory {
+ public static final class NotInIndexException extends Exception {
+ private static final long serialVersionUID = 2859848007651528256L;
+
+ public NotInIndexException() {
+ }
+ }
+
+ private final static char[] PACKAGE_INFO = "package-info".toCharArray(); //$NON-NLS-1$
+
+ /**
+ * Returns a descriptor for the given class within the given package fragment, or null if the fragment doesn't have
+ * a location on the filesystem.
+ */
+ private static BinaryTypeDescriptor createDescriptor(PackageFragment pkg, ClassFile classFile) {
+ String name = classFile.getName();
+ IJavaElement root = pkg.getParent();
+ IPath location = JavaIndex.getLocationForElement(root);
+ String entryName = Util.concatWith(pkg.names, classFile.getElementName(), '/');
+ char[] fieldDescriptor = CharArrayUtils.concat(new char[] { 'L' },
+ Util.concatWith(pkg.names, name, '/').toCharArray(), new char[] { ';' });
+ IPath workspacePath = root.getPath();
+ String indexPath;
+
+ if (location == null) {
+ return null;
+ }
+
+ if (root instanceof JarPackageFragmentRoot) {
+ // The old version returned this, but it doesn't conform to the spec on IBinaryType.getFileName():
+ indexPath = root.getHandleIdentifier() + IDependent.JAR_FILE_ENTRY_SEPARATOR + entryName;
+ // Version that conforms to the JavaDoc spec on IBinaryType.getFileName() -- note that this breaks
+ // InlineMethodTests in the JDT UI project. Need to investigate why before using it.
+ //indexPath = workspacePath.toString() + IDependent.JAR_FILE_ENTRY_SEPARATOR + entryName;
+ } else {
+ location = location.append(entryName);
+ indexPath = workspacePath.append(entryName).toString();
+ workspacePath = classFile.resource().getFullPath();
+ }
+
+ return new BinaryTypeDescriptor(location.toString().toCharArray(), fieldDescriptor,
+ workspacePath.toString().toCharArray(), indexPath.toCharArray());
+ }
+
+ public static BinaryTypeDescriptor createDescriptor(IClassFile classFile) {
+ ClassFile concreteClass = (ClassFile)classFile;
+ PackageFragment parent = (PackageFragment) classFile.getParent();
+
+ return createDescriptor(parent, concreteClass);
+ }
+
+ public static BinaryTypeDescriptor createDescriptor(IType type) {
+ return createDescriptor(type.getClassFile());
+ }
+
+ public static IBinaryType create(IClassFile classFile, IProgressMonitor monitor) throws JavaModelException, ClassFormatException {
+ BinaryTypeDescriptor descriptor = createDescriptor(classFile);
+ return readType(descriptor, monitor);
+ }
+
+ /**
+ * Reads the given binary type. If the type can be found in the index with a fingerprint that exactly matches
+ * the file on disk, the type is read from the index. Otherwise the type is read from disk. Returns null if
+ * no such type exists.
+ * @throws ClassFormatException
+ */
+ public static IBinaryType readType(BinaryTypeDescriptor descriptor,
+ IProgressMonitor monitor) throws JavaModelException, ClassFormatException {
+
+ if (JavaIndex.isEnabled()) {
+ try {
+ return readFromIndex(JavaIndex.getIndex(), descriptor, monitor);
+ } catch (NotInIndexException e) {
+ // fall back to reading the zip file, below
+ }
+ }
+
+ return rawReadType(descriptor, true);
+ }
+
+ /**
+ * Read the class file from disk, circumventing the index's cache. This should only be used by callers
+ * that need to read information from the class file which aren't present in the index (such as method bodies).
+ *
+ * @return the newly-created ClassFileReader or null if the given class file does not exist.
+ * @throws ClassFormatException if the class file existed but was corrupt
+ * @throws JavaModelException if unable to read the class file due to a transient failure
+ */
+ public static ClassFileReader rawReadType(BinaryTypeDescriptor descriptor, boolean fullyInitialize) throws JavaModelException, ClassFormatException {
+ if (descriptor == null) {
+ return null;
+ }
+ if (descriptor.isInJarFile()) {
+ ZipFile zip = null;
+ try {
+ zip = JavaModelManager.getJavaModelManager().getZipFile(new Path(new String(descriptor.workspacePath)));
+ char[] entryNameCharArray = CharArrayUtils.concat(
+ JavaNames.fieldDescriptorToBinaryName(descriptor.fieldDescriptor), SuffixConstants.SUFFIX_class);
+ String entryName = new String(entryNameCharArray);
+ ZipEntry ze = zip.getEntry(entryName);
+ if (ze != null) {
+ byte contents[];
+ try {
+ contents = org.eclipse.jdt.internal.compiler.util.Util.getZipEntryByteContent(ze, zip);
+ } catch (IOException ioe) {
+ throw new JavaModelException(ioe, IJavaModelStatusConstants.IO_EXCEPTION);
+ }
+ return new ClassFileReader(contents, descriptor.indexPath, fullyInitialize);
+ }
+ } catch (CoreException e) {
+ throw new JavaModelException(e);
+ } finally {
+ JavaModelManager.getJavaModelManager().closeZipFile(zip);
+ }
+ } else {
+ IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(new String(descriptor.workspacePath)));
+ byte[] contents = Util.getResourceContentsAsByteArray(file);
+ return new ClassFileReader(contents, file.getFullPath().toString().toCharArray(), fullyInitialize);
+ }
+ return null;
+ }
+
+ /**
+ * Tries to read the given IBinaryType from the index. The return value is lightweight and may be cached
+ * with minimal memory cost. Returns an IBinaryType if the type was found in the index and the index
+ * was up-to-date. Throws a NotInIndexException if the index does not contain an up-to-date cache of the
+ * requested file. Returns null if the index contains an up-to-date cache of the requested file and it was
+ * able to determine that the requested class does not exist in that file.
+ */
+ public static IBinaryType readFromIndex(JavaIndex index, BinaryTypeDescriptor descriptor, IProgressMonitor monitor) throws JavaModelException, NotInIndexException {
+ char[] className = JavaNames.fieldDescriptorToSimpleName(descriptor.fieldDescriptor);
+
+ // If the new index is enabled, check if we have this class file cached in the index already
+ char[] fieldDescriptor = descriptor.fieldDescriptor;
+
+ if (!CharArrayUtils.equals(PACKAGE_INFO, className)) {
+ Nd nd = index.getNd();
+
+ // We don't currently cache package-info files in the index
+ if (descriptor.location != null) {
+ // Acquire a read lock on the index
+ try (IReader lock = nd.acquireReadLock()) {
+ try {
+ TypeRef typeRef = TypeRef.create(nd, descriptor.location, fieldDescriptor);
+ NdType type = typeRef.get();
+
+ if (type == null) {
+ // If we couldn't find the type in the index, determine whether the cause is
+ // that the type is known not to exist or whether the resource just hasn't
+ // been indexed yet
+
+ NdResourceFile resourceFile = index.getResourceFile(descriptor.location);
+ if (index.isUpToDate(resourceFile)) {
+ return null;
+ }
+ throw new NotInIndexException();
+ }
+ NdResourceFile resourceFile = type.getResourceFile();
+ if (index.isUpToDate(resourceFile)) {
+ IndexBinaryType result = new IndexBinaryType(typeRef, descriptor.indexPath);
+
+ // We already have the database lock open and have located the element, so we may as
+ // well prefetch the inexpensive attributes.
+ result.initSimpleAttributes();
+
+ return result;
+ }
+ throw new NotInIndexException();
+ } catch (CoreException e) {
+ throw new JavaModelException(e);
+ }
+ } catch (IndexException e) {
+ // Index corrupted. Rebuild it.
+ index.rebuildIndex();
+ }
+ }
+ }
+
+ throw new NotInIndexException();
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/ITypeAnnotationBuilder.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/ITypeAnnotationBuilder.java
new file mode 100644
index 000000000..39e950133
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/ITypeAnnotationBuilder.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java.model;
+
+import org.eclipse.jdt.internal.compiler.env.IBinaryAnnotation;
+import org.eclipse.jdt.internal.compiler.env.IBinaryTypeAnnotation;
+
+public interface ITypeAnnotationBuilder {
+ ITypeAnnotationBuilder toField();
+ ITypeAnnotationBuilder toThrows(int rank);
+ ITypeAnnotationBuilder toTypeArgument(int rank);
+ ITypeAnnotationBuilder toMethodParameter(short index);
+ ITypeAnnotationBuilder toSupertype(short index);
+ ITypeAnnotationBuilder toTypeParameterBounds(boolean isClassTypeParameter, int parameterRank);
+ ITypeAnnotationBuilder toTypeBound(short boundIndex);
+ ITypeAnnotationBuilder toTypeParameter(boolean isClassTypeParameter, int rank);
+ ITypeAnnotationBuilder toMethodReturn();
+ ITypeAnnotationBuilder toReceiver();
+ ITypeAnnotationBuilder toWildcardBound();
+ ITypeAnnotationBuilder toNextArrayDimension();
+ ITypeAnnotationBuilder toNextNestedType();
+
+ IBinaryTypeAnnotation build(IBinaryAnnotation annotation);
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/IndexBinaryField.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/IndexBinaryField.java
new file mode 100644
index 000000000..3c1f7634c
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/IndexBinaryField.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java.model;
+
+import org.eclipse.jdt.internal.compiler.env.IBinaryAnnotation;
+import org.eclipse.jdt.internal.compiler.env.IBinaryField;
+import org.eclipse.jdt.internal.compiler.env.IBinaryTypeAnnotation;
+import org.eclipse.jdt.internal.compiler.impl.Constant;
+
+public class IndexBinaryField implements IBinaryField {
+ private int modifiers;
+ private IBinaryAnnotation[] annotations;
+ private IBinaryTypeAnnotation[] typeAnnotations;
+ private Constant constant;
+ private char[] genericSignature;
+ private char[] name;
+ private long tagBits;
+ private char[] typeName;
+
+ public IndexBinaryField(IBinaryAnnotation[] annotations, Constant constant, char[] genericSignature, int modifiers,
+ char[] name, long tagBits, IBinaryTypeAnnotation[] typeAnnotations, char[] fieldDescriptor) {
+ super();
+ this.modifiers = modifiers;
+ this.annotations = annotations;
+ this.typeAnnotations = typeAnnotations;
+ this.constant = constant;
+ this.genericSignature = genericSignature;
+ this.name = name;
+ this.tagBits = tagBits;
+ this.typeName = fieldDescriptor;
+ }
+
+ @Override
+ public int getModifiers() {
+ return this.modifiers;
+ }
+
+ @Override
+ public IBinaryAnnotation[] getAnnotations() {
+ return this.annotations;
+ }
+
+ @Override
+ public IBinaryTypeAnnotation[] getTypeAnnotations() {
+ return this.typeAnnotations;
+ }
+
+ @Override
+ public Constant getConstant() {
+ return this.constant;
+ }
+
+ @Override
+ public char[] getGenericSignature() {
+ return this.genericSignature;
+ }
+
+ @Override
+ public char[] getName() {
+ return this.name;
+ }
+
+ @Override
+ public long getTagBits() {
+ return this.tagBits;
+ }
+
+ @Override
+ public char[] getTypeName() {
+ return this.typeName;
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/IndexBinaryMethod.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/IndexBinaryMethod.java
new file mode 100644
index 000000000..5ce3c4cd5
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/IndexBinaryMethod.java
@@ -0,0 +1,182 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java.model;
+
+import org.eclipse.jdt.internal.compiler.classfmt.BinaryTypeFormatter;
+import org.eclipse.jdt.internal.compiler.env.IBinaryAnnotation;
+import org.eclipse.jdt.internal.compiler.env.IBinaryMethod;
+import org.eclipse.jdt.internal.compiler.env.IBinaryTypeAnnotation;
+
+public final class IndexBinaryMethod implements IBinaryMethod {
+ private int modifiers;
+ private boolean isConstructor;
+ private char[][] argumentNames;
+ private IBinaryAnnotation[] annotations;
+ private Object defaultValue;
+ private char[][] exceptionTypeNames;
+ private char[] genericSignature;
+ private char[] methodDescriptor;
+ private IBinaryAnnotation[][] parameterAnnotations;
+ private char[] selector;
+ private long tagBits;
+ private boolean isClInit;
+ private IBinaryTypeAnnotation[] typeAnnotations;
+
+ public static IndexBinaryMethod create() {
+ return new IndexBinaryMethod();
+ }
+
+ public IndexBinaryMethod setModifiers(int modifiers) {
+ this.modifiers = modifiers;
+ return this;
+ }
+
+ public IndexBinaryMethod setIsConstructor(boolean isConstructor) {
+ this.isConstructor = isConstructor;
+ return this;
+ }
+
+ public IndexBinaryMethod setArgumentNames(char[][] argumentNames) {
+ this.argumentNames = argumentNames;
+ return this;
+ }
+
+ public IndexBinaryMethod setAnnotations(IBinaryAnnotation[] annotations) {
+ this.annotations = annotations;
+ return this;
+ }
+
+ public IndexBinaryMethod setDefaultValue(Object defaultValue) {
+ this.defaultValue = defaultValue;
+ return this;
+ }
+
+ public IndexBinaryMethod setExceptionTypeNames(char[][] exceptionTypeNames) {
+ this.exceptionTypeNames = exceptionTypeNames;
+ return this;
+ }
+
+ public IndexBinaryMethod setGenericSignature(char[] genericSignature) {
+ this.genericSignature = genericSignature;
+ return this;
+ }
+
+ public IndexBinaryMethod setMethodDescriptor(char[] methodDescriptor) {
+ this.methodDescriptor = methodDescriptor;
+ return this;
+ }
+
+ public IndexBinaryMethod setParameterAnnotations(IBinaryAnnotation[][] parameterAnnotations) {
+ this.parameterAnnotations = parameterAnnotations;
+ return this;
+ }
+
+ public IndexBinaryMethod setSelector(char[] selector) {
+ this.selector = selector;
+ return this;
+ }
+
+ public IndexBinaryMethod setTagBits(long tagBits) {
+ this.tagBits = tagBits;
+ return this;
+ }
+
+ public IndexBinaryMethod setIsClInit(boolean isClInit) {
+ this.isClInit = isClInit;
+ return this;
+ }
+
+ public IndexBinaryMethod setTypeAnnotations(IBinaryTypeAnnotation[] typeAnnotations) {
+ this.typeAnnotations = typeAnnotations;
+ return this;
+ }
+
+ @Override
+ public int getModifiers() {
+ return this.modifiers;
+ }
+
+ @Override
+ public boolean isConstructor() {
+ return this.isConstructor;
+ }
+
+ @Override
+ public char[][] getArgumentNames() {
+ return this.argumentNames;
+ }
+
+ @Override
+ public IBinaryAnnotation[] getAnnotations() {
+ return this.annotations;
+ }
+
+ @Override
+ public Object getDefaultValue() {
+ return this.defaultValue;
+ }
+
+ @Override
+ public char[][] getExceptionTypeNames() {
+ return this.exceptionTypeNames;
+ }
+
+ @Override
+ public char[] getGenericSignature() {
+ return this.genericSignature;
+ }
+
+ @Override
+ public char[] getMethodDescriptor() {
+ return this.methodDescriptor;
+ }
+
+ @Override
+ public IBinaryAnnotation[] getParameterAnnotations(int index, char[] classFileName) {
+ if (this.parameterAnnotations == null || this.parameterAnnotations.length <= index) {
+ return null;
+ }
+ return this.parameterAnnotations[index];
+ }
+
+ @Override
+ public int getAnnotatedParametersCount() {
+ if (this.parameterAnnotations == null) {
+ return 0;
+ }
+ return this.parameterAnnotations.length;
+ }
+
+ @Override
+ public char[] getSelector() {
+ return this.selector;
+ }
+
+ @Override
+ public long getTagBits() {
+ return this.tagBits;
+ }
+
+ @Override
+ public boolean isClinit() {
+ return this.isClInit;
+ }
+
+ @Override
+ public IBinaryTypeAnnotation[] getTypeAnnotations() {
+ return this.typeAnnotations;
+ }
+
+ @Override
+ public String toString() {
+ return BinaryTypeFormatter.methodToString(this);
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/IndexBinaryNestedType.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/IndexBinaryNestedType.java
new file mode 100644
index 000000000..40d8a5402
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/IndexBinaryNestedType.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java.model;
+
+import org.eclipse.jdt.internal.compiler.env.IBinaryNestedType;
+
+public class IndexBinaryNestedType implements IBinaryNestedType {
+ private char[] enclosingTypeName;
+ private char[] name;
+ private int modifiers;
+
+ public IndexBinaryNestedType(char[] name, char[] enclosingTypeName, int modifiers) {
+ super();
+ this.name = name;
+ this.enclosingTypeName = enclosingTypeName;
+ this.modifiers = modifiers;
+ }
+
+ @Override
+ public char[] getEnclosingTypeName() {
+ return this.enclosingTypeName;
+ }
+
+ @Override
+ public int getModifiers() {
+ return this.modifiers;
+ }
+
+ @Override
+ public char[] getName() {
+ return this.name;
+ }
+
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/IndexBinaryType.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/IndexBinaryType.java
new file mode 100644
index 000000000..aaa7576a2
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/IndexBinaryType.java
@@ -0,0 +1,672 @@
+/*******************************************************************************
+ * 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.nd.java.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.classfmt.BinaryTypeFormatter;
+import org.eclipse.jdt.internal.compiler.classfmt.ElementValuePairInfo;
+import org.eclipse.jdt.internal.compiler.codegen.AnnotationTargetTypeConstants;
+import org.eclipse.jdt.internal.compiler.env.ClassSignature;
+import org.eclipse.jdt.internal.compiler.env.EnumConstantSignature;
+import org.eclipse.jdt.internal.compiler.env.IBinaryAnnotation;
+import org.eclipse.jdt.internal.compiler.env.IBinaryElementValuePair;
+import org.eclipse.jdt.internal.compiler.env.IBinaryField;
+import org.eclipse.jdt.internal.compiler.env.IBinaryMethod;
+import org.eclipse.jdt.internal.compiler.env.IBinaryNestedType;
+import org.eclipse.jdt.internal.compiler.env.IBinaryType;
+import org.eclipse.jdt.internal.compiler.env.IBinaryTypeAnnotation;
+import org.eclipse.jdt.internal.compiler.env.ITypeAnnotationWalker;
+import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding.ExternalAnnotationStatus;
+import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
+import org.eclipse.jdt.internal.core.nd.IReader;
+import org.eclipse.jdt.internal.core.nd.db.IString;
+import org.eclipse.jdt.internal.core.nd.java.JavaNames;
+import org.eclipse.jdt.internal.core.nd.java.NdAnnotation;
+import org.eclipse.jdt.internal.core.nd.java.NdAnnotationValuePair;
+import org.eclipse.jdt.internal.core.nd.java.NdConstant;
+import org.eclipse.jdt.internal.core.nd.java.NdConstantAnnotation;
+import org.eclipse.jdt.internal.core.nd.java.NdConstantArray;
+import org.eclipse.jdt.internal.core.nd.java.NdConstantClass;
+import org.eclipse.jdt.internal.core.nd.java.NdConstantEnum;
+import org.eclipse.jdt.internal.core.nd.java.NdMethod;
+import org.eclipse.jdt.internal.core.nd.java.NdMethodException;
+import org.eclipse.jdt.internal.core.nd.java.NdMethodId;
+import org.eclipse.jdt.internal.core.nd.java.NdMethodParameter;
+import org.eclipse.jdt.internal.core.nd.java.NdResourceFile;
+import org.eclipse.jdt.internal.core.nd.java.NdType;
+import org.eclipse.jdt.internal.core.nd.java.NdTypeAnnotation;
+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.NdTypeParameter;
+import org.eclipse.jdt.internal.core.nd.java.NdTypeSignature;
+import org.eclipse.jdt.internal.core.nd.java.NdVariable;
+import org.eclipse.jdt.internal.core.nd.java.TypeRef;
+import org.eclipse.jdt.internal.core.nd.util.CharArrayUtils;
+import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
+
+/**
+ * Implementation of {@link IBinaryType} that reads all its content from the index
+ */
+public class IndexBinaryType implements IBinaryType {
+ private final TypeRef typeRef;
+
+ private boolean simpleAttributesInitialized;
+ private char[] enclosingMethod;
+ private char[] enclosingType;
+ private char[] fileName;
+ private char[] superclassName;
+ private int modifiers;
+ private boolean isAnonymous;
+ private boolean isLocal;
+ private boolean isMember;
+
+ private long tagBits;
+
+ private char[] binaryTypeName;
+
+ private static final IBinaryAnnotation[] NO_ANNOTATIONS = new IBinaryAnnotation[0];
+ private static final int[] NO_PATH = new int[0];
+
+ public IndexBinaryType(TypeRef type, char[] indexPath) {
+ this.typeRef = type;
+ this.fileName = indexPath;
+ }
+
+ public boolean exists() {
+ return this.typeRef.get() != null;
+ }
+
+ @Override
+ public int getModifiers() {
+ initSimpleAttributes();
+
+ return this.modifiers;
+ }
+
+ @Override
+ public boolean isBinaryType() {
+ return true;
+ }
+
+ @Override
+ public char[] getFileName() {
+ return this.fileName;
+ }
+
+ @Override
+ public IBinaryAnnotation[] getAnnotations() {
+ try (IReader rl = this.typeRef.lock()) {
+ NdType type = this.typeRef.get();
+ if (type != null) {
+ return toAnnotationArray(this.typeRef.get().getAnnotations());
+ } else {
+ return NO_ANNOTATIONS;
+ }
+ }
+ }
+
+ private static IBinaryAnnotation[] toAnnotationArray(List<? extends NdAnnotation> annotations) {
+ if (annotations.isEmpty()) {
+ return NO_ANNOTATIONS;
+ }
+ IBinaryAnnotation[] result = new IBinaryAnnotation[annotations.size()];
+
+ for (int idx = 0; idx < result.length; idx++) {
+ result[idx] = createBinaryAnnotation(annotations.get(idx));
+ }
+ return result;
+ }
+
+ @Override
+ public IBinaryTypeAnnotation[] getTypeAnnotations() {
+ try (IReader rl = this.typeRef.lock()) {
+ NdType type = this.typeRef.get();
+ if (type != null) {
+ return createBinaryTypeAnnotations(type.getTypeAnnotations());
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public char[] getEnclosingMethod() {
+ initSimpleAttributes();
+
+ return this.enclosingMethod;
+ }
+
+ @Override
+ public char[] getEnclosingTypeName() {
+ initSimpleAttributes();
+
+ return this.enclosingType;
+ }
+
+ @Override
+ public IBinaryField[] getFields() {
+ try (IReader rl = this.typeRef.lock()) {
+ NdType type = this.typeRef.get();
+ if (type != null) {
+ List<NdVariable> variables = type.getVariables();
+
+ if (variables.isEmpty()) {
+ return null;
+ }
+
+ IBinaryField[] result = new IBinaryField[variables.size()];
+ for (int fieldIdx = 0; fieldIdx < variables.size(); fieldIdx++) {
+ result[fieldIdx] = createBinaryField(variables.get(fieldIdx));
+ }
+ return result;
+ } else {
+ return null;
+ }
+ }
+ }
+
+ @Override
+ public char[] getGenericSignature() {
+ try (IReader rl = this.typeRef.lock()) {
+ NdType type = this.typeRef.get();
+ if (type != null) {
+ if (!type.getFlag(NdType.FLG_GENERIC_SIGNATURE_PRESENT)) {
+ return null;
+ }
+ CharArrayBuffer buffer = new CharArrayBuffer();
+ NdTypeParameter.getSignature(buffer, type.getTypeParameters());
+ NdTypeSignature superclass = type.getSuperclass();
+ if (superclass != null) {
+ superclass.getSignature(buffer);
+ }
+ for (NdTypeInterface nextInterface : type.getInterfaces()) {
+ nextInterface.getInterface().getSignature(buffer);
+ }
+ return buffer.getContents();
+ } else {
+ return null;
+ }
+ }
+ }
+
+ @Override
+ public char[][] getInterfaceNames() {
+ try (IReader rl = this.typeRef.lock()) {
+ NdType type = this.typeRef.get();
+ if (type != null) {
+ List<NdTypeInterface> interfaces = type.getInterfaces();
+
+ if (interfaces.isEmpty()) {
+ return null;
+ }
+
+ char[][] result = new char[interfaces.size()][];
+ for (int idx = 0; idx < interfaces.size(); idx++) {
+ NdTypeSignature nextInterface = interfaces.get(idx).getInterface();
+
+ result[idx] = nextInterface.getRawType().getBinaryName();
+ }
+ return result;
+ } else {
+ return null;
+ }
+ }
+ }
+
+ @Override
+ public IBinaryNestedType[] getMemberTypes() {
+ try (IReader rl = this.typeRef.lock()) {
+ NdType type = this.typeRef.get();
+ if (type != null) {
+ List<NdType> declaredTypes = type.getTypeId().getDeclaredTypes();
+ if (declaredTypes.isEmpty()) {
+ return null;
+ }
+
+ NdResourceFile resFile = type.getResourceFile();
+ IString javaRoot = resFile.getPackageFragmentRoot();
+
+ // Filter out all the declared types which are at different java roots (only keep the ones belonging
+ // to the same .jar file or to another .class file in the same folder).
+ List<IBinaryNestedType> result = new ArrayList<>();
+ for (NdType next : declaredTypes) {
+ NdResourceFile nextResFile = next.getResourceFile();
+
+ if (nextResFile.getPackageFragmentRoot().compare(javaRoot, true) == 0) {
+ result.add(createBinaryNestedType(next));
+ }
+ }
+ return result.isEmpty() ? null : result.toArray(new IBinaryNestedType[result.size()]);
+ } else {
+ return null;
+ }
+ }
+ }
+
+ private IBinaryNestedType createBinaryNestedType(NdType next) {
+ return new IndexBinaryNestedType(next.getTypeId().getBinaryName(), next.getDeclaringType().getBinaryName(),
+ next.getModifiers());
+ }
+
+ @Override
+ public IBinaryMethod[] getMethods() {
+ try (IReader rl = this.typeRef.lock()) {
+ NdType type = this.typeRef.get();
+ if (type != null) {
+ List<NdMethod> methods = type.getMethods();
+
+ if (methods.isEmpty()) {
+ return null;
+ }
+
+ IBinaryMethod[] result = new IBinaryMethod[methods.size()];
+ for (int idx = 0; idx < result.length; idx++) {
+ result[idx] = createBinaryMethod(methods.get(idx));
+ }
+
+ return result;
+ } else {
+ return null;
+ }
+ }
+ }
+
+ @Override
+ public char[][][] getMissingTypeNames() {
+ try (IReader rl = this.typeRef.lock()) {
+ NdType type = this.typeRef.get();
+ if (type != null) {
+ IString string = type.getMissingTypeNames();
+ if (string.length() == 0) {
+ return null;
+ }
+ char[] missingTypeNames = string.getChars();
+ char[][] paths = CharOperation.splitOn(',', missingTypeNames);
+ char[][][] result = new char[paths.length][][];
+ for (int idx = 0; idx < paths.length; idx++) {
+ result[idx] = CharOperation.splitOn('/', paths[idx]);
+ }
+ return result;
+ } else {
+ return null;
+ }
+ }
+ }
+
+ @Override
+ public char[] getName() {
+ initSimpleAttributes();
+
+ return this.binaryTypeName;
+ }
+
+ @Override
+ public char[] getSourceName() {
+ try (IReader rl = this.typeRef.lock()) {
+ NdType type = this.typeRef.get();
+ if (type != null) {
+ return type.getSourceName();
+ } else {
+ return new char[0];
+ }
+ }
+ }
+
+ @Override
+ public char[] getSuperclassName() {
+ initSimpleAttributes();
+
+ return this.superclassName;
+ }
+
+ @Override
+ public long getTagBits() {
+ initSimpleAttributes();
+
+ return this.tagBits;
+ }
+
+ @Override
+ public boolean isAnonymous() {
+ initSimpleAttributes();
+
+ return this.isAnonymous;
+ }
+
+ @Override
+ public boolean isLocal() {
+ initSimpleAttributes();
+
+ return this.isLocal;
+ }
+
+ @Override
+ public boolean isMember() {
+ initSimpleAttributes();
+
+ return this.isMember;
+ }
+
+ @Override
+ public char[] sourceFileName() {
+ try (IReader rl = this.typeRef.lock()) {
+ NdType type = this.typeRef.get();
+ if (type != null) {
+ char[] result = type.getSourceFileName().getChars();
+ if (result.length == 0) {
+ return null;
+ }
+ return result;
+ } else {
+ return null;
+ }
+ }
+ }
+
+ @Override
+ public ITypeAnnotationWalker enrichWithExternalAnnotationsFor(ITypeAnnotationWalker walker, Object member,
+ LookupEnvironment environment) {
+ return walker;
+ }
+
+ private IBinaryMethod createBinaryMethod(NdMethod ndMethod) {
+ NdMethodId methodId = ndMethod.getMethodId();
+
+ return IndexBinaryMethod.create().setAnnotations(toAnnotationArray(ndMethod.getAnnotations()))
+ .setModifiers(ndMethod.getModifiers()).setIsConstructor(methodId.isConstructor())
+ .setArgumentNames(getArgumentNames(ndMethod)).setDefaultValue(unpackValue(ndMethod.getDefaultValue()))
+ .setExceptionTypeNames(getExceptionTypeNames(ndMethod))
+ .setGenericSignature(getGenericSignatureFor(ndMethod))
+ .setMethodDescriptor(methodId.getMethodDescriptor())
+ .setParameterAnnotations(getParameterAnnotations(ndMethod))
+ .setSelector(ndMethod.getMethodId().getSelector()).setTagBits(ndMethod.getTagBits())
+ .setIsClInit(methodId.isClInit()).setTypeAnnotations(createBinaryTypeAnnotations(ndMethod.getTypeAnnotations()));
+ }
+
+ private static IBinaryTypeAnnotation[] createBinaryTypeAnnotations(List<? extends NdTypeAnnotation> typeAnnotations) {
+ if (typeAnnotations.isEmpty()) {
+ return null;
+ }
+ IBinaryTypeAnnotation[] result = new IBinaryTypeAnnotation[typeAnnotations.size()];
+ int idx = 0;
+ for (NdTypeAnnotation next : typeAnnotations) {
+ IBinaryAnnotation annotation = createBinaryAnnotation(next);
+ int[] typePath = getTypePath(next.getTypePath());
+ int info = 0;
+ int info2 = 0;
+ switch (next.getTargetType()) {
+ case AnnotationTargetTypeConstants.CLASS_TYPE_PARAMETER:
+ case AnnotationTargetTypeConstants.METHOD_TYPE_PARAMETER:
+ info = next.getTargetInfoArg0();
+ break;
+ case AnnotationTargetTypeConstants.CLASS_EXTENDS:
+ info = next.getTarget();
+ break;
+ case AnnotationTargetTypeConstants.CLASS_TYPE_PARAMETER_BOUND:
+ case AnnotationTargetTypeConstants.METHOD_TYPE_PARAMETER_BOUND:
+ info = next.getTargetInfoArg0();
+ info2 = next.getTargetInfoArg1();
+ break;
+ case AnnotationTargetTypeConstants.FIELD:
+ case AnnotationTargetTypeConstants.METHOD_RETURN:
+ case AnnotationTargetTypeConstants.METHOD_RECEIVER:
+ break;
+ case AnnotationTargetTypeConstants.METHOD_FORMAL_PARAMETER :
+ info = next.getTargetInfoArg0();
+ break;
+ case AnnotationTargetTypeConstants.THROWS :
+ info = next.getTarget();
+ break;
+
+ default:
+ throw new IllegalStateException("Target type not handled " + next.getTargetType()); //$NON-NLS-1$
+ }
+ result[idx++] = new IndexBinaryTypeAnnotation(next.getTargetType(), info, info2, typePath, annotation);
+ }
+ return result;
+ }
+
+ private static int[] getTypePath(byte[] typePath) {
+ if (typePath.length == 0) {
+ return NO_PATH;
+ }
+ int[] result = new int[typePath.length];
+ for (int idx = 0; idx < typePath.length; idx++) {
+ result[idx] = typePath[idx];
+ }
+ return result;
+ }
+
+ private static char[] getGenericSignatureFor(NdMethod method) {
+ if (!method.hasAllFlags(NdMethod.FLG_GENERIC_SIGNATURE_PRESENT)) {
+ return null;
+ }
+ CharArrayBuffer result = new CharArrayBuffer();
+ method.getGenericSignature(result, method.hasAllFlags(NdMethod.FLG_THROWS_SIGNATURE_PRESENT));
+ return result.getContents();
+ }
+
+ private char[][] getArgumentNames(NdMethod ndMethod) {
+ // Unlike what its JavaDoc says, IBinaryType returns an empty array if no argument names are available, so
+ // we replicate this weird undocumented corner case here.
+ char[][] result = ndMethod.getParameterNames();
+ int lastNonEmpty = -1;
+ for (int idx = 0; idx < result.length; idx++) {
+ if (result[idx] != null && result[idx].length != 0) {
+ lastNonEmpty = idx;
+ }
+ }
+
+ if (lastNonEmpty != result.length - 1) {
+ char[][] newResult = new char[lastNonEmpty + 1][];
+ System.arraycopy(result, 0, newResult, 0, lastNonEmpty + 1);
+ return newResult;
+ }
+ return result;
+ }
+
+ private IBinaryAnnotation[][] getParameterAnnotations(NdMethod ndMethod) {
+ List<NdMethodParameter> parameters = ndMethod.getMethodParameters();
+ if (parameters.isEmpty()) {
+ return null;
+ }
+
+ IBinaryAnnotation[][] result = new IBinaryAnnotation[parameters.size()][];
+ for (int idx = 0; idx < parameters.size(); idx++) {
+ NdMethodParameter next = parameters.get(idx);
+
+ result[idx] = toAnnotationArray(next.getAnnotations());
+ }
+
+ // int newLength = result.length;
+ // while (newLength > 0 && result[newLength - 1] == null) {
+ // --newLength;
+ // }
+ //
+ // if (newLength < result.length) {
+ // if (newLength == 0) {
+ // return null;
+ // }
+ // IBinaryAnnotation[][] newResult = new IBinaryAnnotation[newLength][];
+ // System.arraycopy(result, 0, newResult, 0, newLength);
+ // result = newResult;
+ // }
+
+ return result;
+ }
+
+ private char[][] getExceptionTypeNames(NdMethod ndMethod) {
+ List<NdMethodException> exceptions = ndMethod.getExceptions();
+
+ // Although the JavaDoc for IBinaryMethod says that the exception list will be null if empty,
+ // the implementation in MethodInfo returns an empty array rather than null. We copy the
+ // same behavior here in case something is relying on it. Uncomment the following if the "null"
+ // version is deemed correct.
+
+ // if (exceptions.isEmpty()) {
+ // return null;
+ // }
+
+ char[][] result = new char[exceptions.size()][];
+ for (int idx = 0; idx < exceptions.size(); idx++) {
+ NdMethodException next = exceptions.get(idx);
+
+ result[idx] = next.getExceptionType().getRawType().getBinaryName();
+ }
+ return result;
+ }
+
+ public static IBinaryField createBinaryField(NdVariable ndVariable) {
+ char[] name = ndVariable.getName().getChars();
+ Constant constant = null;
+ NdConstant ndConstant = ndVariable.getConstant();
+ if (ndConstant != null) {
+ constant = ndConstant.getConstant();
+ }
+ if (constant == null) {
+ constant = Constant.NotAConstant;
+ }
+
+ NdTypeSignature type = ndVariable.getType();
+
+ IBinaryTypeAnnotation[] typeAnnotationArray = createBinaryTypeAnnotations(ndVariable.getTypeAnnotations());
+
+ IBinaryAnnotation[] annotations = toAnnotationArray(ndVariable.getAnnotations());
+
+ CharArrayBuffer signature = new CharArrayBuffer();
+ if (ndVariable.hasVariableFlag(NdVariable.FLG_GENERIC_SIGNATURE_PRESENT)) {
+ type.getSignature(signature);
+ }
+
+ long tagBits = ndVariable.getTagBits();
+ return new IndexBinaryField(annotations, constant, signature.getContents(), ndVariable.getModifiers(), name,
+ tagBits, typeAnnotationArray, type.getRawType().getFieldDescriptor().getChars());
+ }
+
+ public static IBinaryAnnotation createBinaryAnnotation(NdAnnotation ndAnnotation) {
+ List<NdAnnotationValuePair> elementValuePairs = ndAnnotation.getElementValuePairs();
+
+ final IBinaryElementValuePair[] resultingPair = new IBinaryElementValuePair[elementValuePairs.size()];
+
+ for (int idx = 0; idx < elementValuePairs.size(); idx++) {
+ NdAnnotationValuePair next = elementValuePairs.get(idx);
+
+ resultingPair[idx] = new ElementValuePairInfo(next.getName().getChars(), unpackValue(next.getValue()));
+ }
+
+ final char[] binaryName = JavaNames.fieldDescriptorToBinaryName(
+ ndAnnotation.getType().getRawType().getFieldDescriptor().getChars());
+
+ return new IBinaryAnnotation() {
+ @Override
+ public char[] getTypeName() {
+ return binaryName;
+ }
+
+ @Override
+ public IBinaryElementValuePair[] getElementValuePairs() {
+ return resultingPair;
+ }
+
+ @Override
+ public String toString() {
+ return BinaryTypeFormatter.annotationToString(this);
+ }
+ };
+ }
+
+ public void initSimpleAttributes() {
+ if (!this.simpleAttributesInitialized) {
+ this.simpleAttributesInitialized = true;
+
+ try (IReader rl = this.typeRef.lock()) {
+ NdType type = this.typeRef.get();
+ if (type != null) {
+ NdMethodId methodId = type.getDeclaringMethod();
+
+ if (methodId != null) {
+ char[] methodName = methodId.getMethodName().getChars();
+ int startIdx = CharArrayUtils.lastIndexOf('#', methodName);
+ this.enclosingMethod = CharArrayUtils.subarray(methodName, startIdx + 1);
+ this.enclosingType = CharArrayUtils.subarray(methodName, 1, startIdx);
+ } else {
+ NdTypeId typeId = type.getDeclaringType();
+
+ if (typeId != null) {
+ this.enclosingType = typeId.getBinaryName();
+ }
+ }
+
+ this.modifiers = type.getModifiers();
+ this.isAnonymous = type.isAnonymous();
+ this.isLocal = type.isLocal();
+ this.isMember = type.isMember();
+ this.tagBits = type.getTagBits();
+
+ NdTypeSignature superclass = type.getSuperclass();
+ if (superclass != null) {
+ this.superclassName = superclass.getRawType().getBinaryName();
+ } else {
+ this.superclassName = null;
+ }
+
+ this.binaryTypeName = JavaNames.fieldDescriptorToBinaryName(type.getFieldDescriptor().getChars());
+ } else {
+ this.binaryTypeName = JavaNames.fieldDescriptorToBinaryName(this.typeRef.getFieldDescriptor());
+ }
+ }
+ }
+ }
+
+ private static Object unpackValue(NdConstant value) {
+ if (value == null) {
+ return null;
+ }
+ if (value instanceof NdConstantAnnotation) {
+ NdConstantAnnotation annotation = (NdConstantAnnotation) value;
+
+ return createBinaryAnnotation(annotation.getValue());
+ }
+ if (value instanceof NdConstantArray) {
+ NdConstantArray array = (NdConstantArray) value;
+
+ List<NdConstant> arrayContents = array.getValue();
+
+ Object[] result = new Object[arrayContents.size()];
+ for (int idx = 0; idx < arrayContents.size(); idx++) {
+ result[idx] = unpackValue(arrayContents.get(idx));
+ }
+ return result;
+ }
+ if (value instanceof NdConstantEnum) {
+ NdConstantEnum ndConstantEnum = (NdConstantEnum) value;
+
+ NdTypeSignature signature = ndConstantEnum.getType();
+
+ return new EnumConstantSignature(signature.getRawType().getBinaryName(), ndConstantEnum.getValue());
+ }
+ if (value instanceof NdConstantClass) {
+ NdConstantClass constant = (NdConstantClass) value;
+
+ return new ClassSignature(constant.getValue().getRawType().getBinaryName());
+ }
+
+ return value.getConstant();
+ }
+
+ @Override
+ public ExternalAnnotationStatus getExternalAnnotationStatus() {
+ return ExternalAnnotationStatus.NOT_EEA_CONFIGURED;
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/IndexBinaryTypeAnnotation.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/IndexBinaryTypeAnnotation.java
new file mode 100644
index 000000000..521e17bd4
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/IndexBinaryTypeAnnotation.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java.model;
+
+import org.eclipse.jdt.internal.compiler.classfmt.BinaryTypeFormatter;
+import org.eclipse.jdt.internal.compiler.env.IBinaryAnnotation;
+import org.eclipse.jdt.internal.compiler.env.IBinaryTypeAnnotation;
+
+public class IndexBinaryTypeAnnotation implements IBinaryTypeAnnotation {
+ private int targetType;
+
+ // info is used in different ways:
+ // TargetType 0x00: CLASS_TYPE_PARAMETER: type parameter index
+ // TargetType 0x01: METHOD_TYPE_PARAMETER: type parameter index
+ // TargetType 0x10: CLASS_EXTENDS: supertype index (-1 = superclass, 0..N superinterface)
+ // TargetType 0x11: CLASS_TYPE_PARAMETER_BOUND: type parameter index
+ // TargetType 0x12: METHOD_TYPE_PARAMETER_BOUND: type parameter index
+ // TargetType 0x16: METHOD_FORMAL_PARAMETER: method formal parameter index
+ // TargetType 0x17: THROWS: throws type index
+ private int info;
+
+ // TargetType 0x11: CLASS_TYPE_PARAMETER_BOUND: bound index
+ // TargetType 0x12: METHOD_TYPE_PARAMETER_BOUND: bound index
+ private int info2;
+
+
+ private int[] typePath;
+ private IBinaryAnnotation annotation;
+
+ public IndexBinaryTypeAnnotation(int targetType, int info, int info2, int[] typePath, IBinaryAnnotation annotation) {
+ this.targetType = targetType;
+ this.info = info;
+ this.info2 = info2;
+ this.typePath = typePath;
+ this.annotation = annotation;
+ }
+
+ @Override
+ public IBinaryAnnotation getAnnotation() {
+ return this.annotation;
+ }
+
+ @Override
+ public int getTargetType() {
+ return this.targetType;
+ }
+
+ @Override
+ public int[] getTypePath() {
+ return this.typePath;
+ }
+
+ @Override
+ public int getSupertypeIndex() {
+ return this.info;
+ }
+
+ @Override
+ public int getTypeParameterIndex() {
+ return this.info;
+}
+
+ @Override
+ public int getBoundIndex() {
+ return this.info2;
+ }
+
+ @Override
+ public int getMethodFormalParameterIndex() {
+ return this.info;
+ }
+
+ @Override
+ public int getThrowsTypeIndex() {
+ return this.info;
+ }
+
+ @Override
+ public String toString() {
+ return BinaryTypeFormatter.annotationToString(this);
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/TypeAnnotationBuilder.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/TypeAnnotationBuilder.java
new file mode 100644
index 000000000..0b8d7d4ed
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/TypeAnnotationBuilder.java
@@ -0,0 +1,150 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 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.nd.java.model;
+
+import org.eclipse.jdt.internal.compiler.codegen.AnnotationTargetTypeConstants;
+import org.eclipse.jdt.internal.compiler.env.IBinaryAnnotation;
+import org.eclipse.jdt.internal.compiler.env.IBinaryTypeAnnotation;
+
+public class TypeAnnotationBuilder implements ITypeAnnotationBuilder {
+ TypeAnnotationBuilder parent;
+ int kind;
+ int index;
+ int length;
+ int target;
+ int targetParameter;
+ int targetParameter2;
+
+ private TypeAnnotationBuilder(TypeAnnotationBuilder parent, int kind, int index,
+ int length, int nextTarget, int nextTargetParameter, int nextTargetParameter2) {
+ super();
+ this.parent = parent;
+ this.kind = kind;
+ this.index = index;
+ this.length = length;
+ this.target = nextTarget;
+ this.targetParameter = nextTargetParameter;
+ this.targetParameter2 = nextTargetParameter2;
+ }
+
+ public static TypeAnnotationBuilder create() {
+ return new TypeAnnotationBuilder(null, 0, 0, 0, -1, -1, -1);
+ }
+
+ private TypeAnnotationBuilder walk(int nextKind, int nextIndex) {
+ return new TypeAnnotationBuilder(this, nextKind, nextIndex, this.length+1, this.target, this.targetParameter, this.targetParameter2);
+ }
+
+ private TypeAnnotationBuilder toTarget(int newTarget) {
+ return new TypeAnnotationBuilder(this.parent, this.kind, this.index, this.length, newTarget, this.targetParameter, this.targetParameter2);
+ }
+
+ private TypeAnnotationBuilder toTarget(int newTarget, int parameter) {
+ return new TypeAnnotationBuilder(this.parent, this.kind, this.index, this.length, newTarget, parameter, this.targetParameter2);
+ }
+
+ private TypeAnnotationBuilder toTarget2(int parameter) {
+ return new TypeAnnotationBuilder(this.parent, this.kind, this.index, this.length, this.target, this.targetParameter, parameter);
+ }
+
+ @Override
+ public ITypeAnnotationBuilder toField() {
+ return toTarget(AnnotationTargetTypeConstants.FIELD);
+ }
+
+ @Override
+ public ITypeAnnotationBuilder toMethodReturn() {
+ return toTarget(AnnotationTargetTypeConstants.METHOD_RETURN);
+ }
+
+ @Override
+ public ITypeAnnotationBuilder toReceiver() {
+ return toTarget(AnnotationTargetTypeConstants.METHOD_RECEIVER);
+ }
+
+ @Override
+ public ITypeAnnotationBuilder toTypeParameter(boolean isClassTypeParameter, int rank) {
+ int targetType = isClassTypeParameter ? AnnotationTargetTypeConstants.CLASS_TYPE_PARAMETER
+ : AnnotationTargetTypeConstants.METHOD_TYPE_PARAMETER;
+ return toTarget(targetType, rank);
+ }
+
+ @Override
+ public ITypeAnnotationBuilder toTypeParameterBounds(boolean isClassTypeParameter, int parameterRank) {
+ int targetType = isClassTypeParameter ?
+ AnnotationTargetTypeConstants.CLASS_TYPE_PARAMETER_BOUND : AnnotationTargetTypeConstants.METHOD_TYPE_PARAMETER_BOUND;
+
+ return toTarget(targetType, parameterRank);
+ }
+
+ @Override
+ public ITypeAnnotationBuilder toTypeBound(short boundIndex) {
+ return toTarget2(boundIndex);
+ }
+
+ @Override
+ public ITypeAnnotationBuilder toSupertype(short superTypeIndex) {
+ return toTarget(AnnotationTargetTypeConstants.CLASS_EXTENDS, superTypeIndex);
+ }
+
+ @Override
+ public ITypeAnnotationBuilder toMethodParameter(short parameterIndex) {
+ return toTarget(AnnotationTargetTypeConstants.METHOD_FORMAL_PARAMETER, parameterIndex);
+ }
+
+ @Override
+ public ITypeAnnotationBuilder toThrows(int rank) {
+ return toTarget(AnnotationTargetTypeConstants.THROWS, rank);
+ }
+
+ @Override
+ public ITypeAnnotationBuilder toTypeArgument(int rank) {
+ return walk(AnnotationTargetTypeConstants.TYPE_ARGUMENT, rank);
+ }
+
+ @Override
+ public ITypeAnnotationBuilder toWildcardBound() {
+ return walk(AnnotationTargetTypeConstants.WILDCARD_BOUND, 0);
+ }
+
+ @Override
+ public ITypeAnnotationBuilder toNextArrayDimension() {
+ return walk(AnnotationTargetTypeConstants.NEXT_ARRAY_DIMENSION, 0);
+ }
+
+ @Override
+ public ITypeAnnotationBuilder toNextNestedType() {
+ return walk(AnnotationTargetTypeConstants.NEXT_NESTED_TYPE, 0);
+ }
+
+ @Override
+ public IBinaryTypeAnnotation build(IBinaryAnnotation annotation) {
+ return new IndexBinaryTypeAnnotation(this.target, this.targetParameter, this.targetParameter2, getTypePath(), annotation);
+ }
+
+ private int[] getTypePath() {
+ if (this.length == 0) {
+ return IBinaryTypeAnnotation.NO_TYPE_PATH;
+ }
+
+ int[] result = new int[this.length * 2];
+
+ TypeAnnotationBuilder next = this;
+ while (next != null && next.length > 0) {
+ int writeIdx = (next.length - 1) * 2;
+ result[writeIdx] = next.kind;
+ result[writeIdx + 1] = next.index;
+ next = next.parent;
+ }
+
+ return result;
+ }
+}

Back to the top