diff options
Diffstat (limited to 'org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java')
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; + } +} |